How React Doctor's Offline Mode Calculates Scores Without API Calls

React Doctor computes quality scores locally by analyzing diagnostic rules and applying penalty calculations, eliminating the need for network requests when the --offline flag is enabled.

React Doctor is a CLI tool that audits React applications for performance anti-patterns and dead code. When running in environments without internet access or when explicitly configured for isolation, the tool switches to a deterministic local scoring algorithm that processes diagnostic data entirely on your machine.

How the CLI Activates Offline Scoring

The offline workflow begins with option resolution in src/cli.ts. When you pass the --offline flag or when the tool detects a CI environment, the resolveCliScanOptions function (around line 176) merges CLI flags with user configuration to set ResolvedScanOptions.offline to true.

This boolean flows through the scan orchestration in src/scan.ts, where a conditional check at lines 817-819 selects the appropriate scoring path:

const scoreResult = options.offline
  ? calculateScoreLocally(diagnostics)
  : await calculateScore(diagnostics);

When options.offline is true, the execution bypasses the async API call entirely and invokes the synchronous calculateScoreLocally function instead.

The Local Scoring Algorithm

The pure-JavaScript implementation in src/utils/calculate-score-locally.ts converts diagnostic findings into a numeric score without external dependencies. The function aggregates linting results and dead-code analysis into a final rating through three distinct phases.

Extracting Unique Rule Sets

First, the algorithm analyzes the collected Diagnostic objects using collectUniqueRuleSets to identify distinct error and warning categories. Rather than counting individual occurrences, it focuses on unique rule violations to determine the penalty scope.

Applying the Penalty Formula

The scoring calculation (lines 49-53) uses constants defined in src/constants.ts:

  • PERFECT_SCORE: 100 (baseline)
  • ERROR_RULE_PENALTY: Deducted for each unique error rule
  • WARNING_RULE_PENALTY: Deducted for each unique warning rule

The formula subtracts the total penalty from the perfect score and clamps the result to a minimum of 0:

const score = Math.max(0, PERFECT_SCORE - 
  (uniqueErrors * ERROR_RULE_PENALTY) - 
  (uniqueWarnings * WARNING_RULE_PENALTY)
);

Mapping Scores to Labels

The numeric result maps to human-readable quality grades:

  • Great: High scores indicating minimal issues
  • Needs work: Moderate scores suggesting improvements required
  • Critical: Low scores requiring immediate attention

Fallback Behavior When APIs Fail

Even when running in standard mode, React Doctor includes defensive logic in src/utils/calculate-score.ts. The calculateScore function attempts remote evaluation via tryScoreFromApi, but automatically falls back to calculateScoreLocally if the network request fails or times out.

This ensures that CI pipelines never fail due to network connectivity issues, always receiving a deterministic score derived from local diagnostics.

Implementation Examples

Trigger offline mode via command line:


# Scan without network requests, score calculated locally

npx react-doctor scan . --offline

Use offline scoring programmatically:

import { scan } from "react-doctor";

// Force local calculation regardless of network status
await scan("./my-app", { offline: true });

Access the raw scoring utility directly:

import { calculateScoreLocally } from "react-doctor/src/utils/calculate-score-locally";
import type { Diagnostic } from "react-doctor/src/types";

const diagnostics: Diagnostic[] = [
  // Populate from lint/dead-code output
];

const { score, label } = calculateScoreLocally(diagnostics);
console.log(`Score: ${score} – ${label}`);

When offline mode is active, the CLI displays the banner defined by OFFLINE_MESSAGE in src/constants.ts: "Score calculated locally (offline mode)."

Summary

  • Offline activation occurs through --offline flags or CI auto-detection in src/cli.ts, stored in ResolvedScanOptions.offline
  • Score calculation happens in src/utils/calculate-score-locally.ts using penalty-based mathematics without HTTP requests
  • Algorithm details: Subtracts ERROR_RULE_PENALTY and WARNING_RULE_PENALTY multipliers from PERFECT_SCORE (100), clamps to ≥0
  • Graceful degradation: The remote scoring function in src/utils/calculate-score.ts automatically falls back to local calculation when APIs are unreachable
  • Zero network traffic: No calls to https://www.react.doctor/api/score occur when offline mode is enabled

Frequently Asked Questions

How does the penalty calculation work in offline mode?

The algorithm counts unique error and warning rules found in your diagnostics, then applies the formula: score = 100 - (uniqueErrors × errorPenalty) - (uniqueWarnings × warningPenalty). The result is clamped to zero if penalties exceed 100, producing a score between 0 and 100.

What happens if I run offline mode but the API is actually available?

When options.offline is true, the code in src/scan.ts (lines 817-819) explicitly routes to calculateScoreLocally, completely skipping the tryScoreFromApi call. Even if the network is healthy, no HTTP requests are attempted, ensuring complete isolation as requested.

Are offline scores comparable to API-generated scores?

Offline scores use the same PERFECT_SCORE baseline of 100 but may differ slightly from API-generated scores because the remote algorithm might weight rules differently or include additional heuristics. However, the local calculation provides a consistent, deterministic baseline for CI/CD pipelines and air-gapped environments.

Can I customize the penalty constants for local scoring?

The penalty values (ERROR_RULE_PENALTY, WARNING_RULE_PENALTY) are defined as constants in src/constants.ts. Currently, these are hardcoded into the package build, but you can view these values to understand how rule severity impacts your final score calculation.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →