react-doctor 0.5.6-dev.431e515 → 0.5.6-dev.44db3e0
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 +605 -366
- package/dist/index.d.ts +10 -0
- package/dist/index.js +237 -182
- package/dist/lsp.js +255 -204
- package/package.json +2 -2
package/dist/lsp.js
CHANGED
|
@@ -19335,6 +19335,7 @@ var JsonReportProjectEntry = class extends Class("JsonReportProjectEntry")({
|
|
|
19335
19335
|
score: Unknown,
|
|
19336
19336
|
skippedChecks: ArraySchema(String$1),
|
|
19337
19337
|
skippedCheckReasons: optional(Record$1(String$1, String$1)),
|
|
19338
|
+
scannedFileCount: optional(Number$1),
|
|
19338
19339
|
elapsedMilliseconds: Number$1
|
|
19339
19340
|
}) {};
|
|
19340
19341
|
/**
|
|
@@ -32761,6 +32762,7 @@ const isLargeMinifiedFile = (absolutePath) => {
|
|
|
32761
32762
|
if (sizeBytes < 2e4) return false;
|
|
32762
32763
|
return isMinifiedSource(absolutePath);
|
|
32763
32764
|
};
|
|
32765
|
+
const isErrnoException = (error) => error instanceof Error && "code" in error;
|
|
32764
32766
|
const IGNORABLE_READDIR_ERROR_CODES = new Set([
|
|
32765
32767
|
"EACCES",
|
|
32766
32768
|
"EPERM",
|
|
@@ -32770,11 +32772,7 @@ const IGNORABLE_READDIR_ERROR_CODES = new Set([
|
|
|
32770
32772
|
"ELOOP",
|
|
32771
32773
|
"ENAMETOOLONG"
|
|
32772
32774
|
]);
|
|
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
|
-
};
|
|
32775
|
+
const isIgnorableReaddirError = (error) => isErrnoException(error) && typeof error.code === "string" && IGNORABLE_READDIR_ERROR_CODES.has(error.code);
|
|
32778
32776
|
const readDirectoryEntries = (directoryPath) => {
|
|
32779
32777
|
try {
|
|
32780
32778
|
return NFS.readdirSync(directoryPath, { withFileTypes: true });
|
|
@@ -32824,7 +32822,7 @@ const readPackageJsonUncached = (packageJsonPath) => {
|
|
|
32824
32822
|
return JSON.parse(NFS.readFileSync(packageJsonPath, "utf-8"));
|
|
32825
32823
|
} catch (error) {
|
|
32826
32824
|
if (error instanceof SyntaxError) return {};
|
|
32827
|
-
if (error
|
|
32825
|
+
if (isErrnoException(error)) {
|
|
32828
32826
|
const { code } = error;
|
|
32829
32827
|
if (code === "EISDIR" || code === "EACCES" || code === "EPERM" || code === "ENOENT") return {};
|
|
32830
32828
|
}
|
|
@@ -33549,17 +33547,13 @@ const isPackageJsonReactNativeAware = (packageJson) => {
|
|
|
33549
33547
|
return false;
|
|
33550
33548
|
};
|
|
33551
33549
|
const hasReactNativeWorkspaceAnywhere = (rootDirectory, rootPackageJson) => someWorkspacePackageJson(rootDirectory, rootPackageJson, isPackageJsonReactNativeAware);
|
|
33552
|
-
const
|
|
33553
|
-
const spec = packageJson.dependencies?.
|
|
33550
|
+
const getDependencySpec = (packageJson, packageName) => {
|
|
33551
|
+
const spec = packageJson.dependencies?.[packageName] ?? packageJson.devDependencies?.[packageName] ?? packageJson.peerDependencies?.[packageName] ?? packageJson.optionalDependencies?.[packageName];
|
|
33554
33552
|
return typeof spec === "string" ? spec : null;
|
|
33555
33553
|
};
|
|
33556
|
-
const findExpoVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson,
|
|
33554
|
+
const findExpoVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, "expo"));
|
|
33557
33555
|
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);
|
|
33556
|
+
const findShopifyFlashListVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, SHOPIFY_FLASH_LIST_PACKAGE_NAME));
|
|
33563
33557
|
const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, version }) => {
|
|
33564
33558
|
if (version === null || !isCatalogReference(version)) return version;
|
|
33565
33559
|
const catalogName = extractCatalogName(version);
|
|
@@ -33571,11 +33565,7 @@ const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson,
|
|
|
33571
33565
|
if (!isFile(monorepoPackageJsonPath)) return version;
|
|
33572
33566
|
return resolveCatalogVersion(readPackageJson(monorepoPackageJsonPath), packageName, monorepoRoot, catalogName) ?? version;
|
|
33573
33567
|
};
|
|
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);
|
|
33568
|
+
const findNextjsVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, "next"));
|
|
33579
33569
|
const getPreactVersion = (packageJson) => {
|
|
33580
33570
|
return {
|
|
33581
33571
|
...packageJson.peerDependencies,
|
|
@@ -33657,6 +33647,11 @@ const ES_TARGET_YEAR_BY_NAME = {
|
|
|
33657
33647
|
esnext: 9999
|
|
33658
33648
|
};
|
|
33659
33649
|
/**
|
|
33650
|
+
* tsconfig filenames probed when resolving a project's TypeScript
|
|
33651
|
+
* compiler options — the root config first, then a monorepo base config.
|
|
33652
|
+
*/
|
|
33653
|
+
const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
|
|
33654
|
+
/**
|
|
33660
33655
|
* Project-config files that `StagedFiles.materialize` copies into
|
|
33661
33656
|
* the temp directory alongside staged sources so oxlint resolves
|
|
33662
33657
|
* `tsconfig` / `package.json` / lint configs the same way it would
|
|
@@ -34178,6 +34173,7 @@ const isTailwindAtLeast = (detected, required) => {
|
|
|
34178
34173
|
if (detected.major !== required.major) return detected.major > required.major;
|
|
34179
34174
|
return detected.minor >= required.minor;
|
|
34180
34175
|
};
|
|
34176
|
+
const messageFromUnknown = (error) => error instanceof Error ? error.message : String(error);
|
|
34181
34177
|
var InvalidGlobPatternError = class extends Error {
|
|
34182
34178
|
pattern;
|
|
34183
34179
|
reason;
|
|
@@ -34206,7 +34202,7 @@ const compileGlobPattern = (rawPattern) => {
|
|
|
34206
34202
|
try {
|
|
34207
34203
|
return import_picomatch.default.makeRe(normalizeGlobPattern(rawPattern), PICOMATCH_OPTIONS);
|
|
34208
34204
|
} catch (caughtError) {
|
|
34209
|
-
throw new InvalidGlobPatternError(rawPattern,
|
|
34205
|
+
throw new InvalidGlobPatternError(rawPattern, messageFromUnknown(caughtError));
|
|
34210
34206
|
}
|
|
34211
34207
|
};
|
|
34212
34208
|
const compileGlobPatternsLenient = (patterns, onInvalid) => {
|
|
@@ -34302,115 +34298,6 @@ const buildRuleSeverityControls = (config) => {
|
|
|
34302
34298
|
...config.buckets !== void 0 ? { buckets: config.buckets } : {}
|
|
34303
34299
|
};
|
|
34304
34300
|
};
|
|
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
34301
|
const LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY = {
|
|
34415
34302
|
"effect/no-adjust-state-on-prop-change": "react-doctor/no-adjust-state-on-prop-change",
|
|
34416
34303
|
"effect/no-chain-state-updates": "react-doctor/no-chain-state-updates",
|
|
@@ -34535,7 +34422,13 @@ for (const [legacyRuleKey, nativeRuleKey] of Object.entries(LEGACY_RULE_KEY_TO_N
|
|
|
34535
34422
|
}
|
|
34536
34423
|
const getLegacyRuleKeysForNative = (ruleKey) => NATIVE_RULE_KEY_TO_LEGACY_RULE_KEYS.get(ruleKey) ?? [];
|
|
34537
34424
|
const canonicalizeRuleKey = (ruleKey) => LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY[ruleKey] ?? ruleKey;
|
|
34538
|
-
const
|
|
34425
|
+
const isReactDoctorShortIdOf = (bareRuleKey, qualifiedRuleKey) => !bareRuleKey.includes("/") && qualifiedRuleKey === `react-doctor/${bareRuleKey}`;
|
|
34426
|
+
const isSameRuleKey = (candidateRuleKey, targetRuleKey) => {
|
|
34427
|
+
const canonicalCandidate = canonicalizeRuleKey(candidateRuleKey);
|
|
34428
|
+
const canonicalTarget = canonicalizeRuleKey(targetRuleKey);
|
|
34429
|
+
if (canonicalCandidate === canonicalTarget) return true;
|
|
34430
|
+
return isReactDoctorShortIdOf(canonicalCandidate, canonicalTarget) || isReactDoctorShortIdOf(canonicalTarget, canonicalCandidate);
|
|
34431
|
+
};
|
|
34539
34432
|
const getEquivalentRuleKeys = (ruleKey) => {
|
|
34540
34433
|
const nativeRuleKey = canonicalizeRuleKey(ruleKey);
|
|
34541
34434
|
return [nativeRuleKey, ...getLegacyRuleKeysForNative(nativeRuleKey)];
|
|
@@ -34545,12 +34438,182 @@ const stripDescriptionTail = (ruleList) => {
|
|
|
34545
34438
|
if (!descriptionMatch || descriptionMatch.index === void 0) return ruleList;
|
|
34546
34439
|
return ruleList.slice(0, descriptionMatch.index);
|
|
34547
34440
|
};
|
|
34548
|
-
const
|
|
34441
|
+
const tokenizeRuleList = (ruleList) => {
|
|
34549
34442
|
const trimmed = ruleList?.trim();
|
|
34550
|
-
if (!trimmed) return
|
|
34443
|
+
if (!trimmed) return [];
|
|
34551
34444
|
const ruleSection = stripDescriptionTail(trimmed).trim();
|
|
34552
|
-
if (!ruleSection) return
|
|
34553
|
-
return ruleSection.split(/[,\s]+/).
|
|
34445
|
+
if (!ruleSection) return [];
|
|
34446
|
+
return ruleSection.split(/[,\s]+/).map((token) => token.trim()).filter(Boolean);
|
|
34447
|
+
};
|
|
34448
|
+
const FOREIGN_INLINE_DISABLE_PATTERN = /(?:\/\/|\/\*)[ \t]*(eslint|oxlint)-disable-(next-line|line)(?![\w-])([^\r\n]*)/;
|
|
34449
|
+
const FOREIGN_BLOCK_DISABLE_PATTERN = /\/\*[ \t]*(eslint|oxlint)-disable(?![\w-])([^*\r\n]*)/;
|
|
34450
|
+
const FOREIGN_BLOCK_ENABLE_PATTERN = /\/\*[ \t]*(?:eslint|oxlint)-enable(?![\w-])([^*\r\n]*)/;
|
|
34451
|
+
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}\`.`;
|
|
34452
|
+
const tokenMisnamesRule = (token, ruleId) => token !== ruleId && isSameRuleKey(token, ruleId);
|
|
34453
|
+
const detectInlineNearMiss = (lines, diagnosticLineIndex, ruleId) => {
|
|
34454
|
+
const candidates = [{
|
|
34455
|
+
line: lines[diagnosticLineIndex],
|
|
34456
|
+
requiredScope: "line"
|
|
34457
|
+
}, {
|
|
34458
|
+
line: lines[diagnosticLineIndex - 1],
|
|
34459
|
+
requiredScope: "next-line"
|
|
34460
|
+
}];
|
|
34461
|
+
for (const { line, requiredScope } of candidates) {
|
|
34462
|
+
const match = line?.match(FOREIGN_INLINE_DISABLE_PATTERN);
|
|
34463
|
+
if (!match) continue;
|
|
34464
|
+
const [, tool, scope, ruleList] = match;
|
|
34465
|
+
if (scope !== requiredScope) continue;
|
|
34466
|
+
const tokens = tokenizeRuleList(ruleList);
|
|
34467
|
+
if (tokens.includes(ruleId)) continue;
|
|
34468
|
+
for (const token of tokens) if (tokenMisnamesRule(token, ruleId)) return buildHint(tool, token, ruleId);
|
|
34469
|
+
}
|
|
34470
|
+
return null;
|
|
34471
|
+
};
|
|
34472
|
+
const detectBlockNearMiss = (lines, diagnosticLineIndex, ruleId) => {
|
|
34473
|
+
let openMisname = null;
|
|
34474
|
+
const lastLineIndex = Math.min(diagnosticLineIndex, lines.length - 1);
|
|
34475
|
+
for (let lineIndex = 0; lineIndex <= lastLineIndex; lineIndex++) {
|
|
34476
|
+
const line = lines[lineIndex];
|
|
34477
|
+
if (line === void 0 || !line.includes("-disable") && !line.includes("-enable")) continue;
|
|
34478
|
+
const disableMatch = line.match(FOREIGN_BLOCK_DISABLE_PATTERN);
|
|
34479
|
+
if (disableMatch) {
|
|
34480
|
+
const [, tool, ruleList] = disableMatch;
|
|
34481
|
+
const tokens = tokenizeRuleList(ruleList);
|
|
34482
|
+
if (tokens.includes(ruleId)) openMisname = null;
|
|
34483
|
+
else {
|
|
34484
|
+
const misnamed = tokens.find((token) => tokenMisnamesRule(token, ruleId));
|
|
34485
|
+
if (misnamed) openMisname = {
|
|
34486
|
+
tool,
|
|
34487
|
+
token: misnamed
|
|
34488
|
+
};
|
|
34489
|
+
}
|
|
34490
|
+
continue;
|
|
34491
|
+
}
|
|
34492
|
+
const enableMatch = line.match(FOREIGN_BLOCK_ENABLE_PATTERN);
|
|
34493
|
+
if (enableMatch) {
|
|
34494
|
+
const enabledRules = tokenizeRuleList(enableMatch[1]);
|
|
34495
|
+
if (enabledRules.length === 0 || enabledRules.some((rule) => isSameRuleKey(rule, ruleId))) openMisname = null;
|
|
34496
|
+
}
|
|
34497
|
+
}
|
|
34498
|
+
return openMisname ? buildHint(openMisname.tool, openMisname.token, ruleId) : null;
|
|
34499
|
+
};
|
|
34500
|
+
const detectForeignDisableNearMiss = (lines, diagnosticLineIndex, ruleId) => {
|
|
34501
|
+
if (!ruleId.startsWith("react-doctor/")) return null;
|
|
34502
|
+
return detectInlineNearMiss(lines, diagnosticLineIndex, ruleId) ?? detectBlockNearMiss(lines, diagnosticLineIndex, ruleId);
|
|
34503
|
+
};
|
|
34504
|
+
const JSX_OPENER_TAG_PATTERN = /<[A-Za-z][\w.]*/g;
|
|
34505
|
+
const JSX_TAG_NAME_FOLLOW = /[A-Za-z]/;
|
|
34506
|
+
const isOpenerMatchInsideLineComment = (line, openerCharIndex) => {
|
|
34507
|
+
let stringDelimiter = null;
|
|
34508
|
+
for (let charIndex = 0; charIndex < openerCharIndex; charIndex++) {
|
|
34509
|
+
const character = line[charIndex];
|
|
34510
|
+
if (stringDelimiter !== null) {
|
|
34511
|
+
if (character === "\\") {
|
|
34512
|
+
charIndex++;
|
|
34513
|
+
continue;
|
|
34514
|
+
}
|
|
34515
|
+
if (character === stringDelimiter) stringDelimiter = null;
|
|
34516
|
+
continue;
|
|
34517
|
+
}
|
|
34518
|
+
if (character === "\"" || character === "'" || character === "`") {
|
|
34519
|
+
stringDelimiter = character;
|
|
34520
|
+
continue;
|
|
34521
|
+
}
|
|
34522
|
+
if (character === "/" && line[charIndex + 1] === "/") return true;
|
|
34523
|
+
}
|
|
34524
|
+
return false;
|
|
34525
|
+
};
|
|
34526
|
+
const findOpenerTagOnLine = (line) => {
|
|
34527
|
+
for (const match of line.matchAll(JSX_OPENER_TAG_PATTERN)) {
|
|
34528
|
+
if (match.index === void 0) continue;
|
|
34529
|
+
if (!isOpenerMatchInsideLineComment(line, match.index)) return { startCharIndex: match.index + match[0].length };
|
|
34530
|
+
}
|
|
34531
|
+
return null;
|
|
34532
|
+
};
|
|
34533
|
+
const findJsxOpenerSpan = (lines, openerLineIndex) => {
|
|
34534
|
+
const openerLine = lines[openerLineIndex];
|
|
34535
|
+
if (openerLine === void 0) return null;
|
|
34536
|
+
const opener = findOpenerTagOnLine(openerLine);
|
|
34537
|
+
if (!opener) return null;
|
|
34538
|
+
const lookaheadLimit = Math.min(lines.length, openerLineIndex + 32);
|
|
34539
|
+
let braceDepth = 0;
|
|
34540
|
+
let innerAngleDepth = 0;
|
|
34541
|
+
let stringDelimiter = null;
|
|
34542
|
+
for (let lineIndex = openerLineIndex; lineIndex < lookaheadLimit; lineIndex++) {
|
|
34543
|
+
const currentLine = lines[lineIndex];
|
|
34544
|
+
const startCharForLine = lineIndex === openerLineIndex ? opener.startCharIndex : 0;
|
|
34545
|
+
for (let charIndex = startCharForLine; charIndex < currentLine.length; charIndex++) {
|
|
34546
|
+
const character = currentLine[charIndex];
|
|
34547
|
+
if (stringDelimiter !== null) {
|
|
34548
|
+
if (character === "\\") {
|
|
34549
|
+
charIndex++;
|
|
34550
|
+
continue;
|
|
34551
|
+
}
|
|
34552
|
+
if (character === stringDelimiter) stringDelimiter = null;
|
|
34553
|
+
continue;
|
|
34554
|
+
}
|
|
34555
|
+
if (character === "\"" || character === "'" || character === "`") {
|
|
34556
|
+
stringDelimiter = character;
|
|
34557
|
+
continue;
|
|
34558
|
+
}
|
|
34559
|
+
if (character === "{") {
|
|
34560
|
+
braceDepth++;
|
|
34561
|
+
continue;
|
|
34562
|
+
}
|
|
34563
|
+
if (character === "}") {
|
|
34564
|
+
braceDepth--;
|
|
34565
|
+
continue;
|
|
34566
|
+
}
|
|
34567
|
+
if (braceDepth !== 0) continue;
|
|
34568
|
+
if (character === "<") {
|
|
34569
|
+
const followCharacter = currentLine[charIndex + 1];
|
|
34570
|
+
if (followCharacter !== void 0 && JSX_TAG_NAME_FOLLOW.test(followCharacter)) innerAngleDepth++;
|
|
34571
|
+
continue;
|
|
34572
|
+
}
|
|
34573
|
+
if (character !== ">") continue;
|
|
34574
|
+
const previousCharacter = currentLine[charIndex - 1];
|
|
34575
|
+
const nextCharacter = currentLine[charIndex + 1];
|
|
34576
|
+
if (previousCharacter === "=" || nextCharacter === "=") continue;
|
|
34577
|
+
if (innerAngleDepth > 0) {
|
|
34578
|
+
innerAngleDepth--;
|
|
34579
|
+
continue;
|
|
34580
|
+
}
|
|
34581
|
+
return lineIndex;
|
|
34582
|
+
}
|
|
34583
|
+
}
|
|
34584
|
+
return null;
|
|
34585
|
+
};
|
|
34586
|
+
const findEnclosingMultilineJsxOpenerStart = (lines, diagnosticLineIndex) => {
|
|
34587
|
+
for (let candidateIndex = diagnosticLineIndex - 1; candidateIndex >= 0 && diagnosticLineIndex - candidateIndex <= 32; candidateIndex--) {
|
|
34588
|
+
const openerCloseIndex = findJsxOpenerSpan(lines, candidateIndex);
|
|
34589
|
+
if (openerCloseIndex !== null && openerCloseIndex >= diagnosticLineIndex) return candidateIndex;
|
|
34590
|
+
}
|
|
34591
|
+
return null;
|
|
34592
|
+
};
|
|
34593
|
+
const DISABLE_NEXT_LINE_PATTERN = /(?:\/\/|\/\*)\s*react-doctor-disable-next-line\b(?:\s+([^\r\n]*?))?\s*(?:\*\/)?\s*\}?\s*$/;
|
|
34594
|
+
const findStackedDisableCommentsAbove = (lines, anchorIndex) => {
|
|
34595
|
+
const collected = [];
|
|
34596
|
+
let isStillInChain = true;
|
|
34597
|
+
for (let candidateIndex = anchorIndex - 1; candidateIndex >= 0 && anchorIndex - candidateIndex <= 10; candidateIndex--) {
|
|
34598
|
+
const candidateLine = lines[candidateIndex];
|
|
34599
|
+
if (candidateLine === void 0) break;
|
|
34600
|
+
const match = candidateLine.match(DISABLE_NEXT_LINE_PATTERN);
|
|
34601
|
+
if (match) {
|
|
34602
|
+
collected.push({
|
|
34603
|
+
commentLineIndex: candidateIndex,
|
|
34604
|
+
ruleList: match[1],
|
|
34605
|
+
isInChain: isStillInChain
|
|
34606
|
+
});
|
|
34607
|
+
continue;
|
|
34608
|
+
}
|
|
34609
|
+
isStillInChain = false;
|
|
34610
|
+
}
|
|
34611
|
+
return collected;
|
|
34612
|
+
};
|
|
34613
|
+
const isRuleListedInComment = (ruleList, ruleId) => {
|
|
34614
|
+
const tokens = tokenizeRuleList(ruleList);
|
|
34615
|
+
if (tokens.length === 0) return true;
|
|
34616
|
+
return tokens.some((token) => isSameRuleKey(token, ruleId));
|
|
34554
34617
|
};
|
|
34555
34618
|
const DISABLE_LINE_PATTERN = /(?:\/\/|\/\*)\s*react-doctor-disable-line\b(?:\s+([^\r\n]*?))?\s*(?:\*\/)?\s*\}?\s*$/;
|
|
34556
34619
|
const formatLineGap = (gapLineCount) => `${gapLineCount} line${gapLineCount === 1 ? "" : "s"}`;
|
|
@@ -34594,7 +34657,7 @@ const evaluateSuppression = (lines, diagnosticLineIndex, ruleId) => {
|
|
|
34594
34657
|
};
|
|
34595
34658
|
return {
|
|
34596
34659
|
isSuppressed: false,
|
|
34597
|
-
nearMissHint: classifyFromComments([directComments, openerComments], diagnosticLineIndex, ruleId)
|
|
34660
|
+
nearMissHint: classifyFromComments([directComments, openerComments], diagnosticLineIndex, ruleId) ?? detectForeignDisableNearMiss(lines, diagnosticLineIndex, ruleId)
|
|
34598
34661
|
};
|
|
34599
34662
|
};
|
|
34600
34663
|
/**
|
|
@@ -35362,7 +35425,6 @@ const PACKAGE_JSON_FILENAME = "package.json";
|
|
|
35362
35425
|
const PACKAGE_JSON_CONFIG_KEY = "reactDoctor";
|
|
35363
35426
|
const LEGACY_CONFIG_FILENAME = "react-doctor.config.json";
|
|
35364
35427
|
const jiti = createJiti(import.meta.url);
|
|
35365
|
-
const formatError = (error) => error instanceof Error ? error.message : String(error);
|
|
35366
35428
|
const importDefaultExport = async (jitiInstance, filePath) => {
|
|
35367
35429
|
const imported = await jitiInstance.import(filePath);
|
|
35368
35430
|
return imported?.default ?? imported;
|
|
@@ -35394,7 +35456,7 @@ const loadModuleConfig = async (filePath) => {
|
|
|
35394
35456
|
try {
|
|
35395
35457
|
return await importDefaultExport(aliasJiti, filePath);
|
|
35396
35458
|
} catch (retryError) {
|
|
35397
|
-
throw new Error(`${
|
|
35459
|
+
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
35460
|
}
|
|
35399
35461
|
}
|
|
35400
35462
|
};
|
|
@@ -35443,7 +35505,7 @@ const loadLegacyConfig = (directory) => {
|
|
|
35443
35505
|
}
|
|
35444
35506
|
warn(`${LEGACY_CONFIG_FILENAME} must contain an object, ignoring.`);
|
|
35445
35507
|
} catch (error) {
|
|
35446
|
-
warn(`Failed to load ${LEGACY_CONFIG_FILENAME}: ${
|
|
35508
|
+
warn(`Failed to load ${LEGACY_CONFIG_FILENAME}: ${messageFromUnknown(error)}`);
|
|
35447
35509
|
}
|
|
35448
35510
|
return {
|
|
35449
35511
|
status: "invalid",
|
|
@@ -35470,7 +35532,7 @@ const loadConfigFromDirectory = async (directory) => {
|
|
|
35470
35532
|
warn(`${CONFIG_BASENAME}.${extension} must export an object, ignoring.`);
|
|
35471
35533
|
sawBrokenConfigFile = true;
|
|
35472
35534
|
} catch (error) {
|
|
35473
|
-
warn(`Failed to load ${CONFIG_BASENAME}.${extension}: ${
|
|
35535
|
+
warn(`Failed to load ${CONFIG_BASENAME}.${extension}: ${messageFromUnknown(error)}`);
|
|
35474
35536
|
sawBrokenConfigFile = true;
|
|
35475
35537
|
}
|
|
35476
35538
|
}
|
|
@@ -36458,15 +36520,10 @@ const buildCapabilities = (project) => {
|
|
|
36458
36520
|
}
|
|
36459
36521
|
if (project.tailwindVersion !== null) {
|
|
36460
36522
|
capabilities.add("tailwind");
|
|
36461
|
-
|
|
36462
|
-
if (isTailwindAtLeast(tailwind, {
|
|
36523
|
+
if (isTailwindAtLeast(parseTailwindMajorMinor(project.tailwindVersion), {
|
|
36463
36524
|
major: 3,
|
|
36464
36525
|
minor: 4
|
|
36465
36526
|
})) capabilities.add("tailwind:3.4");
|
|
36466
|
-
if (tailwind !== null && isTailwindAtLeast(tailwind, {
|
|
36467
|
-
major: 4,
|
|
36468
|
-
minor: 0
|
|
36469
|
-
})) capabilities.add("tailwind:4");
|
|
36470
36527
|
}
|
|
36471
36528
|
if (project.zodVersion !== null) {
|
|
36472
36529
|
capabilities.add("zod");
|
|
@@ -36655,7 +36712,7 @@ const readIgnoreFile = (filePath) => {
|
|
|
36655
36712
|
try {
|
|
36656
36713
|
content = NFS.readFileSync(filePath, "utf-8");
|
|
36657
36714
|
} catch (error) {
|
|
36658
|
-
const errnoCode = error
|
|
36715
|
+
const errnoCode = isErrnoException(error) ? error.code : void 0;
|
|
36659
36716
|
if (errnoCode && errnoCode !== "ENOENT") runSync(warn$1(`Could not read ignore file ${filePath}: ${errnoCode}`));
|
|
36660
36717
|
return [];
|
|
36661
36718
|
}
|
|
@@ -36696,8 +36753,8 @@ const collectIgnorePatterns = (rootDirectory) => {
|
|
|
36696
36753
|
cachedPatternsByRoot.set(rootDirectory, patterns);
|
|
36697
36754
|
return patterns;
|
|
36698
36755
|
};
|
|
36756
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36699
36757
|
const KNIP_JSON_FILENAME = "knip.json";
|
|
36700
|
-
const isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36701
36758
|
const readJsonFileSafe = (filePath) => {
|
|
36702
36759
|
let rawContents;
|
|
36703
36760
|
try {
|
|
@@ -36713,10 +36770,10 @@ const readJsonFileSafe = (filePath) => {
|
|
|
36713
36770
|
};
|
|
36714
36771
|
const readKnipConfig = (rootDirectory) => {
|
|
36715
36772
|
const knipJson = readJsonFileSafe(path.join(rootDirectory, KNIP_JSON_FILENAME));
|
|
36716
|
-
if (isRecord
|
|
36773
|
+
if (isRecord(knipJson)) return knipJson;
|
|
36717
36774
|
const packageJson = readJsonFileSafe(path.join(rootDirectory, "package.json"));
|
|
36718
|
-
const packageKnipConfig = isRecord
|
|
36719
|
-
return isRecord
|
|
36775
|
+
const packageKnipConfig = isRecord(packageJson) ? packageJson.knip : null;
|
|
36776
|
+
return isRecord(packageKnipConfig) ? packageKnipConfig : null;
|
|
36720
36777
|
};
|
|
36721
36778
|
const normalizePatternList = (value) => {
|
|
36722
36779
|
if (typeof value === "string" && value.length > 0) return [value];
|
|
@@ -36728,10 +36785,10 @@ const prefixWorkspacePatterns = (workspacePattern, patterns) => {
|
|
|
36728
36785
|
return patterns.map((pattern) => pattern.startsWith("!") ? `!${normalizedWorkspacePattern}/${pattern.slice(1)}` : `${normalizedWorkspacePattern}/${pattern}`);
|
|
36729
36786
|
};
|
|
36730
36787
|
const collectKnipWorkspacePatterns = (workspaces, settingName) => {
|
|
36731
|
-
if (!isRecord
|
|
36788
|
+
if (!isRecord(workspaces)) return [];
|
|
36732
36789
|
const patterns = [];
|
|
36733
36790
|
for (const [workspacePattern, workspaceConfig] of Object.entries(workspaces)) {
|
|
36734
|
-
if (!isRecord
|
|
36791
|
+
if (!isRecord(workspaceConfig)) continue;
|
|
36735
36792
|
patterns.push(...prefixWorkspacePatterns(workspacePattern, normalizePatternList(workspaceConfig[settingName])));
|
|
36736
36793
|
}
|
|
36737
36794
|
return patterns;
|
|
@@ -36776,8 +36833,6 @@ const toCanonicalPath = (filePath) => {
|
|
|
36776
36833
|
};
|
|
36777
36834
|
const DEAD_CODE_PLUGIN = "deslop";
|
|
36778
36835
|
const DEAD_CODE_CATEGORY = "Maintainability";
|
|
36779
|
-
const TSCONFIG_FILENAMES$1 = ["tsconfig.json", "tsconfig.base.json"];
|
|
36780
|
-
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36781
36836
|
const DEAD_CODE_WORKER_SCRIPT = `
|
|
36782
36837
|
const inputChunks = [];
|
|
36783
36838
|
process.stdin.on("data", (chunk) => inputChunks.push(chunk));
|
|
@@ -36835,7 +36890,7 @@ process.stdin.on("end", () => {
|
|
|
36835
36890
|
});
|
|
36836
36891
|
`;
|
|
36837
36892
|
const resolveTsConfigPath = (rootDirectory) => {
|
|
36838
|
-
for (const filename of TSCONFIG_FILENAMES
|
|
36893
|
+
for (const filename of TSCONFIG_FILENAMES) {
|
|
36839
36894
|
const candidate = Path.join(rootDirectory, filename);
|
|
36840
36895
|
if (NFS.existsSync(candidate)) return candidate;
|
|
36841
36896
|
}
|
|
@@ -37216,15 +37271,13 @@ var DeadCode = class DeadCode extends Service()("react-doctor/DeadCode") {
|
|
|
37216
37271
|
})()) }));
|
|
37217
37272
|
static layerOf = (diagnostics) => succeed$3(DeadCode, DeadCode.of({ run: () => fromIterable$1(diagnostics) }));
|
|
37218
37273
|
};
|
|
37219
|
-
const createNodeReadFileLinesSync = (rootDirectory) => {
|
|
37220
|
-
|
|
37221
|
-
|
|
37222
|
-
|
|
37223
|
-
|
|
37224
|
-
|
|
37225
|
-
|
|
37226
|
-
}
|
|
37227
|
-
};
|
|
37274
|
+
const createNodeReadFileLinesSync = (rootDirectory) => (filePath) => {
|
|
37275
|
+
const absolutePath = Path.isAbsolute(filePath) ? filePath : Path.join(rootDirectory, filePath);
|
|
37276
|
+
try {
|
|
37277
|
+
return NFS.readFileSync(absolutePath, "utf-8").split("\n");
|
|
37278
|
+
} catch {
|
|
37279
|
+
return null;
|
|
37280
|
+
}
|
|
37228
37281
|
};
|
|
37229
37282
|
var Files = class Files extends Service()("react-doctor/Files") {
|
|
37230
37283
|
static layerNode = succeed$3(Files, Files.of({
|
|
@@ -37435,7 +37488,10 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37435
37488
|
directory: input.directory,
|
|
37436
37489
|
cause
|
|
37437
37490
|
}) });
|
|
37438
|
-
})
|
|
37491
|
+
}), withSpan("git.exec", { attributes: {
|
|
37492
|
+
"git.command": input.command,
|
|
37493
|
+
"git.subcommand": input.args[0] ?? ""
|
|
37494
|
+
} }));
|
|
37439
37495
|
const runGit = (directory, args) => runCommand({
|
|
37440
37496
|
command: "git",
|
|
37441
37497
|
args,
|
|
@@ -37463,7 +37519,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37463
37519
|
]);
|
|
37464
37520
|
if (candidates.status !== 0) return null;
|
|
37465
37521
|
return trimOrNull(candidates.stdout.split("\n")[0] ?? "");
|
|
37466
|
-
});
|
|
37522
|
+
}).pipe(withSpan("Git.defaultBranch"));
|
|
37467
37523
|
const branchExists = (directory, branch) => runGit(directory, [
|
|
37468
37524
|
"rev-parse",
|
|
37469
37525
|
"--verify",
|
|
@@ -37510,7 +37566,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37510
37566
|
const result = resultOption.value;
|
|
37511
37567
|
if (result.status !== 0) return null;
|
|
37512
37568
|
return parseGithubViewerPermission(result.stdout);
|
|
37513
|
-
}).pipe(catch_$1(() => succeed$2(null)));
|
|
37569
|
+
}).pipe(catch_$1(() => succeed$2(null)), withSpan("Git.githubViewerPermission"));
|
|
37514
37570
|
/**
|
|
37515
37571
|
* Resolves a `--diff A..B` / `A...B` commit range into a changed-file
|
|
37516
37572
|
* selection. Each endpoint is validated with `isSafeGitRevision`
|
|
@@ -37624,7 +37680,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37624
37680
|
changedFiles: splitNullSeparated(diff.stdout),
|
|
37625
37681
|
isCurrentChanges: false
|
|
37626
37682
|
};
|
|
37627
|
-
}),
|
|
37683
|
+
}).pipe(withSpan("Git.diffSelection")),
|
|
37628
37684
|
stagedFilePaths: (directory) => runGit(directory, [
|
|
37629
37685
|
"diff",
|
|
37630
37686
|
"--cached",
|
|
@@ -37666,7 +37722,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37666
37722
|
status: result.status,
|
|
37667
37723
|
stdout: result.stdout
|
|
37668
37724
|
};
|
|
37669
|
-
}),
|
|
37725
|
+
}).pipe(withSpan("Git.grep")),
|
|
37670
37726
|
changedLineRanges: ({ directory, baseRef, cached, files }) => gen(function* () {
|
|
37671
37727
|
if (files.length === 0) return [];
|
|
37672
37728
|
if (baseRef !== void 0 && !isSafeGitRevision(baseRef)) return null;
|
|
@@ -37682,7 +37738,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37682
37738
|
]);
|
|
37683
37739
|
if (result.status !== 0) return null;
|
|
37684
37740
|
return parseChangedLineRanges(result.stdout);
|
|
37685
|
-
})
|
|
37741
|
+
}).pipe(withSpan("Git.changedLineRanges"))
|
|
37686
37742
|
});
|
|
37687
37743
|
})).pipe(provide$2(layer$2.pipe(provide$2(mergeAll$1(layer$1, layer)))));
|
|
37688
37744
|
/**
|
|
@@ -37897,7 +37953,7 @@ const neutralizeDisableDirectives = async (rootDirectory, includePaths) => {
|
|
|
37897
37953
|
for (const [absolutePath, originalContent] of originalContents) try {
|
|
37898
37954
|
NFS.writeFileSync(absolutePath, originalContent);
|
|
37899
37955
|
} catch (error) {
|
|
37900
|
-
process.stderr.write(`[react-doctor] Failed to restore inline disable directives in ${absolutePath}: ${
|
|
37956
|
+
process.stderr.write(`[react-doctor] Failed to restore inline disable directives in ${absolutePath}: ${messageFromUnknown(error)}\n[react-doctor] Run: git checkout -- ${absolutePath}\n`);
|
|
37901
37957
|
}
|
|
37902
37958
|
};
|
|
37903
37959
|
const onExit = () => restore();
|
|
@@ -38003,7 +38059,7 @@ const resolveUserPlugin = (spec, configSourceDirectory) => {
|
|
|
38003
38059
|
try {
|
|
38004
38060
|
resolvedSpecifier = isRelative ? Path.resolve(configSourceDirectory, spec) : candidateRequire.resolve(spec);
|
|
38005
38061
|
} catch (error) {
|
|
38006
|
-
warnConfigIssue(`config.plugins entry "${spec}" could not be resolved from ${configSourceDirectory}: ${
|
|
38062
|
+
warnConfigIssue(`config.plugins entry "${spec}" could not be resolved from ${configSourceDirectory}: ${messageFromUnknown(error)}`);
|
|
38007
38063
|
return null;
|
|
38008
38064
|
}
|
|
38009
38065
|
const { name, ruleNames } = readPluginShape(resolvedSpecifier, (target) => candidateRequire(target));
|
|
@@ -38136,7 +38192,6 @@ const resolveOxlintBinary = () => {
|
|
|
38136
38192
|
return Path.join(oxlintPackageDirectory, "bin", "oxlint");
|
|
38137
38193
|
};
|
|
38138
38194
|
const resolvePluginPath = () => esmRequire.resolve("oxlint-plugin-react-doctor");
|
|
38139
|
-
const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
|
|
38140
38195
|
const resolveTsConfigRelativePath = (rootDirectory) => {
|
|
38141
38196
|
for (const filename of TSCONFIG_FILENAMES) if (NFS.existsSync(Path.join(rootDirectory, filename))) return `./${filename}`;
|
|
38142
38197
|
return null;
|
|
@@ -38508,7 +38563,7 @@ const scopeContainsNonImportBinding = (node, scopeNode, identifierName) => {
|
|
|
38508
38563
|
const isIdentifierShadowedByLocalBinding = (identifier, sourceFile) => {
|
|
38509
38564
|
let currentNode = identifier.parent;
|
|
38510
38565
|
while (currentNode) {
|
|
38511
|
-
if (
|
|
38566
|
+
if (isScopeBoundary(currentNode)) {
|
|
38512
38567
|
if (scopeContainsNonImportBinding(currentNode, currentNode, identifier.text)) return true;
|
|
38513
38568
|
}
|
|
38514
38569
|
if (currentNode === sourceFile) return false;
|
|
@@ -38599,11 +38654,10 @@ const findResolutionInScope = (scopeNode, identifierName, reactImportBindings, s
|
|
|
38599
38654
|
});
|
|
38600
38655
|
return resolution;
|
|
38601
38656
|
};
|
|
38602
|
-
const isScopeNode = isScopeBoundary;
|
|
38603
38657
|
const resolveIdentifierBinding = (identifier, reactImportBindings, sourceFile, visitedDeclarations = /* @__PURE__ */ new Set()) => {
|
|
38604
38658
|
let currentNode = identifier.parent;
|
|
38605
38659
|
while (currentNode) {
|
|
38606
|
-
if (
|
|
38660
|
+
if (isScopeBoundary(currentNode)) {
|
|
38607
38661
|
const resolution = findResolutionInScope(currentNode, identifier.text, reactImportBindings, sourceFile, visitedDeclarations);
|
|
38608
38662
|
if (resolution) return resolution;
|
|
38609
38663
|
}
|
|
@@ -38851,7 +38905,7 @@ const spawnOxlint = (args, rootDirectory, nodeBinaryPath, spawnTimeoutMs = OXLIN
|
|
|
38851
38905
|
child.kill("SIGKILL");
|
|
38852
38906
|
reject(new ReactDoctorError({ reason: new OxlintBatchExceeded({
|
|
38853
38907
|
kind: "timeout",
|
|
38854
|
-
detail: `${spawnTimeoutMs /
|
|
38908
|
+
detail: `${spawnTimeoutMs / MILLISECONDS_PER_SECOND}s budget exceeded`
|
|
38855
38909
|
}) }));
|
|
38856
38910
|
}, spawnTimeoutMs);
|
|
38857
38911
|
timeoutHandle.unref?.();
|
|
@@ -39973,7 +40027,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
39973
40027
|
}))))))));
|
|
39974
40028
|
const deadCodeFailureState = yield* get$2(deadCodeFailure);
|
|
39975
40029
|
const scanElapsedMilliseconds = Date.now() - scanStartTime;
|
|
39976
|
-
const scanElapsedSeconds = (scanElapsedMilliseconds /
|
|
40030
|
+
const scanElapsedSeconds = (scanElapsedMilliseconds / MILLISECONDS_PER_SECOND).toFixed(1);
|
|
39977
40031
|
if (!lintFailureState.didFail) if (deadCodeFailureState.didFail) yield* scanProgress.fail(DEAD_CODE_FAIL_TEXT);
|
|
39978
40032
|
else if (input.suppressScanSummary) yield* scanProgress.stop();
|
|
39979
40033
|
else yield* scanProgress.succeed(`Scanned ${scannedFilesLabel} in ${scanElapsedSeconds}s${workerCountSuffix}`);
|
|
@@ -40187,7 +40241,7 @@ const materializeSourceTree = (input) => gen(function* () {
|
|
|
40187
40241
|
static layerNode = effect(StagedFiles, gen(function* () {
|
|
40188
40242
|
const git = yield* Git;
|
|
40189
40243
|
return StagedFiles.of({
|
|
40190
|
-
discoverSourceFiles: (directory) => git.stagedFilePaths(directory).pipe(map$3((entries) => entries.filter(isLintableSourceFile))),
|
|
40244
|
+
discoverSourceFiles: (directory) => git.stagedFilePaths(directory).pipe(map$3((entries) => entries.filter(isLintableSourceFile)), withSpan("StagedFiles.discoverSourceFiles")),
|
|
40191
40245
|
materialize: ({ directory, stagedFiles, tempDirectory }) => materializeSourceTree({
|
|
40192
40246
|
directory,
|
|
40193
40247
|
files: stagedFiles,
|
|
@@ -40197,7 +40251,7 @@ const materializeSourceTree = (input) => gen(function* () {
|
|
|
40197
40251
|
tempDirectory: tree.tempDirectory,
|
|
40198
40252
|
stagedFiles: tree.materializedFiles,
|
|
40199
40253
|
cleanup: tree.cleanup
|
|
40200
|
-
})))
|
|
40254
|
+
})), withSpan("StagedFiles.materialize"))
|
|
40201
40255
|
});
|
|
40202
40256
|
}));
|
|
40203
40257
|
/**
|
|
@@ -40265,7 +40319,10 @@ const runEditorScan = async (input) => {
|
|
|
40265
40319
|
isCi: false,
|
|
40266
40320
|
resolveLocalGithubViewerPermission: false,
|
|
40267
40321
|
skipJsxIncludeFilter: true
|
|
40268
|
-
}).pipe(
|
|
40322
|
+
}).pipe(withSpan("runEditorScan", { attributes: {
|
|
40323
|
+
"editor.lint": lint,
|
|
40324
|
+
"editor.runDeadCode": runDeadCode
|
|
40325
|
+
} }), provide(layers), provide(layerOtlp)));
|
|
40269
40326
|
if (isSuccess(exit)) {
|
|
40270
40327
|
const output = exit.value;
|
|
40271
40328
|
return {
|
|
@@ -40295,7 +40352,7 @@ const runEditorScan = async (input) => {
|
|
|
40295
40352
|
didDeadCodeFail: false,
|
|
40296
40353
|
deadCodeFailureReason: null,
|
|
40297
40354
|
lintPartialFailures: [],
|
|
40298
|
-
error:
|
|
40355
|
+
error: messageFromUnknown(error)
|
|
40299
40356
|
};
|
|
40300
40357
|
};
|
|
40301
40358
|
/**
|
|
@@ -40577,7 +40634,6 @@ const toLspDiagnostic = (input) => {
|
|
|
40577
40634
|
data
|
|
40578
40635
|
};
|
|
40579
40636
|
};
|
|
40580
|
-
const toUri = (absoluteFilePath) => fsPathToUri(absoluteFilePath);
|
|
40581
40637
|
/**
|
|
40582
40638
|
* Owns the published-diagnostic state. Maps scan outcomes to LSP
|
|
40583
40639
|
* diagnostics, publishes complete per-URI replacement sets (so the
|
|
@@ -40607,7 +40663,7 @@ var DiagnosticsManager = class {
|
|
|
40607
40663
|
const isProtectedPath = (fsPath) => protectOpen && this.isOpen(fsPath);
|
|
40608
40664
|
for (const [fsPath, coreDiagnostics] of outcome.byFile) {
|
|
40609
40665
|
if (isProtectedPath(fsPath)) continue;
|
|
40610
|
-
const uri =
|
|
40666
|
+
const uri = fsPathToUri(fsPath);
|
|
40611
40667
|
const text = this.textProvider(fsPath);
|
|
40612
40668
|
const lspDiagnostics = coreDiagnostics.map((diagnostic) => toLspDiagnostic({
|
|
40613
40669
|
diagnostic,
|
|
@@ -40629,7 +40685,7 @@ var DiagnosticsManager = class {
|
|
|
40629
40685
|
for (const fsPath of outcome.requestedPaths) {
|
|
40630
40686
|
if (isProtectedPath(fsPath)) continue;
|
|
40631
40687
|
if (outcome.byFile.has(fsPath)) continue;
|
|
40632
|
-
const uri =
|
|
40688
|
+
const uri = fsPathToUri(fsPath);
|
|
40633
40689
|
if (this.byUri.has(uri)) this.byUri.delete(uri);
|
|
40634
40690
|
this.publish(uri, []);
|
|
40635
40691
|
}
|
|
@@ -40654,7 +40710,7 @@ var DiagnosticsManager = class {
|
|
|
40654
40710
|
const set = this.projectUris.get(project) ?? /* @__PURE__ */ new Set();
|
|
40655
40711
|
for (const uri of liveUris) set.add(uri);
|
|
40656
40712
|
for (const fsPath of outcome.requestedPaths) {
|
|
40657
|
-
const uri =
|
|
40713
|
+
const uri = fsPathToUri(fsPath);
|
|
40658
40714
|
if (!liveUris.has(uri)) set.delete(uri);
|
|
40659
40715
|
}
|
|
40660
40716
|
this.projectUris.set(project, set);
|
|
@@ -40682,7 +40738,7 @@ var DiagnosticsManager = class {
|
|
|
40682
40738
|
const tracked = this.projectUris.get(project);
|
|
40683
40739
|
if (!tracked) return;
|
|
40684
40740
|
const liveUris = /* @__PURE__ */ new Set();
|
|
40685
|
-
for (const fsPath of liveFsPaths) liveUris.add(
|
|
40741
|
+
for (const fsPath of liveFsPaths) liveUris.add(fsPathToUri(fsPath));
|
|
40686
40742
|
for (const uri of [...tracked]) {
|
|
40687
40743
|
if (liveUris.has(uri)) continue;
|
|
40688
40744
|
this.byUri.delete(uri);
|
|
@@ -40979,7 +41035,7 @@ const createProjectGraph = (options) => {
|
|
|
40979
41035
|
});
|
|
40980
41036
|
}
|
|
40981
41037
|
} catch (error) {
|
|
40982
|
-
logger.warn(`Project discovery failed for ${root}: ${
|
|
41038
|
+
logger.warn(`Project discovery failed for ${root}: ${messageFromUnknown(error)}`);
|
|
40983
41039
|
}
|
|
40984
41040
|
return [...seen.values()].sort((first, second) => second.directory.length - first.directory.length);
|
|
40985
41041
|
};
|
|
@@ -41007,6 +41063,11 @@ const createProjectGraph = (options) => {
|
|
|
41007
41063
|
}
|
|
41008
41064
|
};
|
|
41009
41065
|
};
|
|
41066
|
+
const toProjectRelative = (projectDirectory, filePath) => {
|
|
41067
|
+
const relative = Path.relative(projectDirectory, filePath).replace(/\\/g, "/");
|
|
41068
|
+
if (relative.length === 0 || relative.startsWith("../") || Path.isAbsolute(relative)) return null;
|
|
41069
|
+
return relative;
|
|
41070
|
+
};
|
|
41010
41071
|
const resolveCacheFilePath = (projectDirectory) => {
|
|
41011
41072
|
const nodeModules = path.join(projectDirectory, "node_modules");
|
|
41012
41073
|
if (fs.existsSync(nodeModules)) return path.join(nodeModules, ".cache", "react-doctor", "lint-cache.json");
|
|
@@ -41041,7 +41102,7 @@ const createLintCache = (input) => {
|
|
|
41041
41102
|
fs.writeFileSync(tempPath, JSON.stringify(payload));
|
|
41042
41103
|
fs.renameSync(tempPath, cacheFilePath);
|
|
41043
41104
|
} catch (error) {
|
|
41044
|
-
logger.warn(`Failed to persist lint cache: ${
|
|
41105
|
+
logger.warn(`Failed to persist lint cache: ${messageFromUnknown(error)}`);
|
|
41045
41106
|
}
|
|
41046
41107
|
};
|
|
41047
41108
|
return {
|
|
@@ -41067,11 +41128,6 @@ const createLintCache = (input) => {
|
|
|
41067
41128
|
};
|
|
41068
41129
|
const OVERLAY_TEMP_PREFIX = "react-doctor-lsp-";
|
|
41069
41130
|
const OVERLAY_CONFIG_FILENAMES = [...new Set([...STAGED_FILES_PROJECT_CONFIG_FILENAMES, ...ADOPTABLE_LINT_CONFIG_FILENAMES])];
|
|
41070
|
-
const toProjectRelative$1 = (projectDirectory, filePath) => {
|
|
41071
|
-
const relative = path.relative(projectDirectory, filePath).replace(/\\/g, "/");
|
|
41072
|
-
if (relative.length === 0 || relative.startsWith("../") || path.isAbsolute(relative)) return null;
|
|
41073
|
-
return relative;
|
|
41074
|
-
};
|
|
41075
41131
|
/**
|
|
41076
41132
|
* Writes the live (possibly unsaved) content of the target files into a
|
|
41077
41133
|
* throwaway temp tree that mirrors the project, alongside the well-known
|
|
@@ -41085,7 +41141,7 @@ const materializeOverlay = (input) => {
|
|
|
41085
41141
|
const relativePaths = [];
|
|
41086
41142
|
try {
|
|
41087
41143
|
for (const filePath of input.files) {
|
|
41088
|
-
const relative = toProjectRelative
|
|
41144
|
+
const relative = toProjectRelative(input.projectDirectory, filePath);
|
|
41089
41145
|
if (relative === null) continue;
|
|
41090
41146
|
const content = input.readText(filePath);
|
|
41091
41147
|
if (content === null) continue;
|
|
@@ -41133,11 +41189,6 @@ const materializeOverlay = (input) => {
|
|
|
41133
41189
|
throw error;
|
|
41134
41190
|
}
|
|
41135
41191
|
};
|
|
41136
|
-
const toProjectRelative = (projectDirectory, filePath) => {
|
|
41137
|
-
const relative = path.relative(projectDirectory, filePath).replace(/\\/g, "/");
|
|
41138
|
-
if (relative.length === 0 || relative.startsWith("../") || path.isAbsolute(relative)) return null;
|
|
41139
|
-
return relative;
|
|
41140
|
-
};
|
|
41141
41192
|
/**
|
|
41142
41193
|
* Resolves a diagnostic's (possibly relative, possibly overlay-temp)
|
|
41143
41194
|
* file path back to the canonical absolute path inside the real project.
|
|
@@ -41359,7 +41410,7 @@ const createScheduler = (options) => {
|
|
|
41359
41410
|
if (outcome && !token.isCancelled) options.onResult(outcome);
|
|
41360
41411
|
}).catch((error) => {
|
|
41361
41412
|
if (options.onError) options.onError(error, request);
|
|
41362
|
-
else logger.error(`Scan failed: ${
|
|
41413
|
+
else logger.error(`Scan failed: ${messageFromUnknown(error)}`);
|
|
41363
41414
|
}).finally(() => {
|
|
41364
41415
|
running -= 1;
|
|
41365
41416
|
if (isBackground) runningBackground -= 1;
|
|
@@ -41746,7 +41797,7 @@ const createServer = (connection, options = {}) => {
|
|
|
41746
41797
|
maybeWarnLintUnavailable(outcome);
|
|
41747
41798
|
if (outcome.request.priority === "background") scanTelemetry.accumulate(outcome);
|
|
41748
41799
|
},
|
|
41749
|
-
onError: (error, request) => logger.error(`Scan of ${request.projectDirectory} threw: ${
|
|
41800
|
+
onError: (error, request) => logger.error(`Scan of ${request.projectDirectory} threw: ${messageFromUnknown(error)}`),
|
|
41750
41801
|
onIdleChange: (idle) => {
|
|
41751
41802
|
setBusy(!idle);
|
|
41752
41803
|
if (idle) scanTelemetry.finish();
|
|
@@ -42394,5 +42445,5 @@ const startLanguageServer = () => {
|
|
|
42394
42445
|
};
|
|
42395
42446
|
//#endregion
|
|
42396
42447
|
export { startLanguageServer };
|
|
42397
|
-
!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]="
|
|
42398
|
-
//# debugId=
|
|
42448
|
+
!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]="66ef8d70-3b06-5d78-ba3e-0907cc82425c")}catch(e){}}();
|
|
42449
|
+
//# debugId=66ef8d70-3b06-5d78-ba3e-0907cc82425c
|