react-doctor 0.7.0 → 0.7.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.
- package/dist/cli.js +51 -9
- package/dist/index.d.ts +51 -1
- package/dist/index.js +35 -7
- package/dist/lsp.js +31 -6
- package/package.json +6 -6
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="8cb1a73e-b148-513d-a3eb-69f3a12430a5")}catch(e){}}();
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import * as NodeChildProcess from "node:child_process";
|
|
5
5
|
import { execFile, execFileSync, spawn, spawnSync } from "node:child_process";
|
|
@@ -22405,6 +22405,7 @@ var Diagnostic = class extends Class("Diagnostic")({
|
|
|
22405
22405
|
endLine: optional(Number$1),
|
|
22406
22406
|
endColumn: optional(Number$1),
|
|
22407
22407
|
category: String$1,
|
|
22408
|
+
matchByOccurrence: optional(Boolean$1),
|
|
22408
22409
|
fileContext: optional(Literals(["test", "story"])),
|
|
22409
22410
|
suppressionHint: optional(String$1),
|
|
22410
22411
|
relatedLocations: optional(ArraySchema(DiagnosticRelatedLocation)),
|
|
@@ -22475,6 +22476,16 @@ var JsonReportV1 = class extends Class("JsonReportV1")({
|
|
|
22475
22476
|
* successful `baseline` run (`schemaVersion: 2`) and on non-compare scopes.
|
|
22476
22477
|
*/
|
|
22477
22478
|
baselineDegraded: optional(Boolean$1),
|
|
22479
|
+
/**
|
|
22480
|
+
* Whether any scanned project resolved a React-compatible runtime (React
|
|
22481
|
+
* or Preact). `false` means every React-runtime rule family was gated off,
|
|
22482
|
+
* so an empty `diagnostics` array is vacuous — NOT the same as a clean
|
|
22483
|
+
* React scan. Consumers gating on the report (CI, verifiers, hooks) should
|
|
22484
|
+
* treat `reactDetected === false` as "wrong scan target", not "all clear".
|
|
22485
|
+
* Absent when nothing was scanned (`projects` is empty), on error reports,
|
|
22486
|
+
* and on reports from older CLI versions.
|
|
22487
|
+
*/
|
|
22488
|
+
reactDetected: optional(Boolean$1),
|
|
22478
22489
|
diff: NullOr(JsonReportDiffInfo),
|
|
22479
22490
|
projects: ArraySchema(JsonReportProjectEntry),
|
|
22480
22491
|
diagnostics: ArraySchema(Diagnostic),
|
|
@@ -22500,6 +22511,8 @@ var JsonReportV2 = class extends Class("JsonReportV2")({
|
|
|
22500
22511
|
ok: Boolean$1,
|
|
22501
22512
|
directory: String$1,
|
|
22502
22513
|
mode: JsonReportMode,
|
|
22514
|
+
/** See `JsonReportV1.reactDetected`. */
|
|
22515
|
+
reactDetected: optional(Boolean$1),
|
|
22503
22516
|
diff: NullOr(JsonReportDiffInfo),
|
|
22504
22517
|
baseline: JsonReportBaseline,
|
|
22505
22518
|
projects: ArraySchema(JsonReportProjectEntry),
|
|
@@ -36108,6 +36121,7 @@ const DIAGNOSTIC_CATEGORY_BUCKETS = [
|
|
|
36108
36121
|
"Accessibility",
|
|
36109
36122
|
"Maintainability"
|
|
36110
36123
|
];
|
|
36124
|
+
const OCCURRENCE_MATCHED_CATEGORIES = new Set(["Accessibility"]);
|
|
36111
36125
|
const APP_ONLY_RULE_KEYS = new Set([
|
|
36112
36126
|
"react-hooks-js/static-components",
|
|
36113
36127
|
"react-doctor/no-render-prop-children",
|
|
@@ -36130,7 +36144,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
|
|
|
36130
36144
|
const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
|
|
36131
36145
|
const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
|
|
36132
36146
|
const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
|
|
36133
|
-
const CORE_PACKAGE_VERSION = "0.7.
|
|
36147
|
+
const CORE_PACKAGE_VERSION = "0.7.1";
|
|
36134
36148
|
const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
|
|
36135
36149
|
const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
|
|
36136
36150
|
const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
@@ -40237,10 +40251,17 @@ function* collectSecurityScanFiles(rootDirectory) {
|
|
|
40237
40251
|
}
|
|
40238
40252
|
}
|
|
40239
40253
|
}
|
|
40254
|
+
/**
|
|
40255
|
+
* Whether project discovery resolved a React-compatible runtime (React or
|
|
40256
|
+
* Preact, which ships the same hooks + JSX model). This is the same
|
|
40257
|
+
* predicate that grants the `react` capability, so `false` means every
|
|
40258
|
+
* React-runtime rule family was gated off for the project.
|
|
40259
|
+
*/
|
|
40260
|
+
const hasReactRuntime = (project) => project.reactVersion !== null || project.preactVersion !== null;
|
|
40240
40261
|
const buildCapabilities = (project) => {
|
|
40241
40262
|
const capabilities = /* @__PURE__ */ new Set();
|
|
40242
40263
|
capabilities.add(project.framework);
|
|
40243
|
-
if (project
|
|
40264
|
+
if (hasReactRuntime(project)) capabilities.add("react");
|
|
40244
40265
|
if (project.framework === "expo" || project.framework === "react-native" || project.hasReactNativeWorkspace) capabilities.add("react-native");
|
|
40245
40266
|
if (project.expoVersion !== null) capabilities.add("expo");
|
|
40246
40267
|
if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 15) capabilities.add("nextjs:15");
|
|
@@ -43092,6 +43113,7 @@ const parseRuleCode = (code) => {
|
|
|
43092
43113
|
};
|
|
43093
43114
|
};
|
|
43094
43115
|
const resolveDiagnosticCategory = (plugin, rule) => getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
|
|
43116
|
+
const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORIES.has(category) || Boolean(reactDoctorPlugin.rules[rule]?.matchByOccurrence);
|
|
43095
43117
|
/**
|
|
43096
43118
|
* Maps oxlint's non-primary labels (`labels[1..]`) into related source
|
|
43097
43119
|
* locations. Editors surface these as a diagnostic's
|
|
@@ -43155,6 +43177,7 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
43155
43177
|
const normalizedFilePath = diagnostic.filename.replaceAll("\\", "/");
|
|
43156
43178
|
const primarySpan = primaryLabel?.span;
|
|
43157
43179
|
const relatedLocations = buildRelatedLocations(diagnostic.labels, normalizedFilePath);
|
|
43180
|
+
const category = resolveDiagnosticCategory(plugin, rule);
|
|
43158
43181
|
return {
|
|
43159
43182
|
filePath: normalizedFilePath,
|
|
43160
43183
|
plugin,
|
|
@@ -43170,7 +43193,8 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
43170
43193
|
offset: primarySpan.offset,
|
|
43171
43194
|
length: primarySpan.length
|
|
43172
43195
|
} : {},
|
|
43173
|
-
category
|
|
43196
|
+
category,
|
|
43197
|
+
...resolveMatchByOccurrence(rule, category) ? { matchByOccurrence: true } : {},
|
|
43174
43198
|
...relatedLocations.length > 0 ? { relatedLocations } : {}
|
|
43175
43199
|
};
|
|
43176
43200
|
});
|
|
@@ -45355,6 +45379,7 @@ const buildJsonReport = (input) => {
|
|
|
45355
45379
|
const worstScoredProject = findWorstScoredProject(projects);
|
|
45356
45380
|
const summary = summarizeDiagnostics(flattenedDiagnostics, worstScoredProject?.score?.score ?? null, worstScoredProject?.score?.label ?? null);
|
|
45357
45381
|
const shared = {
|
|
45382
|
+
...input.scans.length > 0 ? { reactDetected: input.scans.some((scan) => hasReactRuntime(scan.result.project)) } : {},
|
|
45358
45383
|
version: input.version,
|
|
45359
45384
|
ok: true,
|
|
45360
45385
|
directory: input.directory,
|
|
@@ -45405,7 +45430,7 @@ const buildSkippedChecks = (input) => {
|
|
|
45405
45430
|
};
|
|
45406
45431
|
const fingerprintDiagnostic = (diagnostic, lineText) => {
|
|
45407
45432
|
const ruleKey = `${diagnostic.plugin}/${diagnostic.rule}`;
|
|
45408
|
-
const snippet = lineText === null ? "" : createHash("sha1").update(lineText.trim()).digest("hex");
|
|
45433
|
+
const snippet = lineText === null || diagnostic.matchByOccurrence ? "" : createHash("sha1").update(lineText.trim()).digest("hex");
|
|
45409
45434
|
return `${diagnostic.filePath}\u0000${ruleKey}\u0000${snippet}`;
|
|
45410
45435
|
};
|
|
45411
45436
|
/**
|
|
@@ -45416,6 +45441,17 @@ const fingerprintDiagnostic = (diagnostic, lineText) => {
|
|
|
45416
45441
|
* look new, while a genuinely new occurrence (new line text, or one more of
|
|
45417
45442
|
* the same) surfaces. Identical repeated findings are matched by count.
|
|
45418
45443
|
*
|
|
45444
|
+
* Diagnostics carrying `matchByOccurrence` (resolved at diagnostic creation:
|
|
45445
|
+
* every Accessibility-category finding, plus rules opting in via their
|
|
45446
|
+
* `matchByOccurrence` metadata flag) drop the line-text snippet and match by
|
|
45447
|
+
* `(filePath, plugin/rule)` occurrence count alone. Their identity is the
|
|
45448
|
+
* flagged element, not the line's text, so editing the line (reindentation,
|
|
45449
|
+
* prettier reflow, collapsing a multi-line JSX element) doesn't reclassify a
|
|
45450
|
+
* pre-existing finding as new — while one MORE occurrence of the same rule in
|
|
45451
|
+
* the file still surfaces. Expression-level rules keep the line-text snippet:
|
|
45452
|
+
* there the flagged expression IS the finding, so changed text means new +
|
|
45453
|
+
* fixed.
|
|
45454
|
+
*
|
|
45419
45455
|
* v1 limitation: the fingerprint keys on the head-relative `filePath`, and base
|
|
45420
45456
|
* content is read at that same path. A file renamed by the change therefore has
|
|
45421
45457
|
* no base match, so its pre-existing findings are reported as new. This
|
|
@@ -45818,6 +45854,7 @@ const METRIC = {
|
|
|
45818
45854
|
scanScore: "scan.score",
|
|
45819
45855
|
scanClean: "scan.clean",
|
|
45820
45856
|
scanCheckSkipped: "scan.check_skipped",
|
|
45857
|
+
scanNoReactDetected: "scan.no_react_detected",
|
|
45821
45858
|
baselineDegraded: "baseline.degraded",
|
|
45822
45859
|
ruleFired: "rule.fired",
|
|
45823
45860
|
ruleDisabled: "rule.disabled",
|
|
@@ -45887,7 +45924,7 @@ const makeNoopConsole = () => ({
|
|
|
45887
45924
|
});
|
|
45888
45925
|
//#endregion
|
|
45889
45926
|
//#region src/cli/utils/version.ts
|
|
45890
|
-
const VERSION = "0.7.
|
|
45927
|
+
const VERSION = "0.7.1";
|
|
45891
45928
|
//#endregion
|
|
45892
45929
|
//#region src/cli/utils/json-mode.ts
|
|
45893
45930
|
let context = null;
|
|
@@ -46256,13 +46293,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
|
|
|
46256
46293
|
* uploads source-map artifacts under, so stack frames symbolicate. Honors the
|
|
46257
46294
|
* standard `SENTRY_RELEASE` override.
|
|
46258
46295
|
*/
|
|
46259
|
-
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.
|
|
46296
|
+
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.1`;
|
|
46260
46297
|
/**
|
|
46261
46298
|
* Deployment environment shown in Sentry's environment filter. Defaults to
|
|
46262
46299
|
* `production` for tagged releases and `development` for dev/unbuilt versions,
|
|
46263
46300
|
* overridable via the standard `SENTRY_ENVIRONMENT` env var.
|
|
46264
46301
|
*/
|
|
46265
|
-
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.
|
|
46302
|
+
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.1") ? "development" : "production");
|
|
46266
46303
|
/**
|
|
46267
46304
|
* Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
|
|
46268
46305
|
* (set to `0` to disable tracing) and falls back to
|
|
@@ -62975,6 +63012,11 @@ const finalizeScans = (input) => {
|
|
|
62975
63012
|
const baselineComputed = input.completedScans.length > 0 && input.completedScans.every((scan) => scan.result.baselineDelta !== void 0);
|
|
62976
63013
|
const baselineDegraded = input.baselineIntended && !baselineComputed;
|
|
62977
63014
|
const mode = baselineDegraded ? "diff" : input.mode;
|
|
63015
|
+
const isReactDetected = input.completedScans.some((scan) => hasReactRuntime(scan.result.project));
|
|
63016
|
+
if (input.completedScans.length > 0 && !isReactDetected) {
|
|
63017
|
+
recordCount(METRIC.scanNoReactDetected, 1);
|
|
63018
|
+
cliLogger.warn(`No React project detected at ${input.resolvedDirectory} — React rules were gated off; this is not the same as a clean scan.`);
|
|
63019
|
+
}
|
|
62978
63020
|
const jsonCompletedScans = filterCompletedScansByCategories(input.completedScans, input.categoryFilters);
|
|
62979
63021
|
if (input.isJsonMode) {
|
|
62980
63022
|
const baseline = baselineComputed && baselineDeltas.length > 0 ? {
|
|
@@ -64412,4 +64454,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
|
|
|
64412
64454
|
export {};
|
|
64413
64455
|
|
|
64414
64456
|
//# sourceMappingURL=cli.js.map
|
|
64415
|
-
//# debugId=
|
|
64457
|
+
//# debugId=8cb1a73e-b148-513d-a3eb-69f3a12430a5
|
package/dist/index.d.ts
CHANGED
|
@@ -9493,6 +9493,17 @@ interface Diagnostic {
|
|
|
9493
9493
|
/** 1-indexed end column of the primary span, when derivable. */
|
|
9494
9494
|
endColumn?: number;
|
|
9495
9495
|
category: string;
|
|
9496
|
+
/**
|
|
9497
|
+
* Set when the finding's identity is the flagged element itself (a missing
|
|
9498
|
+
* attribute, a wrong element) rather than the flagged line's text — every
|
|
9499
|
+
* Accessibility-category finding, plus rules that opt in via their
|
|
9500
|
+
* `matchByOccurrence` metadata flag. `computeDiagnosticDelta` matches these
|
|
9501
|
+
* by `(filePath, plugin/rule)` occurrence count, so reformatting the flagged
|
|
9502
|
+
* line doesn't reclassify a pre-existing finding as new. Resolved at
|
|
9503
|
+
* diagnostic creation, where rule metadata is available. Absent means
|
|
9504
|
+
* line-text-sensitive matching (the default).
|
|
9505
|
+
*/
|
|
9506
|
+
matchByOccurrence?: boolean;
|
|
9496
9507
|
/**
|
|
9497
9508
|
* Set when the file never ships to users (`"test"` / `"story"`), so
|
|
9498
9509
|
* renderers can label the site instead of implying production impact.
|
|
@@ -9644,6 +9655,17 @@ interface DiagnoseResult {
|
|
|
9644
9655
|
/** See `InspectResult.skippedCheckReasons`. */
|
|
9645
9656
|
skippedCheckReasons?: Record<string, string>;
|
|
9646
9657
|
project: ProjectInfo;
|
|
9658
|
+
/**
|
|
9659
|
+
* Whether the scanned project resolved a React-compatible runtime (React
|
|
9660
|
+
* or Preact). `false` means every React-runtime rule family was gated
|
|
9661
|
+
* off, so an empty `diagnostics` array is vacuous — NOT the same as a
|
|
9662
|
+
* clean React scan. Consumers gating on the result should treat
|
|
9663
|
+
* `reactDetected === false` as "wrong scan target", not "all clear".
|
|
9664
|
+
* Mirrors `JsonReport.reactDetected`; same predicate as
|
|
9665
|
+
* `hasReactRuntime(result.project)`. Always set by `diagnose()`;
|
|
9666
|
+
* optional so hand-constructed results keep compiling.
|
|
9667
|
+
*/
|
|
9668
|
+
reactDetected?: boolean;
|
|
9647
9669
|
elapsedMilliseconds: number;
|
|
9648
9670
|
}
|
|
9649
9671
|
/**
|
|
@@ -9693,6 +9715,13 @@ interface DiagnoseProjectsResult {
|
|
|
9693
9715
|
projects: ProjectResult[];
|
|
9694
9716
|
diagnostics: Diagnostic[];
|
|
9695
9717
|
score: ScoreResult | null;
|
|
9718
|
+
/**
|
|
9719
|
+
* Whether any successfully scanned project resolved a React-compatible
|
|
9720
|
+
* runtime (React or Preact). Absent when no project scanned successfully.
|
|
9721
|
+
* See `DiagnoseResult.reactDetected` for gating guidance; per-project
|
|
9722
|
+
* detail is on each `ProjectResultOk.reactDetected`.
|
|
9723
|
+
*/
|
|
9724
|
+
reactDetected?: boolean;
|
|
9696
9725
|
elapsedMilliseconds: number;
|
|
9697
9726
|
} //#endregion
|
|
9698
9727
|
//#region src/types/handle-error.d.ts
|
|
@@ -9888,6 +9917,17 @@ interface JsonReportV1$1 {
|
|
|
9888
9917
|
ok: boolean;
|
|
9889
9918
|
directory: string;
|
|
9890
9919
|
mode: JsonReportMode;
|
|
9920
|
+
/**
|
|
9921
|
+
* Whether any scanned project resolved a React-compatible runtime (React
|
|
9922
|
+
* or Preact). `false` means every React-runtime rule family was gated off,
|
|
9923
|
+
* so an empty `diagnostics` array is vacuous — NOT the same as a clean
|
|
9924
|
+
* React scan. Consumers gating on the report (CI, verifiers, hooks) should
|
|
9925
|
+
* treat `reactDetected === false` as "wrong scan target", not "all clear"
|
|
9926
|
+
* (per project, `projects[].project.reactVersion` / `preactVersion` say
|
|
9927
|
+
* which roots were non-React). Absent when nothing was scanned (`projects`
|
|
9928
|
+
* is empty), on error reports, and on reports from older CLI versions.
|
|
9929
|
+
*/
|
|
9930
|
+
reactDetected?: boolean;
|
|
9891
9931
|
diff: JsonReportDiffInfo | null;
|
|
9892
9932
|
projects: JsonReportProjectEntry[];
|
|
9893
9933
|
/**
|
|
@@ -10172,6 +10212,16 @@ declare const summarizeDiagnostics: (diagnostics: Diagnostic[], worstScore?: num
|
|
|
10172
10212
|
declare const defineConfig: (config: ReactDoctorConfig) => ReactDoctorConfig; //#endregion
|
|
10173
10213
|
//#region src/utils/detect-ai-training-environment.d.ts
|
|
10174
10214
|
//#endregion
|
|
10215
|
+
//#region src/utils/has-react-runtime.d.ts
|
|
10216
|
+
/**
|
|
10217
|
+
* Whether project discovery resolved a React-compatible runtime (React or
|
|
10218
|
+
* Preact, which ships the same hooks + JSX model). This is the same
|
|
10219
|
+
* predicate that grants the `react` capability, so `false` means every
|
|
10220
|
+
* React-runtime rule family was gated off for the project.
|
|
10221
|
+
*/
|
|
10222
|
+
declare const hasReactRuntime: (project: ProjectInfo) => boolean; //#endregion
|
|
10223
|
+
//#region src/utils/is-errno-exception.d.ts
|
|
10224
|
+
//#endregion
|
|
10175
10225
|
//#region ../api/dist/index.d.ts
|
|
10176
10226
|
//#region src/diagnose.d.ts
|
|
10177
10227
|
interface Diagnose {
|
|
@@ -10198,5 +10248,5 @@ interface ToJsonReportOptions {
|
|
|
10198
10248
|
}
|
|
10199
10249
|
declare const toJsonReport: (result: DiagnoseResult, options: ToJsonReportOptions) => JsonReport;
|
|
10200
10250
|
//#endregion
|
|
10201
|
-
export { AmbiguousProjectError, type DiagnoseOptions, type DiagnoseProjectsInput, type DiagnoseProjectsResult, type DiagnoseResult, type Diagnostic, type DiffInfo, type JsonReport, type JsonReportDiffInfo, type JsonReportError, type JsonReportMode, type JsonReportProjectEntry, type JsonReportSummary, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, type ProjectDefinition, type ProjectInfo, ProjectNotFoundError, type ProjectResult, type ProjectResultError, type ProjectResultOk, type ReactDoctorConfig, ReactDoctorError, type ScoreResult, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
|
|
10251
|
+
export { AmbiguousProjectError, type DiagnoseOptions, type DiagnoseProjectsInput, type DiagnoseProjectsResult, type DiagnoseResult, type Diagnostic, type DiffInfo, type JsonReport, type JsonReportDiffInfo, type JsonReportError, type JsonReportMode, type JsonReportProjectEntry, type JsonReportSummary, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, type ProjectDefinition, type ProjectInfo, ProjectNotFoundError, type ProjectResult, type ProjectResultError, type ProjectResultOk, type ReactDoctorConfig, ReactDoctorError, type ScoreResult, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
|
|
10202
10252
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="7cb857ba-6f0a-57d9-91f3-3c286472121d")}catch(e){}}();
|
|
3
3
|
import { r as __toESM$1, t as __commonJSMin$1 } from "./chunk-N93fKeF6.js";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import * as NFS from "node:fs";
|
|
@@ -19304,6 +19304,7 @@ var Diagnostic = class extends Class("Diagnostic")({
|
|
|
19304
19304
|
endLine: optional(Number$1),
|
|
19305
19305
|
endColumn: optional(Number$1),
|
|
19306
19306
|
category: String$1,
|
|
19307
|
+
matchByOccurrence: optional(Boolean$1),
|
|
19307
19308
|
fileContext: optional(Literals(["test", "story"])),
|
|
19308
19309
|
suppressionHint: optional(String$1),
|
|
19309
19310
|
relatedLocations: optional(ArraySchema(DiagnosticRelatedLocation)),
|
|
@@ -19374,6 +19375,16 @@ var JsonReportV1 = class extends Class("JsonReportV1")({
|
|
|
19374
19375
|
* successful `baseline` run (`schemaVersion: 2`) and on non-compare scopes.
|
|
19375
19376
|
*/
|
|
19376
19377
|
baselineDegraded: optional(Boolean$1),
|
|
19378
|
+
/**
|
|
19379
|
+
* Whether any scanned project resolved a React-compatible runtime (React
|
|
19380
|
+
* or Preact). `false` means every React-runtime rule family was gated off,
|
|
19381
|
+
* so an empty `diagnostics` array is vacuous — NOT the same as a clean
|
|
19382
|
+
* React scan. Consumers gating on the report (CI, verifiers, hooks) should
|
|
19383
|
+
* treat `reactDetected === false` as "wrong scan target", not "all clear".
|
|
19384
|
+
* Absent when nothing was scanned (`projects` is empty), on error reports,
|
|
19385
|
+
* and on reports from older CLI versions.
|
|
19386
|
+
*/
|
|
19387
|
+
reactDetected: optional(Boolean$1),
|
|
19377
19388
|
diff: NullOr(JsonReportDiffInfo),
|
|
19378
19389
|
projects: ArraySchema(JsonReportProjectEntry),
|
|
19379
19390
|
diagnostics: ArraySchema(Diagnostic),
|
|
@@ -19399,6 +19410,8 @@ var JsonReportV2 = class extends Class("JsonReportV2")({
|
|
|
19399
19410
|
ok: Boolean$1,
|
|
19400
19411
|
directory: String$1,
|
|
19401
19412
|
mode: JsonReportMode,
|
|
19413
|
+
/** See `JsonReportV1.reactDetected`. */
|
|
19414
|
+
reactDetected: optional(Boolean$1),
|
|
19402
19415
|
diff: NullOr(JsonReportDiffInfo),
|
|
19403
19416
|
baseline: JsonReportBaseline,
|
|
19404
19417
|
projects: ArraySchema(JsonReportProjectEntry),
|
|
@@ -32907,6 +32920,7 @@ const DIAGNOSTIC_CATEGORY_BUCKETS = [
|
|
|
32907
32920
|
"Accessibility",
|
|
32908
32921
|
"Maintainability"
|
|
32909
32922
|
];
|
|
32923
|
+
const OCCURRENCE_MATCHED_CATEGORIES = new Set(["Accessibility"]);
|
|
32910
32924
|
const APP_ONLY_RULE_KEYS = new Set([
|
|
32911
32925
|
"react-hooks-js/static-components",
|
|
32912
32926
|
"react-doctor/no-render-prop-children",
|
|
@@ -32929,7 +32943,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
|
|
|
32929
32943
|
const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
|
|
32930
32944
|
const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
|
|
32931
32945
|
const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
|
|
32932
|
-
const CORE_PACKAGE_VERSION = "0.7.
|
|
32946
|
+
const CORE_PACKAGE_VERSION = "0.7.1";
|
|
32933
32947
|
const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
|
|
32934
32948
|
const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
|
|
32935
32949
|
const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
@@ -37010,10 +37024,17 @@ function* collectSecurityScanFiles(rootDirectory) {
|
|
|
37010
37024
|
}
|
|
37011
37025
|
}
|
|
37012
37026
|
}
|
|
37027
|
+
/**
|
|
37028
|
+
* Whether project discovery resolved a React-compatible runtime (React or
|
|
37029
|
+
* Preact, which ships the same hooks + JSX model). This is the same
|
|
37030
|
+
* predicate that grants the `react` capability, so `false` means every
|
|
37031
|
+
* React-runtime rule family was gated off for the project.
|
|
37032
|
+
*/
|
|
37033
|
+
const hasReactRuntime = (project) => project.reactVersion !== null || project.preactVersion !== null;
|
|
37013
37034
|
const buildCapabilities = (project) => {
|
|
37014
37035
|
const capabilities = /* @__PURE__ */ new Set();
|
|
37015
37036
|
capabilities.add(project.framework);
|
|
37016
|
-
if (project
|
|
37037
|
+
if (hasReactRuntime(project)) capabilities.add("react");
|
|
37017
37038
|
if (project.framework === "expo" || project.framework === "react-native" || project.hasReactNativeWorkspace) capabilities.add("react-native");
|
|
37018
37039
|
if (project.expoVersion !== null) capabilities.add("expo");
|
|
37019
37040
|
if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 15) capabilities.add("nextjs:15");
|
|
@@ -39849,6 +39870,7 @@ const parseRuleCode = (code) => {
|
|
|
39849
39870
|
};
|
|
39850
39871
|
};
|
|
39851
39872
|
const resolveDiagnosticCategory = (plugin, rule) => getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
|
|
39873
|
+
const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORIES.has(category) || Boolean(reactDoctorPlugin.rules[rule]?.matchByOccurrence);
|
|
39852
39874
|
/**
|
|
39853
39875
|
* Maps oxlint's non-primary labels (`labels[1..]`) into related source
|
|
39854
39876
|
* locations. Editors surface these as a diagnostic's
|
|
@@ -39912,6 +39934,7 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
39912
39934
|
const normalizedFilePath = diagnostic.filename.replaceAll("\\", "/");
|
|
39913
39935
|
const primarySpan = primaryLabel?.span;
|
|
39914
39936
|
const relatedLocations = buildRelatedLocations(diagnostic.labels, normalizedFilePath);
|
|
39937
|
+
const category = resolveDiagnosticCategory(plugin, rule);
|
|
39915
39938
|
return {
|
|
39916
39939
|
filePath: normalizedFilePath,
|
|
39917
39940
|
plugin,
|
|
@@ -39927,7 +39950,8 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
39927
39950
|
offset: primarySpan.offset,
|
|
39928
39951
|
length: primarySpan.length
|
|
39929
39952
|
} : {},
|
|
39930
|
-
category
|
|
39953
|
+
category,
|
|
39954
|
+
...resolveMatchByOccurrence(rule, category) ? { matchByOccurrence: true } : {},
|
|
39931
39955
|
...relatedLocations.length > 0 ? { relatedLocations } : {}
|
|
39932
39956
|
};
|
|
39933
39957
|
});
|
|
@@ -42088,6 +42112,7 @@ const buildJsonReport = (input) => {
|
|
|
42088
42112
|
const worstScoredProject = findWorstScoredProject(projects);
|
|
42089
42113
|
const summary = summarizeDiagnostics(flattenedDiagnostics, worstScoredProject?.score?.score ?? null, worstScoredProject?.score?.label ?? null);
|
|
42090
42114
|
const shared = {
|
|
42115
|
+
...input.scans.length > 0 ? { reactDetected: input.scans.some((scan) => hasReactRuntime(scan.result.project)) } : {},
|
|
42091
42116
|
version: input.version,
|
|
42092
42117
|
ok: true,
|
|
42093
42118
|
directory: input.directory,
|
|
@@ -42317,6 +42342,7 @@ const outputToDiagnoseResult = (output, elapsedMilliseconds) => {
|
|
|
42317
42342
|
skippedChecks,
|
|
42318
42343
|
...Object.keys(skippedCheckReasons).length > 0 ? { skippedCheckReasons } : {},
|
|
42319
42344
|
project: output.project,
|
|
42345
|
+
reactDetected: hasReactRuntime(output.project),
|
|
42320
42346
|
elapsedMilliseconds
|
|
42321
42347
|
};
|
|
42322
42348
|
};
|
|
@@ -42372,10 +42398,12 @@ const diagnoseProjectBatch = async (input) => {
|
|
|
42372
42398
|
const startTime = globalThis.performance.now();
|
|
42373
42399
|
const { projects, concurrency, config: batchConfig, ...baseOptions } = input;
|
|
42374
42400
|
const projectResults = await mapWithConcurrency(projects, concurrency ?? 4, (projectDefinition) => diagnoseProject(projectDefinition, baseOptions, batchConfig));
|
|
42401
|
+
const succeededProjects = projectResults.filter((projectResult) => projectResult.ok);
|
|
42375
42402
|
return {
|
|
42376
42403
|
projects: projectResults,
|
|
42377
|
-
diagnostics:
|
|
42404
|
+
diagnostics: succeededProjects.flatMap((projectResult) => projectResult.diagnostics),
|
|
42378
42405
|
score: findWorstScore(projectResults),
|
|
42406
|
+
...succeededProjects.length > 0 ? { reactDetected: succeededProjects.some((projectResult) => projectResult.reactDetected) } : {},
|
|
42379
42407
|
elapsedMilliseconds: globalThis.performance.now() - startTime
|
|
42380
42408
|
};
|
|
42381
42409
|
};
|
|
@@ -42410,7 +42438,7 @@ const toJsonReport = (result, options) => buildJsonReport({
|
|
|
42410
42438
|
totalElapsedMilliseconds: result.elapsedMilliseconds
|
|
42411
42439
|
});
|
|
42412
42440
|
//#endregion
|
|
42413
|
-
export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
|
|
42441
|
+
export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
|
|
42414
42442
|
|
|
42415
42443
|
//# sourceMappingURL=index.js.map
|
|
42416
|
-
//# debugId=
|
|
42444
|
+
//# debugId=7cb857ba-6f0a-57d9-91f3-3c286472121d
|
package/dist/lsp.js
CHANGED
|
@@ -19333,6 +19333,7 @@ var Diagnostic = class extends Class("Diagnostic")({
|
|
|
19333
19333
|
endLine: optional(Number$1),
|
|
19334
19334
|
endColumn: optional(Number$1),
|
|
19335
19335
|
category: String$1,
|
|
19336
|
+
matchByOccurrence: optional(Boolean$1),
|
|
19336
19337
|
fileContext: optional(Literals(["test", "story"])),
|
|
19337
19338
|
suppressionHint: optional(String$1),
|
|
19338
19339
|
relatedLocations: optional(ArraySchema(DiagnosticRelatedLocation)),
|
|
@@ -19410,6 +19411,16 @@ var JsonReportV1 = class extends Class("JsonReportV1")({
|
|
|
19410
19411
|
* successful `baseline` run (`schemaVersion: 2`) and on non-compare scopes.
|
|
19411
19412
|
*/
|
|
19412
19413
|
baselineDegraded: optional(Boolean$1),
|
|
19414
|
+
/**
|
|
19415
|
+
* Whether any scanned project resolved a React-compatible runtime (React
|
|
19416
|
+
* or Preact). `false` means every React-runtime rule family was gated off,
|
|
19417
|
+
* so an empty `diagnostics` array is vacuous — NOT the same as a clean
|
|
19418
|
+
* React scan. Consumers gating on the report (CI, verifiers, hooks) should
|
|
19419
|
+
* treat `reactDetected === false` as "wrong scan target", not "all clear".
|
|
19420
|
+
* Absent when nothing was scanned (`projects` is empty), on error reports,
|
|
19421
|
+
* and on reports from older CLI versions.
|
|
19422
|
+
*/
|
|
19423
|
+
reactDetected: optional(Boolean$1),
|
|
19413
19424
|
diff: NullOr(JsonReportDiffInfo),
|
|
19414
19425
|
projects: ArraySchema(JsonReportProjectEntry),
|
|
19415
19426
|
diagnostics: ArraySchema(Diagnostic),
|
|
@@ -19435,6 +19446,8 @@ var JsonReportV2 = class extends Class("JsonReportV2")({
|
|
|
19435
19446
|
ok: Boolean$1,
|
|
19436
19447
|
directory: String$1,
|
|
19437
19448
|
mode: JsonReportMode,
|
|
19449
|
+
/** See `JsonReportV1.reactDetected`. */
|
|
19450
|
+
reactDetected: optional(Boolean$1),
|
|
19438
19451
|
diff: NullOr(JsonReportDiffInfo),
|
|
19439
19452
|
baseline: JsonReportBaseline,
|
|
19440
19453
|
projects: ArraySchema(JsonReportProjectEntry),
|
|
@@ -32966,6 +32979,7 @@ const DIAGNOSTIC_CATEGORY_BUCKETS = [
|
|
|
32966
32979
|
"Accessibility",
|
|
32967
32980
|
"Maintainability"
|
|
32968
32981
|
];
|
|
32982
|
+
const OCCURRENCE_MATCHED_CATEGORIES = new Set(["Accessibility"]);
|
|
32969
32983
|
const APP_ONLY_RULE_KEYS = new Set([
|
|
32970
32984
|
"react-hooks-js/static-components",
|
|
32971
32985
|
"react-doctor/no-render-prop-children",
|
|
@@ -32988,7 +33002,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
|
|
|
32988
33002
|
const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
|
|
32989
33003
|
const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
|
|
32990
33004
|
const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
|
|
32991
|
-
const CORE_PACKAGE_VERSION = "0.7.
|
|
33005
|
+
const CORE_PACKAGE_VERSION = "0.7.1";
|
|
32992
33006
|
const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
|
|
32993
33007
|
const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
|
|
32994
33008
|
const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
@@ -36995,10 +37009,17 @@ function* collectSecurityScanFiles(rootDirectory) {
|
|
|
36995
37009
|
}
|
|
36996
37010
|
}
|
|
36997
37011
|
}
|
|
37012
|
+
/**
|
|
37013
|
+
* Whether project discovery resolved a React-compatible runtime (React or
|
|
37014
|
+
* Preact, which ships the same hooks + JSX model). This is the same
|
|
37015
|
+
* predicate that grants the `react` capability, so `false` means every
|
|
37016
|
+
* React-runtime rule family was gated off for the project.
|
|
37017
|
+
*/
|
|
37018
|
+
const hasReactRuntime = (project) => project.reactVersion !== null || project.preactVersion !== null;
|
|
36998
37019
|
const buildCapabilities = (project) => {
|
|
36999
37020
|
const capabilities = /* @__PURE__ */ new Set();
|
|
37000
37021
|
capabilities.add(project.framework);
|
|
37001
|
-
if (project
|
|
37022
|
+
if (hasReactRuntime(project)) capabilities.add("react");
|
|
37002
37023
|
if (project.framework === "expo" || project.framework === "react-native" || project.hasReactNativeWorkspace) capabilities.add("react-native");
|
|
37003
37024
|
if (project.expoVersion !== null) capabilities.add("expo");
|
|
37004
37025
|
if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 15) capabilities.add("nextjs:15");
|
|
@@ -39834,6 +39855,7 @@ const parseRuleCode = (code) => {
|
|
|
39834
39855
|
};
|
|
39835
39856
|
};
|
|
39836
39857
|
const resolveDiagnosticCategory = (plugin, rule) => getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
|
|
39858
|
+
const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORIES.has(category) || Boolean(reactDoctorPlugin.rules[rule]?.matchByOccurrence);
|
|
39837
39859
|
/**
|
|
39838
39860
|
* Maps oxlint's non-primary labels (`labels[1..]`) into related source
|
|
39839
39861
|
* locations. Editors surface these as a diagnostic's
|
|
@@ -39897,6 +39919,7 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
39897
39919
|
const normalizedFilePath = diagnostic.filename.replaceAll("\\", "/");
|
|
39898
39920
|
const primarySpan = primaryLabel?.span;
|
|
39899
39921
|
const relatedLocations = buildRelatedLocations(diagnostic.labels, normalizedFilePath);
|
|
39922
|
+
const category = resolveDiagnosticCategory(plugin, rule);
|
|
39900
39923
|
return {
|
|
39901
39924
|
filePath: normalizedFilePath,
|
|
39902
39925
|
plugin,
|
|
@@ -39912,7 +39935,8 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
39912
39935
|
offset: primarySpan.offset,
|
|
39913
39936
|
length: primarySpan.length
|
|
39914
39937
|
} : {},
|
|
39915
|
-
category
|
|
39938
|
+
category,
|
|
39939
|
+
...resolveMatchByOccurrence(rule, category) ? { matchByOccurrence: true } : {},
|
|
39916
39940
|
...relatedLocations.length > 0 ? { relatedLocations } : {}
|
|
39917
39941
|
};
|
|
39918
39942
|
});
|
|
@@ -42085,7 +42109,7 @@ const computeConfigFingerprint = (projectDirectory, version) => {
|
|
|
42085
42109
|
/** Display name used in client-facing messages and progress titles. */
|
|
42086
42110
|
const SERVER_DISPLAY_NAME = "React Doctor";
|
|
42087
42111
|
/** Server version reported in `serverInfo`; injected at build, `dev` from source. */
|
|
42088
|
-
const SERVER_VERSION = "0.7.
|
|
42112
|
+
const SERVER_VERSION = "0.7.1";
|
|
42089
42113
|
/** `Diagnostic.source` shown next to every published diagnostic. */
|
|
42090
42114
|
const DIAGNOSTIC_SOURCE = "react-doctor";
|
|
42091
42115
|
/**
|
|
@@ -43792,6 +43816,7 @@ const METRIC = {
|
|
|
43792
43816
|
scanScore: "scan.score",
|
|
43793
43817
|
scanClean: "scan.clean",
|
|
43794
43818
|
scanCheckSkipped: "scan.check_skipped",
|
|
43819
|
+
scanNoReactDetected: "scan.no_react_detected",
|
|
43795
43820
|
baselineDegraded: "baseline.degraded",
|
|
43796
43821
|
ruleFired: "rule.fired",
|
|
43797
43822
|
ruleDisabled: "rule.disabled",
|
|
@@ -44135,5 +44160,5 @@ const startLanguageServer = () => {
|
|
|
44135
44160
|
};
|
|
44136
44161
|
//#endregion
|
|
44137
44162
|
export { startLanguageServer };
|
|
44138
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
44139
|
-
//# debugId=
|
|
44163
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="027c66d6-b30a-59de-ad83-58f5ad304c94")}catch(e){}}();
|
|
44164
|
+
//# debugId=027c66d6-b30a-59de-ad83-58f5ad304c94
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-doctor",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Your agent writes bad React. This catches it",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"accessibility",
|
|
@@ -65,8 +65,8 @@
|
|
|
65
65
|
"vscode-languageserver-textdocument": "^1.0.12",
|
|
66
66
|
"vscode-uri": "^3.1.0",
|
|
67
67
|
"yaml": "^2.9.0",
|
|
68
|
-
"deslop-js": "0.7.
|
|
69
|
-
"oxlint-plugin-react-doctor": "0.7.
|
|
68
|
+
"deslop-js": "0.7.1",
|
|
69
|
+
"oxlint-plugin-react-doctor": "0.7.1"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@types/babel__code-frame": "^7.27.0",
|
|
@@ -74,9 +74,9 @@
|
|
|
74
74
|
"@xterm/headless": "^6.0.0",
|
|
75
75
|
"commander": "^14.0.3",
|
|
76
76
|
"ora": "^9.4.0",
|
|
77
|
-
"@react-doctor/api": "0.7.
|
|
78
|
-
"@react-doctor/core": "0.7.
|
|
79
|
-
"@react-doctor/language-server": "0.7.
|
|
77
|
+
"@react-doctor/api": "0.7.1",
|
|
78
|
+
"@react-doctor/core": "0.7.1",
|
|
79
|
+
"@react-doctor/language-server": "0.7.1"
|
|
80
80
|
},
|
|
81
81
|
"engines": {
|
|
82
82
|
"node": "^20.19.0 || >=22.13.0"
|