react-doctor 0.5.6-dev.f45cb29 → 0.5.7-dev.242bf69
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 +763 -404
- package/dist/index.d.ts +23 -3
- package/dist/index.js +313 -188
- package/dist/lsp.js +332 -212
- package/package.json +5 -5
package/dist/lsp.js
CHANGED
|
@@ -14,7 +14,7 @@ import * as NodeUrl from "node:url";
|
|
|
14
14
|
import { fileURLToPath } from "node:url";
|
|
15
15
|
import { createJiti } from "jiti";
|
|
16
16
|
import * as Crypto from "node:crypto";
|
|
17
|
-
import crypto from "node:crypto";
|
|
17
|
+
import crypto, { createHash } from "node:crypto";
|
|
18
18
|
import { gzipSync } from "node:zlib";
|
|
19
19
|
import { CodeActionKind, CodeActionTriggerKind, DidChangeWatchedFilesNotification, DocumentDiagnosticReportKind, FileChangeType, TextDocumentSyncKind, TextDocuments, createConnection } from "vscode-languageserver/node.js";
|
|
20
20
|
import { TextDocument } from "vscode-languageserver-textdocument";
|
|
@@ -19286,7 +19286,8 @@ var Diagnostic = class extends Class("Diagnostic")({
|
|
|
19286
19286
|
category: String$1,
|
|
19287
19287
|
fileContext: optional(Literals(["test", "story"])),
|
|
19288
19288
|
suppressionHint: optional(String$1),
|
|
19289
|
-
relatedLocations: optional(ArraySchema(DiagnosticRelatedLocation))
|
|
19289
|
+
relatedLocations: optional(ArraySchema(DiagnosticRelatedLocation)),
|
|
19290
|
+
fixGroupId: optional(String$1)
|
|
19290
19291
|
}) {};
|
|
19291
19292
|
/**
|
|
19292
19293
|
* Deterministic identity string for a diagnostic. Same diagnostic
|
|
@@ -19335,6 +19336,7 @@ var JsonReportProjectEntry = class extends Class("JsonReportProjectEntry")({
|
|
|
19335
19336
|
score: Unknown,
|
|
19336
19337
|
skippedChecks: ArraySchema(String$1),
|
|
19337
19338
|
skippedCheckReasons: optional(Record$1(String$1, String$1)),
|
|
19339
|
+
scannedFileCount: optional(Number$1),
|
|
19338
19340
|
elapsedMilliseconds: Number$1
|
|
19339
19341
|
}) {};
|
|
19340
19342
|
/**
|
|
@@ -32761,6 +32763,7 @@ const isLargeMinifiedFile = (absolutePath) => {
|
|
|
32761
32763
|
if (sizeBytes < 2e4) return false;
|
|
32762
32764
|
return isMinifiedSource(absolutePath);
|
|
32763
32765
|
};
|
|
32766
|
+
const isErrnoException = (error) => error instanceof Error && "code" in error;
|
|
32764
32767
|
const IGNORABLE_READDIR_ERROR_CODES = new Set([
|
|
32765
32768
|
"EACCES",
|
|
32766
32769
|
"EPERM",
|
|
@@ -32770,11 +32773,7 @@ const IGNORABLE_READDIR_ERROR_CODES = new Set([
|
|
|
32770
32773
|
"ELOOP",
|
|
32771
32774
|
"ENAMETOOLONG"
|
|
32772
32775
|
]);
|
|
32773
|
-
const isIgnorableReaddirError = (error) =>
|
|
32774
|
-
if (typeof error !== "object" || error === null) return false;
|
|
32775
|
-
const errorCode = error.code;
|
|
32776
|
-
return typeof errorCode === "string" && IGNORABLE_READDIR_ERROR_CODES.has(errorCode);
|
|
32777
|
-
};
|
|
32776
|
+
const isIgnorableReaddirError = (error) => isErrnoException(error) && typeof error.code === "string" && IGNORABLE_READDIR_ERROR_CODES.has(error.code);
|
|
32778
32777
|
const readDirectoryEntries = (directoryPath) => {
|
|
32779
32778
|
try {
|
|
32780
32779
|
return NFS.readdirSync(directoryPath, { withFileTypes: true });
|
|
@@ -32824,7 +32823,7 @@ const readPackageJsonUncached = (packageJsonPath) => {
|
|
|
32824
32823
|
return JSON.parse(NFS.readFileSync(packageJsonPath, "utf-8"));
|
|
32825
32824
|
} catch (error) {
|
|
32826
32825
|
if (error instanceof SyntaxError) return {};
|
|
32827
|
-
if (error
|
|
32826
|
+
if (isErrnoException(error)) {
|
|
32828
32827
|
const { code } = error;
|
|
32829
32828
|
if (code === "EISDIR" || code === "EACCES" || code === "EPERM" || code === "ENOENT") return {};
|
|
32830
32829
|
}
|
|
@@ -33549,17 +33548,13 @@ const isPackageJsonReactNativeAware = (packageJson) => {
|
|
|
33549
33548
|
return false;
|
|
33550
33549
|
};
|
|
33551
33550
|
const hasReactNativeWorkspaceAnywhere = (rootDirectory, rootPackageJson) => someWorkspacePackageJson(rootDirectory, rootPackageJson, isPackageJsonReactNativeAware);
|
|
33552
|
-
const
|
|
33553
|
-
const spec = packageJson.dependencies?.
|
|
33551
|
+
const getDependencySpec = (packageJson, packageName) => {
|
|
33552
|
+
const spec = packageJson.dependencies?.[packageName] ?? packageJson.devDependencies?.[packageName] ?? packageJson.peerDependencies?.[packageName] ?? packageJson.optionalDependencies?.[packageName];
|
|
33554
33553
|
return typeof spec === "string" ? spec : null;
|
|
33555
33554
|
};
|
|
33556
|
-
const findExpoVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson,
|
|
33555
|
+
const findExpoVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, "expo"));
|
|
33557
33556
|
const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
|
|
33558
|
-
const
|
|
33559
|
-
const spec = packageJson.dependencies?.["@shopify/flash-list"] ?? packageJson.devDependencies?.["@shopify/flash-list"] ?? packageJson.peerDependencies?.["@shopify/flash-list"] ?? packageJson.optionalDependencies?.["@shopify/flash-list"];
|
|
33560
|
-
return typeof spec === "string" ? spec : null;
|
|
33561
|
-
};
|
|
33562
|
-
const findShopifyFlashListVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, getShopifyFlashListDependencySpec);
|
|
33557
|
+
const findShopifyFlashListVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, SHOPIFY_FLASH_LIST_PACKAGE_NAME));
|
|
33563
33558
|
const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, version }) => {
|
|
33564
33559
|
if (version === null || !isCatalogReference(version)) return version;
|
|
33565
33560
|
const catalogName = extractCatalogName(version);
|
|
@@ -33571,11 +33566,7 @@ const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson,
|
|
|
33571
33566
|
if (!isFile(monorepoPackageJsonPath)) return version;
|
|
33572
33567
|
return resolveCatalogVersion(readPackageJson(monorepoPackageJsonPath), packageName, monorepoRoot, catalogName) ?? version;
|
|
33573
33568
|
};
|
|
33574
|
-
const
|
|
33575
|
-
const spec = packageJson.dependencies?.next ?? packageJson.devDependencies?.next ?? packageJson.peerDependencies?.next ?? packageJson.optionalDependencies?.next;
|
|
33576
|
-
return typeof spec === "string" ? spec : null;
|
|
33577
|
-
};
|
|
33578
|
-
const findNextjsVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, getNextjsDependencySpec);
|
|
33569
|
+
const findNextjsVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, "next"));
|
|
33579
33570
|
const getPreactVersion = (packageJson) => {
|
|
33580
33571
|
return {
|
|
33581
33572
|
...packageJson.peerDependencies,
|
|
@@ -33657,6 +33648,11 @@ const ES_TARGET_YEAR_BY_NAME = {
|
|
|
33657
33648
|
esnext: 9999
|
|
33658
33649
|
};
|
|
33659
33650
|
/**
|
|
33651
|
+
* tsconfig filenames probed when resolving a project's TypeScript
|
|
33652
|
+
* compiler options — the root config first, then a monorepo base config.
|
|
33653
|
+
*/
|
|
33654
|
+
const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
|
|
33655
|
+
/**
|
|
33660
33656
|
* Project-config files that `StagedFiles.materialize` copies into
|
|
33661
33657
|
* the temp directory alongside staged sources so oxlint resolves
|
|
33662
33658
|
* `tsconfig` / `package.json` / lint configs the same way it would
|
|
@@ -33726,6 +33722,13 @@ const APP_ONLY_RULE_KEYS = new Set([
|
|
|
33726
33722
|
]);
|
|
33727
33723
|
const COMPILER_CLEANUP_BUCKET = "compiler-cleanup";
|
|
33728
33724
|
const COMPILER_CLEANUP_RULE_KEYS = new Set(["react-doctor/react-compiler-no-manual-memoization"]);
|
|
33725
|
+
const ROOT_CAUSE_GROUPABLE_RULE_KEYS = new Set([
|
|
33726
|
+
"react-doctor/no-derived-state",
|
|
33727
|
+
"react-doctor/no-derived-state-effect",
|
|
33728
|
+
"react-doctor/no-derived-useState",
|
|
33729
|
+
"react-doctor/no-adjust-state-on-prop-change",
|
|
33730
|
+
"react-doctor/no-reset-all-state-on-prop-change"
|
|
33731
|
+
]);
|
|
33729
33732
|
const MAX_GLOB_PATTERN_LENGTH_CHARS = 1024;
|
|
33730
33733
|
const CONFIG_CACHE_TTL_MS = 300 * 1e3;
|
|
33731
33734
|
const SOCKET_FREE_PURL_API_BASE = "https://firewall-api.socket.dev/purl";
|
|
@@ -34178,6 +34181,7 @@ const isTailwindAtLeast = (detected, required) => {
|
|
|
34178
34181
|
if (detected.major !== required.major) return detected.major > required.major;
|
|
34179
34182
|
return detected.minor >= required.minor;
|
|
34180
34183
|
};
|
|
34184
|
+
const messageFromUnknown = (error) => error instanceof Error ? error.message : String(error);
|
|
34181
34185
|
var InvalidGlobPatternError = class extends Error {
|
|
34182
34186
|
pattern;
|
|
34183
34187
|
reason;
|
|
@@ -34206,7 +34210,7 @@ const compileGlobPattern = (rawPattern) => {
|
|
|
34206
34210
|
try {
|
|
34207
34211
|
return import_picomatch.default.makeRe(normalizeGlobPattern(rawPattern), PICOMATCH_OPTIONS);
|
|
34208
34212
|
} catch (caughtError) {
|
|
34209
|
-
throw new InvalidGlobPatternError(rawPattern,
|
|
34213
|
+
throw new InvalidGlobPatternError(rawPattern, messageFromUnknown(caughtError));
|
|
34210
34214
|
}
|
|
34211
34215
|
};
|
|
34212
34216
|
const compileGlobPatternsLenient = (patterns, onInvalid) => {
|
|
@@ -34302,115 +34306,6 @@ const buildRuleSeverityControls = (config) => {
|
|
|
34302
34306
|
...config.buckets !== void 0 ? { buckets: config.buckets } : {}
|
|
34303
34307
|
};
|
|
34304
34308
|
};
|
|
34305
|
-
const JSX_OPENER_TAG_PATTERN = /<[A-Za-z][\w.]*/g;
|
|
34306
|
-
const JSX_TAG_NAME_FOLLOW = /[A-Za-z]/;
|
|
34307
|
-
const isOpenerMatchInsideLineComment = (line, openerCharIndex) => {
|
|
34308
|
-
let stringDelimiter = null;
|
|
34309
|
-
for (let charIndex = 0; charIndex < openerCharIndex; charIndex++) {
|
|
34310
|
-
const character = line[charIndex];
|
|
34311
|
-
if (stringDelimiter !== null) {
|
|
34312
|
-
if (character === "\\") {
|
|
34313
|
-
charIndex++;
|
|
34314
|
-
continue;
|
|
34315
|
-
}
|
|
34316
|
-
if (character === stringDelimiter) stringDelimiter = null;
|
|
34317
|
-
continue;
|
|
34318
|
-
}
|
|
34319
|
-
if (character === "\"" || character === "'" || character === "`") {
|
|
34320
|
-
stringDelimiter = character;
|
|
34321
|
-
continue;
|
|
34322
|
-
}
|
|
34323
|
-
if (character === "/" && line[charIndex + 1] === "/") return true;
|
|
34324
|
-
}
|
|
34325
|
-
return false;
|
|
34326
|
-
};
|
|
34327
|
-
const findOpenerTagOnLine = (line) => {
|
|
34328
|
-
for (const match of line.matchAll(JSX_OPENER_TAG_PATTERN)) {
|
|
34329
|
-
if (match.index === void 0) continue;
|
|
34330
|
-
if (!isOpenerMatchInsideLineComment(line, match.index)) return { startCharIndex: match.index + match[0].length };
|
|
34331
|
-
}
|
|
34332
|
-
return null;
|
|
34333
|
-
};
|
|
34334
|
-
const findJsxOpenerSpan = (lines, openerLineIndex) => {
|
|
34335
|
-
const openerLine = lines[openerLineIndex];
|
|
34336
|
-
if (openerLine === void 0) return null;
|
|
34337
|
-
const opener = findOpenerTagOnLine(openerLine);
|
|
34338
|
-
if (!opener) return null;
|
|
34339
|
-
const lookaheadLimit = Math.min(lines.length, openerLineIndex + 32);
|
|
34340
|
-
let braceDepth = 0;
|
|
34341
|
-
let innerAngleDepth = 0;
|
|
34342
|
-
let stringDelimiter = null;
|
|
34343
|
-
for (let lineIndex = openerLineIndex; lineIndex < lookaheadLimit; lineIndex++) {
|
|
34344
|
-
const currentLine = lines[lineIndex];
|
|
34345
|
-
const startCharForLine = lineIndex === openerLineIndex ? opener.startCharIndex : 0;
|
|
34346
|
-
for (let charIndex = startCharForLine; charIndex < currentLine.length; charIndex++) {
|
|
34347
|
-
const character = currentLine[charIndex];
|
|
34348
|
-
if (stringDelimiter !== null) {
|
|
34349
|
-
if (character === "\\") {
|
|
34350
|
-
charIndex++;
|
|
34351
|
-
continue;
|
|
34352
|
-
}
|
|
34353
|
-
if (character === stringDelimiter) stringDelimiter = null;
|
|
34354
|
-
continue;
|
|
34355
|
-
}
|
|
34356
|
-
if (character === "\"" || character === "'" || character === "`") {
|
|
34357
|
-
stringDelimiter = character;
|
|
34358
|
-
continue;
|
|
34359
|
-
}
|
|
34360
|
-
if (character === "{") {
|
|
34361
|
-
braceDepth++;
|
|
34362
|
-
continue;
|
|
34363
|
-
}
|
|
34364
|
-
if (character === "}") {
|
|
34365
|
-
braceDepth--;
|
|
34366
|
-
continue;
|
|
34367
|
-
}
|
|
34368
|
-
if (braceDepth !== 0) continue;
|
|
34369
|
-
if (character === "<") {
|
|
34370
|
-
const followCharacter = currentLine[charIndex + 1];
|
|
34371
|
-
if (followCharacter !== void 0 && JSX_TAG_NAME_FOLLOW.test(followCharacter)) innerAngleDepth++;
|
|
34372
|
-
continue;
|
|
34373
|
-
}
|
|
34374
|
-
if (character !== ">") continue;
|
|
34375
|
-
const previousCharacter = currentLine[charIndex - 1];
|
|
34376
|
-
const nextCharacter = currentLine[charIndex + 1];
|
|
34377
|
-
if (previousCharacter === "=" || nextCharacter === "=") continue;
|
|
34378
|
-
if (innerAngleDepth > 0) {
|
|
34379
|
-
innerAngleDepth--;
|
|
34380
|
-
continue;
|
|
34381
|
-
}
|
|
34382
|
-
return lineIndex;
|
|
34383
|
-
}
|
|
34384
|
-
}
|
|
34385
|
-
return null;
|
|
34386
|
-
};
|
|
34387
|
-
const findEnclosingMultilineJsxOpenerStart = (lines, diagnosticLineIndex) => {
|
|
34388
|
-
for (let candidateIndex = diagnosticLineIndex - 1; candidateIndex >= 0 && diagnosticLineIndex - candidateIndex <= 32; candidateIndex--) {
|
|
34389
|
-
const openerCloseIndex = findJsxOpenerSpan(lines, candidateIndex);
|
|
34390
|
-
if (openerCloseIndex !== null && openerCloseIndex >= diagnosticLineIndex) return candidateIndex;
|
|
34391
|
-
}
|
|
34392
|
-
return null;
|
|
34393
|
-
};
|
|
34394
|
-
const DISABLE_NEXT_LINE_PATTERN = /(?:\/\/|\/\*)\s*react-doctor-disable-next-line\b(?:\s+([^\r\n]*?))?\s*(?:\*\/)?\s*\}?\s*$/;
|
|
34395
|
-
const findStackedDisableCommentsAbove = (lines, anchorIndex) => {
|
|
34396
|
-
const collected = [];
|
|
34397
|
-
let isStillInChain = true;
|
|
34398
|
-
for (let candidateIndex = anchorIndex - 1; candidateIndex >= 0 && anchorIndex - candidateIndex <= 10; candidateIndex--) {
|
|
34399
|
-
const candidateLine = lines[candidateIndex];
|
|
34400
|
-
if (candidateLine === void 0) break;
|
|
34401
|
-
const match = candidateLine.match(DISABLE_NEXT_LINE_PATTERN);
|
|
34402
|
-
if (match) {
|
|
34403
|
-
collected.push({
|
|
34404
|
-
commentLineIndex: candidateIndex,
|
|
34405
|
-
ruleList: match[1],
|
|
34406
|
-
isInChain: isStillInChain
|
|
34407
|
-
});
|
|
34408
|
-
continue;
|
|
34409
|
-
}
|
|
34410
|
-
isStillInChain = false;
|
|
34411
|
-
}
|
|
34412
|
-
return collected;
|
|
34413
|
-
};
|
|
34414
34309
|
const LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY = {
|
|
34415
34310
|
"effect/no-adjust-state-on-prop-change": "react-doctor/no-adjust-state-on-prop-change",
|
|
34416
34311
|
"effect/no-chain-state-updates": "react-doctor/no-chain-state-updates",
|
|
@@ -34535,7 +34430,13 @@ for (const [legacyRuleKey, nativeRuleKey] of Object.entries(LEGACY_RULE_KEY_TO_N
|
|
|
34535
34430
|
}
|
|
34536
34431
|
const getLegacyRuleKeysForNative = (ruleKey) => NATIVE_RULE_KEY_TO_LEGACY_RULE_KEYS.get(ruleKey) ?? [];
|
|
34537
34432
|
const canonicalizeRuleKey = (ruleKey) => LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY[ruleKey] ?? ruleKey;
|
|
34538
|
-
const
|
|
34433
|
+
const isReactDoctorShortIdOf = (bareRuleKey, qualifiedRuleKey) => !bareRuleKey.includes("/") && qualifiedRuleKey === `react-doctor/${bareRuleKey}`;
|
|
34434
|
+
const isSameRuleKey = (candidateRuleKey, targetRuleKey) => {
|
|
34435
|
+
const canonicalCandidate = canonicalizeRuleKey(candidateRuleKey);
|
|
34436
|
+
const canonicalTarget = canonicalizeRuleKey(targetRuleKey);
|
|
34437
|
+
if (canonicalCandidate === canonicalTarget) return true;
|
|
34438
|
+
return isReactDoctorShortIdOf(canonicalCandidate, canonicalTarget) || isReactDoctorShortIdOf(canonicalTarget, canonicalCandidate);
|
|
34439
|
+
};
|
|
34539
34440
|
const getEquivalentRuleKeys = (ruleKey) => {
|
|
34540
34441
|
const nativeRuleKey = canonicalizeRuleKey(ruleKey);
|
|
34541
34442
|
return [nativeRuleKey, ...getLegacyRuleKeysForNative(nativeRuleKey)];
|
|
@@ -34545,12 +34446,182 @@ const stripDescriptionTail = (ruleList) => {
|
|
|
34545
34446
|
if (!descriptionMatch || descriptionMatch.index === void 0) return ruleList;
|
|
34546
34447
|
return ruleList.slice(0, descriptionMatch.index);
|
|
34547
34448
|
};
|
|
34548
|
-
const
|
|
34449
|
+
const tokenizeRuleList = (ruleList) => {
|
|
34549
34450
|
const trimmed = ruleList?.trim();
|
|
34550
|
-
if (!trimmed) return
|
|
34451
|
+
if (!trimmed) return [];
|
|
34551
34452
|
const ruleSection = stripDescriptionTail(trimmed).trim();
|
|
34552
|
-
if (!ruleSection) return
|
|
34553
|
-
return ruleSection.split(/[,\s]+/).
|
|
34453
|
+
if (!ruleSection) return [];
|
|
34454
|
+
return ruleSection.split(/[,\s]+/).map((token) => token.trim()).filter(Boolean);
|
|
34455
|
+
};
|
|
34456
|
+
const FOREIGN_INLINE_DISABLE_PATTERN = /(?:\/\/|\/\*)[ \t]*(eslint|oxlint)-disable-(next-line|line)(?![\w-])([^\r\n]*)/;
|
|
34457
|
+
const FOREIGN_BLOCK_DISABLE_PATTERN = /\/\*[ \t]*(eslint|oxlint)-disable(?![\w-])([^*\r\n]*)/;
|
|
34458
|
+
const FOREIGN_BLOCK_ENABLE_PATTERN = /\/\*[ \t]*(?:eslint|oxlint)-enable(?![\w-])([^*\r\n]*)/;
|
|
34459
|
+
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}\` — change it to \`${ruleId}\`.`;
|
|
34460
|
+
const tokenMisnamesRule = (token, ruleId) => token !== ruleId && isSameRuleKey(token, ruleId);
|
|
34461
|
+
const detectInlineNearMiss = (lines, diagnosticLineIndex, ruleId) => {
|
|
34462
|
+
const candidates = [{
|
|
34463
|
+
line: lines[diagnosticLineIndex],
|
|
34464
|
+
requiredScope: "line"
|
|
34465
|
+
}, {
|
|
34466
|
+
line: lines[diagnosticLineIndex - 1],
|
|
34467
|
+
requiredScope: "next-line"
|
|
34468
|
+
}];
|
|
34469
|
+
for (const { line, requiredScope } of candidates) {
|
|
34470
|
+
const match = line?.match(FOREIGN_INLINE_DISABLE_PATTERN);
|
|
34471
|
+
if (!match) continue;
|
|
34472
|
+
const [, tool, scope, ruleList] = match;
|
|
34473
|
+
if (scope !== requiredScope) continue;
|
|
34474
|
+
const tokens = tokenizeRuleList(ruleList);
|
|
34475
|
+
if (tokens.includes(ruleId)) continue;
|
|
34476
|
+
for (const token of tokens) if (tokenMisnamesRule(token, ruleId)) return buildHint(tool, token, ruleId);
|
|
34477
|
+
}
|
|
34478
|
+
return null;
|
|
34479
|
+
};
|
|
34480
|
+
const detectBlockNearMiss = (lines, diagnosticLineIndex, ruleId) => {
|
|
34481
|
+
let openMisname = null;
|
|
34482
|
+
const lastLineIndex = Math.min(diagnosticLineIndex, lines.length - 1);
|
|
34483
|
+
for (let lineIndex = 0; lineIndex <= lastLineIndex; lineIndex++) {
|
|
34484
|
+
const line = lines[lineIndex];
|
|
34485
|
+
if (line === void 0 || !line.includes("-disable") && !line.includes("-enable")) continue;
|
|
34486
|
+
const disableMatch = line.match(FOREIGN_BLOCK_DISABLE_PATTERN);
|
|
34487
|
+
if (disableMatch) {
|
|
34488
|
+
const [, tool, ruleList] = disableMatch;
|
|
34489
|
+
const tokens = tokenizeRuleList(ruleList);
|
|
34490
|
+
if (tokens.includes(ruleId)) openMisname = null;
|
|
34491
|
+
else {
|
|
34492
|
+
const misnamed = tokens.find((token) => tokenMisnamesRule(token, ruleId));
|
|
34493
|
+
if (misnamed) openMisname = {
|
|
34494
|
+
tool,
|
|
34495
|
+
token: misnamed
|
|
34496
|
+
};
|
|
34497
|
+
}
|
|
34498
|
+
continue;
|
|
34499
|
+
}
|
|
34500
|
+
const enableMatch = line.match(FOREIGN_BLOCK_ENABLE_PATTERN);
|
|
34501
|
+
if (enableMatch) {
|
|
34502
|
+
const enabledRules = tokenizeRuleList(enableMatch[1]);
|
|
34503
|
+
if (enabledRules.length === 0 || enabledRules.some((rule) => isSameRuleKey(rule, ruleId))) openMisname = null;
|
|
34504
|
+
}
|
|
34505
|
+
}
|
|
34506
|
+
return openMisname ? buildHint(openMisname.tool, openMisname.token, ruleId) : null;
|
|
34507
|
+
};
|
|
34508
|
+
const detectForeignDisableNearMiss = (lines, diagnosticLineIndex, ruleId) => {
|
|
34509
|
+
if (!ruleId.startsWith("react-doctor/")) return null;
|
|
34510
|
+
return detectInlineNearMiss(lines, diagnosticLineIndex, ruleId) ?? detectBlockNearMiss(lines, diagnosticLineIndex, ruleId);
|
|
34511
|
+
};
|
|
34512
|
+
const JSX_OPENER_TAG_PATTERN = /<[A-Za-z][\w.]*/g;
|
|
34513
|
+
const JSX_TAG_NAME_FOLLOW = /[A-Za-z]/;
|
|
34514
|
+
const isOpenerMatchInsideLineComment = (line, openerCharIndex) => {
|
|
34515
|
+
let stringDelimiter = null;
|
|
34516
|
+
for (let charIndex = 0; charIndex < openerCharIndex; charIndex++) {
|
|
34517
|
+
const character = line[charIndex];
|
|
34518
|
+
if (stringDelimiter !== null) {
|
|
34519
|
+
if (character === "\\") {
|
|
34520
|
+
charIndex++;
|
|
34521
|
+
continue;
|
|
34522
|
+
}
|
|
34523
|
+
if (character === stringDelimiter) stringDelimiter = null;
|
|
34524
|
+
continue;
|
|
34525
|
+
}
|
|
34526
|
+
if (character === "\"" || character === "'" || character === "`") {
|
|
34527
|
+
stringDelimiter = character;
|
|
34528
|
+
continue;
|
|
34529
|
+
}
|
|
34530
|
+
if (character === "/" && line[charIndex + 1] === "/") return true;
|
|
34531
|
+
}
|
|
34532
|
+
return false;
|
|
34533
|
+
};
|
|
34534
|
+
const findOpenerTagOnLine = (line) => {
|
|
34535
|
+
for (const match of line.matchAll(JSX_OPENER_TAG_PATTERN)) {
|
|
34536
|
+
if (match.index === void 0) continue;
|
|
34537
|
+
if (!isOpenerMatchInsideLineComment(line, match.index)) return { startCharIndex: match.index + match[0].length };
|
|
34538
|
+
}
|
|
34539
|
+
return null;
|
|
34540
|
+
};
|
|
34541
|
+
const findJsxOpenerSpan = (lines, openerLineIndex) => {
|
|
34542
|
+
const openerLine = lines[openerLineIndex];
|
|
34543
|
+
if (openerLine === void 0) return null;
|
|
34544
|
+
const opener = findOpenerTagOnLine(openerLine);
|
|
34545
|
+
if (!opener) return null;
|
|
34546
|
+
const lookaheadLimit = Math.min(lines.length, openerLineIndex + 32);
|
|
34547
|
+
let braceDepth = 0;
|
|
34548
|
+
let innerAngleDepth = 0;
|
|
34549
|
+
let stringDelimiter = null;
|
|
34550
|
+
for (let lineIndex = openerLineIndex; lineIndex < lookaheadLimit; lineIndex++) {
|
|
34551
|
+
const currentLine = lines[lineIndex];
|
|
34552
|
+
const startCharForLine = lineIndex === openerLineIndex ? opener.startCharIndex : 0;
|
|
34553
|
+
for (let charIndex = startCharForLine; charIndex < currentLine.length; charIndex++) {
|
|
34554
|
+
const character = currentLine[charIndex];
|
|
34555
|
+
if (stringDelimiter !== null) {
|
|
34556
|
+
if (character === "\\") {
|
|
34557
|
+
charIndex++;
|
|
34558
|
+
continue;
|
|
34559
|
+
}
|
|
34560
|
+
if (character === stringDelimiter) stringDelimiter = null;
|
|
34561
|
+
continue;
|
|
34562
|
+
}
|
|
34563
|
+
if (character === "\"" || character === "'" || character === "`") {
|
|
34564
|
+
stringDelimiter = character;
|
|
34565
|
+
continue;
|
|
34566
|
+
}
|
|
34567
|
+
if (character === "{") {
|
|
34568
|
+
braceDepth++;
|
|
34569
|
+
continue;
|
|
34570
|
+
}
|
|
34571
|
+
if (character === "}") {
|
|
34572
|
+
braceDepth--;
|
|
34573
|
+
continue;
|
|
34574
|
+
}
|
|
34575
|
+
if (braceDepth !== 0) continue;
|
|
34576
|
+
if (character === "<") {
|
|
34577
|
+
const followCharacter = currentLine[charIndex + 1];
|
|
34578
|
+
if (followCharacter !== void 0 && JSX_TAG_NAME_FOLLOW.test(followCharacter)) innerAngleDepth++;
|
|
34579
|
+
continue;
|
|
34580
|
+
}
|
|
34581
|
+
if (character !== ">") continue;
|
|
34582
|
+
const previousCharacter = currentLine[charIndex - 1];
|
|
34583
|
+
const nextCharacter = currentLine[charIndex + 1];
|
|
34584
|
+
if (previousCharacter === "=" || nextCharacter === "=") continue;
|
|
34585
|
+
if (innerAngleDepth > 0) {
|
|
34586
|
+
innerAngleDepth--;
|
|
34587
|
+
continue;
|
|
34588
|
+
}
|
|
34589
|
+
return lineIndex;
|
|
34590
|
+
}
|
|
34591
|
+
}
|
|
34592
|
+
return null;
|
|
34593
|
+
};
|
|
34594
|
+
const findEnclosingMultilineJsxOpenerStart = (lines, diagnosticLineIndex) => {
|
|
34595
|
+
for (let candidateIndex = diagnosticLineIndex - 1; candidateIndex >= 0 && diagnosticLineIndex - candidateIndex <= 32; candidateIndex--) {
|
|
34596
|
+
const openerCloseIndex = findJsxOpenerSpan(lines, candidateIndex);
|
|
34597
|
+
if (openerCloseIndex !== null && openerCloseIndex >= diagnosticLineIndex) return candidateIndex;
|
|
34598
|
+
}
|
|
34599
|
+
return null;
|
|
34600
|
+
};
|
|
34601
|
+
const DISABLE_NEXT_LINE_PATTERN = /(?:\/\/|\/\*)\s*react-doctor-disable-next-line\b(?:\s+([^\r\n]*?))?\s*(?:\*\/)?\s*\}?\s*$/;
|
|
34602
|
+
const findStackedDisableCommentsAbove = (lines, anchorIndex) => {
|
|
34603
|
+
const collected = [];
|
|
34604
|
+
let isStillInChain = true;
|
|
34605
|
+
for (let candidateIndex = anchorIndex - 1; candidateIndex >= 0 && anchorIndex - candidateIndex <= 10; candidateIndex--) {
|
|
34606
|
+
const candidateLine = lines[candidateIndex];
|
|
34607
|
+
if (candidateLine === void 0) break;
|
|
34608
|
+
const match = candidateLine.match(DISABLE_NEXT_LINE_PATTERN);
|
|
34609
|
+
if (match) {
|
|
34610
|
+
collected.push({
|
|
34611
|
+
commentLineIndex: candidateIndex,
|
|
34612
|
+
ruleList: match[1],
|
|
34613
|
+
isInChain: isStillInChain
|
|
34614
|
+
});
|
|
34615
|
+
continue;
|
|
34616
|
+
}
|
|
34617
|
+
isStillInChain = false;
|
|
34618
|
+
}
|
|
34619
|
+
return collected;
|
|
34620
|
+
};
|
|
34621
|
+
const isRuleListedInComment = (ruleList, ruleId) => {
|
|
34622
|
+
const tokens = tokenizeRuleList(ruleList);
|
|
34623
|
+
if (tokens.length === 0) return true;
|
|
34624
|
+
return tokens.some((token) => isSameRuleKey(token, ruleId));
|
|
34554
34625
|
};
|
|
34555
34626
|
const DISABLE_LINE_PATTERN = /(?:\/\/|\/\*)\s*react-doctor-disable-line\b(?:\s+([^\r\n]*?))?\s*(?:\*\/)?\s*\}?\s*$/;
|
|
34556
34627
|
const formatLineGap = (gapLineCount) => `${gapLineCount} line${gapLineCount === 1 ? "" : "s"}`;
|
|
@@ -34594,7 +34665,7 @@ const evaluateSuppression = (lines, diagnosticLineIndex, ruleId) => {
|
|
|
34594
34665
|
};
|
|
34595
34666
|
return {
|
|
34596
34667
|
isSuppressed: false,
|
|
34597
|
-
nearMissHint: classifyFromComments([directComments, openerComments], diagnosticLineIndex, ruleId)
|
|
34668
|
+
nearMissHint: classifyFromComments([directComments, openerComments], diagnosticLineIndex, ruleId) ?? detectForeignDisableNearMiss(lines, diagnosticLineIndex, ruleId)
|
|
34598
34669
|
};
|
|
34599
34670
|
};
|
|
34600
34671
|
/**
|
|
@@ -35362,7 +35433,6 @@ const PACKAGE_JSON_FILENAME = "package.json";
|
|
|
35362
35433
|
const PACKAGE_JSON_CONFIG_KEY = "reactDoctor";
|
|
35363
35434
|
const LEGACY_CONFIG_FILENAME = "react-doctor.config.json";
|
|
35364
35435
|
const jiti = createJiti(import.meta.url);
|
|
35365
|
-
const formatError = (error) => error instanceof Error ? error.message : String(error);
|
|
35366
35436
|
const importDefaultExport = async (jitiInstance, filePath) => {
|
|
35367
35437
|
const imported = await jitiInstance.import(filePath);
|
|
35368
35438
|
return imported?.default ?? imported;
|
|
@@ -35394,7 +35464,7 @@ const loadModuleConfig = async (filePath) => {
|
|
|
35394
35464
|
try {
|
|
35395
35465
|
return await importDefaultExport(aliasJiti, filePath);
|
|
35396
35466
|
} catch (retryError) {
|
|
35397
|
-
throw new Error(`${
|
|
35467
|
+
throw new Error(`${messageFromUnknown(error)} (retry with ${SELF_PACKAGE_IMPORT_SPECIFIER} aliased to the running react-doctor package also failed: ${messageFromUnknown(retryError)})`, { cause: retryError });
|
|
35398
35468
|
}
|
|
35399
35469
|
}
|
|
35400
35470
|
};
|
|
@@ -35443,7 +35513,7 @@ const loadLegacyConfig = (directory) => {
|
|
|
35443
35513
|
}
|
|
35444
35514
|
warn(`${LEGACY_CONFIG_FILENAME} must contain an object, ignoring.`);
|
|
35445
35515
|
} catch (error) {
|
|
35446
|
-
warn(`Failed to load ${LEGACY_CONFIG_FILENAME}: ${
|
|
35516
|
+
warn(`Failed to load ${LEGACY_CONFIG_FILENAME}: ${messageFromUnknown(error)}`);
|
|
35447
35517
|
}
|
|
35448
35518
|
return {
|
|
35449
35519
|
status: "invalid",
|
|
@@ -35470,7 +35540,7 @@ const loadConfigFromDirectory = async (directory) => {
|
|
|
35470
35540
|
warn(`${CONFIG_BASENAME}.${extension} must export an object, ignoring.`);
|
|
35471
35541
|
sawBrokenConfigFile = true;
|
|
35472
35542
|
} catch (error) {
|
|
35473
|
-
warn(`Failed to load ${CONFIG_BASENAME}.${extension}: ${
|
|
35543
|
+
warn(`Failed to load ${CONFIG_BASENAME}.${extension}: ${messageFromUnknown(error)}`);
|
|
35474
35544
|
sawBrokenConfigFile = true;
|
|
35475
35545
|
}
|
|
35476
35546
|
}
|
|
@@ -35524,6 +35594,29 @@ const resolveConfigRootDir = (config, configSourceDirectory) => {
|
|
|
35524
35594
|
}
|
|
35525
35595
|
return resolvedRootDir;
|
|
35526
35596
|
};
|
|
35597
|
+
const buildFixGroupId = (diagnostic) => createHash("sha1").update(JSON.stringify([
|
|
35598
|
+
diagnostic.filePath,
|
|
35599
|
+
`${diagnostic.plugin}/${diagnostic.rule}`,
|
|
35600
|
+
diagnostic.message
|
|
35601
|
+
])).digest("hex").slice(0, 16);
|
|
35602
|
+
const isGroupableRule = (diagnostic) => ROOT_CAUSE_GROUPABLE_RULE_KEYS.has(`${diagnostic.plugin}/${diagnostic.rule}`);
|
|
35603
|
+
const assignFixGroups = (diagnostics) => {
|
|
35604
|
+
const siteCountByGroupId = /* @__PURE__ */ new Map();
|
|
35605
|
+
for (const diagnostic of diagnostics) {
|
|
35606
|
+
if (!isGroupableRule(diagnostic)) continue;
|
|
35607
|
+
const groupId = buildFixGroupId(diagnostic);
|
|
35608
|
+
siteCountByGroupId.set(groupId, (siteCountByGroupId.get(groupId) ?? 0) + 1);
|
|
35609
|
+
}
|
|
35610
|
+
return diagnostics.map((diagnostic) => {
|
|
35611
|
+
if (!isGroupableRule(diagnostic)) return diagnostic;
|
|
35612
|
+
const groupId = buildFixGroupId(diagnostic);
|
|
35613
|
+
if ((siteCountByGroupId.get(groupId) ?? 0) < 2) return diagnostic;
|
|
35614
|
+
return {
|
|
35615
|
+
...diagnostic,
|
|
35616
|
+
fixGroupId: groupId
|
|
35617
|
+
};
|
|
35618
|
+
});
|
|
35619
|
+
};
|
|
35527
35620
|
const getDirectDependencyNames = (packageJson) => new Set([...Object.keys(packageJson.dependencies ?? {}), ...Object.keys(packageJson.devDependencies ?? {})]);
|
|
35528
35621
|
const buildExpoCheckContext = (rootDirectory, expoVersion) => {
|
|
35529
35622
|
const packageJson = readPackageJson(Path.join(rootDirectory, "package.json"));
|
|
@@ -36650,7 +36743,7 @@ const readIgnoreFile = (filePath) => {
|
|
|
36650
36743
|
try {
|
|
36651
36744
|
content = NFS.readFileSync(filePath, "utf-8");
|
|
36652
36745
|
} catch (error) {
|
|
36653
|
-
const errnoCode = error
|
|
36746
|
+
const errnoCode = isErrnoException(error) ? error.code : void 0;
|
|
36654
36747
|
if (errnoCode && errnoCode !== "ENOENT") runSync(warn$1(`Could not read ignore file ${filePath}: ${errnoCode}`));
|
|
36655
36748
|
return [];
|
|
36656
36749
|
}
|
|
@@ -36691,8 +36784,8 @@ const collectIgnorePatterns = (rootDirectory) => {
|
|
|
36691
36784
|
cachedPatternsByRoot.set(rootDirectory, patterns);
|
|
36692
36785
|
return patterns;
|
|
36693
36786
|
};
|
|
36787
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36694
36788
|
const KNIP_JSON_FILENAME = "knip.json";
|
|
36695
|
-
const isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36696
36789
|
const readJsonFileSafe = (filePath) => {
|
|
36697
36790
|
let rawContents;
|
|
36698
36791
|
try {
|
|
@@ -36708,10 +36801,10 @@ const readJsonFileSafe = (filePath) => {
|
|
|
36708
36801
|
};
|
|
36709
36802
|
const readKnipConfig = (rootDirectory) => {
|
|
36710
36803
|
const knipJson = readJsonFileSafe(path.join(rootDirectory, KNIP_JSON_FILENAME));
|
|
36711
|
-
if (isRecord
|
|
36804
|
+
if (isRecord(knipJson)) return knipJson;
|
|
36712
36805
|
const packageJson = readJsonFileSafe(path.join(rootDirectory, "package.json"));
|
|
36713
|
-
const packageKnipConfig = isRecord
|
|
36714
|
-
return isRecord
|
|
36806
|
+
const packageKnipConfig = isRecord(packageJson) ? packageJson.knip : null;
|
|
36807
|
+
return isRecord(packageKnipConfig) ? packageKnipConfig : null;
|
|
36715
36808
|
};
|
|
36716
36809
|
const normalizePatternList = (value) => {
|
|
36717
36810
|
if (typeof value === "string" && value.length > 0) return [value];
|
|
@@ -36723,10 +36816,10 @@ const prefixWorkspacePatterns = (workspacePattern, patterns) => {
|
|
|
36723
36816
|
return patterns.map((pattern) => pattern.startsWith("!") ? `!${normalizedWorkspacePattern}/${pattern.slice(1)}` : `${normalizedWorkspacePattern}/${pattern}`);
|
|
36724
36817
|
};
|
|
36725
36818
|
const collectKnipWorkspacePatterns = (workspaces, settingName) => {
|
|
36726
|
-
if (!isRecord
|
|
36819
|
+
if (!isRecord(workspaces)) return [];
|
|
36727
36820
|
const patterns = [];
|
|
36728
36821
|
for (const [workspacePattern, workspaceConfig] of Object.entries(workspaces)) {
|
|
36729
|
-
if (!isRecord
|
|
36822
|
+
if (!isRecord(workspaceConfig)) continue;
|
|
36730
36823
|
patterns.push(...prefixWorkspacePatterns(workspacePattern, normalizePatternList(workspaceConfig[settingName])));
|
|
36731
36824
|
}
|
|
36732
36825
|
return patterns;
|
|
@@ -36771,8 +36864,6 @@ const toCanonicalPath = (filePath) => {
|
|
|
36771
36864
|
};
|
|
36772
36865
|
const DEAD_CODE_PLUGIN = "deslop";
|
|
36773
36866
|
const DEAD_CODE_CATEGORY = "Maintainability";
|
|
36774
|
-
const TSCONFIG_FILENAMES$1 = ["tsconfig.json", "tsconfig.base.json"];
|
|
36775
|
-
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36776
36867
|
const DEAD_CODE_WORKER_SCRIPT = `
|
|
36777
36868
|
const inputChunks = [];
|
|
36778
36869
|
process.stdin.on("data", (chunk) => inputChunks.push(chunk));
|
|
@@ -36830,7 +36921,7 @@ process.stdin.on("end", () => {
|
|
|
36830
36921
|
});
|
|
36831
36922
|
`;
|
|
36832
36923
|
const resolveTsConfigPath = (rootDirectory) => {
|
|
36833
|
-
for (const filename of TSCONFIG_FILENAMES
|
|
36924
|
+
for (const filename of TSCONFIG_FILENAMES) {
|
|
36834
36925
|
const candidate = Path.join(rootDirectory, filename);
|
|
36835
36926
|
if (NFS.existsSync(candidate)) return candidate;
|
|
36836
36927
|
}
|
|
@@ -37211,15 +37302,13 @@ var DeadCode = class DeadCode extends Service()("react-doctor/DeadCode") {
|
|
|
37211
37302
|
})()) }));
|
|
37212
37303
|
static layerOf = (diagnostics) => succeed$3(DeadCode, DeadCode.of({ run: () => fromIterable$1(diagnostics) }));
|
|
37213
37304
|
};
|
|
37214
|
-
const createNodeReadFileLinesSync = (rootDirectory) => {
|
|
37215
|
-
|
|
37216
|
-
|
|
37217
|
-
|
|
37218
|
-
|
|
37219
|
-
|
|
37220
|
-
|
|
37221
|
-
}
|
|
37222
|
-
};
|
|
37305
|
+
const createNodeReadFileLinesSync = (rootDirectory) => (filePath) => {
|
|
37306
|
+
const absolutePath = Path.isAbsolute(filePath) ? filePath : Path.join(rootDirectory, filePath);
|
|
37307
|
+
try {
|
|
37308
|
+
return NFS.readFileSync(absolutePath, "utf-8").split("\n");
|
|
37309
|
+
} catch {
|
|
37310
|
+
return null;
|
|
37311
|
+
}
|
|
37223
37312
|
};
|
|
37224
37313
|
var Files = class Files extends Service()("react-doctor/Files") {
|
|
37225
37314
|
static layerNode = succeed$3(Files, Files.of({
|
|
@@ -37430,7 +37519,10 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37430
37519
|
directory: input.directory,
|
|
37431
37520
|
cause
|
|
37432
37521
|
}) });
|
|
37433
|
-
})
|
|
37522
|
+
}), withSpan("git.exec", { attributes: {
|
|
37523
|
+
"git.command": input.command,
|
|
37524
|
+
"git.subcommand": input.args[0] ?? ""
|
|
37525
|
+
} }));
|
|
37434
37526
|
const runGit = (directory, args) => runCommand({
|
|
37435
37527
|
command: "git",
|
|
37436
37528
|
args,
|
|
@@ -37458,7 +37550,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37458
37550
|
]);
|
|
37459
37551
|
if (candidates.status !== 0) return null;
|
|
37460
37552
|
return trimOrNull(candidates.stdout.split("\n")[0] ?? "");
|
|
37461
|
-
});
|
|
37553
|
+
}).pipe(withSpan("Git.defaultBranch"));
|
|
37462
37554
|
const branchExists = (directory, branch) => runGit(directory, [
|
|
37463
37555
|
"rev-parse",
|
|
37464
37556
|
"--verify",
|
|
@@ -37505,7 +37597,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37505
37597
|
const result = resultOption.value;
|
|
37506
37598
|
if (result.status !== 0) return null;
|
|
37507
37599
|
return parseGithubViewerPermission(result.stdout);
|
|
37508
|
-
}).pipe(catch_$1(() => succeed$2(null)));
|
|
37600
|
+
}).pipe(catch_$1(() => succeed$2(null)), withSpan("Git.githubViewerPermission"));
|
|
37509
37601
|
/**
|
|
37510
37602
|
* Resolves a `--diff A..B` / `A...B` commit range into a changed-file
|
|
37511
37603
|
* selection. Each endpoint is validated with `isSafeGitRevision`
|
|
@@ -37619,7 +37711,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37619
37711
|
changedFiles: splitNullSeparated(diff.stdout),
|
|
37620
37712
|
isCurrentChanges: false
|
|
37621
37713
|
};
|
|
37622
|
-
}),
|
|
37714
|
+
}).pipe(withSpan("Git.diffSelection")),
|
|
37623
37715
|
stagedFilePaths: (directory) => runGit(directory, [
|
|
37624
37716
|
"diff",
|
|
37625
37717
|
"--cached",
|
|
@@ -37661,7 +37753,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37661
37753
|
status: result.status,
|
|
37662
37754
|
stdout: result.stdout
|
|
37663
37755
|
};
|
|
37664
|
-
}),
|
|
37756
|
+
}).pipe(withSpan("Git.grep")),
|
|
37665
37757
|
changedLineRanges: ({ directory, baseRef, cached, files }) => gen(function* () {
|
|
37666
37758
|
if (files.length === 0) return [];
|
|
37667
37759
|
if (baseRef !== void 0 && !isSafeGitRevision(baseRef)) return null;
|
|
@@ -37677,7 +37769,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37677
37769
|
]);
|
|
37678
37770
|
if (result.status !== 0) return null;
|
|
37679
37771
|
return parseChangedLineRanges(result.stdout);
|
|
37680
|
-
})
|
|
37772
|
+
}).pipe(withSpan("Git.changedLineRanges"))
|
|
37681
37773
|
});
|
|
37682
37774
|
})).pipe(provide$2(layer$2.pipe(provide$2(mergeAll$1(layer$1, layer)))));
|
|
37683
37775
|
/**
|
|
@@ -37892,7 +37984,7 @@ const neutralizeDisableDirectives = async (rootDirectory, includePaths) => {
|
|
|
37892
37984
|
for (const [absolutePath, originalContent] of originalContents) try {
|
|
37893
37985
|
NFS.writeFileSync(absolutePath, originalContent);
|
|
37894
37986
|
} catch (error) {
|
|
37895
|
-
process.stderr.write(`[react-doctor] Failed to restore inline disable directives in ${absolutePath}: ${
|
|
37987
|
+
process.stderr.write(`[react-doctor] Failed to restore inline disable directives in ${absolutePath}: ${messageFromUnknown(error)}\n[react-doctor] Run: git checkout -- ${absolutePath}\n`);
|
|
37896
37988
|
}
|
|
37897
37989
|
};
|
|
37898
37990
|
const onExit = () => restore();
|
|
@@ -37998,7 +38090,7 @@ const resolveUserPlugin = (spec, configSourceDirectory) => {
|
|
|
37998
38090
|
try {
|
|
37999
38091
|
resolvedSpecifier = isRelative ? Path.resolve(configSourceDirectory, spec) : candidateRequire.resolve(spec);
|
|
38000
38092
|
} catch (error) {
|
|
38001
|
-
warnConfigIssue(`config.plugins entry "${spec}" could not be resolved from ${configSourceDirectory}: ${
|
|
38093
|
+
warnConfigIssue(`config.plugins entry "${spec}" could not be resolved from ${configSourceDirectory}: ${messageFromUnknown(error)}`);
|
|
38002
38094
|
return null;
|
|
38003
38095
|
}
|
|
38004
38096
|
const { name, ruleNames } = readPluginShape(resolvedSpecifier, (target) => candidateRequire(target));
|
|
@@ -38070,8 +38162,8 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
38070
38162
|
}
|
|
38071
38163
|
return enabled;
|
|
38072
38164
|
};
|
|
38073
|
-
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [] }) => {
|
|
38074
|
-
const reactHooksJsPlugin = resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
|
|
38165
|
+
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false }) => {
|
|
38166
|
+
const reactHooksJsPlugin = disableReactHooksJsPlugin ? null : resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
|
|
38075
38167
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
38076
38168
|
const jsPlugins = [];
|
|
38077
38169
|
if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
|
|
@@ -38131,7 +38223,6 @@ const resolveOxlintBinary = () => {
|
|
|
38131
38223
|
return Path.join(oxlintPackageDirectory, "bin", "oxlint");
|
|
38132
38224
|
};
|
|
38133
38225
|
const resolvePluginPath = () => esmRequire.resolve("oxlint-plugin-react-doctor");
|
|
38134
|
-
const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
|
|
38135
38226
|
const resolveTsConfigRelativePath = (rootDirectory) => {
|
|
38136
38227
|
for (const filename of TSCONFIG_FILENAMES) if (NFS.existsSync(Path.join(rootDirectory, filename))) return `./${filename}`;
|
|
38137
38228
|
return null;
|
|
@@ -38503,7 +38594,7 @@ const scopeContainsNonImportBinding = (node, scopeNode, identifierName) => {
|
|
|
38503
38594
|
const isIdentifierShadowedByLocalBinding = (identifier, sourceFile) => {
|
|
38504
38595
|
let currentNode = identifier.parent;
|
|
38505
38596
|
while (currentNode) {
|
|
38506
|
-
if (
|
|
38597
|
+
if (isScopeBoundary(currentNode)) {
|
|
38507
38598
|
if (scopeContainsNonImportBinding(currentNode, currentNode, identifier.text)) return true;
|
|
38508
38599
|
}
|
|
38509
38600
|
if (currentNode === sourceFile) return false;
|
|
@@ -38594,11 +38685,10 @@ const findResolutionInScope = (scopeNode, identifierName, reactImportBindings, s
|
|
|
38594
38685
|
});
|
|
38595
38686
|
return resolution;
|
|
38596
38687
|
};
|
|
38597
|
-
const isScopeNode = isScopeBoundary;
|
|
38598
38688
|
const resolveIdentifierBinding = (identifier, reactImportBindings, sourceFile, visitedDeclarations = /* @__PURE__ */ new Set()) => {
|
|
38599
38689
|
let currentNode = identifier.parent;
|
|
38600
38690
|
while (currentNode) {
|
|
38601
|
-
if (
|
|
38691
|
+
if (isScopeBoundary(currentNode)) {
|
|
38602
38692
|
const resolution = findResolutionInScope(currentNode, identifier.text, reactImportBindings, sourceFile, visitedDeclarations);
|
|
38603
38693
|
if (resolution) return resolution;
|
|
38604
38694
|
}
|
|
@@ -38768,9 +38858,9 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
38768
38858
|
try {
|
|
38769
38859
|
parsed = JSON.parse(sanitizedStdout);
|
|
38770
38860
|
} catch {
|
|
38771
|
-
throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0,
|
|
38861
|
+
throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
38772
38862
|
}
|
|
38773
|
-
if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0,
|
|
38863
|
+
if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
38774
38864
|
const minifiedFileCache = /* @__PURE__ */ new Map();
|
|
38775
38865
|
const isMinifiedDiagnosticFile = (filename) => {
|
|
38776
38866
|
const absolutePath = Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
|
|
@@ -38846,7 +38936,7 @@ const spawnOxlint = (args, rootDirectory, nodeBinaryPath, spawnTimeoutMs = OXLIN
|
|
|
38846
38936
|
child.kill("SIGKILL");
|
|
38847
38937
|
reject(new ReactDoctorError({ reason: new OxlintBatchExceeded({
|
|
38848
38938
|
kind: "timeout",
|
|
38849
|
-
detail: `${spawnTimeoutMs /
|
|
38939
|
+
detail: `${spawnTimeoutMs / MILLISECONDS_PER_SECOND}s budget exceeded`
|
|
38850
38940
|
}) }));
|
|
38851
38941
|
}, spawnTimeoutMs);
|
|
38852
38942
|
timeoutHandle.unref?.();
|
|
@@ -39061,6 +39151,28 @@ const writeOxlintConfig = (configPath, configToWrite) => {
|
|
|
39061
39151
|
NFS.closeSync(fileHandle);
|
|
39062
39152
|
}
|
|
39063
39153
|
};
|
|
39154
|
+
const REACT_HOOKS_JS_DROP_PREFIX = "React Compiler rules (react-hooks-js/*) skipped — eslint-plugin-react-hooks failed to load in this environment";
|
|
39155
|
+
/**
|
|
39156
|
+
* Detects an oxlint config-load crash caused by the optional
|
|
39157
|
+
* `react-hooks-js` (eslint-plugin-react-hooks) React Compiler plugin and
|
|
39158
|
+
* builds the partial-failure note for it; returns `null` when the failure
|
|
39159
|
+
* was anything else.
|
|
39160
|
+
*
|
|
39161
|
+
* oxlint prints a framed error to stdout (not stderr) and exits non-zero
|
|
39162
|
+
* when a `jsPlugins` entry can't be imported; that non-JSON stdout
|
|
39163
|
+
* surfaces as `OxlintOutputUnparseable`. Because oxlint fails the WHOLE
|
|
39164
|
+
* config load on it, leaving the plugin in would drop every curated
|
|
39165
|
+
* react-doctor diagnostic too — so the caller retries with the plugin
|
|
39166
|
+
* stripped (issue #833). Both markers sit at the start of oxlint's
|
|
39167
|
+
* message, so they survive the `preview` slice even for deep pnpm paths.
|
|
39168
|
+
*/
|
|
39169
|
+
const reactHooksJsPluginDropNote = (error) => {
|
|
39170
|
+
if (!(error instanceof ReactDoctorError) || error.reason._tag !== "OxlintOutputUnparseable") return null;
|
|
39171
|
+
const { preview } = error.reason;
|
|
39172
|
+
if (!preview.includes("Failed to load JS plugin") || !preview.includes("eslint-plugin-react-hooks")) return null;
|
|
39173
|
+
const underlyingReason = preview.match(/Error:[^\n]*/)?.[0]?.trim();
|
|
39174
|
+
return `${REACT_HOOKS_JS_DROP_PREFIX}${underlyingReason ? `: ${underlyingReason}` : ""}. Other rules ran normally.`;
|
|
39175
|
+
};
|
|
39064
39176
|
/**
|
|
39065
39177
|
* The oxlint runner. Composed of three pieces in `runners/oxlint/`:
|
|
39066
39178
|
*
|
|
@@ -39088,15 +39200,16 @@ const runOxlint = async (options) => {
|
|
|
39088
39200
|
const pluginPath = resolvePluginPath();
|
|
39089
39201
|
const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
|
|
39090
39202
|
const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
|
|
39091
|
-
const buildConfig = (
|
|
39203
|
+
const buildConfig = (overrides) => createOxlintConfig({
|
|
39092
39204
|
pluginPath,
|
|
39093
39205
|
project,
|
|
39094
39206
|
customRulesOnly,
|
|
39095
|
-
extendsPaths:
|
|
39207
|
+
extendsPaths: overrides.extendsPaths,
|
|
39096
39208
|
ignoredTags,
|
|
39097
39209
|
serverAuthFunctionNames,
|
|
39098
39210
|
severityControls,
|
|
39099
|
-
userPlugins
|
|
39211
|
+
userPlugins,
|
|
39212
|
+
disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin
|
|
39100
39213
|
});
|
|
39101
39214
|
const restoreDisableDirectives = respectInlineDisables ? () => {} : await neutralizeDisableDirectives(rootDirectory, includePaths);
|
|
39102
39215
|
const configDirectory = NFS.mkdtempSync(Path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
|
|
@@ -39132,12 +39245,22 @@ const runOxlint = async (options) => {
|
|
|
39132
39245
|
outputMaxBytes,
|
|
39133
39246
|
concurrency: options.concurrency
|
|
39134
39247
|
});
|
|
39135
|
-
writeOxlintConfig(configPath, buildConfig(extendsPaths));
|
|
39248
|
+
writeOxlintConfig(configPath, buildConfig({ extendsPaths }));
|
|
39136
39249
|
try {
|
|
39137
39250
|
return await runBatches();
|
|
39138
39251
|
} catch (error) {
|
|
39252
|
+
const reactHooksJsDropNote = reactHooksJsPluginDropNote(error);
|
|
39253
|
+
if (reactHooksJsDropNote !== null) {
|
|
39254
|
+
writeOxlintConfig(configPath, buildConfig({
|
|
39255
|
+
extendsPaths,
|
|
39256
|
+
disableReactHooksJsPlugin: true
|
|
39257
|
+
}));
|
|
39258
|
+
const diagnostics = await runBatches();
|
|
39259
|
+
onPartialFailure?.(reactHooksJsDropNote);
|
|
39260
|
+
return diagnostics;
|
|
39261
|
+
}
|
|
39139
39262
|
if (extendsPaths.length === 0) throw error;
|
|
39140
|
-
writeOxlintConfig(configPath, buildConfig([]));
|
|
39263
|
+
writeOxlintConfig(configPath, buildConfig({ extendsPaths: [] }));
|
|
39141
39264
|
return await runBatches();
|
|
39142
39265
|
}
|
|
39143
39266
|
} finally {
|
|
@@ -39935,17 +40058,17 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
39935
40058
|
}))))))));
|
|
39936
40059
|
const deadCodeFailureState = yield* get$2(deadCodeFailure);
|
|
39937
40060
|
const scanElapsedMilliseconds = Date.now() - scanStartTime;
|
|
39938
|
-
const scanElapsedSeconds = (scanElapsedMilliseconds /
|
|
40061
|
+
const scanElapsedSeconds = (scanElapsedMilliseconds / MILLISECONDS_PER_SECOND).toFixed(1);
|
|
39939
40062
|
if (!lintFailureState.didFail) if (deadCodeFailureState.didFail) yield* scanProgress.fail(DEAD_CODE_FAIL_TEXT);
|
|
39940
40063
|
else if (input.suppressScanSummary) yield* scanProgress.stop();
|
|
39941
40064
|
else yield* scanProgress.succeed(`Scanned ${scannedFilesLabel} in ${scanElapsedSeconds}s${workerCountSuffix}`);
|
|
39942
40065
|
yield* reporterService.finalize;
|
|
39943
|
-
const finalDiagnostics = [
|
|
40066
|
+
const finalDiagnostics = assignFixGroups([
|
|
39944
40067
|
...envCollected,
|
|
39945
40068
|
...supplyChainCollected,
|
|
39946
40069
|
...lintCollected,
|
|
39947
40070
|
...deadCodeCollected
|
|
39948
|
-
];
|
|
40071
|
+
]);
|
|
39949
40072
|
const githubViewerPermission = yield* join(githubViewerPermissionFiber);
|
|
39950
40073
|
const scoreMetadata = {
|
|
39951
40074
|
...repo !== null ? { repo } : {},
|
|
@@ -40149,7 +40272,7 @@ const materializeSourceTree = (input) => gen(function* () {
|
|
|
40149
40272
|
static layerNode = effect(StagedFiles, gen(function* () {
|
|
40150
40273
|
const git = yield* Git;
|
|
40151
40274
|
return StagedFiles.of({
|
|
40152
|
-
discoverSourceFiles: (directory) => git.stagedFilePaths(directory).pipe(map$3((entries) => entries.filter(isLintableSourceFile))),
|
|
40275
|
+
discoverSourceFiles: (directory) => git.stagedFilePaths(directory).pipe(map$3((entries) => entries.filter(isLintableSourceFile)), withSpan("StagedFiles.discoverSourceFiles")),
|
|
40153
40276
|
materialize: ({ directory, stagedFiles, tempDirectory }) => materializeSourceTree({
|
|
40154
40277
|
directory,
|
|
40155
40278
|
files: stagedFiles,
|
|
@@ -40159,7 +40282,7 @@ const materializeSourceTree = (input) => gen(function* () {
|
|
|
40159
40282
|
tempDirectory: tree.tempDirectory,
|
|
40160
40283
|
stagedFiles: tree.materializedFiles,
|
|
40161
40284
|
cleanup: tree.cleanup
|
|
40162
|
-
})))
|
|
40285
|
+
})), withSpan("StagedFiles.materialize"))
|
|
40163
40286
|
});
|
|
40164
40287
|
}));
|
|
40165
40288
|
/**
|
|
@@ -40227,7 +40350,10 @@ const runEditorScan = async (input) => {
|
|
|
40227
40350
|
isCi: false,
|
|
40228
40351
|
resolveLocalGithubViewerPermission: false,
|
|
40229
40352
|
skipJsxIncludeFilter: true
|
|
40230
|
-
}).pipe(
|
|
40353
|
+
}).pipe(withSpan("runEditorScan", { attributes: {
|
|
40354
|
+
"editor.lint": lint,
|
|
40355
|
+
"editor.runDeadCode": runDeadCode
|
|
40356
|
+
} }), provide(layers), provide(layerOtlp)));
|
|
40231
40357
|
if (isSuccess(exit)) {
|
|
40232
40358
|
const output = exit.value;
|
|
40233
40359
|
return {
|
|
@@ -40257,7 +40383,7 @@ const runEditorScan = async (input) => {
|
|
|
40257
40383
|
didDeadCodeFail: false,
|
|
40258
40384
|
deadCodeFailureReason: null,
|
|
40259
40385
|
lintPartialFailures: [],
|
|
40260
|
-
error:
|
|
40386
|
+
error: messageFromUnknown(error)
|
|
40261
40387
|
};
|
|
40262
40388
|
};
|
|
40263
40389
|
/**
|
|
@@ -40309,7 +40435,7 @@ const computeConfigFingerprint = (projectDirectory, version) => {
|
|
|
40309
40435
|
/** Display name used in client-facing messages and progress titles. */
|
|
40310
40436
|
const SERVER_DISPLAY_NAME = "React Doctor";
|
|
40311
40437
|
/** Server version reported in `serverInfo`; injected at build, `dev` from source. */
|
|
40312
|
-
const SERVER_VERSION = "0.5.
|
|
40438
|
+
const SERVER_VERSION = "0.5.7";
|
|
40313
40439
|
/** `Diagnostic.source` shown next to every published diagnostic. */
|
|
40314
40440
|
const DIAGNOSTIC_SOURCE = "react-doctor";
|
|
40315
40441
|
/**
|
|
@@ -40539,7 +40665,6 @@ const toLspDiagnostic = (input) => {
|
|
|
40539
40665
|
data
|
|
40540
40666
|
};
|
|
40541
40667
|
};
|
|
40542
|
-
const toUri = (absoluteFilePath) => fsPathToUri(absoluteFilePath);
|
|
40543
40668
|
/**
|
|
40544
40669
|
* Owns the published-diagnostic state. Maps scan outcomes to LSP
|
|
40545
40670
|
* diagnostics, publishes complete per-URI replacement sets (so the
|
|
@@ -40569,7 +40694,7 @@ var DiagnosticsManager = class {
|
|
|
40569
40694
|
const isProtectedPath = (fsPath) => protectOpen && this.isOpen(fsPath);
|
|
40570
40695
|
for (const [fsPath, coreDiagnostics] of outcome.byFile) {
|
|
40571
40696
|
if (isProtectedPath(fsPath)) continue;
|
|
40572
|
-
const uri =
|
|
40697
|
+
const uri = fsPathToUri(fsPath);
|
|
40573
40698
|
const text = this.textProvider(fsPath);
|
|
40574
40699
|
const lspDiagnostics = coreDiagnostics.map((diagnostic) => toLspDiagnostic({
|
|
40575
40700
|
diagnostic,
|
|
@@ -40591,7 +40716,7 @@ var DiagnosticsManager = class {
|
|
|
40591
40716
|
for (const fsPath of outcome.requestedPaths) {
|
|
40592
40717
|
if (isProtectedPath(fsPath)) continue;
|
|
40593
40718
|
if (outcome.byFile.has(fsPath)) continue;
|
|
40594
|
-
const uri =
|
|
40719
|
+
const uri = fsPathToUri(fsPath);
|
|
40595
40720
|
if (this.byUri.has(uri)) this.byUri.delete(uri);
|
|
40596
40721
|
this.publish(uri, []);
|
|
40597
40722
|
}
|
|
@@ -40616,7 +40741,7 @@ var DiagnosticsManager = class {
|
|
|
40616
40741
|
const set = this.projectUris.get(project) ?? /* @__PURE__ */ new Set();
|
|
40617
40742
|
for (const uri of liveUris) set.add(uri);
|
|
40618
40743
|
for (const fsPath of outcome.requestedPaths) {
|
|
40619
|
-
const uri =
|
|
40744
|
+
const uri = fsPathToUri(fsPath);
|
|
40620
40745
|
if (!liveUris.has(uri)) set.delete(uri);
|
|
40621
40746
|
}
|
|
40622
40747
|
this.projectUris.set(project, set);
|
|
@@ -40644,7 +40769,7 @@ var DiagnosticsManager = class {
|
|
|
40644
40769
|
const tracked = this.projectUris.get(project);
|
|
40645
40770
|
if (!tracked) return;
|
|
40646
40771
|
const liveUris = /* @__PURE__ */ new Set();
|
|
40647
|
-
for (const fsPath of liveFsPaths) liveUris.add(
|
|
40772
|
+
for (const fsPath of liveFsPaths) liveUris.add(fsPathToUri(fsPath));
|
|
40648
40773
|
for (const uri of [...tracked]) {
|
|
40649
40774
|
if (liveUris.has(uri)) continue;
|
|
40650
40775
|
this.byUri.delete(uri);
|
|
@@ -40941,7 +41066,7 @@ const createProjectGraph = (options) => {
|
|
|
40941
41066
|
});
|
|
40942
41067
|
}
|
|
40943
41068
|
} catch (error) {
|
|
40944
|
-
logger.warn(`Project discovery failed for ${root}: ${
|
|
41069
|
+
logger.warn(`Project discovery failed for ${root}: ${messageFromUnknown(error)}`);
|
|
40945
41070
|
}
|
|
40946
41071
|
return [...seen.values()].sort((first, second) => second.directory.length - first.directory.length);
|
|
40947
41072
|
};
|
|
@@ -40969,6 +41094,11 @@ const createProjectGraph = (options) => {
|
|
|
40969
41094
|
}
|
|
40970
41095
|
};
|
|
40971
41096
|
};
|
|
41097
|
+
const toProjectRelative = (projectDirectory, filePath) => {
|
|
41098
|
+
const relative = Path.relative(projectDirectory, filePath).replace(/\\/g, "/");
|
|
41099
|
+
if (relative.length === 0 || relative.startsWith("../") || Path.isAbsolute(relative)) return null;
|
|
41100
|
+
return relative;
|
|
41101
|
+
};
|
|
40972
41102
|
const resolveCacheFilePath = (projectDirectory) => {
|
|
40973
41103
|
const nodeModules = path.join(projectDirectory, "node_modules");
|
|
40974
41104
|
if (fs.existsSync(nodeModules)) return path.join(nodeModules, ".cache", "react-doctor", "lint-cache.json");
|
|
@@ -41003,7 +41133,7 @@ const createLintCache = (input) => {
|
|
|
41003
41133
|
fs.writeFileSync(tempPath, JSON.stringify(payload));
|
|
41004
41134
|
fs.renameSync(tempPath, cacheFilePath);
|
|
41005
41135
|
} catch (error) {
|
|
41006
|
-
logger.warn(`Failed to persist lint cache: ${
|
|
41136
|
+
logger.warn(`Failed to persist lint cache: ${messageFromUnknown(error)}`);
|
|
41007
41137
|
}
|
|
41008
41138
|
};
|
|
41009
41139
|
return {
|
|
@@ -41029,11 +41159,6 @@ const createLintCache = (input) => {
|
|
|
41029
41159
|
};
|
|
41030
41160
|
const OVERLAY_TEMP_PREFIX = "react-doctor-lsp-";
|
|
41031
41161
|
const OVERLAY_CONFIG_FILENAMES = [...new Set([...STAGED_FILES_PROJECT_CONFIG_FILENAMES, ...ADOPTABLE_LINT_CONFIG_FILENAMES])];
|
|
41032
|
-
const toProjectRelative$1 = (projectDirectory, filePath) => {
|
|
41033
|
-
const relative = path.relative(projectDirectory, filePath).replace(/\\/g, "/");
|
|
41034
|
-
if (relative.length === 0 || relative.startsWith("../") || path.isAbsolute(relative)) return null;
|
|
41035
|
-
return relative;
|
|
41036
|
-
};
|
|
41037
41162
|
/**
|
|
41038
41163
|
* Writes the live (possibly unsaved) content of the target files into a
|
|
41039
41164
|
* throwaway temp tree that mirrors the project, alongside the well-known
|
|
@@ -41047,7 +41172,7 @@ const materializeOverlay = (input) => {
|
|
|
41047
41172
|
const relativePaths = [];
|
|
41048
41173
|
try {
|
|
41049
41174
|
for (const filePath of input.files) {
|
|
41050
|
-
const relative = toProjectRelative
|
|
41175
|
+
const relative = toProjectRelative(input.projectDirectory, filePath);
|
|
41051
41176
|
if (relative === null) continue;
|
|
41052
41177
|
const content = input.readText(filePath);
|
|
41053
41178
|
if (content === null) continue;
|
|
@@ -41095,11 +41220,6 @@ const materializeOverlay = (input) => {
|
|
|
41095
41220
|
throw error;
|
|
41096
41221
|
}
|
|
41097
41222
|
};
|
|
41098
|
-
const toProjectRelative = (projectDirectory, filePath) => {
|
|
41099
|
-
const relative = path.relative(projectDirectory, filePath).replace(/\\/g, "/");
|
|
41100
|
-
if (relative.length === 0 || relative.startsWith("../") || path.isAbsolute(relative)) return null;
|
|
41101
|
-
return relative;
|
|
41102
|
-
};
|
|
41103
41223
|
/**
|
|
41104
41224
|
* Resolves a diagnostic's (possibly relative, possibly overlay-temp)
|
|
41105
41225
|
* file path back to the canonical absolute path inside the real project.
|
|
@@ -41321,7 +41441,7 @@ const createScheduler = (options) => {
|
|
|
41321
41441
|
if (outcome && !token.isCancelled) options.onResult(outcome);
|
|
41322
41442
|
}).catch((error) => {
|
|
41323
41443
|
if (options.onError) options.onError(error, request);
|
|
41324
|
-
else logger.error(`Scan failed: ${
|
|
41444
|
+
else logger.error(`Scan failed: ${messageFromUnknown(error)}`);
|
|
41325
41445
|
}).finally(() => {
|
|
41326
41446
|
running -= 1;
|
|
41327
41447
|
if (isBackground) runningBackground -= 1;
|
|
@@ -41708,7 +41828,7 @@ const createServer = (connection, options = {}) => {
|
|
|
41708
41828
|
maybeWarnLintUnavailable(outcome);
|
|
41709
41829
|
if (outcome.request.priority === "background") scanTelemetry.accumulate(outcome);
|
|
41710
41830
|
},
|
|
41711
|
-
onError: (error, request) => logger.error(`Scan of ${request.projectDirectory} threw: ${
|
|
41831
|
+
onError: (error, request) => logger.error(`Scan of ${request.projectDirectory} threw: ${messageFromUnknown(error)}`),
|
|
41712
41832
|
onIdleChange: (idle) => {
|
|
41713
41833
|
setBusy(!idle);
|
|
41714
41834
|
if (idle) scanTelemetry.finish();
|
|
@@ -42356,5 +42476,5 @@ const startLanguageServer = () => {
|
|
|
42356
42476
|
};
|
|
42357
42477
|
//#endregion
|
|
42358
42478
|
export { startLanguageServer };
|
|
42359
|
-
!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]="
|
|
42360
|
-
//# debugId=
|
|
42479
|
+
!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]="1afe1e75-32a9-5e7e-bd02-778b52d7ca8d")}catch(e){}}();
|
|
42480
|
+
//# debugId=1afe1e75-32a9-5e7e-bd02-778b52d7ca8d
|