react-doctor 0.7.4-dev.dfccac4 → 0.7.5-dev.037bd56
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/README.md +8 -0
- package/dist/cli.js +335 -88
- package/dist/index.d.ts +58 -9
- package/dist/index.js +310 -73
- package/dist/lsp.js +234 -43
- 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]="ed6bfef3-a274-5972-833b-77462a1156e2")}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";
|
|
@@ -8,8 +8,8 @@ import path from "node:path";
|
|
|
8
8
|
import * as NFS from "node:fs";
|
|
9
9
|
import fs, { mkdtempSync, rmSync } from "node:fs";
|
|
10
10
|
import process$1 from "node:process";
|
|
11
|
-
import
|
|
12
|
-
import
|
|
11
|
+
import reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_DEPENDENCY_COLLECTORS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, FRAMEWORK_TOKENS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, classifySecurityScanFile, collectCrossFileDependencyProbes, resetManifestCaches, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor";
|
|
12
|
+
import ts from "typescript";
|
|
13
13
|
import * as OS from "node:os";
|
|
14
14
|
import os, { tmpdir } from "node:os";
|
|
15
15
|
import { parseJSON5 } from "confbox";
|
|
@@ -22411,12 +22411,45 @@ var Diagnostic = class extends Class("Diagnostic")({
|
|
|
22411
22411
|
relatedLocations: optional(ArraySchema(DiagnosticRelatedLocation)),
|
|
22412
22412
|
fixGroupId: optional(String$1)
|
|
22413
22413
|
}) {};
|
|
22414
|
+
var JsonReportDiagnosticV3 = class extends Class("JsonReportDiagnosticV3")({
|
|
22415
|
+
id: String$1,
|
|
22416
|
+
normalizedFilePath: String$1,
|
|
22417
|
+
filePath: String$1,
|
|
22418
|
+
plugin: String$1,
|
|
22419
|
+
rule: String$1,
|
|
22420
|
+
severity: Severity,
|
|
22421
|
+
tags: ArraySchema(String$1),
|
|
22422
|
+
title: optional(String$1),
|
|
22423
|
+
message: String$1,
|
|
22424
|
+
help: String$1,
|
|
22425
|
+
url: optional(String$1),
|
|
22426
|
+
line: Number$1,
|
|
22427
|
+
column: Number$1,
|
|
22428
|
+
offset: optional(Number$1),
|
|
22429
|
+
length: optional(Number$1),
|
|
22430
|
+
endLine: optional(Number$1),
|
|
22431
|
+
endColumn: optional(Number$1),
|
|
22432
|
+
category: String$1,
|
|
22433
|
+
matchByOccurrence: optional(Boolean$1),
|
|
22434
|
+
fileContext: optional(Literals(["test", "story"])),
|
|
22435
|
+
suppressionHint: optional(String$1),
|
|
22436
|
+
relatedLocations: optional(ArraySchema(DiagnosticRelatedLocation)),
|
|
22437
|
+
fixGroupId: optional(String$1)
|
|
22438
|
+
}) {};
|
|
22439
|
+
/**
|
|
22440
|
+
* Deterministic identity string for a diagnostic. Same diagnostic
|
|
22441
|
+
* across two scans yields the same identity; lets baselines,
|
|
22442
|
+
* suppression files, content-hash caches, and IDE "ignore this"
|
|
22443
|
+
* actions all key off one shared shape.
|
|
22444
|
+
*/
|
|
22445
|
+
const buildDiagnosticIdentity = (input) => `${input.filePath}::${input.line}:${input.column}::${input.plugin}/${input.rule}`;
|
|
22414
22446
|
const JsonReportMode = Literals([
|
|
22415
22447
|
"full",
|
|
22416
22448
|
"diff",
|
|
22417
22449
|
"staged",
|
|
22418
22450
|
"baseline"
|
|
22419
22451
|
]);
|
|
22452
|
+
const Framework = Literals(FRAMEWORK_TOKENS);
|
|
22420
22453
|
var JsonReportSummary = class extends Class("JsonReportSummary")({
|
|
22421
22454
|
errorCount: Number$1,
|
|
22422
22455
|
warningCount: Number$1,
|
|
@@ -22454,13 +22487,22 @@ var JsonReportProjectEntry = class extends Class("JsonReportProjectEntry")({
|
|
|
22454
22487
|
scannedFileCount: optional(Number$1),
|
|
22455
22488
|
elapsedMilliseconds: Number$1
|
|
22456
22489
|
}) {};
|
|
22457
|
-
|
|
22458
|
-
|
|
22459
|
-
|
|
22460
|
-
|
|
22461
|
-
|
|
22462
|
-
|
|
22463
|
-
|
|
22490
|
+
var JsonReportProjectEntryV3 = class extends Class("JsonReportProjectEntryV3")({
|
|
22491
|
+
directory: String$1,
|
|
22492
|
+
packageRoot: String$1,
|
|
22493
|
+
framework: Framework,
|
|
22494
|
+
project: Unknown,
|
|
22495
|
+
diagnostics: ArraySchema(JsonReportDiagnosticV3),
|
|
22496
|
+
score: Unknown,
|
|
22497
|
+
skippedChecks: ArraySchema(String$1),
|
|
22498
|
+
skippedCheckReasons: optional(Record$1(String$1, String$1)),
|
|
22499
|
+
analyzedFiles: ArraySchema(String$1),
|
|
22500
|
+
analyzedFileCount: Number$1,
|
|
22501
|
+
complete: Boolean$1,
|
|
22502
|
+
scannedFileCount: optional(Number$1),
|
|
22503
|
+
elapsedMilliseconds: Number$1
|
|
22504
|
+
}) {};
|
|
22505
|
+
/** Original full, diff, and staged report contract. */
|
|
22464
22506
|
var JsonReportV1 = class extends Class("JsonReportV1")({
|
|
22465
22507
|
schemaVersion: Literal(1),
|
|
22466
22508
|
version: String$1,
|
|
@@ -22521,7 +22563,27 @@ var JsonReportV2 = class extends Class("JsonReportV2")({
|
|
|
22521
22563
|
elapsedMilliseconds: Number$1,
|
|
22522
22564
|
error: NullOr(JsonReportError)
|
|
22523
22565
|
}) {};
|
|
22524
|
-
|
|
22566
|
+
var JsonReportV3 = class extends Class("JsonReportV3")({
|
|
22567
|
+
schemaVersion: Literal(3),
|
|
22568
|
+
version: String$1,
|
|
22569
|
+
ok: Boolean$1,
|
|
22570
|
+
directory: String$1,
|
|
22571
|
+
mode: JsonReportMode,
|
|
22572
|
+
baselineDegraded: optional(Boolean$1),
|
|
22573
|
+
reactDetected: optional(Boolean$1),
|
|
22574
|
+
diff: NullOr(JsonReportDiffInfo),
|
|
22575
|
+
baseline: optional(JsonReportBaseline),
|
|
22576
|
+
projects: ArraySchema(JsonReportProjectEntryV3),
|
|
22577
|
+
diagnostics: ArraySchema(JsonReportDiagnosticV3),
|
|
22578
|
+
summary: JsonReportSummary,
|
|
22579
|
+
elapsedMilliseconds: Number$1,
|
|
22580
|
+
error: NullOr(JsonReportError)
|
|
22581
|
+
}) {};
|
|
22582
|
+
Union([
|
|
22583
|
+
JsonReportV1,
|
|
22584
|
+
JsonReportV2,
|
|
22585
|
+
JsonReportV3
|
|
22586
|
+
]);
|
|
22525
22587
|
//#endregion
|
|
22526
22588
|
//#region ../../node_modules/.pnpm/semver@7.7.4/node_modules/semver/internal/constants.js
|
|
22527
22589
|
var require_constants$1 = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
|
|
@@ -36179,7 +36241,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
|
|
|
36179
36241
|
const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
|
|
36180
36242
|
const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
|
|
36181
36243
|
const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
|
|
36182
|
-
const CORE_PACKAGE_VERSION = "0.7.
|
|
36244
|
+
const CORE_PACKAGE_VERSION = "0.7.5";
|
|
36183
36245
|
const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
|
|
36184
36246
|
const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
|
|
36185
36247
|
const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
@@ -37085,6 +37147,22 @@ const isPackageJsonReanimatedAware = (packageJson) => {
|
|
|
37085
37147
|
};
|
|
37086
37148
|
return Object.hasOwn(allDependencies, REANIMATED_DEPENDENCY_NAME$1);
|
|
37087
37149
|
};
|
|
37150
|
+
const SSR_DEPENDENCY_NAMES = new Set([
|
|
37151
|
+
"@react-router/cloudflare",
|
|
37152
|
+
"@react-router/node",
|
|
37153
|
+
"@react-router/serve",
|
|
37154
|
+
"vike",
|
|
37155
|
+
"vite-plugin-ssr"
|
|
37156
|
+
]);
|
|
37157
|
+
const isPackageJsonSsrAware = (packageJson) => {
|
|
37158
|
+
const allDependencies = {
|
|
37159
|
+
...packageJson.peerDependencies,
|
|
37160
|
+
...packageJson.dependencies,
|
|
37161
|
+
...packageJson.devDependencies,
|
|
37162
|
+
...packageJson.optionalDependencies
|
|
37163
|
+
};
|
|
37164
|
+
return Object.keys(allDependencies).some((packageName) => SSR_DEPENDENCY_NAMES.has(packageName));
|
|
37165
|
+
};
|
|
37088
37166
|
const getWorkspacePatterns = (rootDirectory, packageJson) => {
|
|
37089
37167
|
const pnpmPatterns = parsePnpmWorkspacePatterns(rootDirectory);
|
|
37090
37168
|
if (pnpmPatterns.length > 0) return pnpmPatterns;
|
|
@@ -37225,6 +37303,7 @@ const evaluateManifestFacts = (facts, packageJson, directory) => {
|
|
|
37225
37303
|
}
|
|
37226
37304
|
facts.hasReactNativeAwarePackage = facts.hasReactNativeAwarePackage || isPackageJsonReactNativeAware(packageJson);
|
|
37227
37305
|
facts.hasReanimatedAwarePackage = facts.hasReanimatedAwarePackage || isPackageJsonReanimatedAware(packageJson);
|
|
37306
|
+
facts.hasSsrDependency = facts.hasSsrDependency || isPackageJsonSsrAware(packageJson);
|
|
37228
37307
|
};
|
|
37229
37308
|
const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGroup }) => {
|
|
37230
37309
|
const facts = {
|
|
@@ -37246,6 +37325,7 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
|
|
|
37246
37325
|
},
|
|
37247
37326
|
hasReactNativeAwarePackage: false,
|
|
37248
37327
|
hasReanimatedAwarePackage: false,
|
|
37328
|
+
hasSsrDependency: false,
|
|
37249
37329
|
reanimatedVersion: null
|
|
37250
37330
|
};
|
|
37251
37331
|
evaluateManifestFacts(facts, rootPackageJson, rootDirectory);
|
|
@@ -37482,6 +37562,7 @@ const discoverProjectWithoutPackageJson = (directory) => {
|
|
|
37482
37562
|
hasTypeScript: hasOwnTsConfig,
|
|
37483
37563
|
hasReactCompiler: false,
|
|
37484
37564
|
hasTanStackQuery: false,
|
|
37565
|
+
hasSsrDependency: false,
|
|
37485
37566
|
preactVersion: null,
|
|
37486
37567
|
preactMajorVersion: null,
|
|
37487
37568
|
hasReactNativeWorkspace: false,
|
|
@@ -37601,6 +37682,7 @@ const discoverProject = (directory) => {
|
|
|
37601
37682
|
hasTypeScript,
|
|
37602
37683
|
hasReactCompiler: detectReactCompiler(directory, packageJson),
|
|
37603
37684
|
hasTanStackQuery: hasTanStackQuery(packageJson),
|
|
37685
|
+
hasSsrDependency: workspaceFacts.hasSsrDependency,
|
|
37604
37686
|
preactVersion,
|
|
37605
37687
|
preactMajorVersion: parseReactMajor(preactVersion),
|
|
37606
37688
|
hasReactNativeWorkspace,
|
|
@@ -38687,6 +38769,14 @@ var AmbiguousProject = class extends TaggedErrorClass()("AmbiguousProject", {
|
|
|
38687
38769
|
return `Ambiguous project at ${this.directory}: found ${this.candidates.length} candidates (${this.candidates.join(", ")})`;
|
|
38688
38770
|
}
|
|
38689
38771
|
};
|
|
38772
|
+
var ProjectDiscoveryFailed = class extends TaggedErrorClass()("ProjectDiscoveryFailed", {
|
|
38773
|
+
directory: String$1,
|
|
38774
|
+
cause: Unknown
|
|
38775
|
+
}) {
|
|
38776
|
+
get message() {
|
|
38777
|
+
return `Project discovery failed for ${this.directory}: ${pretty(fail$6(this.cause))}`;
|
|
38778
|
+
}
|
|
38779
|
+
};
|
|
38690
38780
|
var DeadCodeAnalysisFailed = class extends TaggedErrorClass()("DeadCodeAnalysisFailed", { cause: Unknown }) {
|
|
38691
38781
|
get message() {
|
|
38692
38782
|
return `Dead-code analysis failed: ${pretty(fail$6(this.cause))}`;
|
|
@@ -38721,6 +38811,7 @@ const ReactDoctorErrorReason = Union([
|
|
|
38721
38811
|
ProjectNotFound,
|
|
38722
38812
|
NoReactDependency,
|
|
38723
38813
|
AmbiguousProject,
|
|
38814
|
+
ProjectDiscoveryFailed,
|
|
38724
38815
|
DeadCodeAnalysisFailed,
|
|
38725
38816
|
GitInvocationFailed,
|
|
38726
38817
|
GitBaseBranchMissing,
|
|
@@ -40445,6 +40536,12 @@ const CLIENT_ONLY_FRAMEWORKS = new Set([
|
|
|
40445
40536
|
"react-native",
|
|
40446
40537
|
"expo"
|
|
40447
40538
|
]);
|
|
40539
|
+
const SSR_FRAMEWORKS = new Set([
|
|
40540
|
+
"nextjs",
|
|
40541
|
+
"remix",
|
|
40542
|
+
"gatsby",
|
|
40543
|
+
"tanstack-start"
|
|
40544
|
+
]);
|
|
40448
40545
|
const addMajorLadder = (capabilities, name, major, earliest, latest) => {
|
|
40449
40546
|
if (major === null) return;
|
|
40450
40547
|
const cappedMajor = Math.min(major, latest);
|
|
@@ -40457,6 +40554,7 @@ const buildCapabilities = (project) => {
|
|
|
40457
40554
|
if (project.framework === "expo" || project.framework === "react-native" || project.hasReactNativeWorkspace) capabilities.add("react-native");
|
|
40458
40555
|
if (project.expoVersion !== null) capabilities.add("expo");
|
|
40459
40556
|
if ((project.framework === "nextjs" || project.framework === "tanstack-start" || project.framework === "remix") && !project.isStaticExport) capabilities.add("server-actions");
|
|
40557
|
+
if (SSR_FRAMEWORKS.has(project.framework) || project.hasSsrDependency) capabilities.add("ssr");
|
|
40460
40558
|
if (CLIENT_ONLY_FRAMEWORKS.has(project.framework)) capabilities.add("client-only");
|
|
40461
40559
|
if (project.isStaticExport) capabilities.add("nextjs:static-export");
|
|
40462
40560
|
if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 15) capabilities.add("nextjs:15");
|
|
@@ -42270,7 +42368,7 @@ const normalizeConfigForHash = (config) => {
|
|
|
42270
42368
|
if (Array.isArray(clone?.jsPlugins)) clone.jsPlugins = clone.jsPlugins.map((_, index) => `<plugin:${index}>`);
|
|
42271
42369
|
return clone;
|
|
42272
42370
|
};
|
|
42273
|
-
const computeRulesetHash = (input) => crypto.createHash("sha1").update(JSON.stringify(normalizeConfigForHash(input.config))).update("\0").update([...input.toolchainVersions].join("\0")).update("\0").update([...input.ignorePatterns].join("\n")).update("\0").update(input.tsconfigContent ?? "").digest("hex");
|
|
42371
|
+
const computeRulesetHash = (input) => crypto.createHash("sha1").update(JSON.stringify(normalizeConfigForHash(input.config))).update("\0").update([...input.toolchainVersions].join("\0")).update("\0").update([...input.ignorePatterns].join("\n")).update("\0").update(input.tsconfigContent ?? "").update("\0").update(input.respectInlineDisables ? "respect-inline-disables" : "audit-mode").digest("hex");
|
|
42274
42372
|
/**
|
|
42275
42373
|
* Loads a plugin module via the local require resolver and extracts
|
|
42276
42374
|
* `(name, ruleNames)` from either `module.exports.meta + rules` or
|
|
@@ -42306,7 +42404,7 @@ const resolveReactHooksJsPlugin = (hasReactCompiler, customRulesOnly) => {
|
|
|
42306
42404
|
} catch {
|
|
42307
42405
|
return null;
|
|
42308
42406
|
}
|
|
42309
|
-
const { ruleNames } = readPluginShape(pluginSpecifier, (
|
|
42407
|
+
const { ruleNames } = readPluginShape(pluginSpecifier, (specifier) => bundledRequire$1(specifier));
|
|
42310
42408
|
return {
|
|
42311
42409
|
entry: {
|
|
42312
42410
|
name: "react-hooks-js",
|
|
@@ -42714,6 +42812,23 @@ const resolveTsConfigRelativePath = (rootDirectory) => {
|
|
|
42714
42812
|
for (const filename of TSCONFIG_FILENAMES) if (NFS.existsSync(Path.join(rootDirectory, filename))) return `./${filename}`;
|
|
42715
42813
|
return null;
|
|
42716
42814
|
};
|
|
42815
|
+
const DERIVED_STATE_RULE_PRIORITY = new Map([
|
|
42816
|
+
["no-initialize-state", 0],
|
|
42817
|
+
["no-adjust-state-on-prop-change", 1],
|
|
42818
|
+
["no-derived-state", 2],
|
|
42819
|
+
["no-derived-state-effect", 3]
|
|
42820
|
+
]);
|
|
42821
|
+
const doDiagnosticSpansOverlap = (first, second) => {
|
|
42822
|
+
if (first.filePath !== second.filePath || first.plugin !== second.plugin) return false;
|
|
42823
|
+
if (first.offset !== void 0 && second.offset !== void 0) {
|
|
42824
|
+
const firstEnd = first.offset + Math.max(first.length ?? 1, 1);
|
|
42825
|
+
const secondEnd = second.offset + Math.max(second.length ?? 1, 1);
|
|
42826
|
+
return first.offset < secondEnd && second.offset < firstEnd;
|
|
42827
|
+
}
|
|
42828
|
+
const firstEndLine = first.endLine ?? first.line;
|
|
42829
|
+
const secondEndLine = second.endLine ?? second.line;
|
|
42830
|
+
return first.line <= secondEndLine && second.line <= firstEndLine;
|
|
42831
|
+
};
|
|
42717
42832
|
const dedupeDiagnostics = (diagnostics) => {
|
|
42718
42833
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
42719
42834
|
const uniqueDiagnostics = [];
|
|
@@ -42721,6 +42836,16 @@ const dedupeDiagnostics = (diagnostics) => {
|
|
|
42721
42836
|
const key = `${diagnostic.filePath}\u0000${diagnostic.line}\u0000${diagnostic.column}\u0000${diagnostic.plugin}\u0000${diagnostic.rule}\u0000${diagnostic.severity}\u0000${diagnostic.message}`;
|
|
42722
42837
|
if (seenKeys.has(key)) continue;
|
|
42723
42838
|
seenKeys.add(key);
|
|
42839
|
+
const priority = DERIVED_STATE_RULE_PRIORITY.get(diagnostic.rule);
|
|
42840
|
+
if (priority !== void 0) {
|
|
42841
|
+
const overlappingDiagnosticIndex = uniqueDiagnostics.findIndex((candidate) => candidate.rule !== diagnostic.rule && candidate.severity === diagnostic.severity && DERIVED_STATE_RULE_PRIORITY.has(candidate.rule) && doDiagnosticSpansOverlap(candidate, diagnostic));
|
|
42842
|
+
if (overlappingDiagnosticIndex >= 0) {
|
|
42843
|
+
const existingDiagnostic = uniqueDiagnostics[overlappingDiagnosticIndex];
|
|
42844
|
+
const existingPriority = existingDiagnostic ? DERIVED_STATE_RULE_PRIORITY.get(existingDiagnostic.rule) : void 0;
|
|
42845
|
+
if (existingPriority !== void 0 && priority < existingPriority) uniqueDiagnostics[overlappingDiagnosticIndex] = diagnostic;
|
|
42846
|
+
continue;
|
|
42847
|
+
}
|
|
42848
|
+
}
|
|
42724
42849
|
uniqueDiagnostics.push(diagnostic);
|
|
42725
42850
|
}
|
|
42726
42851
|
return uniqueDiagnostics;
|
|
@@ -43594,6 +43719,11 @@ const buildOxlintChildEnv = (sourceEnv) => {
|
|
|
43594
43719
|
if (!isCompileCacheDisabled && !isCompileCacheAlreadySet) childEnv.NODE_COMPILE_CACHE = Path.join(os.tmpdir(), NODE_COMPILE_CACHE_DIR_NAME);
|
|
43595
43720
|
return childEnv;
|
|
43596
43721
|
};
|
|
43722
|
+
const buildProfiledNodeArguments = (input) => [
|
|
43723
|
+
...input.cpuProfileDirectory ? ["--cpu-prof", `--cpu-prof-dir=${input.cpuProfileDirectory}`] : [],
|
|
43724
|
+
...input.heapProfileDirectory ? ["--heap-prof", `--heap-prof-dir=${input.heapProfileDirectory}`] : [],
|
|
43725
|
+
...input.argumentsList
|
|
43726
|
+
];
|
|
43597
43727
|
const SANITIZED_ENV = buildOxlintChildEnv(process.env);
|
|
43598
43728
|
/**
|
|
43599
43729
|
* Spawn one oxlint subprocess with hard ceilings on wall time and
|
|
@@ -43618,7 +43748,11 @@ const spawnOxlint = (args, rootDirectory, nodeBinaryPath, spawnTimeoutMs = OXLIN
|
|
|
43618
43748
|
reject(new ReactDoctorError({ reason: new OxlintSpawnFailed({ cause: "lint phase aborted" }) }));
|
|
43619
43749
|
return;
|
|
43620
43750
|
}
|
|
43621
|
-
const child = spawn(nodeBinaryPath,
|
|
43751
|
+
const child = spawn(nodeBinaryPath, buildProfiledNodeArguments({
|
|
43752
|
+
argumentsList: args,
|
|
43753
|
+
cpuProfileDirectory: SANITIZED_ENV.REACT_DOCTOR_CPU_PROFILE_DIR,
|
|
43754
|
+
heapProfileDirectory: SANITIZED_ENV.REACT_DOCTOR_HEAP_PROFILE_DIR
|
|
43755
|
+
}), {
|
|
43622
43756
|
cwd: rootDirectory,
|
|
43623
43757
|
env: SANITIZED_ENV,
|
|
43624
43758
|
stdio: [
|
|
@@ -43877,6 +44011,8 @@ const spawnLintBatches = async (input) => {
|
|
|
43877
44011
|
const reasonHint = firstDropReason ? ` — first failure: ${firstDropReason}` : "";
|
|
43878
44012
|
reportSkippedFiles(droppedFiles, (fileListPreview) => `${droppedFiles.length} file(s) failed to lint and were skipped (${fileListPreview})${reasonHint}`);
|
|
43879
44013
|
reportSkippedFiles(outcome.deadlineSkippedFiles, (fileListPreview) => `${outcome.deadlineSkippedFiles.length} file(s) skipped — max scan duration reached before they were linted (${fileListPreview})`);
|
|
44014
|
+
const unavailableFiles = new Set([...droppedFiles, ...outcome.deadlineSkippedFiles]);
|
|
44015
|
+
input.onAnalyzedFiles?.([...new Set(fileBatches.flat().filter((filePath) => !unavailableFiles.has(filePath)))].sort());
|
|
43880
44016
|
return dedupeDiagnostics(diagnostics);
|
|
43881
44017
|
};
|
|
43882
44018
|
let didValidate = false;
|
|
@@ -44133,12 +44269,18 @@ const reactHooksJsPluginDropNote = (error) => {
|
|
|
44133
44269
|
* 6. always restore disable directives + clean up the temp dir
|
|
44134
44270
|
*/
|
|
44135
44271
|
const runOxlint = async (options) => {
|
|
44136
|
-
const { rootDirectory, project, includePaths, nodeBinaryPath = process.execPath, customRulesOnly = false, respectInlineDisables = true, adoptExistingLintConfig = true, ignoredTags = /* @__PURE__ */ new Set(), userConfig, configSourceDirectory = rootDirectory, onPartialFailure, perFileLintCacheEnabled = false, sidecarLintCacheEnabled = false, onCacheStats, onSidecarStats, spawnTimeoutMs, outputMaxBytes, lintBatchOrdering = "cost" } = options;
|
|
44272
|
+
const { rootDirectory, project, includePaths, nodeBinaryPath = process.execPath, customRulesOnly = false, respectInlineDisables = true, adoptExistingLintConfig = true, ignoredTags = /* @__PURE__ */ new Set(), userConfig, configSourceDirectory = rootDirectory, onPartialFailure, onFileCoverage, perFileLintCacheEnabled = false, sidecarLintCacheEnabled = false, onCacheStats, onSidecarStats, spawnTimeoutMs, outputMaxBytes, lintBatchOrdering = "cost" } = options;
|
|
44137
44273
|
const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
|
|
44138
44274
|
const severityControls = buildRuleSeverityControls(userConfig);
|
|
44139
44275
|
validateRuleRegistration();
|
|
44140
44276
|
resetManifestCaches();
|
|
44141
|
-
if (includePaths !== void 0 && includePaths.length === 0)
|
|
44277
|
+
if (includePaths !== void 0 && includePaths.length === 0) {
|
|
44278
|
+
onFileCoverage?.({
|
|
44279
|
+
candidateFiles: [],
|
|
44280
|
+
analyzedFiles: []
|
|
44281
|
+
});
|
|
44282
|
+
return [];
|
|
44283
|
+
}
|
|
44142
44284
|
const pluginPath = resolvePluginPath();
|
|
44143
44285
|
const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
|
|
44144
44286
|
const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
|
|
@@ -44199,6 +44341,7 @@ const runOxlint = async (options) => {
|
|
|
44199
44341
|
const runConfigOverFiles = async (buildConfigForPass, configFileName, files, fileProgress) => {
|
|
44200
44342
|
if (files.length === 0) return {
|
|
44201
44343
|
diagnostics: [],
|
|
44344
|
+
analyzedFiles: [],
|
|
44202
44345
|
didDropReactHooksJsPlugin: false,
|
|
44203
44346
|
hadPartialFailure: false
|
|
44204
44347
|
};
|
|
@@ -44210,24 +44353,32 @@ const runOxlint = async (options) => {
|
|
|
44210
44353
|
const passConfigPath = Path.join(configDirectory, configFileName);
|
|
44211
44354
|
const passBaseArgs = makeBaseArgs(passConfigPath);
|
|
44212
44355
|
const passFileBatches = buildFileBatches(passBaseArgs, files);
|
|
44213
|
-
|
|
44214
|
-
|
|
44215
|
-
|
|
44216
|
-
|
|
44217
|
-
|
|
44218
|
-
|
|
44219
|
-
|
|
44220
|
-
|
|
44221
|
-
|
|
44222
|
-
|
|
44223
|
-
|
|
44224
|
-
|
|
44225
|
-
|
|
44226
|
-
|
|
44356
|
+
let analyzedFiles = [];
|
|
44357
|
+
const spawnPass = () => {
|
|
44358
|
+
analyzedFiles = [];
|
|
44359
|
+
return spawnLintBatches({
|
|
44360
|
+
baseArgs: passBaseArgs,
|
|
44361
|
+
fileBatches: passFileBatches,
|
|
44362
|
+
rootDirectory,
|
|
44363
|
+
nodeBinaryPath,
|
|
44364
|
+
project,
|
|
44365
|
+
onPartialFailure: reportPartialFailure,
|
|
44366
|
+
onAnalyzedFiles: (filePaths) => {
|
|
44367
|
+
analyzedFiles = filePaths;
|
|
44368
|
+
},
|
|
44369
|
+
onFileProgress: fileProgress,
|
|
44370
|
+
spawnTimeoutMs,
|
|
44371
|
+
outputMaxBytes,
|
|
44372
|
+
concurrency: options.concurrency,
|
|
44373
|
+
signal: options.signal,
|
|
44374
|
+
deadlineEpochMs: options.deadlineEpochMs
|
|
44375
|
+
});
|
|
44376
|
+
};
|
|
44227
44377
|
writeOxlintConfig(passConfigPath, buildConfigForPass({}));
|
|
44228
44378
|
try {
|
|
44229
44379
|
return {
|
|
44230
44380
|
diagnostics: await spawnPass(),
|
|
44381
|
+
analyzedFiles,
|
|
44231
44382
|
didDropReactHooksJsPlugin: false,
|
|
44232
44383
|
hadPartialFailure
|
|
44233
44384
|
};
|
|
@@ -44239,12 +44390,13 @@ const runOxlint = async (options) => {
|
|
|
44239
44390
|
reportPartialFailure(reactHooksJsDropNote);
|
|
44240
44391
|
return {
|
|
44241
44392
|
diagnostics,
|
|
44393
|
+
analyzedFiles,
|
|
44242
44394
|
didDropReactHooksJsPlugin: true,
|
|
44243
44395
|
hadPartialFailure
|
|
44244
44396
|
};
|
|
44245
44397
|
}
|
|
44246
44398
|
};
|
|
44247
|
-
if (perFileLintCacheEnabled &&
|
|
44399
|
+
if (perFileLintCacheEnabled && !project.hasReactCompiler && extendsPaths.length === 0 && userPlugins.length === 0) {
|
|
44248
44400
|
const rulesetHash = computeRulesetHash({
|
|
44249
44401
|
config: buildConfig({
|
|
44250
44402
|
extendsPaths: [],
|
|
@@ -44252,7 +44404,8 @@ const runOxlint = async (options) => {
|
|
|
44252
44404
|
}),
|
|
44253
44405
|
toolchainVersions: resolveOxlintToolchainVersions(nodeBinaryPath),
|
|
44254
44406
|
ignorePatterns: combinedPatterns,
|
|
44255
|
-
tsconfigContent
|
|
44407
|
+
tsconfigContent,
|
|
44408
|
+
respectInlineDisables
|
|
44256
44409
|
});
|
|
44257
44410
|
const cache = createFileLintCache(resolveReactDoctorCacheDir(rootDirectory), rulesetHash);
|
|
44258
44411
|
const cacheKeyByFile = /* @__PURE__ */ new Map();
|
|
@@ -44295,7 +44448,8 @@ const runOxlint = async (options) => {
|
|
|
44295
44448
|
}),
|
|
44296
44449
|
toolchainVersions: resolveOxlintToolchainVersions(nodeBinaryPath),
|
|
44297
44450
|
ignorePatterns: combinedPatterns,
|
|
44298
|
-
tsconfigContent
|
|
44451
|
+
tsconfigContent,
|
|
44452
|
+
respectInlineDisables
|
|
44299
44453
|
})) : null;
|
|
44300
44454
|
const probeAnswers = createSidecarProbeAnswerResolver({
|
|
44301
44455
|
rootDirectory,
|
|
@@ -44314,6 +44468,7 @@ const runOxlint = async (options) => {
|
|
|
44314
44468
|
const missFileSet = new Set(missFiles);
|
|
44315
44469
|
const hitFiles = candidateFiles.filter((candidateFile) => !missFileSet.has(candidateFile));
|
|
44316
44470
|
const sidecarReplayedDiagnostics = [];
|
|
44471
|
+
const sidecarReplayedFiles = [];
|
|
44317
44472
|
const sidecarLintFiles = [];
|
|
44318
44473
|
if (sidecarCache === null) sidecarLintFiles.push(...hitFiles);
|
|
44319
44474
|
else {
|
|
@@ -44321,8 +44476,10 @@ const runOxlint = async (options) => {
|
|
|
44321
44476
|
for (const hitFile of hitFiles) {
|
|
44322
44477
|
const cacheKey = cacheKeyByFile.get(hitFile);
|
|
44323
44478
|
const entry = cacheKey === void 0 ? null : sidecarCache.lookup(cacheKey);
|
|
44324
|
-
if (entry !== null && entry.probes.every((probe) => probeAnswers.answerFor(probe.kind, probe.path) === probe.answer))
|
|
44325
|
-
|
|
44479
|
+
if (entry !== null && entry.probes.every((probe) => probeAnswers.answerFor(probe.kind, probe.path) === probe.answer)) {
|
|
44480
|
+
sidecarReplayedFiles.push(hitFile);
|
|
44481
|
+
sidecarReplayedDiagnostics.push(...entry.diagnostics);
|
|
44482
|
+
} else sidecarLintFiles.push(hitFile);
|
|
44326
44483
|
if (performance.now() - verifySliceStartedAt >= 12) {
|
|
44327
44484
|
await yieldToEventLoop();
|
|
44328
44485
|
verifySliceStartedAt = performance.now();
|
|
@@ -44348,6 +44505,7 @@ const runOxlint = async (options) => {
|
|
|
44348
44505
|
sidecarRuleIdFilter: new Set(unboundedSidecarRuleIds)
|
|
44349
44506
|
}), "oxlintrc.sidecar-unbounded.json", hitFiles, void 0) : {
|
|
44350
44507
|
diagnostics: [],
|
|
44508
|
+
analyzedFiles: [],
|
|
44351
44509
|
didDropReactHooksJsPlugin: false,
|
|
44352
44510
|
hadPartialFailure: false
|
|
44353
44511
|
};
|
|
@@ -44378,6 +44536,15 @@ const runOxlint = async (options) => {
|
|
|
44378
44536
|
probesByFile: await missProbesTask
|
|
44379
44537
|
}]
|
|
44380
44538
|
});
|
|
44539
|
+
const analyzedFileSet = new Set(fullResult.analyzedFiles);
|
|
44540
|
+
const boundedSidecarAnalyzedFileSet = new Set(boundedSidecarResult.analyzedFiles);
|
|
44541
|
+
const unboundedSidecarAnalyzedFileSet = new Set(unboundedSidecarResult.analyzedFiles);
|
|
44542
|
+
const sidecarReplayedFileSet = new Set(sidecarReplayedFiles);
|
|
44543
|
+
for (const hitFile of hitFiles) if (useSidecarCache ? (sidecarReplayedFileSet.has(hitFile) || boundedSidecarAnalyzedFileSet.has(hitFile)) && (unboundedSidecarRuleIds.length === 0 || unboundedSidecarAnalyzedFileSet.has(hitFile)) : boundedSidecarAnalyzedFileSet.has(hitFile)) analyzedFileSet.add(hitFile);
|
|
44544
|
+
onFileCoverage?.({
|
|
44545
|
+
candidateFiles,
|
|
44546
|
+
analyzedFiles: candidateFiles.filter((candidateFile) => analyzedFileSet.has(candidateFile))
|
|
44547
|
+
});
|
|
44381
44548
|
return dedupeDiagnostics([
|
|
44382
44549
|
...replayedDiagnostics,
|
|
44383
44550
|
...fullResult.diagnostics,
|
|
@@ -44388,6 +44555,7 @@ const runOxlint = async (options) => {
|
|
|
44388
44555
|
}
|
|
44389
44556
|
const baseArgs = makeBaseArgs(configPath);
|
|
44390
44557
|
const fileBatches = buildFileBatches(baseArgs, candidateFiles);
|
|
44558
|
+
let analyzedFiles = [];
|
|
44391
44559
|
const runBatches = () => spawnLintBatches({
|
|
44392
44560
|
baseArgs,
|
|
44393
44561
|
fileBatches,
|
|
@@ -44395,6 +44563,9 @@ const runOxlint = async (options) => {
|
|
|
44395
44563
|
nodeBinaryPath,
|
|
44396
44564
|
project,
|
|
44397
44565
|
onPartialFailure,
|
|
44566
|
+
onAnalyzedFiles: (filePaths) => {
|
|
44567
|
+
analyzedFiles = filePaths;
|
|
44568
|
+
},
|
|
44398
44569
|
onFileProgress: options.onFileProgress,
|
|
44399
44570
|
spawnTimeoutMs,
|
|
44400
44571
|
outputMaxBytes,
|
|
@@ -44404,7 +44575,12 @@ const runOxlint = async (options) => {
|
|
|
44404
44575
|
});
|
|
44405
44576
|
writeOxlintConfig(configPath, buildConfig({ extendsPaths }));
|
|
44406
44577
|
try {
|
|
44407
|
-
|
|
44578
|
+
const diagnostics = await runBatches();
|
|
44579
|
+
onFileCoverage?.({
|
|
44580
|
+
candidateFiles,
|
|
44581
|
+
analyzedFiles
|
|
44582
|
+
});
|
|
44583
|
+
return diagnostics;
|
|
44408
44584
|
} catch (error) {
|
|
44409
44585
|
const reactHooksJsDropNote = reactHooksJsPluginDropNote(error);
|
|
44410
44586
|
if (reactHooksJsDropNote !== null) {
|
|
@@ -44414,11 +44590,20 @@ const runOxlint = async (options) => {
|
|
|
44414
44590
|
}));
|
|
44415
44591
|
const diagnostics = await runBatches();
|
|
44416
44592
|
onPartialFailure?.(reactHooksJsDropNote);
|
|
44593
|
+
onFileCoverage?.({
|
|
44594
|
+
candidateFiles,
|
|
44595
|
+
analyzedFiles
|
|
44596
|
+
});
|
|
44417
44597
|
return diagnostics;
|
|
44418
44598
|
}
|
|
44419
44599
|
if (extendsPaths.length === 0) throw error;
|
|
44420
44600
|
writeOxlintConfig(configPath, buildConfig({ extendsPaths: [] }));
|
|
44421
|
-
|
|
44601
|
+
const diagnostics = await runBatches();
|
|
44602
|
+
onFileCoverage?.({
|
|
44603
|
+
candidateFiles,
|
|
44604
|
+
analyzedFiles
|
|
44605
|
+
});
|
|
44606
|
+
return diagnostics;
|
|
44422
44607
|
}
|
|
44423
44608
|
} finally {
|
|
44424
44609
|
restoreDisableDirectives();
|
|
@@ -44498,6 +44683,7 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
|
|
|
44498
44683
|
onPartialFailure: (reason) => {
|
|
44499
44684
|
collectedFailures.push(reason);
|
|
44500
44685
|
},
|
|
44686
|
+
onFileCoverage: input.onFileCoverage,
|
|
44501
44687
|
onFileProgress: input.onFileProgress,
|
|
44502
44688
|
perFileLintCacheEnabled,
|
|
44503
44689
|
sidecarLintCacheEnabled,
|
|
@@ -44590,7 +44776,10 @@ const translateProjectInfoError = (cause, directory) => {
|
|
|
44590
44776
|
directory: cause.directory,
|
|
44591
44777
|
candidates: cause.candidates
|
|
44592
44778
|
}) });
|
|
44593
|
-
return new ReactDoctorError({ reason: new
|
|
44779
|
+
return new ReactDoctorError({ reason: new ProjectDiscoveryFailed({
|
|
44780
|
+
directory,
|
|
44781
|
+
cause
|
|
44782
|
+
}) });
|
|
44594
44783
|
};
|
|
44595
44784
|
var Project = class Project extends Service()("react-doctor/Project") {
|
|
44596
44785
|
static layerNode = succeed$3(Project, Project.of({ discover: fn("Project.discover")(function* (directory) {
|
|
@@ -45202,6 +45391,7 @@ const resolveGithubActionsScoreMetadata = (environment = process.env) => {
|
|
|
45202
45391
|
...actorAssociation !== void 0 ? { githubActorAssociation: actorAssociation } : {}
|
|
45203
45392
|
};
|
|
45204
45393
|
};
|
|
45394
|
+
const toNormalizedRelativePath = (filePath, rootDirectory) => Path.relative(Path.resolve(rootDirectory), Path.resolve(rootDirectory, filePath)).replaceAll("\\", "/") || ".";
|
|
45205
45395
|
const NO_HOOKS = {
|
|
45206
45396
|
beforeLint: () => void_,
|
|
45207
45397
|
afterLint: () => void_
|
|
@@ -45300,7 +45490,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
45300
45490
|
repo
|
|
45301
45491
|
}).pipe(orElseSucceed(() => null)) : succeed$2(null));
|
|
45302
45492
|
const lintIncludePaths = (input.skipJsxIncludeFilter ? input.includePaths.length > 0 ? [...input.includePaths] : void 0 : computeExplicitLintIncludePaths([...input.includePaths], project)) ?? resolveLintIncludePaths(scanDirectory, resolvedConfig.config, project);
|
|
45303
|
-
const
|
|
45493
|
+
const fallbackScannedFilePaths = input.suppressScanSummary ? (lintIncludePaths ?? (yield* filesService.listSourceFiles(scanDirectory))).map((relativePath) => Path.resolve(scanDirectory, relativePath)) : [];
|
|
45304
45494
|
const beforeLint = hooks.beforeLint ?? NO_HOOKS.beforeLint;
|
|
45305
45495
|
const afterLint = hooks.afterLint ?? NO_HOOKS.afterLint;
|
|
45306
45496
|
yield* beforeLint(project, lintIncludePaths ?? void 0);
|
|
@@ -45405,6 +45595,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
45405
45595
|
let deadCodeCacheHit = null;
|
|
45406
45596
|
let deadCodeSummaryCacheHits = null;
|
|
45407
45597
|
let deadCodeSummaryCacheMisses = null;
|
|
45598
|
+
const lintFileCoverageState = { value: null };
|
|
45408
45599
|
const baseLintStream = linterService.run({
|
|
45409
45600
|
rootDirectory: scanDirectory,
|
|
45410
45601
|
project,
|
|
@@ -45420,6 +45611,9 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
45420
45611
|
lastReportedTotalFileCount = totalFileCount;
|
|
45421
45612
|
runSync(scanProgress.update(`Scanning files (${scannedFileCount}/${totalFileCount})${workerCountSuffix}...`));
|
|
45422
45613
|
},
|
|
45614
|
+
onFileCoverage: (coverage) => {
|
|
45615
|
+
lintFileCoverageState.value = coverage;
|
|
45616
|
+
},
|
|
45423
45617
|
onCacheStats: (cacheHitFileCount, totalConsideredFileCount) => {
|
|
45424
45618
|
lintCacheHitFileCount = cacheHitFileCount;
|
|
45425
45619
|
lintCacheTotalFileCount = totalConsideredFileCount;
|
|
@@ -45450,7 +45644,10 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
45450
45644
|
const lintFailureState = yield* get$2(lintFailure);
|
|
45451
45645
|
yield* afterLint(lintFailureState.didFail);
|
|
45452
45646
|
if (lintFailureState.didFail) yield* scanProgress.fail(formatLintFailText(lintFailureState.reasonTag, process.version));
|
|
45453
|
-
const
|
|
45647
|
+
const candidateFiles = lintFileCoverageState.value === null ? [] : [...new Set(lintFileCoverageState.value.candidateFiles.map((filePath) => toNormalizedRelativePath(filePath, scanDirectory)))];
|
|
45648
|
+
const analyzedFiles = lintFileCoverageState.value === null ? [] : [...new Set(lintFileCoverageState.value.analyzedFiles.map((filePath) => toNormalizedRelativePath(filePath, scanDirectory)))].sort();
|
|
45649
|
+
const totalFileCount = candidateFiles.length || lastReportedTotalFileCount || (lintIncludePaths?.length ?? project.sourceFileCount);
|
|
45650
|
+
const scannedFilePaths = input.suppressScanSummary ? candidateFiles.length > 0 ? candidateFiles.map((filePath) => Path.resolve(scanDirectory, filePath)) : fallbackScannedFilePaths : [];
|
|
45454
45651
|
const scannedFilesLabel = `${totalFileCount} ${totalFileCount === 1 ? "file" : "files"}`;
|
|
45455
45652
|
let deadCodeCollected = [];
|
|
45456
45653
|
if (lintFailureState.didFail) {
|
|
@@ -45532,6 +45729,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
45532
45729
|
deadCodeOverlapped: shouldOverlapDeadCode,
|
|
45533
45730
|
scannedFileCount: totalFileCount,
|
|
45534
45731
|
scannedFilePaths,
|
|
45732
|
+
analyzedFiles,
|
|
45535
45733
|
scanElapsedMilliseconds,
|
|
45536
45734
|
scanConcurrency,
|
|
45537
45735
|
supplyChainOverlapTimedOut: supplyChainResult.timedOut,
|
|
@@ -45807,7 +46005,7 @@ const buildJsonReportError = (input) => {
|
|
|
45807
46005
|
sentryEventId
|
|
45808
46006
|
};
|
|
45809
46007
|
return {
|
|
45810
|
-
schemaVersion:
|
|
46008
|
+
schemaVersion: 3,
|
|
45811
46009
|
version: input.version,
|
|
45812
46010
|
ok: false,
|
|
45813
46011
|
directory: input.directory,
|
|
@@ -45852,6 +46050,7 @@ const summarizeDiagnostics = (diagnostics, worstScore = null, worstScoreLabel =
|
|
|
45852
46050
|
* React-runtime rule family was gated off for the project.
|
|
45853
46051
|
*/
|
|
45854
46052
|
const hasReactRuntime = (project) => project.reactVersion !== null || project.preactVersion !== null;
|
|
46053
|
+
const isScanComplete = (input) => input.analyzedFileCount !== void 0 && input.scannedFileCount !== void 0 && input.skippedCheckCount === 0 && input.skippedCheckReasonCount === 0 && input.analyzedFileCount === input.scannedFileCount;
|
|
45855
46054
|
const toJsonDiff = (diff) => {
|
|
45856
46055
|
if (!diff) return null;
|
|
45857
46056
|
return {
|
|
@@ -45874,21 +46073,68 @@ const findWorstScoredProject = (projects) => {
|
|
|
45874
46073
|
}
|
|
45875
46074
|
return worst;
|
|
45876
46075
|
};
|
|
46076
|
+
const toJsonReportDiagnostic = (diagnostic, projectRoot, reportRoot) => {
|
|
46077
|
+
const normalizedFilePath = toNormalizedRelativePath(diagnostic.filePath, projectRoot);
|
|
46078
|
+
const reportRelativeFilePath = toNormalizedRelativePath(Path.resolve(projectRoot, diagnostic.filePath), reportRoot);
|
|
46079
|
+
const ruleIdentity = getDiagnosticRuleIdentity(diagnostic);
|
|
46080
|
+
return {
|
|
46081
|
+
...diagnostic,
|
|
46082
|
+
id: buildDiagnosticIdentity({
|
|
46083
|
+
filePath: reportRelativeFilePath,
|
|
46084
|
+
line: diagnostic.line,
|
|
46085
|
+
column: diagnostic.column,
|
|
46086
|
+
plugin: diagnostic.plugin,
|
|
46087
|
+
rule: diagnostic.rule
|
|
46088
|
+
}),
|
|
46089
|
+
normalizedFilePath,
|
|
46090
|
+
category: ruleIdentity.category,
|
|
46091
|
+
tags: [...new Set(ruleIdentity.tags)].sort()
|
|
46092
|
+
};
|
|
46093
|
+
};
|
|
45877
46094
|
const buildJsonReport = (input) => {
|
|
45878
|
-
const projects = input.scans.map(({ directory, result }) =>
|
|
45879
|
-
|
|
45880
|
-
|
|
45881
|
-
|
|
45882
|
-
|
|
45883
|
-
|
|
45884
|
-
|
|
45885
|
-
|
|
45886
|
-
|
|
45887
|
-
|
|
46095
|
+
const projects = input.scans.map(({ directory, result }) => {
|
|
46096
|
+
const skippedChecks = result.skippedChecks ?? [];
|
|
46097
|
+
const analyzedFiles = [...new Set((result.analyzedFiles ?? []).map((filePath) => toNormalizedRelativePath(filePath, result.project.rootDirectory)))].sort();
|
|
46098
|
+
const scannedFileCount = result.scannedFileCount ?? result.project.sourceFileCount;
|
|
46099
|
+
return {
|
|
46100
|
+
directory,
|
|
46101
|
+
packageRoot: result.project.rootDirectory,
|
|
46102
|
+
framework: result.project.framework,
|
|
46103
|
+
project: result.project,
|
|
46104
|
+
diagnostics: result.diagnostics.map((diagnostic) => toJsonReportDiagnostic(diagnostic, result.project.rootDirectory, input.directory)),
|
|
46105
|
+
score: result.score,
|
|
46106
|
+
skippedChecks,
|
|
46107
|
+
...result.skippedCheckReasons ? { skippedCheckReasons: result.skippedCheckReasons } : {},
|
|
46108
|
+
analyzedFiles,
|
|
46109
|
+
analyzedFileCount: analyzedFiles.length,
|
|
46110
|
+
complete: isScanComplete({
|
|
46111
|
+
analyzedFileCount: result.analyzedFiles === void 0 ? void 0 : analyzedFiles.length,
|
|
46112
|
+
scannedFileCount,
|
|
46113
|
+
skippedCheckCount: skippedChecks.length,
|
|
46114
|
+
skippedCheckReasonCount: Object.keys(result.skippedCheckReasons ?? {}).length
|
|
46115
|
+
}),
|
|
46116
|
+
...typeof result.scannedFileCount === "number" ? { scannedFileCount } : {},
|
|
46117
|
+
elapsedMilliseconds: result.elapsedMilliseconds
|
|
46118
|
+
};
|
|
46119
|
+
});
|
|
45888
46120
|
const flattenedDiagnostics = projects.flatMap((entry) => entry.diagnostics);
|
|
45889
46121
|
const worstScoredProject = findWorstScoredProject(projects);
|
|
45890
|
-
const
|
|
45891
|
-
const
|
|
46122
|
+
const diagnosticSummary = summarizeDiagnostics(flattenedDiagnostics, worstScoredProject?.score?.score ?? null, worstScoredProject?.score?.label ?? null);
|
|
46123
|
+
const affectedFileCount = projects.reduce((totalAffectedFileCount, project) => totalAffectedFileCount + new Set(project.diagnostics.map((diagnostic) => diagnostic.normalizedFilePath)).size, 0);
|
|
46124
|
+
const summary = {
|
|
46125
|
+
...diagnosticSummary,
|
|
46126
|
+
affectedFileCount
|
|
46127
|
+
};
|
|
46128
|
+
return {
|
|
46129
|
+
schemaVersion: 3,
|
|
46130
|
+
mode: input.baseline !== void 0 ? "baseline" : input.baselineDegraded && input.mode === "baseline" ? "diff" : input.mode,
|
|
46131
|
+
...input.baseline ? { baseline: {
|
|
46132
|
+
baseRef: input.baseline.baseRef,
|
|
46133
|
+
newCount: summary.totalDiagnosticCount,
|
|
46134
|
+
fixedCount: input.baseline.fixedCount,
|
|
46135
|
+
baseTotalCount: input.baseline.baseTotalCount
|
|
46136
|
+
} } : {},
|
|
46137
|
+
...input.baselineDegraded ? { baselineDegraded: true } : {},
|
|
45892
46138
|
...input.scans.length > 0 ? { reactDetected: input.scans.some((scan) => hasReactRuntime(scan.result.project)) } : {},
|
|
45893
46139
|
version: input.version,
|
|
45894
46140
|
ok: true,
|
|
@@ -45900,39 +46146,26 @@ const buildJsonReport = (input) => {
|
|
|
45900
46146
|
elapsedMilliseconds: input.totalElapsedMilliseconds,
|
|
45901
46147
|
error: null
|
|
45902
46148
|
};
|
|
45903
|
-
if (input.baseline) return {
|
|
45904
|
-
schemaVersion: 2,
|
|
45905
|
-
mode: "baseline",
|
|
45906
|
-
baseline: {
|
|
45907
|
-
baseRef: input.baseline.baseRef,
|
|
45908
|
-
newCount: summary.totalDiagnosticCount,
|
|
45909
|
-
fixedCount: input.baseline.fixedCount,
|
|
45910
|
-
baseTotalCount: input.baseline.baseTotalCount
|
|
45911
|
-
},
|
|
45912
|
-
...shared
|
|
45913
|
-
};
|
|
45914
|
-
return {
|
|
45915
|
-
schemaVersion: 1,
|
|
45916
|
-
mode: input.mode,
|
|
45917
|
-
...input.baselineDegraded ? { baselineDegraded: true } : {},
|
|
45918
|
-
...shared
|
|
45919
|
-
};
|
|
45920
46149
|
};
|
|
45921
46150
|
/**
|
|
45922
46151
|
* Single source of truth for the skipped-check accounting shared by the
|
|
45923
46152
|
* CLI renderer (`react-doctor/src/inspect.ts → finalizeAndRender`) and the
|
|
45924
46153
|
* programmatic shell (`@react-doctor/api → diagnose()`). Both surface a
|
|
45925
|
-
* failed
|
|
46154
|
+
* failed or partial analysis pass instead of a false "all clear", so the
|
|
45926
46155
|
* branch logic lives here once.
|
|
45927
46156
|
*/
|
|
45928
46157
|
const buildSkippedChecks = (input) => {
|
|
45929
46158
|
const skippedChecks = [];
|
|
45930
46159
|
if (input.didLintFail) skippedChecks.push("lint");
|
|
45931
46160
|
if (input.didDeadCodeFail) skippedChecks.push("dead-code");
|
|
46161
|
+
if (input.supplyChainOverlapTimedOut) skippedChecks.push("supply-chain");
|
|
46162
|
+
if (input.securityScanFailed) skippedChecks.push("security-scan");
|
|
45932
46163
|
const skippedCheckReasons = {};
|
|
45933
46164
|
if (input.didLintFail && input.lintFailureReason !== null) skippedCheckReasons.lint = input.lintFailureReason;
|
|
45934
46165
|
else if (input.lintPartialFailures.length > 0) skippedCheckReasons["lint:partial"] = input.lintPartialFailures.join("; ");
|
|
45935
46166
|
if (input.didDeadCodeFail && input.deadCodeFailureReason !== null) skippedCheckReasons["dead-code"] = input.deadCodeFailureReason;
|
|
46167
|
+
if (input.supplyChainOverlapTimedOut) skippedCheckReasons["supply-chain"] = "Supply-chain analysis timed out and was skipped.";
|
|
46168
|
+
if (input.securityScanFailed) skippedCheckReasons["security-scan"] = "Security scan failed and was skipped.";
|
|
45936
46169
|
return {
|
|
45937
46170
|
skippedChecks,
|
|
45938
46171
|
skippedCheckReasons
|
|
@@ -46347,7 +46580,7 @@ const GH_DEFAULT_BRANCH_PROBE_TIMEOUT_MS = 5e3;
|
|
|
46347
46580
|
const CI_TRUST_COMPANIES = "PayPal, Rippling, and Alibaba";
|
|
46348
46581
|
const WELCOME_EXPLANATION_HOLD_MS = 1e3;
|
|
46349
46582
|
const CATEGORY_COUNTUP_SETTLE_HOLD_MS = 1e3;
|
|
46350
|
-
const INTERNAL_ERROR_JSON_FALLBACK = "{\"schemaVersion\":
|
|
46583
|
+
const INTERNAL_ERROR_JSON_FALLBACK = "{\"schemaVersion\":3,\"version\":\"unknown\",\"ok\":false,\"directory\":\"\",\"mode\":\"full\",\"diff\":null,\"projects\":[],\"diagnostics\":[],\"summary\":{\"errorCount\":0,\"warningCount\":0,\"affectedFileCount\":0,\"totalDiagnosticCount\":0,\"score\":null,\"scoreLabel\":null},\"elapsedMilliseconds\":0,\"error\":{\"message\":\"Internal error\",\"name\":\"Error\",\"chain\":[]}}\n";
|
|
46351
46584
|
const SENTRY_FLUSH_TIMEOUT_MS = 2e3;
|
|
46352
46585
|
const NANOSECONDS_PER_SECOND = 1000000000n;
|
|
46353
46586
|
const METRIC = {
|
|
@@ -46434,7 +46667,7 @@ const makeNoopConsole = () => ({
|
|
|
46434
46667
|
});
|
|
46435
46668
|
//#endregion
|
|
46436
46669
|
//#region src/cli/utils/version.ts
|
|
46437
|
-
const VERSION = "0.7.
|
|
46670
|
+
const VERSION = "0.7.5-dev.037bd56";
|
|
46438
46671
|
//#endregion
|
|
46439
46672
|
//#region src/cli/utils/json-mode.ts
|
|
46440
46673
|
let context = null;
|
|
@@ -46803,13 +47036,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
|
|
|
46803
47036
|
* uploads source-map artifacts under, so stack frames symbolicate. Honors the
|
|
46804
47037
|
* standard `SENTRY_RELEASE` override.
|
|
46805
47038
|
*/
|
|
46806
|
-
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.
|
|
47039
|
+
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.5-dev.037bd56`;
|
|
46807
47040
|
/**
|
|
46808
47041
|
* Deployment environment shown in Sentry's environment filter. Defaults to
|
|
46809
47042
|
* `production` for tagged releases and `development` for dev/unbuilt versions,
|
|
46810
47043
|
* overridable via the standard `SENTRY_ENVIRONMENT` env var.
|
|
46811
47044
|
*/
|
|
46812
|
-
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.
|
|
47045
|
+
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.5-dev.037bd56") ? "development" : "production");
|
|
46813
47046
|
/**
|
|
46814
47047
|
* Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
|
|
46815
47048
|
* (set to `0` to disable tracing) and falls back to
|
|
@@ -59019,12 +59252,12 @@ const resolveCacheFilePath = (projectDirectory) => path.join(resolveReactDoctorC
|
|
|
59019
59252
|
const readPersistedCache = (cacheFilePath) => {
|
|
59020
59253
|
try {
|
|
59021
59254
|
const parsed = JSON.parse(fs.readFileSync(cacheFilePath, "utf8"));
|
|
59022
|
-
if (!isRecord(parsed) || parsed.version !==
|
|
59023
|
-
version:
|
|
59255
|
+
if (!isRecord(parsed) || parsed.version !== 5) return {
|
|
59256
|
+
version: 5,
|
|
59024
59257
|
entries: []
|
|
59025
59258
|
};
|
|
59026
59259
|
if (!Array.isArray(parsed.entries)) return {
|
|
59027
|
-
version:
|
|
59260
|
+
version: 5,
|
|
59028
59261
|
entries: []
|
|
59029
59262
|
};
|
|
59030
59263
|
const entries = [];
|
|
@@ -59034,12 +59267,12 @@ const readPersistedCache = (cacheFilePath) => {
|
|
|
59034
59267
|
entries.push(entry);
|
|
59035
59268
|
}
|
|
59036
59269
|
return {
|
|
59037
|
-
version:
|
|
59270
|
+
version: 5,
|
|
59038
59271
|
entries
|
|
59039
59272
|
};
|
|
59040
59273
|
} catch {
|
|
59041
59274
|
return {
|
|
59042
|
-
version:
|
|
59275
|
+
version: 5,
|
|
59043
59276
|
entries: []
|
|
59044
59277
|
};
|
|
59045
59278
|
}
|
|
@@ -59101,7 +59334,7 @@ const buildScanResultCacheKey = (input) => {
|
|
|
59101
59334
|
if (headSha === null) return null;
|
|
59102
59335
|
if (stringifyStableJson(input.userConfig) === null) return null;
|
|
59103
59336
|
const cacheKeyJson = stringifyStableJson({
|
|
59104
|
-
schemaVersion:
|
|
59337
|
+
schemaVersion: 5,
|
|
59105
59338
|
projectIdentity: resolveProjectIdentity(input.projectDirectory),
|
|
59106
59339
|
headSha,
|
|
59107
59340
|
worktreeFingerprint,
|
|
@@ -59142,7 +59375,7 @@ const createScanResultCache = (projectDirectory) => {
|
|
|
59142
59375
|
for (const entry of persistedCache.entries) entries.set(entry.key, entry);
|
|
59143
59376
|
const persist = () => {
|
|
59144
59377
|
writePersistedCache(cacheFilePath, {
|
|
59145
|
-
version:
|
|
59378
|
+
version: 5,
|
|
59146
59379
|
entries: [...entries.values()].sort((firstEntry, secondEntry) => secondEntry.createdAtMs - firstEntry.createdAtMs).slice(0, 20)
|
|
59147
59380
|
});
|
|
59148
59381
|
};
|
|
@@ -59283,6 +59516,7 @@ const buildOutcomeAttributes = (input) => {
|
|
|
59283
59516
|
return withNamespace("outcome", {
|
|
59284
59517
|
status: "error",
|
|
59285
59518
|
exitCode: 1,
|
|
59519
|
+
complete: false,
|
|
59286
59520
|
knownError: known,
|
|
59287
59521
|
errorTag: known ? error.reason._tag : error instanceof Error ? error.name : null
|
|
59288
59522
|
});
|
|
@@ -59292,8 +59526,13 @@ const buildOutcomeAttributes = (input) => {
|
|
|
59292
59526
|
const blockingLevel = resolveTelemetryBlocking(input.userConfig);
|
|
59293
59527
|
const gateDiagnostics = filterDiagnosticsForSurface(result.diagnostics, "ciFailure", input.userConfig);
|
|
59294
59528
|
const wouldBlock = !input.scoreOnly && !input.gateExempt && shouldBlockCi(gateDiagnostics, blockingLevel);
|
|
59295
|
-
const
|
|
59296
|
-
|
|
59529
|
+
const complete = isScanComplete({
|
|
59530
|
+
analyzedFileCount: result.analyzedFiles?.length,
|
|
59531
|
+
scannedFileCount: result.scannedFileCount,
|
|
59532
|
+
skippedCheckCount: result.skippedChecks.length,
|
|
59533
|
+
skippedCheckReasonCount: Object.keys(result.skippedCheckReasons ?? {}).length
|
|
59534
|
+
});
|
|
59535
|
+
const isClean = result.diagnostics.length === 0 && complete;
|
|
59297
59536
|
const outcome = wouldBlock ? "blocked" : isClean ? "clean" : "ok";
|
|
59298
59537
|
const firings = summarizeRuleFirings(result.diagnostics);
|
|
59299
59538
|
const countByRule = /* @__PURE__ */ new Map();
|
|
@@ -59343,6 +59582,7 @@ const buildOutcomeAttributes = (input) => {
|
|
|
59343
59582
|
wouldBlock,
|
|
59344
59583
|
blocking: blockingLevel,
|
|
59345
59584
|
clean: isClean,
|
|
59585
|
+
complete,
|
|
59346
59586
|
skippedChecks: result.skippedChecks.length
|
|
59347
59587
|
}),
|
|
59348
59588
|
...withNamespace("diag", {
|
|
@@ -60993,6 +61233,7 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
|
|
|
60993
61233
|
directory: output.resolvedDirectory,
|
|
60994
61234
|
scannedFileCount: output.scannedFileCount,
|
|
60995
61235
|
scannedFilePaths: output.scannedFilePaths,
|
|
61236
|
+
analyzedFiles: output.analyzedFiles,
|
|
60996
61237
|
scanElapsedMilliseconds: output.scanElapsedMilliseconds,
|
|
60997
61238
|
scanConcurrency: output.scanConcurrency,
|
|
60998
61239
|
baselineDelta,
|
|
@@ -61047,9 +61288,12 @@ const renderAndRecordScan = async (input) => {
|
|
|
61047
61288
|
lintPartialFailures: input.payload.lintPartialFailures,
|
|
61048
61289
|
didDeadCodeFail: input.payload.didDeadCodeFail,
|
|
61049
61290
|
deadCodeFailureReason: input.payload.deadCodeFailureReason,
|
|
61291
|
+
supplyChainOverlapTimedOut: input.payload.supplyChainOverlapTimedOut,
|
|
61292
|
+
securityScanFailed: input.payload.securityScanFailed ?? false,
|
|
61050
61293
|
directory: input.payload.directory,
|
|
61051
61294
|
scannedFileCount: input.payload.scannedFileCount,
|
|
61052
61295
|
scannedFilePaths: input.payload.scannedFilePaths,
|
|
61296
|
+
analyzedFiles: input.payload.analyzedFiles ?? [],
|
|
61053
61297
|
scanElapsedMilliseconds: input.payload.scanElapsedMilliseconds,
|
|
61054
61298
|
lintCacheHitFileCount: input.lintCacheHitFileCount ?? null,
|
|
61055
61299
|
lintCacheTotalFileCount: input.lintCacheTotalFileCount ?? null,
|
|
@@ -61097,13 +61341,15 @@ const renderAndRecordScan = async (input) => {
|
|
|
61097
61341
|
return result;
|
|
61098
61342
|
};
|
|
61099
61343
|
const finalizeAndRender = (input) => gen(function* () {
|
|
61100
|
-
const { options, elapsedMilliseconds, diagnostics, score, project, userConfig, didLintFail, lintFailureReason, lintPartialFailures, didDeadCodeFail, deadCodeFailureReason, directory, scannedFileCount, scannedFilePaths, scanElapsedMilliseconds, lintCacheHitFileCount, lintCacheTotalFileCount, lintSidecarReplayedFileCount, lintSidecarTotalFileCount, deadCodeCacheHit, deadCodeSummaryCacheHits, deadCodeSummaryCacheMisses, baselineDelta } = input;
|
|
61344
|
+
const { options, elapsedMilliseconds, diagnostics, score, project, userConfig, didLintFail, lintFailureReason, lintPartialFailures, didDeadCodeFail, deadCodeFailureReason, supplyChainOverlapTimedOut, securityScanFailed, directory, scannedFileCount, scannedFilePaths, analyzedFiles, scanElapsedMilliseconds, lintCacheHitFileCount, lintCacheTotalFileCount, lintSidecarReplayedFileCount, lintSidecarTotalFileCount, deadCodeCacheHit, deadCodeSummaryCacheHits, deadCodeSummaryCacheMisses, baselineDelta } = input;
|
|
61101
61345
|
const { skippedChecks, skippedCheckReasons } = buildSkippedChecks({
|
|
61102
61346
|
didLintFail,
|
|
61103
61347
|
lintFailureReason,
|
|
61104
61348
|
lintPartialFailures,
|
|
61105
61349
|
didDeadCodeFail,
|
|
61106
|
-
deadCodeFailureReason
|
|
61350
|
+
deadCodeFailureReason,
|
|
61351
|
+
supplyChainOverlapTimedOut,
|
|
61352
|
+
securityScanFailed
|
|
61107
61353
|
});
|
|
61108
61354
|
const hasSkippedChecks = skippedChecks.length > 0;
|
|
61109
61355
|
const noScoreMessage = buildNoScoreMessage(options.noScore);
|
|
@@ -61116,6 +61362,7 @@ const finalizeAndRender = (input) => gen(function* () {
|
|
|
61116
61362
|
elapsedMilliseconds,
|
|
61117
61363
|
scannedFileCount,
|
|
61118
61364
|
scannedFilePaths,
|
|
61365
|
+
analyzedFiles,
|
|
61119
61366
|
scanElapsedMilliseconds,
|
|
61120
61367
|
...lintCacheTotalFileCount !== null ? {
|
|
61121
61368
|
lintCacheHitFileCount,
|
|
@@ -64984,4 +65231,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
|
|
|
64984
65231
|
export {};
|
|
64985
65232
|
|
|
64986
65233
|
//# sourceMappingURL=cli.js.map
|
|
64987
|
-
//# debugId=
|
|
65234
|
+
//# debugId=ed6bfef3-a274-5972-833b-77462a1156e2
|