react-doctor 0.7.6-dev.17418 → 0.7.6-dev.1d7b6e2
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 +227 -61
- package/dist/index.d.ts +5 -4
- package/dist/index.js +87 -37
- package/dist/lsp.js +104 -61
- package/package.json +4 -4
package/dist/lsp.js
CHANGED
|
@@ -32959,7 +32959,6 @@ const IGNORED_DIRECTORIES = new Set([
|
|
|
32959
32959
|
"out",
|
|
32960
32960
|
"storybook-static"
|
|
32961
32961
|
]);
|
|
32962
|
-
const JSX_FILE_PATTERN = /\.(tsx|jsx)$/;
|
|
32963
32962
|
const MILLISECONDS_PER_SECOND = 1e3;
|
|
32964
32963
|
const SCORE_API_URL = "https://www.react.doctor/api/score";
|
|
32965
32964
|
const FETCH_TIMEOUT_MS = 1e4;
|
|
@@ -33195,13 +33194,15 @@ const listSourceFilesViaFilesystem = (rootDirectory) => {
|
|
|
33195
33194
|
const listSourceFilesWithSize = (rootDirectory) => collectSizedSourceFiles(rootDirectory, (listSourceFilesViaGit(rootDirectory) ?? listSourceFilesViaFilesystem(rootDirectory)).sort());
|
|
33196
33195
|
const listSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).map((entry) => entry.path);
|
|
33197
33196
|
const countSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).length;
|
|
33197
|
+
const UTF8_BOM_CHARACTER = "";
|
|
33198
|
+
const stripUtf8Bom = (content) => content.startsWith(UTF8_BOM_CHARACTER) ? content.slice(1) : content;
|
|
33198
33199
|
const cachedPackageJsons = /* @__PURE__ */ new Map();
|
|
33199
33200
|
const clearPackageJsonCache = () => {
|
|
33200
33201
|
cachedPackageJsons.clear();
|
|
33201
33202
|
};
|
|
33202
33203
|
const readPackageJsonUncached = (packageJsonPath) => {
|
|
33203
33204
|
try {
|
|
33204
|
-
return JSON.parse(NFS.readFileSync(packageJsonPath, "utf-8"));
|
|
33205
|
+
return JSON.parse(stripUtf8Bom(NFS.readFileSync(packageJsonPath, "utf-8")));
|
|
33205
33206
|
} catch (error) {
|
|
33206
33207
|
if (error instanceof SyntaxError) return {};
|
|
33207
33208
|
if (isErrnoException(error)) {
|
|
@@ -36768,7 +36769,6 @@ const PNPM_WORKSPACE_FILE = "pnpm-workspace.yaml";
|
|
|
36768
36769
|
const PNPM_LOCKFILE = "pnpm-lock.yaml";
|
|
36769
36770
|
const PACKAGE_JSON_FILE = "package.json";
|
|
36770
36771
|
const PNPM_HARDENING_RULE_KEY = "require-pnpm-hardening";
|
|
36771
|
-
const UTF8_BOM_CHAR = "";
|
|
36772
36772
|
const HARDENING_SETTING_KEYS = new Set([
|
|
36773
36773
|
"minimumReleaseAge",
|
|
36774
36774
|
"blockExoticSubdeps",
|
|
@@ -36793,12 +36793,11 @@ const stripInlineComment = (rawValue) => {
|
|
|
36793
36793
|
return rawValue;
|
|
36794
36794
|
};
|
|
36795
36795
|
const unquote = (rawValue) => rawValue.replace(/^["']|["']$/g, "");
|
|
36796
|
-
const stripBom = (rawContent) => rawContent.startsWith(UTF8_BOM_CHAR) ? rawContent.slice(1) : rawContent;
|
|
36797
36796
|
const parseHardeningSettings = (content) => {
|
|
36798
36797
|
let minimumReleaseAge = null;
|
|
36799
36798
|
let blockExoticSubdeps = null;
|
|
36800
36799
|
let trustPolicy = null;
|
|
36801
|
-
const lines =
|
|
36800
|
+
const lines = stripUtf8Bom(content).split(/\r?\n/);
|
|
36802
36801
|
for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
|
|
36803
36802
|
const lineText = lines[lineIndex];
|
|
36804
36803
|
if (lineText === void 0) continue;
|
|
@@ -36832,7 +36831,7 @@ const isPnpmManagedProject = (rootDirectory) => {
|
|
|
36832
36831
|
const packageJsonPath = Path.join(rootDirectory, PACKAGE_JSON_FILE);
|
|
36833
36832
|
if (!isFile(packageJsonPath)) return false;
|
|
36834
36833
|
try {
|
|
36835
|
-
const packageJsonRaw = NFS.readFileSync(packageJsonPath, "utf-8");
|
|
36834
|
+
const packageJsonRaw = stripUtf8Bom(NFS.readFileSync(packageJsonPath, "utf-8"));
|
|
36836
36835
|
const packageJson = JSON.parse(packageJsonRaw);
|
|
36837
36836
|
if (packageJson !== null && typeof packageJson === "object" && "packageManager" in packageJson && typeof packageJson.packageManager === "string" && packageJson.packageManager.startsWith("pnpm@")) return true;
|
|
36838
36837
|
} catch {
|
|
@@ -37494,9 +37493,7 @@ const highlighter = {
|
|
|
37494
37493
|
gray: import_picocolors.default.gray,
|
|
37495
37494
|
bold: import_picocolors.default.bold
|
|
37496
37495
|
};
|
|
37497
|
-
const
|
|
37498
|
-
const shouldIncludeExplicitLintPath = (filePath, project) => JSX_FILE_PATTERN.test(filePath) || project?.framework === "nextjs" && NEXT_ENTRY_FILE_PATTERN.test(filePath);
|
|
37499
|
-
const computeExplicitLintIncludePaths = (includePaths, project) => includePaths.length > 0 ? includePaths.filter((filePath) => shouldIncludeExplicitLintPath(filePath, project)) : void 0;
|
|
37496
|
+
const computeExplicitLintIncludePaths = (includePaths) => includePaths.length > 0 ? includePaths.filter(isLintableSourceFile) : void 0;
|
|
37500
37497
|
const LINGUIST_ATTRIBUTE_PATTERN = /^linguist-(?:vendored|generated)(?:=([a-zA-Z0-9]+))?$/i;
|
|
37501
37498
|
const FALSY_VALUES = new Set([
|
|
37502
37499
|
"false",
|
|
@@ -38338,11 +38335,11 @@ const resolveDeadCodeTimeout = (input) => {
|
|
|
38338
38335
|
phaseTimeoutMs: workerTimeoutMs + DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS
|
|
38339
38336
|
};
|
|
38340
38337
|
};
|
|
38341
|
-
const resolveLintIncludePaths = (rootDirectory, userConfig
|
|
38338
|
+
const resolveLintIncludePaths = (rootDirectory, userConfig) => {
|
|
38342
38339
|
if (!Array.isArray(userConfig?.ignore?.files) || userConfig.ignore.files.length === 0) return;
|
|
38343
38340
|
const ignoredPatterns = compileIgnoredFilePatterns(userConfig);
|
|
38344
38341
|
return listSourceFiles(rootDirectory).filter((filePath) => {
|
|
38345
|
-
if (!
|
|
38342
|
+
if (!isLintableSourceFile(filePath)) return false;
|
|
38346
38343
|
return !isFileIgnoredByPatterns(filePath, rootDirectory, ignoredPatterns);
|
|
38347
38344
|
});
|
|
38348
38345
|
};
|
|
@@ -38560,6 +38557,7 @@ const parseGithubViewerPermission = (stdout) => {
|
|
|
38560
38557
|
return /^[A-Z_]+$/.test(value) ? value.toLowerCase() : null;
|
|
38561
38558
|
};
|
|
38562
38559
|
const splitNullSeparated = (value) => value.split("\0").filter((entry) => entry.length > 0);
|
|
38560
|
+
const UNTRACKED_FILE_LAST_LINE = Number.MAX_SAFE_INTEGER;
|
|
38563
38561
|
/**
|
|
38564
38562
|
* `Git` wraps every `git`-via-subprocess call react-doctor makes
|
|
38565
38563
|
* behind a `Context.Service`. The production layer (`layerNode`)
|
|
@@ -38630,6 +38628,14 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
38630
38628
|
args,
|
|
38631
38629
|
directory
|
|
38632
38630
|
});
|
|
38631
|
+
const listUntrackedFilePaths = (directory, includePaths = []) => runGit(directory, [
|
|
38632
|
+
"ls-files",
|
|
38633
|
+
"-z",
|
|
38634
|
+
"--others",
|
|
38635
|
+
"--exclude-standard",
|
|
38636
|
+
...includePaths.length > 0 ? ["--", ...includePaths] : []
|
|
38637
|
+
]).pipe(map$3((result) => result.status === 0 ? splitNullSeparated(result.stdout) : null));
|
|
38638
|
+
const mergeUntracked = (directory, trackedFilePaths, includeUntracked) => includeUntracked ? listUntrackedFilePaths(directory).pipe(map$3((untracked) => untracked === null ? trackedFilePaths : [...new Set([...trackedFilePaths, ...untracked])])) : succeed$2(trackedFilePaths);
|
|
38633
38639
|
const currentBranch = (directory) => runGit(directory, [
|
|
38634
38640
|
"rev-parse",
|
|
38635
38641
|
"--abbrev-ref",
|
|
@@ -38752,7 +38758,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
38752
38758
|
githubViewerPermission,
|
|
38753
38759
|
branchExists,
|
|
38754
38760
|
mergeBase,
|
|
38755
|
-
diffSelection: ({ directory, explicitBaseBranch }) => gen(function* () {
|
|
38761
|
+
diffSelection: ({ directory, explicitBaseBranch, includeUntracked = false }) => gen(function* () {
|
|
38756
38762
|
if (explicitBaseBranch !== void 0 && explicitBaseBranch.trim().length === 0) return yield* fail$4(new ReactDoctorError({ reason: new GitBaseBranchInvalid({ detail: "Diff base branch cannot be empty." }) }));
|
|
38757
38763
|
if (explicitBaseBranch !== void 0) {
|
|
38758
38764
|
const range = parseGitDiffRange(explicitBaseBranch);
|
|
@@ -38781,7 +38787,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
38781
38787
|
"HEAD"
|
|
38782
38788
|
]);
|
|
38783
38789
|
if (uncommitted.status !== 0) return null;
|
|
38784
|
-
const files = splitNullSeparated(uncommitted.stdout);
|
|
38790
|
+
const files = yield* mergeUntracked(directory, splitNullSeparated(uncommitted.stdout), includeUntracked);
|
|
38785
38791
|
if (files.length === 0) return null;
|
|
38786
38792
|
return {
|
|
38787
38793
|
currentBranch: resolvedCurrentBranch,
|
|
@@ -38811,7 +38817,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
38811
38817
|
currentBranch: resolvedCurrentBranch,
|
|
38812
38818
|
baseBranch,
|
|
38813
38819
|
diffBaseRef: mergeBaseRef,
|
|
38814
|
-
changedFiles: splitNullSeparated(diff.stdout),
|
|
38820
|
+
changedFiles: yield* mergeUntracked(directory, splitNullSeparated(diff.stdout), includeUntracked),
|
|
38815
38821
|
isCurrentChanges: false
|
|
38816
38822
|
};
|
|
38817
38823
|
}).pipe(withSpan("Git.diffSelection")),
|
|
@@ -38857,7 +38863,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
38857
38863
|
stdout: result.stdout
|
|
38858
38864
|
};
|
|
38859
38865
|
}).pipe(withSpan("Git.grep")),
|
|
38860
|
-
changedLineRanges: ({ directory, baseRef, cached, files }) => gen(function* () {
|
|
38866
|
+
changedLineRanges: ({ directory, baseRef, cached, files, includeUntracked = false }) => gen(function* () {
|
|
38861
38867
|
if (files.length === 0) return [];
|
|
38862
38868
|
if (baseRef !== void 0 && !isSafeGitRevision(baseRef)) return null;
|
|
38863
38869
|
const result = yield* runGit(directory, [
|
|
@@ -38871,7 +38877,14 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
38871
38877
|
...files
|
|
38872
38878
|
]);
|
|
38873
38879
|
if (result.status !== 0) return null;
|
|
38874
|
-
|
|
38880
|
+
const changedLineRanges = parseChangedLineRanges(result.stdout);
|
|
38881
|
+
if (cached || !includeUntracked) return changedLineRanges;
|
|
38882
|
+
const untrackedFilePaths = yield* listUntrackedFilePaths(directory, files);
|
|
38883
|
+
if (untrackedFilePaths === null) return changedLineRanges;
|
|
38884
|
+
return [...changedLineRanges, ...untrackedFilePaths.map((file) => ({
|
|
38885
|
+
file,
|
|
38886
|
+
ranges: [[1, UNTRACKED_FILE_LAST_LINE]]
|
|
38887
|
+
}))];
|
|
38875
38888
|
}).pipe(catch_$1((error) => error.reason._tag === "GitInvocationFailed" ? succeed$2(null) : fail$4(error)), withSpan("Git.changedLineRanges"))
|
|
38876
38889
|
});
|
|
38877
38890
|
})).pipe(provide$2(layer$2.pipe(provide$2(mergeAll$1(layer$1, layer)))));
|
|
@@ -39623,6 +39636,12 @@ const mapWithConcurrency = async (items, concurrency, task) => {
|
|
|
39623
39636
|
if (errors.length > 0) throw errors[0];
|
|
39624
39637
|
return results;
|
|
39625
39638
|
};
|
|
39639
|
+
const lineOfUtf8Offset = (sourceBuffer, utf8Offset) => {
|
|
39640
|
+
let lineNumber = 1;
|
|
39641
|
+
const scanEnd = Math.min(utf8Offset, sourceBuffer.length);
|
|
39642
|
+
for (let byteIndex = 0; byteIndex < scanEnd; byteIndex++) if (sourceBuffer[byteIndex] === 10) lineNumber++;
|
|
39643
|
+
return lineNumber;
|
|
39644
|
+
};
|
|
39626
39645
|
const REANIMATED_SHARED_VALUE_HINT = "If this is a Reanimated shared value, prefer its React Compiler-compatible `.get()` / `.set()` accessors over `.value` — https://docs.swmansion.com/react-native-reanimated/docs/core/useSharedValue/#react-compiler-support";
|
|
39627
39646
|
const ACCESSORS_MIN_VERSION = "3.15.0";
|
|
39628
39647
|
const supportsAccessors = (reanimatedVersion) => {
|
|
@@ -40194,13 +40213,6 @@ const findOutermostEnclosingFunctionRange = (sourceFile, targetLine) => {
|
|
|
40194
40213
|
visit(sourceFile);
|
|
40195
40214
|
return foundRange;
|
|
40196
40215
|
};
|
|
40197
|
-
const NEWLINE_BYTE = 10;
|
|
40198
|
-
const lineOfUtf8Offset = (sourceBuffer, utf8Offset) => {
|
|
40199
|
-
let lineNumber = 1;
|
|
40200
|
-
const scanEnd = Math.min(utf8Offset, sourceBuffer.length);
|
|
40201
|
-
for (let byteIndex = 0; byteIndex < scanEnd; byteIndex++) if (sourceBuffer[byteIndex] === NEWLINE_BYTE) lineNumber++;
|
|
40202
|
-
return lineNumber;
|
|
40203
|
-
};
|
|
40204
40216
|
/**
|
|
40205
40217
|
* Drops `react-doctor/react-compiler-no-manual-memoization` diagnostics
|
|
40206
40218
|
* whose enclosing function also carries a `react-hooks-js` (React
|
|
@@ -40381,11 +40393,11 @@ const buildRelatedLocations = (labels, filePath) => {
|
|
|
40381
40393
|
}
|
|
40382
40394
|
return related;
|
|
40383
40395
|
};
|
|
40384
|
-
const
|
|
40385
|
-
|
|
40386
|
-
|
|
40387
|
-
|
|
40388
|
-
|
|
40396
|
+
const isOxlintSpan = (value) => isRecord(value) && typeof value.offset === "number" && typeof value.length === "number" && typeof value.line === "number" && typeof value.column === "number";
|
|
40397
|
+
const isOxlintLabel = (value) => isRecord(value) && isOxlintSpan(value.span);
|
|
40398
|
+
const isMappableOxlintDiagnostic = (value) => isRecord(value) && typeof value.code === "string" && value.code.length > 0 && typeof value.filename === "string" && value.filename.length > 0 && (value.severity === "warning" || value.severity === "error") && Array.isArray(value.labels) && value.labels.every(isOxlintLabel);
|
|
40399
|
+
const isEngineFailureDiagnostic = (value) => !isRecord(value) || typeof value.filename !== "string" || value.filename.length === 0;
|
|
40400
|
+
const isOxlintOutput = (value) => isRecord(value) && Array.isArray(value.diagnostics);
|
|
40389
40401
|
/**
|
|
40390
40402
|
* Parses one oxlint subprocess's stdout into a flat `Diagnostic[]`.
|
|
40391
40403
|
* Tolerates the leading-notice-line shape oxlint sometimes prints
|
|
@@ -40404,23 +40416,59 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
40404
40416
|
throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
40405
40417
|
}
|
|
40406
40418
|
if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
40419
|
+
const engineFailureDiagnostic = parsed.diagnostics.find(isEngineFailureDiagnostic);
|
|
40420
|
+
if (engineFailureDiagnostic !== void 0) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: JSON.stringify(engineFailureDiagnostic).slice(0, 600) }) });
|
|
40407
40421
|
const minifiedFileCache = /* @__PURE__ */ new Map();
|
|
40422
|
+
const sourceBufferCache = /* @__PURE__ */ new Map();
|
|
40423
|
+
const sourceLinesCache = /* @__PURE__ */ new Map();
|
|
40424
|
+
const resolveAbsolutePath = (filename) => Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
|
|
40425
|
+
const readSourceBuffer = (filename) => {
|
|
40426
|
+
const absolutePath = resolveAbsolutePath(filename);
|
|
40427
|
+
const cached = sourceBufferCache.get(absolutePath);
|
|
40428
|
+
if (cached !== void 0) return cached;
|
|
40429
|
+
let sourceBuffer;
|
|
40430
|
+
try {
|
|
40431
|
+
sourceBuffer = NFS.readFileSync(absolutePath);
|
|
40432
|
+
} catch {
|
|
40433
|
+
sourceBuffer = null;
|
|
40434
|
+
}
|
|
40435
|
+
sourceBufferCache.set(absolutePath, sourceBuffer);
|
|
40436
|
+
return sourceBuffer;
|
|
40437
|
+
};
|
|
40438
|
+
const readSourceLines = (filename) => {
|
|
40439
|
+
const absolutePath = resolveAbsolutePath(filename);
|
|
40440
|
+
const cached = sourceLinesCache.get(absolutePath);
|
|
40441
|
+
if (cached !== void 0) return cached;
|
|
40442
|
+
const sourceBuffer = readSourceBuffer(filename);
|
|
40443
|
+
const sourceLines = sourceBuffer ? sourceBuffer.toString("utf8").split("\n") : null;
|
|
40444
|
+
sourceLinesCache.set(absolutePath, sourceLines);
|
|
40445
|
+
return sourceLines;
|
|
40446
|
+
};
|
|
40408
40447
|
const isMinifiedDiagnosticFile = (filename) => {
|
|
40409
|
-
const absolutePath =
|
|
40448
|
+
const absolutePath = resolveAbsolutePath(filename);
|
|
40410
40449
|
const cached = minifiedFileCache.get(absolutePath);
|
|
40411
40450
|
if (cached !== void 0) return cached;
|
|
40412
40451
|
const minified = isMinifiedSource(absolutePath);
|
|
40413
40452
|
minifiedFileCache.set(absolutePath, minified);
|
|
40414
40453
|
return minified;
|
|
40415
40454
|
};
|
|
40416
|
-
return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) => diagnostic
|
|
40455
|
+
return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) => isMappableOxlintDiagnostic(diagnostic) && isLintableSourceFile(diagnostic.filename) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory) && !shouldSuppressCompilerFindingInWorklet(diagnostic, project, rootDirectory)).map((diagnostic) => {
|
|
40417
40456
|
const { plugin, rule } = parseRuleCode(diagnostic.code);
|
|
40418
40457
|
const primaryLabel = diagnostic.labels[0];
|
|
40419
40458
|
const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule, project);
|
|
40420
40459
|
const normalizedFilePath = diagnostic.filename.replaceAll("\\", "/");
|
|
40421
40460
|
const primarySpan = primaryLabel?.span;
|
|
40461
|
+
const sourceBuffer = primarySpan ? readSourceBuffer(diagnostic.filename) : null;
|
|
40422
40462
|
const relatedLocations = buildRelatedLocations(diagnostic.labels, normalizedFilePath);
|
|
40423
40463
|
const category = resolveDiagnosticCategory(plugin, rule);
|
|
40464
|
+
const matchByOccurrence = resolveMatchByOccurrence(rule, category);
|
|
40465
|
+
const sourceLines = primarySpan ? readSourceLines(diagnostic.filename) : null;
|
|
40466
|
+
const primaryLineIndex = primarySpan ? primarySpan.line - 1 : -1;
|
|
40467
|
+
const primaryLine = sourceLines?.[primaryLineIndex];
|
|
40468
|
+
const primaryColumnIndex = primarySpan ? primarySpan.column - 1 : -1;
|
|
40469
|
+
const isJsxTagLabel = primaryLine !== void 0 && primaryColumnIndex >= 0 && (primaryLine[primaryColumnIndex] === "<" || primaryLine[primaryColumnIndex - 1] === "<");
|
|
40470
|
+
const jsxOpenerEndLineIndex = sourceLines && isJsxTagLabel ? findJsxOpenerSpan(sourceLines, primaryLineIndex) : null;
|
|
40471
|
+
const primarySpanEndLine = jsxOpenerEndLineIndex !== null ? jsxOpenerEndLineIndex + 1 : primarySpan && sourceBuffer ? lineOfUtf8Offset(sourceBuffer, primarySpan.offset + Math.max(primarySpan.length - 1, 0)) : void 0;
|
|
40424
40472
|
return {
|
|
40425
40473
|
filePath: normalizedFilePath,
|
|
40426
40474
|
plugin,
|
|
@@ -40434,10 +40482,11 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
40434
40482
|
column: primarySpan?.column ?? 0,
|
|
40435
40483
|
...primarySpan ? {
|
|
40436
40484
|
offset: primarySpan.offset,
|
|
40437
|
-
length: primarySpan.length
|
|
40485
|
+
length: primarySpan.length,
|
|
40486
|
+
...primarySpanEndLine !== void 0 ? { endLine: primarySpanEndLine } : {}
|
|
40438
40487
|
} : {},
|
|
40439
40488
|
category,
|
|
40440
|
-
...
|
|
40489
|
+
...matchByOccurrence ? { matchByOccurrence: true } : {},
|
|
40441
40490
|
...relatedLocations.length > 0 ? { relatedLocations } : {}
|
|
40442
40491
|
};
|
|
40443
40492
|
}), rootDirectory);
|
|
@@ -42224,7 +42273,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
42224
42273
|
directory: scanDirectory,
|
|
42225
42274
|
repo
|
|
42226
42275
|
}).pipe(orElseSucceed(() => null)) : succeed$2(null));
|
|
42227
|
-
const lintIncludePaths = (input.
|
|
42276
|
+
const lintIncludePaths = (input.skipExplicitIncludePathFilter ? input.includePaths.length > 0 ? [...input.includePaths] : void 0 : computeExplicitLintIncludePaths([...input.includePaths])) ?? resolveLintIncludePaths(scanDirectory, resolvedConfig.config);
|
|
42228
42277
|
const fallbackScannedFilePaths = input.suppressScanSummary ? (lintIncludePaths ?? (yield* filesService.listSourceFiles(scanDirectory))).map((relativePath) => Path.resolve(scanDirectory, relativePath)) : [];
|
|
42229
42278
|
const beforeLint = hooks.beforeLint ?? NO_HOOKS.beforeLint;
|
|
42230
42279
|
const afterLint = hooks.afterLint ?? NO_HOOKS.afterLint;
|
|
@@ -42719,7 +42768,7 @@ const runEditorScan = async (input) => {
|
|
|
42719
42768
|
warnings,
|
|
42720
42769
|
isCi: false,
|
|
42721
42770
|
resolveLocalGithubViewerPermission: false,
|
|
42722
|
-
|
|
42771
|
+
skipExplicitIncludePathFilter: true
|
|
42723
42772
|
}).pipe(withSpan("runEditorScan", { attributes: {
|
|
42724
42773
|
"editor.lint": lint,
|
|
42725
42774
|
"editor.runDeadCode": runDeadCode
|
|
@@ -43482,7 +43531,7 @@ const createLintCache = (input) => {
|
|
|
43482
43531
|
let persistTimer = null;
|
|
43483
43532
|
try {
|
|
43484
43533
|
const parsed = JSON.parse(fs.readFileSync(cacheFilePath, "utf8"));
|
|
43485
|
-
if (parsed.version ===
|
|
43534
|
+
if (parsed.version === 2 && parsed.fingerprint === input.fingerprint) for (const [fsPath, entry] of Object.entries(parsed.entries)) entries.set(fsPath, entry);
|
|
43486
43535
|
} catch {}
|
|
43487
43536
|
const persist = () => {
|
|
43488
43537
|
if (persistTimer) {
|
|
@@ -43493,7 +43542,7 @@ const createLintCache = (input) => {
|
|
|
43493
43542
|
dirty = false;
|
|
43494
43543
|
try {
|
|
43495
43544
|
const payload = {
|
|
43496
|
-
version:
|
|
43545
|
+
version: 2,
|
|
43497
43546
|
fingerprint: input.fingerprint,
|
|
43498
43547
|
entries: Object.fromEntries(entries)
|
|
43499
43548
|
};
|
|
@@ -43506,14 +43555,14 @@ const createLintCache = (input) => {
|
|
|
43506
43555
|
}
|
|
43507
43556
|
};
|
|
43508
43557
|
return {
|
|
43509
|
-
lookup: (fsPath,
|
|
43558
|
+
lookup: (fsPath, identity) => {
|
|
43510
43559
|
const entry = entries.get(fsPath);
|
|
43511
|
-
if (entry !== void 0 && entry.
|
|
43560
|
+
if (entry !== void 0 && entry.contentHash === identity.contentHash) return entry.diagnostics;
|
|
43512
43561
|
return null;
|
|
43513
43562
|
},
|
|
43514
|
-
store: (fsPath,
|
|
43563
|
+
store: (fsPath, identity, diagnostics) => {
|
|
43515
43564
|
entries.set(fsPath, {
|
|
43516
|
-
...
|
|
43565
|
+
...identity,
|
|
43517
43566
|
diagnostics
|
|
43518
43567
|
});
|
|
43519
43568
|
dirty = true;
|
|
@@ -43602,16 +43651,9 @@ const resolveDiagnosticFsPath = (rawFilePath, scanDirectory, projectDirectory, o
|
|
|
43602
43651
|
}
|
|
43603
43652
|
return normalizeFsPath(absolute);
|
|
43604
43653
|
};
|
|
43605
|
-
const
|
|
43606
|
-
|
|
43607
|
-
|
|
43608
|
-
return {
|
|
43609
|
-
mtimeMs: stat.mtimeMs,
|
|
43610
|
-
size: stat.size
|
|
43611
|
-
};
|
|
43612
|
-
} catch {
|
|
43613
|
-
return null;
|
|
43614
|
-
}
|
|
43654
|
+
const readFileIdentity = (fsPath) => {
|
|
43655
|
+
const contentHash = hashFileContents(fsPath);
|
|
43656
|
+
return contentHash === null ? null : { contentHash };
|
|
43615
43657
|
};
|
|
43616
43658
|
/**
|
|
43617
43659
|
* Outcome for a per-file request served without running oxlint (every
|
|
@@ -43637,7 +43679,7 @@ const outcomeWithoutScan = (request, byFile, requestedPaths) => ({
|
|
|
43637
43679
|
* overlay tree (unsaved buffers) or disk, groups diagnostics by canonical
|
|
43638
43680
|
* absolute path, and reports stale-detection metadata.
|
|
43639
43681
|
*
|
|
43640
|
-
* A persistent per-file lint cache (keyed by
|
|
43682
|
+
* A persistent per-file lint cache (keyed by content, namespaced by a
|
|
43641
43683
|
* config fingerprint) short-circuits unchanged files so a re-opened editor
|
|
43642
43684
|
* or repeated workspace scan skips the oxlint subprocess for everything it
|
|
43643
43685
|
* hasn't edited. The cache applies only to disk-based, lint-only, per-file
|
|
@@ -43667,15 +43709,15 @@ const createScanRunner = (options) => {
|
|
|
43667
43709
|
const requestedPaths = request.priority === "background" && !request.useOverlay && options.isOpen ? allRequested.filter((fsPath) => !options.isOpen?.(fsPath)) : allRequested;
|
|
43668
43710
|
const cache = cacheEnabled && !isWholeProject && !request.useOverlay && !request.runDeadCode ? getCache(projectDirectory) : null;
|
|
43669
43711
|
const byFile = /* @__PURE__ */ new Map();
|
|
43670
|
-
const
|
|
43712
|
+
const identityByPath = /* @__PURE__ */ new Map();
|
|
43671
43713
|
let filesToScan = requestedPaths;
|
|
43672
43714
|
if (cache) {
|
|
43673
43715
|
const uncached = [];
|
|
43674
43716
|
for (const fsPath of requestedPaths) {
|
|
43675
|
-
const
|
|
43676
|
-
if (
|
|
43677
|
-
|
|
43678
|
-
const hit = cache.lookup(fsPath,
|
|
43717
|
+
const identity = readFileIdentity(fsPath);
|
|
43718
|
+
if (identity) {
|
|
43719
|
+
identityByPath.set(fsPath, identity);
|
|
43720
|
+
const hit = cache.lookup(fsPath, identity);
|
|
43679
43721
|
if (hit !== null) {
|
|
43680
43722
|
if (hit.length > 0) byFile.set(fsPath, hit);
|
|
43681
43723
|
continue;
|
|
@@ -43718,9 +43760,9 @@ const createScanRunner = (options) => {
|
|
|
43718
43760
|
}
|
|
43719
43761
|
if (cache && result.ok && !result.skipped && !result.didLintFail && result.lintPartialFailures.length === 0) {
|
|
43720
43762
|
for (const fsPath of filesToScan) {
|
|
43721
|
-
const
|
|
43722
|
-
if (!
|
|
43723
|
-
cache.store(fsPath,
|
|
43763
|
+
const identity = identityByPath.get(fsPath);
|
|
43764
|
+
if (!identity) continue;
|
|
43765
|
+
cache.store(fsPath, identity, byFile.get(fsPath) ?? []);
|
|
43724
43766
|
}
|
|
43725
43767
|
cache.schedulePersist();
|
|
43726
43768
|
}
|
|
@@ -44500,6 +44542,7 @@ const METRIC = {
|
|
|
44500
44542
|
cliInvoked: "cli.invoked",
|
|
44501
44543
|
cliError: "cli.error",
|
|
44502
44544
|
cliEnvironmentError: "cli.env_error",
|
|
44545
|
+
stagedSnapshotDivergence: "staged.snapshot_divergence",
|
|
44503
44546
|
projectDetected: "project.detected",
|
|
44504
44547
|
projectPathSelected: "project.path_selected",
|
|
44505
44548
|
projectConfigSelected: "project.config_selected",
|
|
@@ -44854,5 +44897,5 @@ const startLanguageServer = () => {
|
|
|
44854
44897
|
};
|
|
44855
44898
|
//#endregion
|
|
44856
44899
|
export { startLanguageServer };
|
|
44857
|
-
!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]="
|
|
44858
|
-
//# debugId=
|
|
44900
|
+
!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]="8ed74459-2a69-556c-bb95-8cdebdb094cd")}catch(e){}}();
|
|
44901
|
+
//# debugId=8ed74459-2a69-556c-bb95-8cdebdb094cd
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-doctor",
|
|
3
|
-
"version": "0.7.6-dev.
|
|
3
|
+
"version": "0.7.6-dev.1d7b6e2",
|
|
4
4
|
"description": "Your agent writes bad React. This catches it",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"accessibility",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"vscode-uri": "^3.1.0",
|
|
67
67
|
"yaml": "^2.9.0",
|
|
68
68
|
"deslop-js": "0.7.6",
|
|
69
|
-
"oxlint-plugin-react-doctor": "0.7.6-dev.
|
|
69
|
+
"oxlint-plugin-react-doctor": "0.7.6-dev.1d7b6e2"
|
|
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.6",
|
|
78
77
|
"@react-doctor/core": "0.7.6",
|
|
79
|
-
"@react-doctor/language-server": "0.7.6"
|
|
78
|
+
"@react-doctor/language-server": "0.7.6",
|
|
79
|
+
"@react-doctor/api": "0.7.6"
|
|
80
80
|
},
|
|
81
81
|
"engines": {
|
|
82
82
|
"node": "^20.19.0 || >=22.13.0"
|