react-doctor 0.5.6-dev.93b796d → 0.5.6-dev.a9d2713
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 +341 -181
- package/dist/index.d.ts +19 -0
- package/dist/index.js +257 -166
- package/dist/lsp.js +269 -178
- package/package.json +2 -2
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,
|
|
@@ -33731,6 +33722,13 @@ const APP_ONLY_RULE_KEYS = new Set([
|
|
|
33731
33722
|
]);
|
|
33732
33723
|
const COMPILER_CLEANUP_BUCKET = "compiler-cleanup";
|
|
33733
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
|
+
]);
|
|
33734
33732
|
const MAX_GLOB_PATTERN_LENGTH_CHARS = 1024;
|
|
33735
33733
|
const CONFIG_CACHE_TTL_MS = 300 * 1e3;
|
|
33736
33734
|
const SOCKET_FREE_PURL_API_BASE = "https://firewall-api.socket.dev/purl";
|
|
@@ -34183,6 +34181,7 @@ const isTailwindAtLeast = (detected, required) => {
|
|
|
34183
34181
|
if (detected.major !== required.major) return detected.major > required.major;
|
|
34184
34182
|
return detected.minor >= required.minor;
|
|
34185
34183
|
};
|
|
34184
|
+
const messageFromUnknown = (error) => error instanceof Error ? error.message : String(error);
|
|
34186
34185
|
var InvalidGlobPatternError = class extends Error {
|
|
34187
34186
|
pattern;
|
|
34188
34187
|
reason;
|
|
@@ -34211,7 +34210,7 @@ const compileGlobPattern = (rawPattern) => {
|
|
|
34211
34210
|
try {
|
|
34212
34211
|
return import_picomatch.default.makeRe(normalizeGlobPattern(rawPattern), PICOMATCH_OPTIONS);
|
|
34213
34212
|
} catch (caughtError) {
|
|
34214
|
-
throw new InvalidGlobPatternError(rawPattern,
|
|
34213
|
+
throw new InvalidGlobPatternError(rawPattern, messageFromUnknown(caughtError));
|
|
34215
34214
|
}
|
|
34216
34215
|
};
|
|
34217
34216
|
const compileGlobPatternsLenient = (patterns, onInvalid) => {
|
|
@@ -34307,115 +34306,6 @@ const buildRuleSeverityControls = (config) => {
|
|
|
34307
34306
|
...config.buckets !== void 0 ? { buckets: config.buckets } : {}
|
|
34308
34307
|
};
|
|
34309
34308
|
};
|
|
34310
|
-
const JSX_OPENER_TAG_PATTERN = /<[A-Za-z][\w.]*/g;
|
|
34311
|
-
const JSX_TAG_NAME_FOLLOW = /[A-Za-z]/;
|
|
34312
|
-
const isOpenerMatchInsideLineComment = (line, openerCharIndex) => {
|
|
34313
|
-
let stringDelimiter = null;
|
|
34314
|
-
for (let charIndex = 0; charIndex < openerCharIndex; charIndex++) {
|
|
34315
|
-
const character = line[charIndex];
|
|
34316
|
-
if (stringDelimiter !== null) {
|
|
34317
|
-
if (character === "\\") {
|
|
34318
|
-
charIndex++;
|
|
34319
|
-
continue;
|
|
34320
|
-
}
|
|
34321
|
-
if (character === stringDelimiter) stringDelimiter = null;
|
|
34322
|
-
continue;
|
|
34323
|
-
}
|
|
34324
|
-
if (character === "\"" || character === "'" || character === "`") {
|
|
34325
|
-
stringDelimiter = character;
|
|
34326
|
-
continue;
|
|
34327
|
-
}
|
|
34328
|
-
if (character === "/" && line[charIndex + 1] === "/") return true;
|
|
34329
|
-
}
|
|
34330
|
-
return false;
|
|
34331
|
-
};
|
|
34332
|
-
const findOpenerTagOnLine = (line) => {
|
|
34333
|
-
for (const match of line.matchAll(JSX_OPENER_TAG_PATTERN)) {
|
|
34334
|
-
if (match.index === void 0) continue;
|
|
34335
|
-
if (!isOpenerMatchInsideLineComment(line, match.index)) return { startCharIndex: match.index + match[0].length };
|
|
34336
|
-
}
|
|
34337
|
-
return null;
|
|
34338
|
-
};
|
|
34339
|
-
const findJsxOpenerSpan = (lines, openerLineIndex) => {
|
|
34340
|
-
const openerLine = lines[openerLineIndex];
|
|
34341
|
-
if (openerLine === void 0) return null;
|
|
34342
|
-
const opener = findOpenerTagOnLine(openerLine);
|
|
34343
|
-
if (!opener) return null;
|
|
34344
|
-
const lookaheadLimit = Math.min(lines.length, openerLineIndex + 32);
|
|
34345
|
-
let braceDepth = 0;
|
|
34346
|
-
let innerAngleDepth = 0;
|
|
34347
|
-
let stringDelimiter = null;
|
|
34348
|
-
for (let lineIndex = openerLineIndex; lineIndex < lookaheadLimit; lineIndex++) {
|
|
34349
|
-
const currentLine = lines[lineIndex];
|
|
34350
|
-
const startCharForLine = lineIndex === openerLineIndex ? opener.startCharIndex : 0;
|
|
34351
|
-
for (let charIndex = startCharForLine; charIndex < currentLine.length; charIndex++) {
|
|
34352
|
-
const character = currentLine[charIndex];
|
|
34353
|
-
if (stringDelimiter !== null) {
|
|
34354
|
-
if (character === "\\") {
|
|
34355
|
-
charIndex++;
|
|
34356
|
-
continue;
|
|
34357
|
-
}
|
|
34358
|
-
if (character === stringDelimiter) stringDelimiter = null;
|
|
34359
|
-
continue;
|
|
34360
|
-
}
|
|
34361
|
-
if (character === "\"" || character === "'" || character === "`") {
|
|
34362
|
-
stringDelimiter = character;
|
|
34363
|
-
continue;
|
|
34364
|
-
}
|
|
34365
|
-
if (character === "{") {
|
|
34366
|
-
braceDepth++;
|
|
34367
|
-
continue;
|
|
34368
|
-
}
|
|
34369
|
-
if (character === "}") {
|
|
34370
|
-
braceDepth--;
|
|
34371
|
-
continue;
|
|
34372
|
-
}
|
|
34373
|
-
if (braceDepth !== 0) continue;
|
|
34374
|
-
if (character === "<") {
|
|
34375
|
-
const followCharacter = currentLine[charIndex + 1];
|
|
34376
|
-
if (followCharacter !== void 0 && JSX_TAG_NAME_FOLLOW.test(followCharacter)) innerAngleDepth++;
|
|
34377
|
-
continue;
|
|
34378
|
-
}
|
|
34379
|
-
if (character !== ">") continue;
|
|
34380
|
-
const previousCharacter = currentLine[charIndex - 1];
|
|
34381
|
-
const nextCharacter = currentLine[charIndex + 1];
|
|
34382
|
-
if (previousCharacter === "=" || nextCharacter === "=") continue;
|
|
34383
|
-
if (innerAngleDepth > 0) {
|
|
34384
|
-
innerAngleDepth--;
|
|
34385
|
-
continue;
|
|
34386
|
-
}
|
|
34387
|
-
return lineIndex;
|
|
34388
|
-
}
|
|
34389
|
-
}
|
|
34390
|
-
return null;
|
|
34391
|
-
};
|
|
34392
|
-
const findEnclosingMultilineJsxOpenerStart = (lines, diagnosticLineIndex) => {
|
|
34393
|
-
for (let candidateIndex = diagnosticLineIndex - 1; candidateIndex >= 0 && diagnosticLineIndex - candidateIndex <= 32; candidateIndex--) {
|
|
34394
|
-
const openerCloseIndex = findJsxOpenerSpan(lines, candidateIndex);
|
|
34395
|
-
if (openerCloseIndex !== null && openerCloseIndex >= diagnosticLineIndex) return candidateIndex;
|
|
34396
|
-
}
|
|
34397
|
-
return null;
|
|
34398
|
-
};
|
|
34399
|
-
const DISABLE_NEXT_LINE_PATTERN = /(?:\/\/|\/\*)\s*react-doctor-disable-next-line\b(?:\s+([^\r\n]*?))?\s*(?:\*\/)?\s*\}?\s*$/;
|
|
34400
|
-
const findStackedDisableCommentsAbove = (lines, anchorIndex) => {
|
|
34401
|
-
const collected = [];
|
|
34402
|
-
let isStillInChain = true;
|
|
34403
|
-
for (let candidateIndex = anchorIndex - 1; candidateIndex >= 0 && anchorIndex - candidateIndex <= 10; candidateIndex--) {
|
|
34404
|
-
const candidateLine = lines[candidateIndex];
|
|
34405
|
-
if (candidateLine === void 0) break;
|
|
34406
|
-
const match = candidateLine.match(DISABLE_NEXT_LINE_PATTERN);
|
|
34407
|
-
if (match) {
|
|
34408
|
-
collected.push({
|
|
34409
|
-
commentLineIndex: candidateIndex,
|
|
34410
|
-
ruleList: match[1],
|
|
34411
|
-
isInChain: isStillInChain
|
|
34412
|
-
});
|
|
34413
|
-
continue;
|
|
34414
|
-
}
|
|
34415
|
-
isStillInChain = false;
|
|
34416
|
-
}
|
|
34417
|
-
return collected;
|
|
34418
|
-
};
|
|
34419
34309
|
const LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY = {
|
|
34420
34310
|
"effect/no-adjust-state-on-prop-change": "react-doctor/no-adjust-state-on-prop-change",
|
|
34421
34311
|
"effect/no-chain-state-updates": "react-doctor/no-chain-state-updates",
|
|
@@ -34540,7 +34430,13 @@ for (const [legacyRuleKey, nativeRuleKey] of Object.entries(LEGACY_RULE_KEY_TO_N
|
|
|
34540
34430
|
}
|
|
34541
34431
|
const getLegacyRuleKeysForNative = (ruleKey) => NATIVE_RULE_KEY_TO_LEGACY_RULE_KEYS.get(ruleKey) ?? [];
|
|
34542
34432
|
const canonicalizeRuleKey = (ruleKey) => LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY[ruleKey] ?? ruleKey;
|
|
34543
|
-
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
|
+
};
|
|
34544
34440
|
const getEquivalentRuleKeys = (ruleKey) => {
|
|
34545
34441
|
const nativeRuleKey = canonicalizeRuleKey(ruleKey);
|
|
34546
34442
|
return [nativeRuleKey, ...getLegacyRuleKeysForNative(nativeRuleKey)];
|
|
@@ -34550,12 +34446,182 @@ const stripDescriptionTail = (ruleList) => {
|
|
|
34550
34446
|
if (!descriptionMatch || descriptionMatch.index === void 0) return ruleList;
|
|
34551
34447
|
return ruleList.slice(0, descriptionMatch.index);
|
|
34552
34448
|
};
|
|
34553
|
-
const
|
|
34449
|
+
const tokenizeRuleList = (ruleList) => {
|
|
34554
34450
|
const trimmed = ruleList?.trim();
|
|
34555
|
-
if (!trimmed) return
|
|
34451
|
+
if (!trimmed) return [];
|
|
34556
34452
|
const ruleSection = stripDescriptionTail(trimmed).trim();
|
|
34557
|
-
if (!ruleSection) return
|
|
34558
|
-
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));
|
|
34559
34625
|
};
|
|
34560
34626
|
const DISABLE_LINE_PATTERN = /(?:\/\/|\/\*)\s*react-doctor-disable-line\b(?:\s+([^\r\n]*?))?\s*(?:\*\/)?\s*\}?\s*$/;
|
|
34561
34627
|
const formatLineGap = (gapLineCount) => `${gapLineCount} line${gapLineCount === 1 ? "" : "s"}`;
|
|
@@ -34599,7 +34665,7 @@ const evaluateSuppression = (lines, diagnosticLineIndex, ruleId) => {
|
|
|
34599
34665
|
};
|
|
34600
34666
|
return {
|
|
34601
34667
|
isSuppressed: false,
|
|
34602
|
-
nearMissHint: classifyFromComments([directComments, openerComments], diagnosticLineIndex, ruleId)
|
|
34668
|
+
nearMissHint: classifyFromComments([directComments, openerComments], diagnosticLineIndex, ruleId) ?? detectForeignDisableNearMiss(lines, diagnosticLineIndex, ruleId)
|
|
34603
34669
|
};
|
|
34604
34670
|
};
|
|
34605
34671
|
/**
|
|
@@ -35367,7 +35433,6 @@ const PACKAGE_JSON_FILENAME = "package.json";
|
|
|
35367
35433
|
const PACKAGE_JSON_CONFIG_KEY = "reactDoctor";
|
|
35368
35434
|
const LEGACY_CONFIG_FILENAME = "react-doctor.config.json";
|
|
35369
35435
|
const jiti = createJiti(import.meta.url);
|
|
35370
|
-
const formatError = (error) => error instanceof Error ? error.message : String(error);
|
|
35371
35436
|
const importDefaultExport = async (jitiInstance, filePath) => {
|
|
35372
35437
|
const imported = await jitiInstance.import(filePath);
|
|
35373
35438
|
return imported?.default ?? imported;
|
|
@@ -35399,7 +35464,7 @@ const loadModuleConfig = async (filePath) => {
|
|
|
35399
35464
|
try {
|
|
35400
35465
|
return await importDefaultExport(aliasJiti, filePath);
|
|
35401
35466
|
} catch (retryError) {
|
|
35402
|
-
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 });
|
|
35403
35468
|
}
|
|
35404
35469
|
}
|
|
35405
35470
|
};
|
|
@@ -35448,7 +35513,7 @@ const loadLegacyConfig = (directory) => {
|
|
|
35448
35513
|
}
|
|
35449
35514
|
warn(`${LEGACY_CONFIG_FILENAME} must contain an object, ignoring.`);
|
|
35450
35515
|
} catch (error) {
|
|
35451
|
-
warn(`Failed to load ${LEGACY_CONFIG_FILENAME}: ${
|
|
35516
|
+
warn(`Failed to load ${LEGACY_CONFIG_FILENAME}: ${messageFromUnknown(error)}`);
|
|
35452
35517
|
}
|
|
35453
35518
|
return {
|
|
35454
35519
|
status: "invalid",
|
|
@@ -35475,7 +35540,7 @@ const loadConfigFromDirectory = async (directory) => {
|
|
|
35475
35540
|
warn(`${CONFIG_BASENAME}.${extension} must export an object, ignoring.`);
|
|
35476
35541
|
sawBrokenConfigFile = true;
|
|
35477
35542
|
} catch (error) {
|
|
35478
|
-
warn(`Failed to load ${CONFIG_BASENAME}.${extension}: ${
|
|
35543
|
+
warn(`Failed to load ${CONFIG_BASENAME}.${extension}: ${messageFromUnknown(error)}`);
|
|
35479
35544
|
sawBrokenConfigFile = true;
|
|
35480
35545
|
}
|
|
35481
35546
|
}
|
|
@@ -35529,6 +35594,29 @@ const resolveConfigRootDir = (config, configSourceDirectory) => {
|
|
|
35529
35594
|
}
|
|
35530
35595
|
return resolvedRootDir;
|
|
35531
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
|
+
};
|
|
35532
35620
|
const getDirectDependencyNames = (packageJson) => new Set([...Object.keys(packageJson.dependencies ?? {}), ...Object.keys(packageJson.devDependencies ?? {})]);
|
|
35533
35621
|
const buildExpoCheckContext = (rootDirectory, expoVersion) => {
|
|
35534
35622
|
const packageJson = readPackageJson(Path.join(rootDirectory, "package.json"));
|
|
@@ -36655,7 +36743,7 @@ const readIgnoreFile = (filePath) => {
|
|
|
36655
36743
|
try {
|
|
36656
36744
|
content = NFS.readFileSync(filePath, "utf-8");
|
|
36657
36745
|
} catch (error) {
|
|
36658
|
-
const errnoCode = error
|
|
36746
|
+
const errnoCode = isErrnoException(error) ? error.code : void 0;
|
|
36659
36747
|
if (errnoCode && errnoCode !== "ENOENT") runSync(warn$1(`Could not read ignore file ${filePath}: ${errnoCode}`));
|
|
36660
36748
|
return [];
|
|
36661
36749
|
}
|
|
@@ -37214,15 +37302,13 @@ var DeadCode = class DeadCode extends Service()("react-doctor/DeadCode") {
|
|
|
37214
37302
|
})()) }));
|
|
37215
37303
|
static layerOf = (diagnostics) => succeed$3(DeadCode, DeadCode.of({ run: () => fromIterable$1(diagnostics) }));
|
|
37216
37304
|
};
|
|
37217
|
-
const createNodeReadFileLinesSync = (rootDirectory) => {
|
|
37218
|
-
|
|
37219
|
-
|
|
37220
|
-
|
|
37221
|
-
|
|
37222
|
-
|
|
37223
|
-
|
|
37224
|
-
}
|
|
37225
|
-
};
|
|
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
|
+
}
|
|
37226
37312
|
};
|
|
37227
37313
|
var Files = class Files extends Service()("react-doctor/Files") {
|
|
37228
37314
|
static layerNode = succeed$3(Files, Files.of({
|
|
@@ -37433,7 +37519,10 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37433
37519
|
directory: input.directory,
|
|
37434
37520
|
cause
|
|
37435
37521
|
}) });
|
|
37436
|
-
})
|
|
37522
|
+
}), withSpan("git.exec", { attributes: {
|
|
37523
|
+
"git.command": input.command,
|
|
37524
|
+
"git.subcommand": input.args[0] ?? ""
|
|
37525
|
+
} }));
|
|
37437
37526
|
const runGit = (directory, args) => runCommand({
|
|
37438
37527
|
command: "git",
|
|
37439
37528
|
args,
|
|
@@ -37461,7 +37550,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37461
37550
|
]);
|
|
37462
37551
|
if (candidates.status !== 0) return null;
|
|
37463
37552
|
return trimOrNull(candidates.stdout.split("\n")[0] ?? "");
|
|
37464
|
-
});
|
|
37553
|
+
}).pipe(withSpan("Git.defaultBranch"));
|
|
37465
37554
|
const branchExists = (directory, branch) => runGit(directory, [
|
|
37466
37555
|
"rev-parse",
|
|
37467
37556
|
"--verify",
|
|
@@ -37508,7 +37597,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37508
37597
|
const result = resultOption.value;
|
|
37509
37598
|
if (result.status !== 0) return null;
|
|
37510
37599
|
return parseGithubViewerPermission(result.stdout);
|
|
37511
|
-
}).pipe(catch_$1(() => succeed$2(null)));
|
|
37600
|
+
}).pipe(catch_$1(() => succeed$2(null)), withSpan("Git.githubViewerPermission"));
|
|
37512
37601
|
/**
|
|
37513
37602
|
* Resolves a `--diff A..B` / `A...B` commit range into a changed-file
|
|
37514
37603
|
* selection. Each endpoint is validated with `isSafeGitRevision`
|
|
@@ -37622,7 +37711,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37622
37711
|
changedFiles: splitNullSeparated(diff.stdout),
|
|
37623
37712
|
isCurrentChanges: false
|
|
37624
37713
|
};
|
|
37625
|
-
}),
|
|
37714
|
+
}).pipe(withSpan("Git.diffSelection")),
|
|
37626
37715
|
stagedFilePaths: (directory) => runGit(directory, [
|
|
37627
37716
|
"diff",
|
|
37628
37717
|
"--cached",
|
|
@@ -37664,7 +37753,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37664
37753
|
status: result.status,
|
|
37665
37754
|
stdout: result.stdout
|
|
37666
37755
|
};
|
|
37667
|
-
}),
|
|
37756
|
+
}).pipe(withSpan("Git.grep")),
|
|
37668
37757
|
changedLineRanges: ({ directory, baseRef, cached, files }) => gen(function* () {
|
|
37669
37758
|
if (files.length === 0) return [];
|
|
37670
37759
|
if (baseRef !== void 0 && !isSafeGitRevision(baseRef)) return null;
|
|
@@ -37680,7 +37769,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37680
37769
|
]);
|
|
37681
37770
|
if (result.status !== 0) return null;
|
|
37682
37771
|
return parseChangedLineRanges(result.stdout);
|
|
37683
|
-
})
|
|
37772
|
+
}).pipe(withSpan("Git.changedLineRanges"))
|
|
37684
37773
|
});
|
|
37685
37774
|
})).pipe(provide$2(layer$2.pipe(provide$2(mergeAll$1(layer$1, layer)))));
|
|
37686
37775
|
/**
|
|
@@ -37895,7 +37984,7 @@ const neutralizeDisableDirectives = async (rootDirectory, includePaths) => {
|
|
|
37895
37984
|
for (const [absolutePath, originalContent] of originalContents) try {
|
|
37896
37985
|
NFS.writeFileSync(absolutePath, originalContent);
|
|
37897
37986
|
} catch (error) {
|
|
37898
|
-
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`);
|
|
37899
37988
|
}
|
|
37900
37989
|
};
|
|
37901
37990
|
const onExit = () => restore();
|
|
@@ -38001,7 +38090,7 @@ const resolveUserPlugin = (spec, configSourceDirectory) => {
|
|
|
38001
38090
|
try {
|
|
38002
38091
|
resolvedSpecifier = isRelative ? Path.resolve(configSourceDirectory, spec) : candidateRequire.resolve(spec);
|
|
38003
38092
|
} catch (error) {
|
|
38004
|
-
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)}`);
|
|
38005
38094
|
return null;
|
|
38006
38095
|
}
|
|
38007
38096
|
const { name, ruleNames } = readPluginShape(resolvedSpecifier, (target) => candidateRequire(target));
|
|
@@ -38847,7 +38936,7 @@ const spawnOxlint = (args, rootDirectory, nodeBinaryPath, spawnTimeoutMs = OXLIN
|
|
|
38847
38936
|
child.kill("SIGKILL");
|
|
38848
38937
|
reject(new ReactDoctorError({ reason: new OxlintBatchExceeded({
|
|
38849
38938
|
kind: "timeout",
|
|
38850
|
-
detail: `${spawnTimeoutMs /
|
|
38939
|
+
detail: `${spawnTimeoutMs / MILLISECONDS_PER_SECOND}s budget exceeded`
|
|
38851
38940
|
}) }));
|
|
38852
38941
|
}, spawnTimeoutMs);
|
|
38853
38942
|
timeoutHandle.unref?.();
|
|
@@ -39969,17 +40058,17 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
39969
40058
|
}))))))));
|
|
39970
40059
|
const deadCodeFailureState = yield* get$2(deadCodeFailure);
|
|
39971
40060
|
const scanElapsedMilliseconds = Date.now() - scanStartTime;
|
|
39972
|
-
const scanElapsedSeconds = (scanElapsedMilliseconds /
|
|
40061
|
+
const scanElapsedSeconds = (scanElapsedMilliseconds / MILLISECONDS_PER_SECOND).toFixed(1);
|
|
39973
40062
|
if (!lintFailureState.didFail) if (deadCodeFailureState.didFail) yield* scanProgress.fail(DEAD_CODE_FAIL_TEXT);
|
|
39974
40063
|
else if (input.suppressScanSummary) yield* scanProgress.stop();
|
|
39975
40064
|
else yield* scanProgress.succeed(`Scanned ${scannedFilesLabel} in ${scanElapsedSeconds}s${workerCountSuffix}`);
|
|
39976
40065
|
yield* reporterService.finalize;
|
|
39977
|
-
const finalDiagnostics = [
|
|
40066
|
+
const finalDiagnostics = assignFixGroups([
|
|
39978
40067
|
...envCollected,
|
|
39979
40068
|
...supplyChainCollected,
|
|
39980
40069
|
...lintCollected,
|
|
39981
40070
|
...deadCodeCollected
|
|
39982
|
-
];
|
|
40071
|
+
]);
|
|
39983
40072
|
const githubViewerPermission = yield* join(githubViewerPermissionFiber);
|
|
39984
40073
|
const scoreMetadata = {
|
|
39985
40074
|
...repo !== null ? { repo } : {},
|
|
@@ -40183,7 +40272,7 @@ const materializeSourceTree = (input) => gen(function* () {
|
|
|
40183
40272
|
static layerNode = effect(StagedFiles, gen(function* () {
|
|
40184
40273
|
const git = yield* Git;
|
|
40185
40274
|
return StagedFiles.of({
|
|
40186
|
-
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")),
|
|
40187
40276
|
materialize: ({ directory, stagedFiles, tempDirectory }) => materializeSourceTree({
|
|
40188
40277
|
directory,
|
|
40189
40278
|
files: stagedFiles,
|
|
@@ -40193,7 +40282,7 @@ const materializeSourceTree = (input) => gen(function* () {
|
|
|
40193
40282
|
tempDirectory: tree.tempDirectory,
|
|
40194
40283
|
stagedFiles: tree.materializedFiles,
|
|
40195
40284
|
cleanup: tree.cleanup
|
|
40196
|
-
})))
|
|
40285
|
+
})), withSpan("StagedFiles.materialize"))
|
|
40197
40286
|
});
|
|
40198
40287
|
}));
|
|
40199
40288
|
/**
|
|
@@ -40261,7 +40350,10 @@ const runEditorScan = async (input) => {
|
|
|
40261
40350
|
isCi: false,
|
|
40262
40351
|
resolveLocalGithubViewerPermission: false,
|
|
40263
40352
|
skipJsxIncludeFilter: true
|
|
40264
|
-
}).pipe(
|
|
40353
|
+
}).pipe(withSpan("runEditorScan", { attributes: {
|
|
40354
|
+
"editor.lint": lint,
|
|
40355
|
+
"editor.runDeadCode": runDeadCode
|
|
40356
|
+
} }), provide(layers), provide(layerOtlp)));
|
|
40265
40357
|
if (isSuccess(exit)) {
|
|
40266
40358
|
const output = exit.value;
|
|
40267
40359
|
return {
|
|
@@ -40291,7 +40383,7 @@ const runEditorScan = async (input) => {
|
|
|
40291
40383
|
didDeadCodeFail: false,
|
|
40292
40384
|
deadCodeFailureReason: null,
|
|
40293
40385
|
lintPartialFailures: [],
|
|
40294
|
-
error:
|
|
40386
|
+
error: messageFromUnknown(error)
|
|
40295
40387
|
};
|
|
40296
40388
|
};
|
|
40297
40389
|
/**
|
|
@@ -40573,7 +40665,6 @@ const toLspDiagnostic = (input) => {
|
|
|
40573
40665
|
data
|
|
40574
40666
|
};
|
|
40575
40667
|
};
|
|
40576
|
-
const toUri = (absoluteFilePath) => fsPathToUri(absoluteFilePath);
|
|
40577
40668
|
/**
|
|
40578
40669
|
* Owns the published-diagnostic state. Maps scan outcomes to LSP
|
|
40579
40670
|
* diagnostics, publishes complete per-URI replacement sets (so the
|
|
@@ -40603,7 +40694,7 @@ var DiagnosticsManager = class {
|
|
|
40603
40694
|
const isProtectedPath = (fsPath) => protectOpen && this.isOpen(fsPath);
|
|
40604
40695
|
for (const [fsPath, coreDiagnostics] of outcome.byFile) {
|
|
40605
40696
|
if (isProtectedPath(fsPath)) continue;
|
|
40606
|
-
const uri =
|
|
40697
|
+
const uri = fsPathToUri(fsPath);
|
|
40607
40698
|
const text = this.textProvider(fsPath);
|
|
40608
40699
|
const lspDiagnostics = coreDiagnostics.map((diagnostic) => toLspDiagnostic({
|
|
40609
40700
|
diagnostic,
|
|
@@ -40625,7 +40716,7 @@ var DiagnosticsManager = class {
|
|
|
40625
40716
|
for (const fsPath of outcome.requestedPaths) {
|
|
40626
40717
|
if (isProtectedPath(fsPath)) continue;
|
|
40627
40718
|
if (outcome.byFile.has(fsPath)) continue;
|
|
40628
|
-
const uri =
|
|
40719
|
+
const uri = fsPathToUri(fsPath);
|
|
40629
40720
|
if (this.byUri.has(uri)) this.byUri.delete(uri);
|
|
40630
40721
|
this.publish(uri, []);
|
|
40631
40722
|
}
|
|
@@ -40650,7 +40741,7 @@ var DiagnosticsManager = class {
|
|
|
40650
40741
|
const set = this.projectUris.get(project) ?? /* @__PURE__ */ new Set();
|
|
40651
40742
|
for (const uri of liveUris) set.add(uri);
|
|
40652
40743
|
for (const fsPath of outcome.requestedPaths) {
|
|
40653
|
-
const uri =
|
|
40744
|
+
const uri = fsPathToUri(fsPath);
|
|
40654
40745
|
if (!liveUris.has(uri)) set.delete(uri);
|
|
40655
40746
|
}
|
|
40656
40747
|
this.projectUris.set(project, set);
|
|
@@ -40678,7 +40769,7 @@ var DiagnosticsManager = class {
|
|
|
40678
40769
|
const tracked = this.projectUris.get(project);
|
|
40679
40770
|
if (!tracked) return;
|
|
40680
40771
|
const liveUris = /* @__PURE__ */ new Set();
|
|
40681
|
-
for (const fsPath of liveFsPaths) liveUris.add(
|
|
40772
|
+
for (const fsPath of liveFsPaths) liveUris.add(fsPathToUri(fsPath));
|
|
40682
40773
|
for (const uri of [...tracked]) {
|
|
40683
40774
|
if (liveUris.has(uri)) continue;
|
|
40684
40775
|
this.byUri.delete(uri);
|
|
@@ -40975,7 +41066,7 @@ const createProjectGraph = (options) => {
|
|
|
40975
41066
|
});
|
|
40976
41067
|
}
|
|
40977
41068
|
} catch (error) {
|
|
40978
|
-
logger.warn(`Project discovery failed for ${root}: ${
|
|
41069
|
+
logger.warn(`Project discovery failed for ${root}: ${messageFromUnknown(error)}`);
|
|
40979
41070
|
}
|
|
40980
41071
|
return [...seen.values()].sort((first, second) => second.directory.length - first.directory.length);
|
|
40981
41072
|
};
|
|
@@ -41042,7 +41133,7 @@ const createLintCache = (input) => {
|
|
|
41042
41133
|
fs.writeFileSync(tempPath, JSON.stringify(payload));
|
|
41043
41134
|
fs.renameSync(tempPath, cacheFilePath);
|
|
41044
41135
|
} catch (error) {
|
|
41045
|
-
logger.warn(`Failed to persist lint cache: ${
|
|
41136
|
+
logger.warn(`Failed to persist lint cache: ${messageFromUnknown(error)}`);
|
|
41046
41137
|
}
|
|
41047
41138
|
};
|
|
41048
41139
|
return {
|
|
@@ -41350,7 +41441,7 @@ const createScheduler = (options) => {
|
|
|
41350
41441
|
if (outcome && !token.isCancelled) options.onResult(outcome);
|
|
41351
41442
|
}).catch((error) => {
|
|
41352
41443
|
if (options.onError) options.onError(error, request);
|
|
41353
|
-
else logger.error(`Scan failed: ${
|
|
41444
|
+
else logger.error(`Scan failed: ${messageFromUnknown(error)}`);
|
|
41354
41445
|
}).finally(() => {
|
|
41355
41446
|
running -= 1;
|
|
41356
41447
|
if (isBackground) runningBackground -= 1;
|
|
@@ -41737,7 +41828,7 @@ const createServer = (connection, options = {}) => {
|
|
|
41737
41828
|
maybeWarnLintUnavailable(outcome);
|
|
41738
41829
|
if (outcome.request.priority === "background") scanTelemetry.accumulate(outcome);
|
|
41739
41830
|
},
|
|
41740
|
-
onError: (error, request) => logger.error(`Scan of ${request.projectDirectory} threw: ${
|
|
41831
|
+
onError: (error, request) => logger.error(`Scan of ${request.projectDirectory} threw: ${messageFromUnknown(error)}`),
|
|
41741
41832
|
onIdleChange: (idle) => {
|
|
41742
41833
|
setBusy(!idle);
|
|
41743
41834
|
if (idle) scanTelemetry.finish();
|
|
@@ -42385,5 +42476,5 @@ const startLanguageServer = () => {
|
|
|
42385
42476
|
};
|
|
42386
42477
|
//#endregion
|
|
42387
42478
|
export { startLanguageServer };
|
|
42388
|
-
!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]="
|
|
42389
|
-
//# 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]="6fbf847f-43b8-5c5c-ba97-c26c2e08e250")}catch(e){}}();
|
|
42480
|
+
//# debugId=6fbf847f-43b8-5c5c-ba97-c26c2e08e250
|