react-doctor 0.5.8-dev.c16e8ea → 0.5.8-dev.c2af308
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 +9 -3
- package/dist/cli.js +8966 -1325
- package/dist/index.js +139 -82
- package/dist/lsp.js +144 -82
- package/package.json +6 -5
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]="83529d8f-2ca3-50ba-a3b9-44622f913549")}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";
|
|
@@ -7,7 +7,7 @@ import fs from "node:fs";
|
|
|
7
7
|
import * as Path from "node:path";
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
import * as NodeChildProcess from "node:child_process";
|
|
10
|
-
import { spawn, spawnSync } from "node:child_process";
|
|
10
|
+
import { execFileSync, spawn, spawnSync } from "node:child_process";
|
|
11
11
|
import * as ts from "typescript";
|
|
12
12
|
import reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, classifySecurityScanFile, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor";
|
|
13
13
|
import * as OS from "node:os";
|
|
@@ -33695,6 +33695,9 @@ const SCORE_API_URL = "https://www.react.doctor/api/score";
|
|
|
33695
33695
|
const FETCH_TIMEOUT_MS = 1e4;
|
|
33696
33696
|
const GITHUB_VIEWER_PERMISSION_TIMEOUT_MS = 2e3;
|
|
33697
33697
|
const SPAWN_ARGS_MAX_LENGTH_CHARS = 24e3;
|
|
33698
|
+
const SPAWN_ARGS_MAX_LENGTH_CHARS_POSIX = 15e5;
|
|
33699
|
+
const SPAWN_ARGS_MAX_LENGTH_CHARS_DARWIN = 8e5;
|
|
33700
|
+
const NODE_VERSION_PROBE_TIMEOUT_MS = 5e3;
|
|
33698
33701
|
const PER_WORKER_MEM_BUDGET_BYTES = 1024 * 1024 * 1024;
|
|
33699
33702
|
const DEFAULT_BRANCH_CANDIDATES = ["main", "master"];
|
|
33700
33703
|
const ADOPTABLE_LINT_CONFIG_FILENAMES = [".oxlintrc.json", ".eslintrc.json"];
|
|
@@ -34519,7 +34522,7 @@ const tokenizeRuleList = (ruleList) => {
|
|
|
34519
34522
|
const FOREIGN_INLINE_DISABLE_PATTERN = /(?:\/\/|\/\*)[ \t]*(eslint|oxlint)-disable-(next-line|line)(?![\w-])([^\r\n]*)/;
|
|
34520
34523
|
const FOREIGN_BLOCK_DISABLE_PATTERN = /\/\*[ \t]*(eslint|oxlint)-disable(?![\w-])([^*\r\n]*)/;
|
|
34521
34524
|
const FOREIGN_BLOCK_ENABLE_PATTERN = /\/\*[ \t]*(?:eslint|oxlint)-enable(?![\w-])([^*\r\n]*)/;
|
|
34522
|
-
const buildHint = (tool, token, ruleId) => `oxlint matches plugin rules only by their full name, so \`${token}\` in your ${tool}-disable comment does not silence \`${ruleId}\` —
|
|
34525
|
+
const buildHint = (tool, token, ruleId) => `oxlint matches plugin rules only by their full name, so \`${token}\` in your ${tool}-disable comment does not silence \`${ruleId}\` — add \`${ruleId}\` to the comment (e.g. \`${token}, ${ruleId}\`).`;
|
|
34523
34526
|
const tokenMisnamesRule = (token, ruleId) => token !== ruleId && isSameRuleKey(token, ruleId);
|
|
34524
34527
|
const detectInlineNearMiss = (lines, diagnosticLineIndex, ruleId) => {
|
|
34525
34528
|
const candidates = [{
|
|
@@ -35040,6 +35043,21 @@ const buildDiagnosticPipeline = (input) => {
|
|
|
35040
35043
|
const fileLinesCache = /* @__PURE__ */ new Map();
|
|
35041
35044
|
const fileContextCache = /* @__PURE__ */ new Map();
|
|
35042
35045
|
const libraryFileCache = /* @__PURE__ */ new Map();
|
|
35046
|
+
const suppressions = /* @__PURE__ */ new Map();
|
|
35047
|
+
const suppress = (diagnostic, source) => {
|
|
35048
|
+
const { ruleKey } = getDiagnosticRuleIdentity(diagnostic);
|
|
35049
|
+
const suppressionKey = `${ruleKey}\u0000${source}`;
|
|
35050
|
+
const existing = suppressions.get(suppressionKey);
|
|
35051
|
+
suppressions.set(suppressionKey, existing ? {
|
|
35052
|
+
...existing,
|
|
35053
|
+
count: existing.count + 1
|
|
35054
|
+
} : {
|
|
35055
|
+
rule: ruleKey,
|
|
35056
|
+
source,
|
|
35057
|
+
count: 1
|
|
35058
|
+
});
|
|
35059
|
+
return null;
|
|
35060
|
+
};
|
|
35043
35061
|
const isLibraryFile = (filePath) => {
|
|
35044
35062
|
let cached = libraryFileCache.get(filePath);
|
|
35045
35063
|
if (cached === void 0) {
|
|
@@ -35094,51 +35112,54 @@ const buildDiagnosticPipeline = (input) => {
|
|
|
35094
35112
|
const identifierMatch = JSX_NO_UNDEF_IDENTIFIER_PATTERN.exec(diagnostic.message);
|
|
35095
35113
|
return identifierMatch !== null && runtimeGlobalNames.has(identifierMatch[1]);
|
|
35096
35114
|
};
|
|
35097
|
-
return {
|
|
35098
|
-
|
|
35099
|
-
|
|
35100
|
-
|
|
35101
|
-
|
|
35102
|
-
|
|
35103
|
-
|
|
35104
|
-
|
|
35105
|
-
|
|
35106
|
-
|
|
35107
|
-
|
|
35108
|
-
|
|
35109
|
-
|
|
35110
|
-
|
|
35111
|
-
|
|
35112
|
-
if (explicitRuleOverride === void 0) {
|
|
35113
|
-
if (isAppOnlyRule(`${current.plugin}/${current.rule}`) && isLibraryFile(current.filePath)) return null;
|
|
35114
|
-
}
|
|
35115
|
-
if (!showWarnings && current.severity === "warning" && explicitSeverityOverride !== "warn") return null;
|
|
35116
|
-
if (userConfig) {
|
|
35117
|
-
if (isRuleIgnored(`${current.plugin}/${current.rule}`)) return null;
|
|
35118
|
-
if (isFileIgnoredByPatterns(current.filePath, rootDirectory, ignoredFilePatterns)) return null;
|
|
35119
|
-
if (isDiagnosticIgnoredByOverrides(current, rootDirectory, compiledOverrides)) return null;
|
|
35120
|
-
if (isRnRawTextSuppressedByConfig(current)) return null;
|
|
35121
|
-
if (isJsxNoUndefSuppressedByConfig(current)) return null;
|
|
35122
|
-
}
|
|
35123
|
-
if (respectInlineDisables && current.line > 0) {
|
|
35124
|
-
const lines = getFileLines(current.filePath);
|
|
35125
|
-
if (lines) {
|
|
35126
|
-
const ruleIdentifier = `${current.plugin}/${current.rule}`;
|
|
35127
|
-
const evaluation = evaluateSuppression(lines, current.line - 1, ruleIdentifier);
|
|
35128
|
-
if (evaluation.isSuppressed) return null;
|
|
35129
|
-
if (evaluation.nearMissHint) current = {
|
|
35130
|
-
...current,
|
|
35131
|
-
suppressionHint: evaluation.nearMissHint
|
|
35132
|
-
};
|
|
35115
|
+
return {
|
|
35116
|
+
apply: (diagnostic) => {
|
|
35117
|
+
if (shouldAutoSuppress(diagnostic)) return null;
|
|
35118
|
+
let current = diagnostic;
|
|
35119
|
+
let explicitSeverityOverride;
|
|
35120
|
+
let explicitRuleOverride;
|
|
35121
|
+
if (severityControls) {
|
|
35122
|
+
const { ruleKey, category } = getDiagnosticRuleIdentity(current);
|
|
35123
|
+
explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey }, severityControls);
|
|
35124
|
+
explicitSeverityOverride = resolveRuleSeverityOverride({
|
|
35125
|
+
ruleKey,
|
|
35126
|
+
category
|
|
35127
|
+
}, severityControls);
|
|
35128
|
+
if (explicitSeverityOverride === "off") return suppress(current, "config");
|
|
35129
|
+
if (explicitSeverityOverride !== void 0) current = restampSeverity(current, explicitSeverityOverride);
|
|
35133
35130
|
}
|
|
35134
|
-
|
|
35135
|
-
|
|
35136
|
-
|
|
35137
|
-
|
|
35138
|
-
|
|
35139
|
-
|
|
35140
|
-
|
|
35141
|
-
|
|
35131
|
+
if (explicitRuleOverride === void 0) {
|
|
35132
|
+
if (isAppOnlyRule(`${current.plugin}/${current.rule}`) && isLibraryFile(current.filePath)) return null;
|
|
35133
|
+
}
|
|
35134
|
+
if (!showWarnings && current.severity === "warning" && explicitSeverityOverride !== "warn") return null;
|
|
35135
|
+
if (userConfig) {
|
|
35136
|
+
if (isRuleIgnored(`${current.plugin}/${current.rule}`)) return suppress(current, "config");
|
|
35137
|
+
if (isFileIgnoredByPatterns(current.filePath, rootDirectory, ignoredFilePatterns)) return null;
|
|
35138
|
+
if (isDiagnosticIgnoredByOverrides(current, rootDirectory, compiledOverrides)) return suppress(current, "override");
|
|
35139
|
+
if (isRnRawTextSuppressedByConfig(current)) return null;
|
|
35140
|
+
if (isJsxNoUndefSuppressedByConfig(current)) return null;
|
|
35141
|
+
}
|
|
35142
|
+
if (respectInlineDisables && current.line > 0) {
|
|
35143
|
+
const lines = getFileLines(current.filePath);
|
|
35144
|
+
if (lines) {
|
|
35145
|
+
const ruleIdentifier = `${current.plugin}/${current.rule}`;
|
|
35146
|
+
const evaluation = evaluateSuppression(lines, current.line - 1, ruleIdentifier);
|
|
35147
|
+
if (evaluation.isSuppressed) return suppress(current, "inline");
|
|
35148
|
+
if (evaluation.nearMissHint) current = {
|
|
35149
|
+
...current,
|
|
35150
|
+
suppressionHint: evaluation.nearMissHint
|
|
35151
|
+
};
|
|
35152
|
+
}
|
|
35153
|
+
}
|
|
35154
|
+
const fileContext = getFileContext(current.filePath);
|
|
35155
|
+
if (fileContext !== "production") current = {
|
|
35156
|
+
...current,
|
|
35157
|
+
fileContext
|
|
35158
|
+
};
|
|
35159
|
+
return current;
|
|
35160
|
+
},
|
|
35161
|
+
summarizeSuppressions: () => [...suppressions.values()]
|
|
35162
|
+
};
|
|
35142
35163
|
};
|
|
35143
35164
|
const OxlintUnavailableKind = Literals(["binary-not-found", "native-binding-missing"]);
|
|
35144
35165
|
var OxlintUnavailable = class extends TaggedErrorClass()("OxlintUnavailable", {
|
|
@@ -35442,13 +35463,7 @@ var ScanDeadlineMs = class extends Reference("react-doctor/ScanDeadlineMs", { de
|
|
|
35442
35463
|
* without recompiling react-doctor. Tests override via
|
|
35443
35464
|
* `Layer.succeed(SupplyChainOverlapTimeoutMs, ...)`.
|
|
35444
35465
|
*/
|
|
35445
|
-
var SupplyChainOverlapTimeoutMs = class extends Reference("react-doctor/SupplyChainOverlapTimeoutMs", { defaultValue: () => {
|
|
35446
|
-
const raw = process.env["REACT_DOCTOR_SUPPLY_CHAIN_TIMEOUT_MS"];
|
|
35447
|
-
if (raw === void 0) return SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS;
|
|
35448
|
-
const parsed = Number(raw);
|
|
35449
|
-
if (!Number.isFinite(parsed) || parsed <= 0) return SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS;
|
|
35450
|
-
return parsed;
|
|
35451
|
-
} }) {};
|
|
35466
|
+
var SupplyChainOverlapTimeoutMs = class extends Reference("react-doctor/SupplyChainOverlapTimeoutMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_SUPPLY_CHAIN_TIMEOUT_MS", SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS) }) {};
|
|
35452
35467
|
/**
|
|
35453
35468
|
* Hard cap on combined stdout+stderr bytes per oxlint batch. The
|
|
35454
35469
|
* subprocess gets SIGKILL'd if it produces more; the recovery path
|
|
@@ -37790,7 +37805,6 @@ var DeadCode = class DeadCode extends Service()("react-doctor/DeadCode") {
|
|
|
37790
37805
|
return yield* tryPromise({
|
|
37791
37806
|
try: (signal) => checkDeadCode({
|
|
37792
37807
|
rootDirectory: input.rootDirectory,
|
|
37793
|
-
userConfig: input.userConfig,
|
|
37794
37808
|
parseConcurrency: input.parseConcurrency,
|
|
37795
37809
|
workerTimeoutMs: input.workerTimeoutMs,
|
|
37796
37810
|
abortSignal: signal
|
|
@@ -37913,6 +37927,11 @@ const isSafeGitRevision = (candidate) => {
|
|
|
37913
37927
|
if (candidate.includes("..") || candidate.includes("@{")) return false;
|
|
37914
37928
|
return SAFE_GIT_REVISION_PATTERN.test(candidate);
|
|
37915
37929
|
};
|
|
37930
|
+
const resolveSpawnArgsLengthCap = () => {
|
|
37931
|
+
if (process.platform === "win32") return SPAWN_ARGS_MAX_LENGTH_CHARS;
|
|
37932
|
+
if (process.platform === "darwin") return SPAWN_ARGS_MAX_LENGTH_CHARS_DARWIN;
|
|
37933
|
+
return SPAWN_ARGS_MAX_LENGTH_CHARS_POSIX;
|
|
37934
|
+
};
|
|
37916
37935
|
/**
|
|
37917
37936
|
* Splits a git revision range into its endpoints: three-dot `A...B`
|
|
37918
37937
|
* (symmetric, merge-base) or two-dot `A..B` (direct). Returns `null`
|
|
@@ -37997,7 +38016,8 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37997
38016
|
return scoped(gen(function* () {
|
|
37998
38017
|
if (!isDirectory(input.directory)) return yield* foldSpawnFailure(`spawn ENOTDIR (cwd is not a directory: ${input.directory})`);
|
|
37999
38018
|
const argvLengthChars = input.command.length + 1 + input.args.reduce((total, arg) => total + arg.length + 1, 0);
|
|
38000
|
-
|
|
38019
|
+
const spawnArgsLengthCap = resolveSpawnArgsLengthCap();
|
|
38020
|
+
if (argvLengthChars > spawnArgsLengthCap) return yield* foldSpawnFailure(`spawn ENAMETOOLONG (${argvLengthChars} argv chars exceed ${spawnArgsLengthCap})`);
|
|
38001
38021
|
const handle = yield* spawner.spawn(make$1(input.command, [...input.args], {
|
|
38002
38022
|
cwd: input.directory,
|
|
38003
38023
|
env: input.env,
|
|
@@ -38166,6 +38186,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
38166
38186
|
if (resolvedCurrentBranch === null && explicitBaseBranch === void 0) return null;
|
|
38167
38187
|
const baseBranch = explicitBaseBranch ?? (yield* defaultBranch(directory));
|
|
38168
38188
|
if (baseBranch === null) return null;
|
|
38189
|
+
if (!isSafeGitRevision(baseBranch)) return null;
|
|
38169
38190
|
if (explicitBaseBranch !== void 0) {
|
|
38170
38191
|
if (!(yield* branchExists(directory, explicitBaseBranch))) return yield* fail$4(new ReactDoctorError({ reason: new GitBaseBranchMissing({ branch: explicitBaseBranch }) }));
|
|
38171
38192
|
}
|
|
@@ -38516,7 +38537,7 @@ const normalizeConfigForHash = (config) => {
|
|
|
38516
38537
|
if (Array.isArray(clone?.jsPlugins)) clone.jsPlugins = clone.jsPlugins.map((_, index) => `<plugin:${index}>`);
|
|
38517
38538
|
return clone;
|
|
38518
38539
|
};
|
|
38519
|
-
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("
|
|
38540
|
+
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");
|
|
38520
38541
|
/**
|
|
38521
38542
|
* Loads a plugin module via the local require resolver and extracts
|
|
38522
38543
|
* `(name, ruleNames)` from either `module.exports.meta + rules` or
|
|
@@ -38794,24 +38815,38 @@ const createFileLintCache = (cacheDirectory, rulesetHash) => {
|
|
|
38794
38815
|
updatedAtMs: Date.now(),
|
|
38795
38816
|
files: Object.fromEntries(cappedEntries)
|
|
38796
38817
|
};
|
|
38797
|
-
const keptHashes = Object.entries(rulesets).sort(([, first], [, second]) => second.updatedAtMs - first.updatedAtMs).slice(0, 8).map(([hash]) => hash);
|
|
38798
|
-
const prunedRulesets = {};
|
|
38799
|
-
for (const hash of keptHashes) prunedRulesets[hash] = rulesets[hash];
|
|
38800
38818
|
atomicWriteJson(cacheFilePath, {
|
|
38801
38819
|
version: 1,
|
|
38802
|
-
rulesets:
|
|
38820
|
+
rulesets: Object.fromEntries(Object.entries(rulesets).filter(([, bucket]) => isRecord(bucket) && typeof bucket.updatedAtMs === "number").sort(([, first], [, second]) => second.updatedAtMs - first.updatedAtMs).slice(0, 8))
|
|
38803
38821
|
});
|
|
38804
38822
|
}
|
|
38805
38823
|
};
|
|
38806
38824
|
};
|
|
38807
38825
|
const bundledRequire = createRequire(import.meta.url);
|
|
38826
|
+
const childNodeVersionByBinaryPath = /* @__PURE__ */ new Map();
|
|
38827
|
+
const resolveChildNodeVersion = (nodeBinaryPath) => {
|
|
38828
|
+
if (nodeBinaryPath === process.execPath) return process.version;
|
|
38829
|
+
const cachedVersion = childNodeVersionByBinaryPath.get(nodeBinaryPath);
|
|
38830
|
+
if (cachedVersion !== void 0) return cachedVersion;
|
|
38831
|
+
let version;
|
|
38832
|
+
try {
|
|
38833
|
+
version = execFileSync(nodeBinaryPath, ["--version"], {
|
|
38834
|
+
encoding: "utf8",
|
|
38835
|
+
timeout: NODE_VERSION_PROBE_TIMEOUT_MS
|
|
38836
|
+
}).trim();
|
|
38837
|
+
} catch {
|
|
38838
|
+
version = `unknown:${nodeBinaryPath}`;
|
|
38839
|
+
}
|
|
38840
|
+
childNodeVersionByBinaryPath.set(nodeBinaryPath, version);
|
|
38841
|
+
return version;
|
|
38842
|
+
};
|
|
38808
38843
|
const TOOLCHAIN_PACKAGE_SPECIFIERS = [
|
|
38809
38844
|
"oxlint/package.json",
|
|
38810
38845
|
"oxlint-plugin-react-doctor/package.json",
|
|
38811
38846
|
"eslint-plugin-react-hooks/package.json"
|
|
38812
38847
|
];
|
|
38813
|
-
const resolveOxlintToolchainVersions = () => {
|
|
38814
|
-
const versions = [`node=${
|
|
38848
|
+
const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
|
|
38849
|
+
const versions = [`node=${resolveChildNodeVersion(nodeBinaryPath)}`];
|
|
38815
38850
|
for (const specifier of TOOLCHAIN_PACKAGE_SPECIFIERS) try {
|
|
38816
38851
|
const packageJson = bundledRequire(specifier);
|
|
38817
38852
|
const version = typeof packageJson.version === "string" ? packageJson.version : "unknown";
|
|
@@ -39667,21 +39702,27 @@ const spawnLintBatches = async (input) => {
|
|
|
39667
39702
|
const allDiagnostics = [];
|
|
39668
39703
|
const droppedFiles = [];
|
|
39669
39704
|
let firstDropReason = null;
|
|
39670
|
-
const
|
|
39671
|
-
const spawnLintBatch = async (batch, depth) => {
|
|
39705
|
+
const spawnLintBatch = async (batch, depth, splitBudget) => {
|
|
39672
39706
|
const batchArgs = [...baseArgs, ...batch];
|
|
39673
39707
|
try {
|
|
39674
39708
|
return parseOxlintOutput(await spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, spawnTimeoutMs, outputMaxBytes, signal), project, rootDirectory);
|
|
39675
39709
|
} catch (error) {
|
|
39676
39710
|
if (!isSplittableReactDoctorError(error)) throw error;
|
|
39677
|
-
|
|
39678
|
-
|
|
39711
|
+
splitBudget.deadlineMs ??= Date.now() + splitTotalBudgetMs;
|
|
39712
|
+
const isBudgetElapsed = Date.now() >= splitBudget.deadlineMs;
|
|
39713
|
+
const isDepthCapReached = depth >= splitMaxDepth;
|
|
39714
|
+
if (batch.length <= 1 || isBudgetElapsed || isDepthCapReached) {
|
|
39679
39715
|
droppedFiles.push(...batch);
|
|
39680
|
-
if (firstDropReason === null)
|
|
39716
|
+
if (firstDropReason === null) {
|
|
39717
|
+
let limitHint = "";
|
|
39718
|
+
if (isDepthCapReached) limitHint = ` (split depth cap of ${splitMaxDepth} levels reached)`;
|
|
39719
|
+
else if (isBudgetElapsed) limitHint = ` (split budget of ${splitTotalBudgetMs / MILLISECONDS_PER_SECOND}s exhausted at depth ${depth})`;
|
|
39720
|
+
firstDropReason = batch.length > 1 ? `${error.message}${limitHint}` : error.message;
|
|
39721
|
+
}
|
|
39681
39722
|
return [];
|
|
39682
39723
|
}
|
|
39683
39724
|
const splitIndex = Math.ceil(batch.length / 2);
|
|
39684
|
-
return [...await spawnLintBatch(batch.slice(0, splitIndex), depth + 1), ...await spawnLintBatch(batch.slice(splitIndex), depth + 1)];
|
|
39725
|
+
return [...await spawnLintBatch(batch.slice(0, splitIndex), depth + 1, splitBudget), ...await spawnLintBatch(batch.slice(splitIndex), depth + 1, splitBudget)];
|
|
39685
39726
|
}
|
|
39686
39727
|
};
|
|
39687
39728
|
let startedFileCount = 0;
|
|
@@ -39698,7 +39739,7 @@ const spawnLintBatches = async (input) => {
|
|
|
39698
39739
|
try {
|
|
39699
39740
|
const batchResults = await mapWithConcurrency(fileBatches, concurrency, async (batch) => {
|
|
39700
39741
|
startedFileCount += batch.length;
|
|
39701
|
-
const batchDiagnostics = await spawnLintBatch(batch, 0);
|
|
39742
|
+
const batchDiagnostics = await spawnLintBatch(batch, 0, { deadlineMs: null });
|
|
39702
39743
|
scannedFileCount += batch.length;
|
|
39703
39744
|
if (onFileProgress) {
|
|
39704
39745
|
displayedFileCount = Math.min(Math.max(displayedFileCount, scannedFileCount), totalFileCount);
|
|
@@ -39772,7 +39813,14 @@ const resolveReactDoctorCacheDir = (projectDirectory) => {
|
|
|
39772
39813
|
if (cacheDirOverride) return Path.join(cacheDirOverride, projectCacheSubdir(projectDirectory));
|
|
39773
39814
|
const nodeModulesDirectory = Path.join(projectDirectory, "node_modules");
|
|
39774
39815
|
if (NFS.existsSync(nodeModulesDirectory)) return Path.join(nodeModulesDirectory, ".cache", "react-doctor");
|
|
39775
|
-
return Path.join(os.tmpdir(),
|
|
39816
|
+
return Path.join(os.tmpdir(), `react-doctor-cache-${resolveUserCacheScope()}`, projectCacheSubdir(projectDirectory));
|
|
39817
|
+
};
|
|
39818
|
+
const resolveUserCacheScope = () => {
|
|
39819
|
+
try {
|
|
39820
|
+
return String(process.getuid?.() ?? os.userInfo().username);
|
|
39821
|
+
} catch {
|
|
39822
|
+
return "shared";
|
|
39823
|
+
}
|
|
39776
39824
|
};
|
|
39777
39825
|
const sortSourceFilesByCost = (entries) => [...entries].sort((left, right) => right.sizeBytes - left.sizeBytes).map((entry) => entry.path);
|
|
39778
39826
|
/**
|
|
@@ -39940,7 +39988,7 @@ const runOxlint = async (options) => {
|
|
|
39940
39988
|
extendsPaths: [],
|
|
39941
39989
|
ruleSelection: "cacheable"
|
|
39942
39990
|
}),
|
|
39943
|
-
toolchainVersions: resolveOxlintToolchainVersions(),
|
|
39991
|
+
toolchainVersions: resolveOxlintToolchainVersions(nodeBinaryPath),
|
|
39944
39992
|
ignorePatterns: combinedPatterns,
|
|
39945
39993
|
tsconfigContent
|
|
39946
39994
|
});
|
|
@@ -39954,7 +40002,7 @@ const runOxlint = async (options) => {
|
|
|
39954
40002
|
missFiles.push(candidateFile);
|
|
39955
40003
|
continue;
|
|
39956
40004
|
}
|
|
39957
|
-
const cacheKey = `${candidateFile.replaceAll("\\", "/")}
|
|
40005
|
+
const cacheKey = `${candidateFile.replaceAll("\\", "/")}\u0000${contentHash}`;
|
|
39958
40006
|
cacheKeyByFile.set(candidateFile, cacheKey);
|
|
39959
40007
|
const cachedDiagnostics = cache.lookup(cacheKey);
|
|
39960
40008
|
if (cachedDiagnostics === null) missFiles.push(candidateFile);
|
|
@@ -40270,7 +40318,7 @@ const ScoreApiResponseSchema = Struct({
|
|
|
40270
40318
|
})))
|
|
40271
40319
|
});
|
|
40272
40320
|
const parseScoreResult = (value) => getOrNull(decodeUnknownOption(ScoreApiResponseSchema)(value));
|
|
40273
|
-
const stripLocalFileFields = (diagnostics) => diagnostics.map(({ filePath: _filePath, fileContext: _fileContext, ...rest }) => rest);
|
|
40321
|
+
const stripLocalFileFields = (diagnostics) => diagnostics.map(({ filePath: _filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => rest);
|
|
40274
40322
|
const isAbortError = (error) => error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
|
|
40275
40323
|
const describeFailure = (error) => {
|
|
40276
40324
|
if (isAbortError(error)) return `timed out after ${FETCH_TIMEOUT_MS / 1e3}s`;
|
|
@@ -40574,7 +40622,10 @@ const ALERT_SEVERITY_RANK = {
|
|
|
40574
40622
|
medium: 2,
|
|
40575
40623
|
low: 1
|
|
40576
40624
|
};
|
|
40577
|
-
const severityRank = (severity) =>
|
|
40625
|
+
const severityRank = (severity) => {
|
|
40626
|
+
const normalized = severity.toLowerCase();
|
|
40627
|
+
return Object.hasOwn(ALERT_SEVERITY_RANK, normalized) ? ALERT_SEVERITY_RANK[normalized] : 0;
|
|
40628
|
+
};
|
|
40578
40629
|
const displaySeverity = (severity) => {
|
|
40579
40630
|
const normalized = sanitizeTerminalText(severity.toLowerCase());
|
|
40580
40631
|
return normalized === "middle" ? "medium" : normalized;
|
|
@@ -40591,7 +40642,7 @@ const ALERT_TYPE_LABELS = {
|
|
|
40591
40642
|
typosquat: "possible typosquat"
|
|
40592
40643
|
};
|
|
40593
40644
|
const humanizeAlertType = (type) => type.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").toLowerCase().trim();
|
|
40594
|
-
const friendlyAlertType = (type) => ALERT_TYPE_LABELS[type]
|
|
40645
|
+
const friendlyAlertType = (type) => Object.hasOwn(ALERT_TYPE_LABELS, type) ? ALERT_TYPE_LABELS[type] : sanitizeTerminalText(humanizeAlertType(type));
|
|
40595
40646
|
const summarizeAlertNote = (note) => {
|
|
40596
40647
|
const collapsed = sanitizeTerminalText(note.replace(/\s+/g, " ").trim());
|
|
40597
40648
|
const firstSentence = collapsed.split(/(?<=\.)\s/)[0] || collapsed;
|
|
@@ -40686,7 +40737,10 @@ const checkSupplyChain = (input) => gen(function* () {
|
|
|
40686
40737
|
* outage.
|
|
40687
40738
|
*/
|
|
40688
40739
|
var SupplyChain = class SupplyChain extends Service()("react-doctor/SupplyChain") {
|
|
40689
|
-
static layerNode = succeed$3(SupplyChain, SupplyChain.of({ run: (input) => unwrap(
|
|
40740
|
+
static layerNode = succeed$3(SupplyChain, SupplyChain.of({ run: (input) => unwrap(flatMap$2(SupplyChainOverlapTimeoutMs, (totalTimeoutMs) => checkSupplyChain({
|
|
40741
|
+
...input,
|
|
40742
|
+
totalTimeoutMs
|
|
40743
|
+
})).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)), withSpan("SupplyChain.run"))) }));
|
|
40690
40744
|
static layerOf = (diagnostics) => succeed$3(SupplyChain, SupplyChain.of({ run: () => fromIterable$1(diagnostics) }));
|
|
40691
40745
|
};
|
|
40692
40746
|
const getObjectProperty = (value, propertyName) => {
|
|
@@ -40834,10 +40888,11 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
40834
40888
|
...checkExpoProject(scanDirectory, project),
|
|
40835
40889
|
...checkReactNativeProject(scanDirectory, project)
|
|
40836
40890
|
])));
|
|
40837
|
-
const
|
|
40891
|
+
const securityScanFailedRef = yield* make$13(false);
|
|
40892
|
+
const securityScanFiber = yield* forkChild(runCollect(applyPerElementPipeline(isDiffMode ? empty$4 : unwrap(tryPromise(() => checkSecurityScanCooperative(scanDirectory, {
|
|
40838
40893
|
project,
|
|
40839
40894
|
ignoredTags: input.ignoredTags
|
|
40840
|
-
})).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)))))).pipe(withSpan("SecurityScan.run")));
|
|
40895
|
+
})).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)), catch_$1(() => set(securityScanFailedRef, true).pipe(as(empty$4))))))).pipe(withSpan("SecurityScan.run")));
|
|
40841
40896
|
const shouldRunSupplyChain = !isDiffMode || (input.supplyChainManifestChanged ?? false);
|
|
40842
40897
|
const supplyChainOverlapTimeout = yield* SupplyChainOverlapTimeoutMs;
|
|
40843
40898
|
const supplyChainFiber = yield* forkChild(shouldRunSupplyChain ? runCollect(applyPerElementPipeline(supplyChainService.run({
|
|
@@ -40875,7 +40930,6 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
40875
40930
|
const lintConcurrency = deadCodeParseConcurrency === void 0 ? scanConcurrency : Math.max(1, scanConcurrency - deadCodeParseConcurrency);
|
|
40876
40931
|
const buildCollectDeadCode = (deadCodeTimeout) => runCollect(applyPerElementPipeline(deadCodeService.run({
|
|
40877
40932
|
rootDirectory: scanDirectory,
|
|
40878
|
-
userConfig: resolvedConfig.config,
|
|
40879
40933
|
parseConcurrency: deadCodeParseConcurrency,
|
|
40880
40934
|
workerTimeoutMs: deadCodeTimeout.workerTimeoutMs
|
|
40881
40935
|
}).pipe(catchTag("ReactDoctorError", (error) => unwrap(gen(function* () {
|
|
@@ -41003,6 +41057,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
41003
41057
|
metadata: scoreMetadata
|
|
41004
41058
|
});
|
|
41005
41059
|
const lintPartialFailures = yield* get$2(partialFailuresRef);
|
|
41060
|
+
const securityScanFailed = yield* get$2(securityScanFailedRef);
|
|
41006
41061
|
return {
|
|
41007
41062
|
project,
|
|
41008
41063
|
userConfig: resolvedConfig.config,
|
|
@@ -41023,8 +41078,10 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
41023
41078
|
scanElapsedMilliseconds,
|
|
41024
41079
|
scanConcurrency,
|
|
41025
41080
|
supplyChainOverlapTimedOut: supplyChainResult.timedOut,
|
|
41081
|
+
securityScanFailed,
|
|
41026
41082
|
lintCacheHitFileCount,
|
|
41027
|
-
lintCacheTotalFileCount
|
|
41083
|
+
lintCacheTotalFileCount,
|
|
41084
|
+
suppressedRuleCounts: transform.summarizeSuppressions()
|
|
41028
41085
|
};
|
|
41029
41086
|
}).pipe(withSpan("runInspect", { attributes: {
|
|
41030
41087
|
"inspect.directory": input.directory,
|
|
@@ -41663,4 +41720,4 @@ const toJsonReport = (result, options) => buildJsonReport({
|
|
|
41663
41720
|
export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
|
|
41664
41721
|
|
|
41665
41722
|
//# sourceMappingURL=index.js.map
|
|
41666
|
-
//# debugId=
|
|
41723
|
+
//# debugId=83529d8f-2ca3-50ba-a3b9-44622f913549
|