How to Use the `diagnose()` API Programmatically for Custom Analysis in React Doctor
The diagnose() function exported from react-doctor provides a fully-typed, programmatic interface that mirrors the CLI scan command, enabling custom analysis workflows by discovering React projects, running oxlint and knip runners in parallel, and returning a computed health score.
You can embed the millionco/react-doctor toolchain directly into Node.js scripts, CI pipelines, or custom dashboards by importing the diagnose() API from src/index.ts. This method handles project discovery, configuration loading, and diagnostic aggregation automatically, returning a structured result that includes lint errors, dead-code findings, and an overall project health rating.
Importing and Calling diagnose()
Import the public API entry point and invoke it with an absolute path to your React project root.
import { diagnose, clearCaches, AmbiguousProjectError, NoReactDependencyError } from 'react-doctor';
async function runAnalysis() {
try {
const result = await diagnose('/path/to/your/react/app', {
lint: true, // Enable oxlint (default: true)
deadCode: false, // Disable knip dead-code analysis
includePaths: ['src/**/*.tsx'], // Optional custom globs
});
console.log('Diagnostics:', result.diagnostics);
console.log('Score:', result.score?.score, result.score?.label);
console.log('Project:', result.project);
} catch (err) {
if (err instanceof AmbiguousProjectError) {
console.error('Multiple React projects found:', err.candidates);
} else if (err instanceof NoReactDependencyError) {
console.error('No React dependency detected.');
}
}
}
The function accepts a target directory string and an optional DiagnoseOptions object, returning a Promise that resolves to a DiagnoseResult containing diagnostics, score metadata, and project information.
Step-by-Step Execution Flow
According to the source code in src/index.ts, the diagnose() function executes an eight-stage analysis pipeline:
-
Resolve Target Directory –
resolveDiagnoseTarget(viasrc/utils/resolve-diagnose-target.ts) normalizes the input path, handling monorepo wrappers and respecting the optionalrootDirredirect fromreact-doctor.config.json. -
Load Configuration –
loadConfigWithSource(viasrc/utils/load-config.ts) reads the configuration file (or applies defaults) and merges it with any runtime overrides. -
Discover Project –
discoverProject(viasrc/utils/discover-project.ts) traverses up the filesystem to locate the nearestpackage.jsondeclaring a React dependency, extracting version and framework details. This stage throws ProjectNotFoundError, NoReactDependencyError, or AmbiguousProjectError if discovery fails. -
Determine Include Paths –
computeJsxIncludePathsandresolveLintIncludePathscalculate which JSX files oxlint should analyze based on the project structure and user configuration. -
Run Analysis Engines –
runOxlint(src/utils/run-oxlint.ts) andrunKnip(src/utils/run-knip.ts) execute in parallel usingPromise.allSettled(), ensuring a failure in one runner does not abort the entire scan. -
Merge and Filter –
mergeAndFilterDiagnostics(src/utils/merge-and-filter-diagnostics.ts) consolidates results, applies user-level suppressions, handles inline disables, and de-duplicates findings. -
Calculate Health Score –
calculateScore(src/utils/calculate-score.ts) aggregates rule severities into a 0-100 numeric health score with a descriptive label. -
Return Result – The function returns a DiagnoseResult object containing the full diagnostics array, ScoreResult, ProjectInfo, and elapsed time.
Handling Errors and Edge Cases
The discovery phase in src/utils/discover-project.ts validates the target environment strictly. You must catch specific error classes to handle Edge cases gracefully:
- AmbiguousProjectError – Thrown when multiple sub-projects contain React dependencies, requiring you to specify a more precise sub-directory from the provided
candidatesarray. - NoReactDependencyError – Indicates the target directory lacks a
package.jsonwith React listed in dependencies or devDependencies. - ProjectNotFoundError – Raised when no
package.jsonexists in the target or parent directories.
Always wrap calls in try/catch blocks when analyzing unknown or dynamically supplied paths.
Configuring Analysis Options
The DiagnoseOptions interface (defined in src/types.ts) allows granular control over the analysis behavior:
lint– Boolean flag to enable or disable oxlint execution (default:true).deadCode– Boolean flag to enable or disable knip dead-code detection (default:true).includePaths– Array of glob patterns to restrict which files are analyzed.respectInlineDisables– Boolean to toggle honoring inlineeslint-disablestyle comments.
const result = await diagnose('/monorepo/apps/web', {
lint: true,
deadCode: true,
includePaths: ['app/**/*.tsx', 'components/**/*.tsx'],
respectInlineDisables: false,
});
Managing Caches in Long-Running Processes
The react-doctor module maintains internal caches for parsed package.json files, configuration objects, and ignore patterns to improve performance. When implementing watch modes or running sequential analyses in persistent processes, you must invalidate these caches using the clearCaches() function before each new scan:
async function watchMode() {
while (true) {
clearCaches(); // Invalidate memoized reads
const result = await diagnose('/project', { lint: true });
await new Promise(r => setTimeout(r, 5000));
}
}
Failure to call clearCaches() will result in stale diagnostics if underlying files change between runs.
Exporting JSON Reports for Downstream Tooling
To generate the same JSON output format used by the CLI, import the toJsonReport utility and pass the DiagnoseResult:
import { diagnose } from 'react-doctor';
import { writeFileSync } from 'node:fs';
import { join } from 'node:path';
async function exportReport() {
const result = await diagnose('/my/monorepo/apps/web', { lint: true, deadCode: true });
const { toJsonReport } = await import('react-doctor');
const json = toJsonReport(result, { version: '1.0.0', mode: 'full' });
writeFileSync(join(process.cwd(), 'react-doctor-report.json'), JSON.stringify(json, null, 2));
}
This produces a standardized report compatible with CI artifacts and external monitoring systems.
Summary
- Import
diagnosefromsrc/index.tsto access the programmatic API inmillionco/react-doctor. - Pass an absolute path and optional DiagnoseOptions to control linting, dead-code analysis, and file inclusion.
- Handle specific errors (AmbiguousProjectError, NoReactDependencyError) to manage monorepos and invalid targets.
- Call
clearCaches()between runs in long-lived processes to ensure fresh results. - Access the full diagnostic array, health score, and project metadata via the returned DiagnoseResult object.
- Generate CLI-compatible JSON reports using the
toJsonReporthelper for integration with external dashboards.
Frequently Asked Questions
What is the difference between the CLI and the programmatic diagnose() API?
The CLI is a thin wrapper around the same diagnose() function implemented in src/index.ts. While the CLI handles argument parsing and stdout formatting, the programmatic API returns raw typed objects (DiagnoseResult, ProjectInfo) that you can process, filter, or transform in custom Node.js scripts without spawning child processes.
How do I analyze a specific package in a monorepo?
Pass the absolute path to the specific package subdirectory as the first argument to diagnose(). If multiple packages contain React dependencies and you pass a parent directory, the function throws AmbiguousProjectError. Catch this error and inspect the candidates property to select the correct subdirectory, or resolve the target explicitly using resolveDiagnoseTarget before calling diagnose().
Can I run only the linter without dead-code detection?
Yes. Set the deadCode option to false in your DiagnoseOptions object. This skips the runKnip execution phase while still running runOxlint (assuming lint remains true), reducing analysis time when you only need linting results.
How is the health score calculated?
The calculateScore function in src/utils/calculate-score.ts aggregates the severity of all diagnostics returned by oxlint and knip. It applies a weighted algorithm to error and warning counts, producing a 0-100 integer score where 100 indicates a perfectly healthy project with no detected issues. The score is returned as part of the ScoreResult object within the DiagnoseResult.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →