react-doctor 0.1.6 → 0.2.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,28 @@
1
+ import { a as RuleContext, i as RuleVisitors } from "./index-CFzh1cBi.js";
2
+
3
+ //#region src/core/rules/lint/utils/rule-example.d.ts
4
+ interface RuleExample {
5
+ before: string;
6
+ after: string;
7
+ }
8
+ //#endregion
9
+ //#region src/core/rules/lint/utils/rule.d.ts
10
+ interface Rule {
11
+ recommendation: string;
12
+ examples?: RuleExample[];
13
+ create: (context: RuleContext) => RuleVisitors;
14
+ }
15
+ //#endregion
16
+ //#region src/core/rules/lint/utils/rule-plugin.d.ts
17
+ interface RulePlugin {
18
+ meta: {
19
+ name: string;
20
+ };
21
+ rules: Record<string, Rule>;
22
+ }
23
+ //#endregion
24
+ //#region src/core/rules/lint/rules.d.ts
25
+ declare const reactDoctorOxlintPlugin: RulePlugin;
26
+ //#endregion
27
+ export { RuleExample as i, RulePlugin as n, Rule as r, reactDoctorOxlintPlugin as t };
28
+ //# sourceMappingURL=rules-ebKa330H.d.ts.map
@@ -0,0 +1,69 @@
1
+ //#region src/constants.ts
2
+ const REACT_DOCTOR_CONFIG_FILENAME = "react-doctor.config.json";
3
+ const PACKAGE_JSON_FILENAME = "package.json";
4
+ const PACKAGE_JSON_CONFIG_KEY = "reactDoctor";
5
+ const WARNING_RULE_PENALTY = .5;
6
+ const SCORE_API_URL = "https://www.react.doctor/api/score";
7
+ const FETCH_TIMEOUT_MS = 1e4;
8
+ const MILLISECONDS_PER_SECOND = 1e3;
9
+ //#endregion
10
+ //#region src/core/score.ts
11
+ const getScoreLabel = (score) => {
12
+ if (score >= 75) return "Great";
13
+ if (score >= 50) return "Needs work";
14
+ return "Critical";
15
+ };
16
+ const rulePenalty = (severity, count) => {
17
+ return (severity === "error" ? 1 : WARNING_RULE_PENALTY) * Math.min(1 + Math.log2(count), 4);
18
+ };
19
+ const calculateScoreBreakdown = (diagnostics, options = {}) => {
20
+ const perfectScore = options.perfectScore ?? 100;
21
+ const perCategoryCap = options.perCategoryCap ?? 35;
22
+ if (diagnostics.length === 0) return {
23
+ score: perfectScore,
24
+ totalRawPenalty: 0,
25
+ totalCappedPenalty: 0,
26
+ perCategory: []
27
+ };
28
+ const ruleCounts = /* @__PURE__ */ new Map();
29
+ const ruleSeverities = /* @__PURE__ */ new Map();
30
+ const ruleCategories = /* @__PURE__ */ new Map();
31
+ for (const diagnostic of diagnostics) {
32
+ const ruleKey = `${diagnostic.plugin}/${diagnostic.rule}`;
33
+ ruleCounts.set(ruleKey, (ruleCounts.get(ruleKey) ?? 0) + 1);
34
+ if (diagnostic.severity === "error" || !ruleSeverities.has(ruleKey)) ruleSeverities.set(ruleKey, diagnostic.severity);
35
+ if (!ruleCategories.has(ruleKey)) ruleCategories.set(ruleKey, diagnostic.category);
36
+ }
37
+ const categoryAggregates = /* @__PURE__ */ new Map();
38
+ for (const [ruleKey, count] of ruleCounts) {
39
+ const severity = ruleSeverities.get(ruleKey) ?? "warning";
40
+ const category = ruleCategories.get(ruleKey) ?? "uncategorized";
41
+ const penalty = rulePenalty(severity, count);
42
+ const existing = categoryAggregates.get(category) ?? {
43
+ rawPenalty: 0,
44
+ ruleKeys: 0
45
+ };
46
+ existing.rawPenalty += penalty;
47
+ existing.ruleKeys += 1;
48
+ categoryAggregates.set(category, existing);
49
+ }
50
+ const perCategory = [...categoryAggregates.entries()].map(([category, aggregate]) => ({
51
+ category,
52
+ rawPenalty: aggregate.rawPenalty,
53
+ cappedPenalty: Math.min(aggregate.rawPenalty, perCategoryCap),
54
+ ruleKeys: aggregate.ruleKeys
55
+ })).toSorted((first, second) => second.cappedPenalty - first.cappedPenalty);
56
+ const totalRawPenalty = perCategory.reduce((total, entry) => total + entry.rawPenalty, 0);
57
+ const totalCappedPenalty = perCategory.reduce((total, entry) => total + entry.cappedPenalty, 0);
58
+ return {
59
+ score: Math.max(0, Math.min(perfectScore, Math.round(perfectScore - totalCappedPenalty))),
60
+ totalRawPenalty,
61
+ totalCappedPenalty,
62
+ perCategory
63
+ };
64
+ };
65
+ const calculateScore = (diagnostics, options = {}) => calculateScoreBreakdown(diagnostics, options).score;
66
+ //#endregion
67
+ export { FETCH_TIMEOUT_MS as a, PACKAGE_JSON_FILENAME as c, rulePenalty as i, REACT_DOCTOR_CONFIG_FILENAME as l, calculateScoreBreakdown as n, MILLISECONDS_PER_SECOND as o, getScoreLabel as r, PACKAGE_JSON_CONFIG_KEY as s, calculateScore as t, SCORE_API_URL as u };
68
+
69
+ //# sourceMappingURL=score-CzbtoFAu.js.map
@@ -0,0 +1,35 @@
1
+ //#region src/core/score.d.ts
2
+ /**
3
+ * Log-scaled per rule, capped per category. One issue still costs; 1000
4
+ * issues don't zero a big repo. Categories cap so a single noisy area
5
+ * (oxlint, codebase) can't single-handedly tank the score.
6
+ */
7
+ interface ScoreDiagnostic {
8
+ plugin: string;
9
+ rule: string;
10
+ category: string;
11
+ severity: "error" | "warning";
12
+ }
13
+ interface CalculateScoreOptions {
14
+ perfectScore?: number;
15
+ perCategoryCap?: number;
16
+ }
17
+ interface ScoreCategoryBreakdown {
18
+ category: string;
19
+ rawPenalty: number;
20
+ cappedPenalty: number;
21
+ ruleKeys: number;
22
+ }
23
+ interface ScoreBreakdown {
24
+ score: number;
25
+ totalRawPenalty: number;
26
+ totalCappedPenalty: number;
27
+ perCategory: ScoreCategoryBreakdown[];
28
+ }
29
+ declare const getScoreLabel: (score: number) => string;
30
+ declare const rulePenalty: (severity: "error" | "warning", count: number) => number;
31
+ declare const calculateScoreBreakdown: (diagnostics: ScoreDiagnostic[], options?: CalculateScoreOptions) => ScoreBreakdown;
32
+ declare const calculateScore: (diagnostics: ScoreDiagnostic[], options?: CalculateScoreOptions) => number;
33
+ //#endregion
34
+ export { CalculateScoreOptions, ScoreBreakdown, ScoreCategoryBreakdown, ScoreDiagnostic, calculateScore, calculateScoreBreakdown, getScoreLabel, rulePenalty };
35
+ //# sourceMappingURL=score.d.ts.map
package/dist/score.js ADDED
@@ -0,0 +1,2 @@
1
+ import { i as rulePenalty, n as calculateScoreBreakdown, r as getScoreLabel, t as calculateScore } from "./score-CzbtoFAu.js";
2
+ export { calculateScore, calculateScoreBreakdown, getScoreLabel, rulePenalty };
package/dist/sdk.d.ts ADDED
@@ -0,0 +1,90 @@
1
+ import { CalculateScoreOptions, ScoreBreakdown, ScoreCategoryBreakdown, ScoreDiagnostic, calculateScore, calculateScoreBreakdown, getScoreLabel } from "./score.js";
2
+ import { A as ReactProjectFramework, C as ReactDoctorIssue, D as ReactDoctorResult, E as ReactDoctorJsonReportSummary, M as SourceLocation, O as ReactDoctorRuleSelection, S as ReactDoctorIgnoreOverride, T as ReactDoctorJsonReport, _ as LoadedReactDoctorConfig, a as RuleContext, b as ReactDoctorFailOnLevel, c as ReactDoctorRuleRegistry, d as ReactDoctorRule, f as ReactDoctorRuleContext, g as InspectReactProjectOptions, h as ReactDoctorRuleResult, i as RuleVisitors, j as ReactProjectInfo, k as ReactDoctorScore, l as RuleRegistryOptions, m as ReactDoctorRuleMetadata, n as createRuleRegistry, o as EsTreeNode, p as ReactDoctorRuleExample, r as ruleRegistry, s as reactProjectStructureRule, t as coreRules, u as defineRule, v as ReactDoctorCheckResult, w as ReactDoctorIssueSource, x as ReactDoctorIgnoreConfig, y as ReactDoctorConfig } from "./index-CFzh1cBi.js";
3
+ import { _ as ReactDoctorRunnerUnavailableError, a as ReactDoctorCheckSkippedError, b as isReactDoctorError, c as ReactDoctorError, d as ReactDoctorInvalidConfigError, f as ReactDoctorNoReactDependencyError, g as ReactDoctorReportError, h as ReactDoctorProjectNotFoundError, i as ReactDoctorCheckFailedError, l as ReactDoctorErrorInfo, m as ReactDoctorProjectError, n as ReactDoctorCancelledError, o as ReactDoctorConfigError, p as ReactDoctorPackageJsonNotFoundError, r as ReactDoctorCheckError, s as ReactDoctorConfigNotFoundError, t as ReactDoctorAmbiguousProjectError, u as ReactDoctorErrorOptions, v as ReactDoctorTimeoutError, x as toReactDoctorErrorInfo, y as ReactDoctorUnsupportedRuntimeError } from "./errors-ZdckckLr.js";
4
+ import { C as shouldEnableReactDoctorOxlintRule, S as reactPeerRangeMinMajor, _ as ReactDoctorOxlintProjectInfo, a as BUILTIN_REACT_OXLINT_RULES, b as buildReactDoctorOxlintCapabilities, c as NEXTJS_OXLINT_RULES, d as REACT_DOCTOR_CUSTOM_OXLINT_RULES, f as REACT_NATIVE_OXLINT_RULES, g as ReactDoctorOxlintJsPluginEntry, h as ReactDoctorOxlintGeneratedConfig, i as BUILTIN_OXLINT_RULES, l as OxlintRuleSeverityMap, m as ReactDoctorOxlintFramework, n as ALL_REACT_DOCTOR_OXLINT_RULE_KEYS, o as CURATED_OXLINT_RULES, p as ReactDoctorOxlintConfigOptions, r as BUILTIN_A11Y_OXLINT_RULES, s as GLOBAL_REACT_DOCTOR_OXLINT_RULES, t as reactDoctorEslintPlugin, u as REACT_COMPILER_OXLINT_RULES, v as TANSTACK_QUERY_OXLINT_RULES, x as createReactDoctorOxlintConfig, y as TANSTACK_START_OXLINT_RULES } from "./eslint-plugin-BIjw2MeW.js";
5
+ import { i as RuleExample, n as RulePlugin, r as Rule, t as reactDoctorOxlintPlugin } from "./rules-ebKa330H.js";
6
+ import { DiagnoseOptions, DiagnoseResult, Diagnostic, ProjectInfo, ScoreResult, clearCaches, diagnose } from "./compat.js";
7
+
8
+ //#region src/core/rules/codebase/dead-code.d.ts
9
+ declare const DEAD_CODE_RULE_ID = "react-doctor/codebase/dead-code";
10
+ //#endregion
11
+ //#region src/core/rules/codebase/dependencies.d.ts
12
+ declare const DEPENDENCIES_RULE_ID = "react-doctor/codebase/dependencies";
13
+ //#endregion
14
+ //#region src/core/rules/codebase/react-architecture.d.ts
15
+ declare const REACT_ARCHITECTURE_RULE_ID = "react-doctor/codebase/react-architecture";
16
+ //#endregion
17
+ //#region src/core/rules/lint/utils/parsed-rgb.d.ts
18
+ interface ParsedRgb {
19
+ red: number;
20
+ green: number;
21
+ blue: number;
22
+ }
23
+ //#endregion
24
+ //#region src/core/rules/lint/metadata.d.ts
25
+ interface OxlintRuleMetadata extends ReactDoctorRuleMetadata {
26
+ oxlintRuleName: string;
27
+ oxlintRuleKey: string;
28
+ }
29
+ declare const REACT_DOCTOR_OXLINT_PLUGIN_NAMESPACE = "react-doctor";
30
+ declare const REACT_DOCTOR_OXLINT_RULE_ID_PREFIX = "oxlint/react-doctor/";
31
+ declare const reactDoctorOxlintRuleMetadata: OxlintRuleMetadata[];
32
+ //#endregion
33
+ //#region src/core/config.d.ts
34
+ declare const clearReactDoctorConfigCache: () => void;
35
+ declare const loadReactDoctorConfig: (startDirectory: string) => Promise<LoadedReactDoctorConfig | null>;
36
+ declare const resolveConfigRootDirectory: (loadedConfig: LoadedReactDoctorConfig | null, fallbackDirectory: string) => Promise<string>;
37
+ //#endregion
38
+ //#region src/core/reports.d.ts
39
+ declare const calculateReactDoctorScore: (issues: ReactDoctorIssue[]) => ReactDoctorScore;
40
+ declare const summarizeReactDoctorResult: (result: ReactDoctorResult) => ReactDoctorJsonReportSummary;
41
+ declare const buildReactDoctorJsonReport: (result: ReactDoctorResult) => ReactDoctorJsonReport;
42
+ //#endregion
43
+ //#region src/core/project.d.ts
44
+ declare const parseReactMajorVersion: (version: string | null) => number | null;
45
+ declare const toOxlintProjectInfo: (project: ReactProjectInfo) => ReactDoctorOxlintProjectInfo;
46
+ declare const discoverReactProject: (rootDirectory: string) => Promise<ReactProjectInfo>;
47
+ //#endregion
48
+ //#region src/core/diagnostics.d.ts
49
+ interface FilterReactDoctorIssuesOptions {
50
+ jsxImportSource?: string;
51
+ }
52
+ declare const filterReactDoctorIssues: (issues: ReactDoctorIssue[], config: ReactDoctorConfig, rootDirectory: string, readSourceLines?: (filePath: string) => string[] | undefined, options?: FilterReactDoctorIssuesOptions) => ReactDoctorIssue[];
53
+ //#endregion
54
+ //#region src/core/runners/check-ids.d.ts
55
+ declare const OXLINT_CHECK_ID = "react-doctor/oxlint";
56
+ //#endregion
57
+ //#region src/core/runners/oxlint.d.ts
58
+ interface RunOxlintOptions {
59
+ rootDirectory: string;
60
+ includePaths?: string[];
61
+ excludePatterns?: string[];
62
+ project: ReactDoctorOxlintProjectInfo;
63
+ customRulesOnly?: boolean;
64
+ includeEcosystemRules?: boolean;
65
+ adoptExistingLintConfig?: boolean;
66
+ ignoredTags?: ReadonlySet<string>;
67
+ signal?: AbortSignal;
68
+ }
69
+ declare const runOxlint: (options: RunOxlintOptions) => Promise<ReactDoctorIssue[]>;
70
+ //#endregion
71
+ //#region src/sdk/create-react-doctor.d.ts
72
+ interface CreateReactDoctorOptions {
73
+ rootDirectory?: string;
74
+ includePaths?: string[];
75
+ excludePatterns?: string[];
76
+ rules?: InspectReactProjectOptions["rules"];
77
+ lint?: boolean;
78
+ deadCode?: boolean;
79
+ customRulesOnly?: boolean;
80
+ respectInlineDisables?: boolean;
81
+ offline?: boolean;
82
+ }
83
+ interface ReactDoctor {
84
+ inspect: (options?: InspectReactProjectOptions) => Promise<ReactDoctorResult>;
85
+ }
86
+ declare const createReactDoctor: (options?: CreateReactDoctorOptions) => ReactDoctor;
87
+ declare const inspectReactProject: (options?: InspectReactProjectOptions) => Promise<ReactDoctorResult>;
88
+ //#endregion
89
+ export { ALL_REACT_DOCTOR_OXLINT_RULE_KEYS, BUILTIN_A11Y_OXLINT_RULES, BUILTIN_OXLINT_RULES, BUILTIN_REACT_OXLINT_RULES, CURATED_OXLINT_RULES, type CalculateScoreOptions, type CreateReactDoctorOptions, DEAD_CODE_RULE_ID, DEPENDENCIES_RULE_ID, type DiagnoseOptions, type DiagnoseResult, type Diagnostic, GLOBAL_REACT_DOCTOR_OXLINT_RULES, type InspectReactProjectOptions, NEXTJS_OXLINT_RULES, OXLINT_CHECK_ID, type EsTreeNode as OxlintEsTreeNode, type ParsedRgb as OxlintParsedRgb, type Rule as OxlintRule, type RuleContext as OxlintRuleContext, type RuleExample as OxlintRuleExample, type OxlintRuleMetadata, type RulePlugin as OxlintRulePlugin, type OxlintRuleSeverityMap, type RuleVisitors as OxlintRuleVisitors, type ProjectInfo, REACT_ARCHITECTURE_RULE_ID, REACT_COMPILER_OXLINT_RULES, REACT_DOCTOR_CUSTOM_OXLINT_RULES, REACT_DOCTOR_OXLINT_PLUGIN_NAMESPACE, REACT_DOCTOR_OXLINT_RULE_ID_PREFIX, REACT_NATIVE_OXLINT_RULES, type ReactDoctor, ReactDoctorAmbiguousProjectError, ReactDoctorCancelledError, ReactDoctorCheckError, ReactDoctorCheckFailedError, type ReactDoctorCheckResult, ReactDoctorCheckSkippedError, type ReactDoctorConfig, ReactDoctorConfigError, ReactDoctorConfigNotFoundError, ReactDoctorError, type ReactDoctorErrorInfo, type ReactDoctorErrorOptions, type ReactDoctorFailOnLevel, type ReactDoctorIgnoreConfig, type ReactDoctorIgnoreOverride, ReactDoctorInvalidConfigError, type ReactDoctorIssue, type ReactDoctorIssueSource, type ReactDoctorJsonReport, type ReactDoctorJsonReportSummary, ReactDoctorNoReactDependencyError, type ReactDoctorOxlintConfigOptions, type ReactDoctorOxlintFramework, type ReactDoctorOxlintGeneratedConfig, type ReactDoctorOxlintJsPluginEntry, type ReactDoctorOxlintProjectInfo, ReactDoctorPackageJsonNotFoundError, ReactDoctorProjectError, ReactDoctorProjectNotFoundError, ReactDoctorReportError, type ReactDoctorResult, type ReactDoctorRule, type ReactDoctorRuleContext, type ReactDoctorRuleExample, type ReactDoctorRuleMetadata, type ReactDoctorRuleRegistry, type ReactDoctorRuleResult, type ReactDoctorRuleSelection, ReactDoctorRunnerUnavailableError, type ReactDoctorScore, ReactDoctorTimeoutError, ReactDoctorUnsupportedRuntimeError, type ReactProjectFramework, type ReactProjectInfo, type RuleRegistryOptions, type RunOxlintOptions, type ScoreBreakdown, type ScoreCategoryBreakdown, type ScoreDiagnostic, type ScoreResult, type SourceLocation, TANSTACK_QUERY_OXLINT_RULES, TANSTACK_START_OXLINT_RULES, buildReactDoctorJsonReport, buildReactDoctorOxlintCapabilities, calculateReactDoctorScore, calculateScore, calculateScoreBreakdown, clearCaches, clearReactDoctorConfigCache, coreRules, createReactDoctor, createReactDoctorOxlintConfig, createRuleRegistry, defineRule, diagnose, discoverReactProject, filterReactDoctorIssues, getScoreLabel, inspectReactProject, isReactDoctorError, loadReactDoctorConfig, parseReactMajorVersion, reactDoctorEslintPlugin, reactDoctorOxlintPlugin, reactDoctorOxlintRuleMetadata, reactPeerRangeMinMajor, reactProjectStructureRule, resolveConfigRootDirectory, ruleRegistry, runOxlint, shouldEnableReactDoctorOxlintRule, summarizeReactDoctorResult, toOxlintProjectInfo, toReactDoctorErrorInfo };
90
+ //# sourceMappingURL=sdk.d.ts.map
package/dist/sdk.js ADDED
@@ -0,0 +1,17 @@
1
+ import { n as calculateScoreBreakdown, r as getScoreLabel, t as calculateScore } from "./score-CzbtoFAu.js";
2
+ import { A as ReactDoctorProjectError, C as ReactDoctorCheckSkippedError, D as ReactDoctorInvalidConfigError, E as ReactDoctorError, F as ReactDoctorUnsupportedRuntimeError, I as isReactDoctorError, L as toReactDoctorErrorInfo, M as ReactDoctorReportError, N as ReactDoctorRunnerUnavailableError, O as ReactDoctorNoReactDependencyError, P as ReactDoctorTimeoutError, S as ReactDoctorCheckFailedError, T as ReactDoctorConfigNotFoundError, a as DEPENDENCIES_RULE_ID, b as ReactDoctorCancelledError, c as reactProjectStructureRule, i as REACT_ARCHITECTURE_RULE_ID, j as ReactDoctorProjectNotFoundError, k as ReactDoctorPackageJsonNotFoundError, l as reactDoctorOxlintPlugin, m as defineRule, n as createRuleRegistry, o as DEAD_CODE_RULE_ID, r as ruleRegistry, t as coreRules, w as ReactDoctorConfigError, x as ReactDoctorCheckError, y as ReactDoctorAmbiguousProjectError } from "./rules-DwGNObf8.js";
3
+ import { a as filterReactDoctorIssues, c as toOxlintProjectInfo, d as summarizeReactDoctorResult, f as OXLINT_CHECK_ID, h as resolveConfigRootDirectory, i as runOxlint, l as buildReactDoctorJsonReport, m as loadReactDoctorConfig, n as diagnose, o as discoverReactProject, p as clearReactDoctorConfigCache, r as inspectReactProjectCore, s as parseReactMajorVersion, t as clearCaches, u as calculateReactDoctorScore } from "./compat-DLFL9-Or.js";
4
+ import { _ as createReactDoctorOxlintConfig, a as BUILTIN_A11Y_OXLINT_RULES, b as shouldEnableReactDoctorOxlintRule, c as CURATED_OXLINT_RULES, d as REACT_COMPILER_OXLINT_RULES, f as REACT_DOCTOR_CUSTOM_OXLINT_RULES, g as buildReactDoctorOxlintCapabilities, h as TANSTACK_START_OXLINT_RULES, i as ALL_REACT_DOCTOR_OXLINT_RULE_KEYS, l as GLOBAL_REACT_DOCTOR_OXLINT_RULES, m as TANSTACK_QUERY_OXLINT_RULES, n as REACT_DOCTOR_OXLINT_RULE_ID_PREFIX, o as BUILTIN_OXLINT_RULES, p as REACT_NATIVE_OXLINT_RULES, r as reactDoctorOxlintRuleMetadata, s as BUILTIN_REACT_OXLINT_RULES, t as REACT_DOCTOR_OXLINT_PLUGIN_NAMESPACE, u as NEXTJS_OXLINT_RULES, y as reactPeerRangeMinMajor } from "./metadata-Bz_yY064.js";
5
+ import reactDoctorEslintPlugin from "./eslint-plugin.js";
6
+ //#region src/sdk/create-react-doctor.ts
7
+ const mergeInspectOptions = (defaults, options) => ({
8
+ ...defaults,
9
+ ...options,
10
+ rootDirectory: options.rootDirectory ?? defaults.rootDirectory
11
+ });
12
+ const createReactDoctor = (options = {}) => ({ inspect: (runOptions = {}) => inspectReactProjectCore(mergeInspectOptions(options, runOptions)) });
13
+ const inspectReactProject = (options = {}) => createReactDoctor(options).inspect();
14
+ //#endregion
15
+ export { ALL_REACT_DOCTOR_OXLINT_RULE_KEYS, BUILTIN_A11Y_OXLINT_RULES, BUILTIN_OXLINT_RULES, BUILTIN_REACT_OXLINT_RULES, CURATED_OXLINT_RULES, DEAD_CODE_RULE_ID, DEPENDENCIES_RULE_ID, GLOBAL_REACT_DOCTOR_OXLINT_RULES, NEXTJS_OXLINT_RULES, OXLINT_CHECK_ID, REACT_ARCHITECTURE_RULE_ID, REACT_COMPILER_OXLINT_RULES, REACT_DOCTOR_CUSTOM_OXLINT_RULES, REACT_DOCTOR_OXLINT_PLUGIN_NAMESPACE, REACT_DOCTOR_OXLINT_RULE_ID_PREFIX, REACT_NATIVE_OXLINT_RULES, ReactDoctorAmbiguousProjectError, ReactDoctorCancelledError, ReactDoctorCheckError, ReactDoctorCheckFailedError, ReactDoctorCheckSkippedError, ReactDoctorConfigError, ReactDoctorConfigNotFoundError, ReactDoctorError, ReactDoctorInvalidConfigError, ReactDoctorNoReactDependencyError, ReactDoctorPackageJsonNotFoundError, ReactDoctorProjectError, ReactDoctorProjectNotFoundError, ReactDoctorReportError, ReactDoctorRunnerUnavailableError, ReactDoctorTimeoutError, ReactDoctorUnsupportedRuntimeError, TANSTACK_QUERY_OXLINT_RULES, TANSTACK_START_OXLINT_RULES, buildReactDoctorJsonReport, buildReactDoctorOxlintCapabilities, calculateReactDoctorScore, calculateScore, calculateScoreBreakdown, clearCaches, clearReactDoctorConfigCache, coreRules, createReactDoctor, createReactDoctorOxlintConfig, createRuleRegistry, defineRule, diagnose, discoverReactProject, filterReactDoctorIssues, getScoreLabel, inspectReactProject, isReactDoctorError, loadReactDoctorConfig, parseReactMajorVersion, reactDoctorEslintPlugin, reactDoctorOxlintPlugin, reactDoctorOxlintRuleMetadata, reactPeerRangeMinMajor, reactProjectStructureRule, resolveConfigRootDirectory, ruleRegistry, runOxlint, shouldEnableReactDoctorOxlintRule, summarizeReactDoctorResult, toOxlintProjectInfo, toReactDoctorErrorInfo };
16
+
17
+ //# sourceMappingURL=sdk.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-doctor",
3
- "version": "0.1.6",
3
+ "version": "0.2.0-beta.1",
4
4
  "description": "Diagnose and fix React codebases for security, performance, correctness, accessibility, bundle-size, and architecture issues",
5
5
  "keywords": [
6
6
  "accessibility",
@@ -41,56 +41,51 @@
41
41
  "sideEffects": false,
42
42
  "exports": {
43
43
  ".": {
44
- "types": "./dist/cli.d.ts",
45
- "default": "./dist/cli.js"
44
+ "types": "./dist/sdk.d.ts",
45
+ "default": "./dist/sdk.js"
46
46
  },
47
47
  "./api": {
48
- "types": "./dist/index.d.ts",
49
- "default": "./dist/index.js"
48
+ "types": "./dist/compat.d.ts",
49
+ "default": "./dist/compat.js"
50
50
  },
51
- "./oxlint-plugin": {
52
- "types": "./dist/react-doctor-plugin.d.ts",
53
- "default": "./dist/react-doctor-plugin.js"
51
+ "./score": {
52
+ "types": "./dist/score.d.ts",
53
+ "default": "./dist/score.js"
54
54
  },
55
55
  "./eslint-plugin": {
56
56
  "types": "./dist/eslint-plugin.d.ts",
57
57
  "default": "./dist/eslint-plugin.js"
58
+ },
59
+ "./oxlint-plugin": {
60
+ "types": "./dist/oxlint-plugin.d.ts",
61
+ "default": "./dist/oxlint-plugin.js"
58
62
  }
59
63
  },
60
64
  "dependencies": {
61
65
  "agent-install": "0.0.5",
62
66
  "commander": "^14.0.3",
63
- "knip": "^6.10.0",
67
+ "eslint-plugin-react-hooks": "^7.1.1",
64
68
  "ora": "^9.4.0",
69
+ "oxc-parser": "^0.130.0",
70
+ "oxc-resolver": "^11.19.1",
65
71
  "oxlint": "^1.63.0",
66
72
  "picocolors": "^1.1.1",
67
- "prompts": "^2.4.2",
68
- "typescript": ">=5.0.4 <7"
73
+ "prompts": "^2.4.2"
69
74
  },
70
75
  "devDependencies": {
76
+ "@oxc-project/types": "^0.130.0",
77
+ "@types/node": "^25.6.0",
71
78
  "@types/prompts": "^2.4.9",
72
- "eslint-plugin-react-hooks": "^7.1.1",
73
- "eslint-plugin-react-you-might-not-need-an-effect": "^0.10.1"
74
- },
75
- "peerDependencies": {
76
- "eslint-plugin-react-hooks": "^6 || ^7",
77
- "eslint-plugin-react-you-might-not-need-an-effect": "^0.10"
78
- },
79
- "peerDependenciesMeta": {
80
- "eslint-plugin-react-hooks": {
81
- "optional": true
82
- },
83
- "eslint-plugin-react-you-might-not-need-an-effect": {
84
- "optional": true
85
- }
79
+ "vite-plus": "^0.1.15"
86
80
  },
87
81
  "engines": {
88
- "node": ">=22"
82
+ "node": ">=22.12.0"
89
83
  },
90
84
  "scripts": {
91
85
  "dev": "vp pack --watch",
92
86
  "build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && NODE_ENV=production vp pack",
93
87
  "typecheck": "tsc --noEmit",
94
- "test": "vp test run"
88
+ "test": "vp test run",
89
+ "test:regression": "node --experimental-strip-types --no-warnings scripts/run-regression.ts"
95
90
  }
96
91
  }
package/dist/index.d.ts DELETED
@@ -1,272 +0,0 @@
1
- //#region src/types.d.ts
2
- type FailOnLevel = "error" | "warning" | "none";
3
- type Framework = "nextjs" | "vite" | "cra" | "remix" | "gatsby" | "expo" | "react-native" | "tanstack-start" | "unknown";
4
- interface ProjectInfo {
5
- rootDirectory: string;
6
- projectName: string;
7
- reactVersion: string | null;
8
- framework: Framework;
9
- hasTypeScript: boolean;
10
- hasReactCompiler: boolean;
11
- hasTanStackQuery: boolean;
12
- sourceFileCount: number;
13
- }
14
- interface Diagnostic {
15
- filePath: string;
16
- plugin: string;
17
- rule: string;
18
- severity: "error" | "warning";
19
- message: string;
20
- help: string;
21
- url?: string;
22
- line: number;
23
- column: number;
24
- category: string;
25
- suppressionHint?: string;
26
- }
27
- interface ScoreResult {
28
- score: number;
29
- label: string;
30
- }
31
- interface DiagnoseOptions {
32
- lint?: boolean;
33
- deadCode?: boolean;
34
- verbose?: boolean;
35
- includePaths?: string[];
36
- /**
37
- * Per-call override for `ReactDoctorConfig.respectInlineDisables`.
38
- * See that field's docs for the full contract.
39
- */
40
- respectInlineDisables?: boolean;
41
- }
42
- interface DiagnoseResult {
43
- diagnostics: Diagnostic[];
44
- score: ScoreResult | null;
45
- project: ProjectInfo;
46
- elapsedMilliseconds: number;
47
- }
48
- interface ScanResult {
49
- diagnostics: Diagnostic[];
50
- score: ScoreResult | null;
51
- skippedChecks: string[];
52
- project: ProjectInfo;
53
- elapsedMilliseconds: number;
54
- }
55
- interface DiffInfo {
56
- currentBranch: string;
57
- baseBranch: string;
58
- changedFiles: string[];
59
- isCurrentChanges?: boolean;
60
- }
61
- interface ReactDoctorIgnoreOverride {
62
- files: string[];
63
- rules?: string[];
64
- }
65
- interface ReactDoctorIgnoreConfig {
66
- rules?: string[];
67
- files?: string[];
68
- overrides?: ReactDoctorIgnoreOverride[];
69
- }
70
- interface ReactDoctorConfig {
71
- ignore?: ReactDoctorIgnoreConfig;
72
- lint?: boolean;
73
- deadCode?: boolean;
74
- verbose?: boolean;
75
- diff?: boolean | string;
76
- failOn?: FailOnLevel;
77
- customRulesOnly?: boolean;
78
- share?: boolean;
79
- /**
80
- * Redirect react-doctor at a different project directory than the one
81
- * it was invoked against. Resolved relative to the location of the
82
- * config file that declared this field (NOT relative to the CWD), so
83
- * the redirect is stable no matter where the CLI / `diagnose()` is
84
- * run from. Absolute paths are used as-is.
85
- *
86
- * Typical use: a monorepo root holds the only `react-doctor.config.json`
87
- * (so editor tooling and child commands all find it), but the React
88
- * app lives in `apps/web`. Setting `"rootDir": "apps/web"` makes
89
- * every invocation that loads this config scan that subproject
90
- * without anyone needing to `cd` first or pass an explicit path.
91
- *
92
- * Ignored if the resolved path does not exist or is not a directory
93
- * (a warning is emitted and react-doctor falls back to the originally
94
- * requested directory).
95
- */
96
- rootDir?: string;
97
- textComponents?: string[];
98
- /**
99
- * Names of components that safely route string-only children through a
100
- * React Native `<Text>` internally (e.g. `heroui-native`'s `Button`,
101
- * which stringifies its children and renders them through a
102
- * `ButtonLabel` → `Text`). For listed components, `rn-no-raw-text`
103
- * is suppressed ONLY when the wrapper's children are entirely
104
- * stringifiable (no nested JSX elements). A wrapper with mixed
105
- * children — e.g. `<Button>Save<Icon /></Button>` — still reports,
106
- * because the wrapper can't safely route raw text alongside a
107
- * sibling JSX element.
108
- *
109
- * Use this instead of `textComponents` when the component is not
110
- * itself a text element but is known to wrap its string children
111
- * in one. `textComponents` is the broader escape hatch and
112
- * suppresses regardless of sibling content.
113
- */
114
- rawTextWrapperComponents?: string[];
115
- /**
116
- * Whether to respect inline `// eslint-disable*`, `// oxlint-disable*`,
117
- * and `// react-doctor-disable*` comments in source files. Default: `true`.
118
- *
119
- * File-level ignores (`.gitignore`, `.eslintignore`, `.oxlintignore`,
120
- * `.prettierignore`, `.gitattributes` `linguist-vendored` /
121
- * `linguist-generated`) are ALWAYS honored regardless of this option
122
- * — they typically point at vendored or generated code that
123
- * genuinely shouldn't be linted at all.
124
- *
125
- * Set to `false` for "audit mode": every inline suppression is
126
- * neutralized so react-doctor reports every diagnostic regardless
127
- * of historical hide-comments.
128
- */
129
- respectInlineDisables?: boolean;
130
- /**
131
- * Whether to merge the user's existing JSON oxlint / eslint config
132
- * (`.oxlintrc.json` or `.eslintrc.json`) into the generated scan via
133
- * oxlint's `extends` field, so diagnostics from those rules count
134
- * toward the react-doctor score. Default: `true`.
135
- *
136
- * Detection runs at the scanned directory and walks up to the
137
- * nearest project boundary (`.git` directory or monorepo root).
138
- * The first match wins, with `.oxlintrc.json` preferred over
139
- * `.eslintrc.json`.
140
- *
141
- * Only JSON-format configs are supported because oxlint's `extends`
142
- * cannot evaluate JS/TS configs. Flat configs (`eslint.config.js`),
143
- * legacy JS configs (`.eslintrc.js`), and TypeScript oxlint configs
144
- * (`oxlint.config.ts`) are silently skipped.
145
- *
146
- * Category-level enables in the user's config (`"categories": { ... }`)
147
- * are NOT honored — react-doctor explicitly disables every oxlint
148
- * category to keep the scan scoped to its curated rule surface, and
149
- * local config wins over `extends`. Use rule-level severities to
150
- * fold rules into the score.
151
- *
152
- * Set to `false` to scan only react-doctor's curated rule set.
153
- */
154
- adoptExistingLintConfig?: boolean;
155
- }
156
- type JsonReportMode = "full" | "diff" | "staged";
157
- interface JsonReportDiffInfo {
158
- baseBranch: string;
159
- currentBranch: string;
160
- changedFileCount: number;
161
- isCurrentChanges: boolean;
162
- }
163
- interface JsonReportProjectEntry {
164
- directory: string;
165
- project: ProjectInfo;
166
- diagnostics: Diagnostic[];
167
- score: ScoreResult | null;
168
- skippedChecks: string[];
169
- elapsedMilliseconds: number;
170
- }
171
- interface JsonReportSummary {
172
- errorCount: number;
173
- warningCount: number;
174
- affectedFileCount: number;
175
- totalDiagnosticCount: number;
176
- score: number | null;
177
- scoreLabel: string | null;
178
- }
179
- interface JsonReportError {
180
- message: string;
181
- name: string;
182
- chain: string[];
183
- }
184
- interface JsonReport {
185
- schemaVersion: 1;
186
- version: string;
187
- ok: boolean;
188
- directory: string;
189
- mode: JsonReportMode;
190
- diff: JsonReportDiffInfo | null;
191
- projects: JsonReportProjectEntry[];
192
- /**
193
- * Flattened across `projects[].diagnostics` for convenience. Equivalent to
194
- * `projects.flatMap((project) => project.diagnostics)`.
195
- */
196
- diagnostics: Diagnostic[];
197
- summary: JsonReportSummary;
198
- elapsedMilliseconds: number;
199
- error: JsonReportError | null;
200
- }
201
- //#endregion
202
- //#region src/utils/build-json-report.d.ts
203
- interface BuildJsonReportInput {
204
- version: string;
205
- directory: string;
206
- mode: JsonReportMode;
207
- diff: DiffInfo | null;
208
- scans: Array<{
209
- directory: string;
210
- result: ScanResult;
211
- }>;
212
- totalElapsedMilliseconds: number;
213
- }
214
- declare const buildJsonReport: (input: BuildJsonReportInput) => JsonReport;
215
- //#endregion
216
- //#region src/utils/build-json-report-error.d.ts
217
- interface BuildJsonReportErrorInput {
218
- version: string;
219
- directory: string;
220
- error: unknown;
221
- elapsedMilliseconds: number;
222
- mode?: JsonReportMode;
223
- }
224
- declare const buildJsonReportError: (input: BuildJsonReportErrorInput) => JsonReport;
225
- //#endregion
226
- //#region src/utils/get-diff-files.d.ts
227
- declare const getDiffInfo: (directory: string, explicitBaseBranch?: string) => DiffInfo | null;
228
- declare const filterSourceFiles: (filePaths: string[]) => string[];
229
- //#endregion
230
- //#region src/utils/summarize-diagnostics.d.ts
231
- declare const summarizeDiagnostics: (diagnostics: Diagnostic[], worstScore?: number | null, worstScoreLabel?: string | null) => JsonReportSummary;
232
- //#endregion
233
- //#region src/errors.d.ts
234
- declare class ReactDoctorError extends Error {
235
- readonly name: string;
236
- constructor(message: string, options?: ErrorOptions);
237
- }
238
- declare class ProjectNotFoundError extends ReactDoctorError {
239
- readonly name = "ProjectNotFoundError";
240
- readonly directory: string;
241
- constructor(directory: string, options?: ErrorOptions);
242
- }
243
- declare class NoReactDependencyError extends ReactDoctorError {
244
- readonly name = "NoReactDependencyError";
245
- readonly directory: string;
246
- constructor(directory: string, options?: ErrorOptions);
247
- }
248
- declare class PackageJsonNotFoundError extends ReactDoctorError {
249
- readonly name = "PackageJsonNotFoundError";
250
- readonly directory: string;
251
- constructor(directory: string, options?: ErrorOptions);
252
- }
253
- declare class AmbiguousProjectError extends ReactDoctorError {
254
- readonly name = "AmbiguousProjectError";
255
- readonly directory: string;
256
- readonly candidates: readonly string[];
257
- constructor(directory: string, candidates: readonly string[], options?: ErrorOptions);
258
- }
259
- declare const isReactDoctorError: (value: unknown) => value is ReactDoctorError;
260
- //#endregion
261
- //#region src/index.d.ts
262
- declare const clearCaches: () => void;
263
- interface ToJsonReportOptions {
264
- version: string;
265
- directory?: string;
266
- mode?: JsonReportMode;
267
- }
268
- declare const toJsonReport: (result: DiagnoseResult, options: ToJsonReportOptions) => JsonReport;
269
- declare const diagnose: (directory: string, options?: DiagnoseOptions) => Promise<DiagnoseResult>;
270
- //#endregion
271
- export { AmbiguousProjectError, type DiagnoseOptions, type DiagnoseResult, type Diagnostic, type DiffInfo, type JsonReport, type JsonReportDiffInfo, type JsonReportError, type JsonReportMode, type JsonReportProjectEntry, type JsonReportSummary, NoReactDependencyError, PackageJsonNotFoundError, type ProjectInfo, ProjectNotFoundError, type ReactDoctorConfig, ReactDoctorError, type ScoreResult, buildJsonReport, buildJsonReportError, clearCaches, diagnose, filterSourceFiles, getDiffInfo, isReactDoctorError, summarizeDiagnostics, toJsonReport };
272
- //# sourceMappingURL=index.d.ts.map