react-doctor 0.5.6-dev.451beeb → 0.5.6-dev.4e06b2a
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 +470 -260
- package/dist/index.d.ts +10 -0
- package/dist/index.js +96 -70
- package/dist/lsp.js +114 -92
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -9794,6 +9794,16 @@ interface JsonReportProjectEntry {
|
|
|
9794
9794
|
skippedChecks: string[];
|
|
9795
9795
|
/** Human-readable explanation per skipped check. See `InspectResult.skippedCheckReasons`. */
|
|
9796
9796
|
skippedCheckReasons?: Record<string, string>;
|
|
9797
|
+
/**
|
|
9798
|
+
* Number of source files this scan's linter examined. In diff / changed
|
|
9799
|
+
* mode it's the count of changed React-eligible files (`.tsx`/`.jsx` plus
|
|
9800
|
+
* framework entry files); in a full scan it's the whole source tree. `0`
|
|
9801
|
+
* in a diff scan means the changed files held nothing React Doctor lints —
|
|
9802
|
+
* the GitHub Action reads that as "nothing to report" (skips the PR comment;
|
|
9803
|
+
* the commit status says "skipped"). Optional: absent on reports from
|
|
9804
|
+
* constructors that don't track it (e.g. `toJsonReport`).
|
|
9805
|
+
*/
|
|
9806
|
+
scannedFileCount?: number;
|
|
9797
9807
|
elapsedMilliseconds: number;
|
|
9798
9808
|
}
|
|
9799
9809
|
interface JsonReportSummary {
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="efaa91ed-3659-50a5-b802-51753472b2d6")}catch(e){}}();
|
|
3
3
|
import { r as __toESM$1, t as __commonJSMin$1 } from "./chunk-N93fKeF6.js";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import * as NFS from "node:fs";
|
|
@@ -19298,6 +19298,7 @@ var JsonReportProjectEntry = class extends Class("JsonReportProjectEntry")({
|
|
|
19298
19298
|
score: Unknown,
|
|
19299
19299
|
skippedChecks: ArraySchema(String$1),
|
|
19300
19300
|
skippedCheckReasons: optional(Record$1(String$1, String$1)),
|
|
19301
|
+
scannedFileCount: optional(Number$1),
|
|
19301
19302
|
elapsedMilliseconds: Number$1
|
|
19302
19303
|
}) {};
|
|
19303
19304
|
/**
|
|
@@ -32724,6 +32725,7 @@ const isLargeMinifiedFile = (absolutePath) => {
|
|
|
32724
32725
|
if (sizeBytes < 2e4) return false;
|
|
32725
32726
|
return isMinifiedSource(absolutePath);
|
|
32726
32727
|
};
|
|
32728
|
+
const isErrnoException = (error) => error instanceof Error && "code" in error;
|
|
32727
32729
|
const IGNORABLE_READDIR_ERROR_CODES = new Set([
|
|
32728
32730
|
"EACCES",
|
|
32729
32731
|
"EPERM",
|
|
@@ -32733,11 +32735,7 @@ const IGNORABLE_READDIR_ERROR_CODES = new Set([
|
|
|
32733
32735
|
"ELOOP",
|
|
32734
32736
|
"ENAMETOOLONG"
|
|
32735
32737
|
]);
|
|
32736
|
-
const isIgnorableReaddirError = (error) =>
|
|
32737
|
-
if (typeof error !== "object" || error === null) return false;
|
|
32738
|
-
const errorCode = error.code;
|
|
32739
|
-
return typeof errorCode === "string" && IGNORABLE_READDIR_ERROR_CODES.has(errorCode);
|
|
32740
|
-
};
|
|
32738
|
+
const isIgnorableReaddirError = (error) => isErrnoException(error) && typeof error.code === "string" && IGNORABLE_READDIR_ERROR_CODES.has(error.code);
|
|
32741
32739
|
const readDirectoryEntries = (directoryPath) => {
|
|
32742
32740
|
try {
|
|
32743
32741
|
return NFS.readdirSync(directoryPath, { withFileTypes: true });
|
|
@@ -32787,7 +32785,7 @@ const readPackageJsonUncached = (packageJsonPath) => {
|
|
|
32787
32785
|
return JSON.parse(NFS.readFileSync(packageJsonPath, "utf-8"));
|
|
32788
32786
|
} catch (error) {
|
|
32789
32787
|
if (error instanceof SyntaxError) return {};
|
|
32790
|
-
if (error
|
|
32788
|
+
if (isErrnoException(error)) {
|
|
32791
32789
|
const { code } = error;
|
|
32792
32790
|
if (code === "EISDIR" || code === "EACCES" || code === "EPERM" || code === "ENOENT") return {};
|
|
32793
32791
|
}
|
|
@@ -33512,17 +33510,13 @@ const isPackageJsonReactNativeAware = (packageJson) => {
|
|
|
33512
33510
|
return false;
|
|
33513
33511
|
};
|
|
33514
33512
|
const hasReactNativeWorkspaceAnywhere = (rootDirectory, rootPackageJson) => someWorkspacePackageJson(rootDirectory, rootPackageJson, isPackageJsonReactNativeAware);
|
|
33515
|
-
const
|
|
33516
|
-
const spec = packageJson.dependencies?.
|
|
33513
|
+
const getDependencySpec = (packageJson, packageName) => {
|
|
33514
|
+
const spec = packageJson.dependencies?.[packageName] ?? packageJson.devDependencies?.[packageName] ?? packageJson.peerDependencies?.[packageName] ?? packageJson.optionalDependencies?.[packageName];
|
|
33517
33515
|
return typeof spec === "string" ? spec : null;
|
|
33518
33516
|
};
|
|
33519
|
-
const findExpoVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson,
|
|
33517
|
+
const findExpoVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, "expo"));
|
|
33520
33518
|
const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
|
|
33521
|
-
const
|
|
33522
|
-
const spec = packageJson.dependencies?.["@shopify/flash-list"] ?? packageJson.devDependencies?.["@shopify/flash-list"] ?? packageJson.peerDependencies?.["@shopify/flash-list"] ?? packageJson.optionalDependencies?.["@shopify/flash-list"];
|
|
33523
|
-
return typeof spec === "string" ? spec : null;
|
|
33524
|
-
};
|
|
33525
|
-
const findShopifyFlashListVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, getShopifyFlashListDependencySpec);
|
|
33519
|
+
const findShopifyFlashListVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, SHOPIFY_FLASH_LIST_PACKAGE_NAME));
|
|
33526
33520
|
const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, version }) => {
|
|
33527
33521
|
if (version === null || !isCatalogReference(version)) return version;
|
|
33528
33522
|
const catalogName = extractCatalogName(version);
|
|
@@ -33534,11 +33528,7 @@ const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson,
|
|
|
33534
33528
|
if (!isFile(monorepoPackageJsonPath)) return version;
|
|
33535
33529
|
return resolveCatalogVersion(readPackageJson(monorepoPackageJsonPath), packageName, monorepoRoot, catalogName) ?? version;
|
|
33536
33530
|
};
|
|
33537
|
-
const
|
|
33538
|
-
const spec = packageJson.dependencies?.next ?? packageJson.devDependencies?.next ?? packageJson.peerDependencies?.next ?? packageJson.optionalDependencies?.next;
|
|
33539
|
-
return typeof spec === "string" ? spec : null;
|
|
33540
|
-
};
|
|
33541
|
-
const findNextjsVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, getNextjsDependencySpec);
|
|
33531
|
+
const findNextjsVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, "next"));
|
|
33542
33532
|
const getPreactVersion = (packageJson) => {
|
|
33543
33533
|
return {
|
|
33544
33534
|
...packageJson.peerDependencies,
|
|
@@ -33620,6 +33610,11 @@ const ES_TARGET_YEAR_BY_NAME = {
|
|
|
33620
33610
|
esnext: 9999
|
|
33621
33611
|
};
|
|
33622
33612
|
/**
|
|
33613
|
+
* tsconfig filenames probed when resolving a project's TypeScript
|
|
33614
|
+
* compiler options — the root config first, then a monorepo base config.
|
|
33615
|
+
*/
|
|
33616
|
+
const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
|
|
33617
|
+
/**
|
|
33623
33618
|
* Project-config files that `StagedFiles.materialize` copies into
|
|
33624
33619
|
* the temp directory alongside staged sources so oxlint resolves
|
|
33625
33620
|
* `tsconfig` / `package.json` / lint configs the same way it would
|
|
@@ -34118,6 +34113,7 @@ const isTailwindAtLeast = (detected, required) => {
|
|
|
34118
34113
|
if (detected.major !== required.major) return detected.major > required.major;
|
|
34119
34114
|
return detected.minor >= required.minor;
|
|
34120
34115
|
};
|
|
34116
|
+
const messageFromUnknown = (error) => error instanceof Error ? error.message : String(error);
|
|
34121
34117
|
var InvalidGlobPatternError = class extends Error {
|
|
34122
34118
|
pattern;
|
|
34123
34119
|
reason;
|
|
@@ -34146,7 +34142,7 @@ const compileGlobPattern = (rawPattern) => {
|
|
|
34146
34142
|
try {
|
|
34147
34143
|
return import_picomatch.default.makeRe(normalizeGlobPattern(rawPattern), PICOMATCH_OPTIONS);
|
|
34148
34144
|
} catch (caughtError) {
|
|
34149
|
-
throw new InvalidGlobPatternError(rawPattern,
|
|
34145
|
+
throw new InvalidGlobPatternError(rawPattern, messageFromUnknown(caughtError));
|
|
34150
34146
|
}
|
|
34151
34147
|
};
|
|
34152
34148
|
const compileGlobPatternsLenient = (patterns, onInvalid) => {
|
|
@@ -35328,7 +35324,6 @@ const PACKAGE_JSON_FILENAME = "package.json";
|
|
|
35328
35324
|
const PACKAGE_JSON_CONFIG_KEY = "reactDoctor";
|
|
35329
35325
|
const LEGACY_CONFIG_FILENAME = "react-doctor.config.json";
|
|
35330
35326
|
const jiti = createJiti(import.meta.url);
|
|
35331
|
-
const formatError = (error) => error instanceof Error ? error.message : String(error);
|
|
35332
35327
|
const importDefaultExport = async (jitiInstance, filePath) => {
|
|
35333
35328
|
const imported = await jitiInstance.import(filePath);
|
|
35334
35329
|
return imported?.default ?? imported;
|
|
@@ -35360,7 +35355,7 @@ const loadModuleConfig = async (filePath) => {
|
|
|
35360
35355
|
try {
|
|
35361
35356
|
return await importDefaultExport(aliasJiti, filePath);
|
|
35362
35357
|
} catch (retryError) {
|
|
35363
|
-
throw new Error(`${
|
|
35358
|
+
throw new Error(`${messageFromUnknown(error)} (retry with ${SELF_PACKAGE_IMPORT_SPECIFIER} aliased to the running react-doctor package also failed: ${messageFromUnknown(retryError)})`, { cause: retryError });
|
|
35364
35359
|
}
|
|
35365
35360
|
}
|
|
35366
35361
|
};
|
|
@@ -35409,7 +35404,7 @@ const loadLegacyConfig = (directory) => {
|
|
|
35409
35404
|
}
|
|
35410
35405
|
warn(`${LEGACY_CONFIG_FILENAME} must contain an object, ignoring.`);
|
|
35411
35406
|
} catch (error) {
|
|
35412
|
-
warn(`Failed to load ${LEGACY_CONFIG_FILENAME}: ${
|
|
35407
|
+
warn(`Failed to load ${LEGACY_CONFIG_FILENAME}: ${messageFromUnknown(error)}`);
|
|
35413
35408
|
}
|
|
35414
35409
|
return {
|
|
35415
35410
|
status: "invalid",
|
|
@@ -35436,7 +35431,7 @@ const loadConfigFromDirectory = async (directory) => {
|
|
|
35436
35431
|
warn(`${CONFIG_BASENAME}.${extension} must export an object, ignoring.`);
|
|
35437
35432
|
sawBrokenConfigFile = true;
|
|
35438
35433
|
} catch (error) {
|
|
35439
|
-
warn(`Failed to load ${CONFIG_BASENAME}.${extension}: ${
|
|
35434
|
+
warn(`Failed to load ${CONFIG_BASENAME}.${extension}: ${messageFromUnknown(error)}`);
|
|
35440
35435
|
sawBrokenConfigFile = true;
|
|
35441
35436
|
}
|
|
35442
35437
|
}
|
|
@@ -36664,7 +36659,7 @@ const readIgnoreFile = (filePath) => {
|
|
|
36664
36659
|
try {
|
|
36665
36660
|
content = NFS.readFileSync(filePath, "utf-8");
|
|
36666
36661
|
} catch (error) {
|
|
36667
|
-
const errnoCode = error
|
|
36662
|
+
const errnoCode = isErrnoException(error) ? error.code : void 0;
|
|
36668
36663
|
if (errnoCode && errnoCode !== "ENOENT") runSync(warn$1(`Could not read ignore file ${filePath}: ${errnoCode}`));
|
|
36669
36664
|
return [];
|
|
36670
36665
|
}
|
|
@@ -36705,8 +36700,8 @@ const collectIgnorePatterns = (rootDirectory) => {
|
|
|
36705
36700
|
cachedPatternsByRoot.set(rootDirectory, patterns);
|
|
36706
36701
|
return patterns;
|
|
36707
36702
|
};
|
|
36703
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36708
36704
|
const KNIP_JSON_FILENAME = "knip.json";
|
|
36709
|
-
const isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36710
36705
|
const readJsonFileSafe = (filePath) => {
|
|
36711
36706
|
let rawContents;
|
|
36712
36707
|
try {
|
|
@@ -36722,10 +36717,10 @@ const readJsonFileSafe = (filePath) => {
|
|
|
36722
36717
|
};
|
|
36723
36718
|
const readKnipConfig = (rootDirectory) => {
|
|
36724
36719
|
const knipJson = readJsonFileSafe(path.join(rootDirectory, KNIP_JSON_FILENAME));
|
|
36725
|
-
if (isRecord
|
|
36720
|
+
if (isRecord(knipJson)) return knipJson;
|
|
36726
36721
|
const packageJson = readJsonFileSafe(path.join(rootDirectory, "package.json"));
|
|
36727
|
-
const packageKnipConfig = isRecord
|
|
36728
|
-
return isRecord
|
|
36722
|
+
const packageKnipConfig = isRecord(packageJson) ? packageJson.knip : null;
|
|
36723
|
+
return isRecord(packageKnipConfig) ? packageKnipConfig : null;
|
|
36729
36724
|
};
|
|
36730
36725
|
const normalizePatternList = (value) => {
|
|
36731
36726
|
if (typeof value === "string" && value.length > 0) return [value];
|
|
@@ -36737,10 +36732,10 @@ const prefixWorkspacePatterns = (workspacePattern, patterns) => {
|
|
|
36737
36732
|
return patterns.map((pattern) => pattern.startsWith("!") ? `!${normalizedWorkspacePattern}/${pattern.slice(1)}` : `${normalizedWorkspacePattern}/${pattern}`);
|
|
36738
36733
|
};
|
|
36739
36734
|
const collectKnipWorkspacePatterns = (workspaces, settingName) => {
|
|
36740
|
-
if (!isRecord
|
|
36735
|
+
if (!isRecord(workspaces)) return [];
|
|
36741
36736
|
const patterns = [];
|
|
36742
36737
|
for (const [workspacePattern, workspaceConfig] of Object.entries(workspaces)) {
|
|
36743
|
-
if (!isRecord
|
|
36738
|
+
if (!isRecord(workspaceConfig)) continue;
|
|
36744
36739
|
patterns.push(...prefixWorkspacePatterns(workspacePattern, normalizePatternList(workspaceConfig[settingName])));
|
|
36745
36740
|
}
|
|
36746
36741
|
return patterns;
|
|
@@ -36785,8 +36780,6 @@ const toCanonicalPath = (filePath) => {
|
|
|
36785
36780
|
};
|
|
36786
36781
|
const DEAD_CODE_PLUGIN = "deslop";
|
|
36787
36782
|
const DEAD_CODE_CATEGORY = "Maintainability";
|
|
36788
|
-
const TSCONFIG_FILENAMES$1 = ["tsconfig.json", "tsconfig.base.json"];
|
|
36789
|
-
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36790
36783
|
const DEAD_CODE_WORKER_SCRIPT = `
|
|
36791
36784
|
const inputChunks = [];
|
|
36792
36785
|
process.stdin.on("data", (chunk) => inputChunks.push(chunk));
|
|
@@ -36844,7 +36837,7 @@ process.stdin.on("end", () => {
|
|
|
36844
36837
|
});
|
|
36845
36838
|
`;
|
|
36846
36839
|
const resolveTsConfigPath = (rootDirectory) => {
|
|
36847
|
-
for (const filename of TSCONFIG_FILENAMES
|
|
36840
|
+
for (const filename of TSCONFIG_FILENAMES) {
|
|
36848
36841
|
const candidate = Path.join(rootDirectory, filename);
|
|
36849
36842
|
if (NFS.existsSync(candidate)) return candidate;
|
|
36850
36843
|
}
|
|
@@ -37225,15 +37218,13 @@ var DeadCode = class DeadCode extends Service()("react-doctor/DeadCode") {
|
|
|
37225
37218
|
})()) }));
|
|
37226
37219
|
static layerOf = (diagnostics) => succeed$3(DeadCode, DeadCode.of({ run: () => fromIterable$1(diagnostics) }));
|
|
37227
37220
|
};
|
|
37228
|
-
const createNodeReadFileLinesSync = (rootDirectory) => {
|
|
37229
|
-
|
|
37230
|
-
|
|
37231
|
-
|
|
37232
|
-
|
|
37233
|
-
|
|
37234
|
-
|
|
37235
|
-
}
|
|
37236
|
-
};
|
|
37221
|
+
const createNodeReadFileLinesSync = (rootDirectory) => (filePath) => {
|
|
37222
|
+
const absolutePath = Path.isAbsolute(filePath) ? filePath : Path.join(rootDirectory, filePath);
|
|
37223
|
+
try {
|
|
37224
|
+
return NFS.readFileSync(absolutePath, "utf-8").split("\n");
|
|
37225
|
+
} catch {
|
|
37226
|
+
return null;
|
|
37227
|
+
}
|
|
37237
37228
|
};
|
|
37238
37229
|
var Files = class Files extends Service()("react-doctor/Files") {
|
|
37239
37230
|
static layerNode = succeed$3(Files, Files.of({
|
|
@@ -37444,7 +37435,10 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37444
37435
|
directory: input.directory,
|
|
37445
37436
|
cause
|
|
37446
37437
|
}) });
|
|
37447
|
-
})
|
|
37438
|
+
}), withSpan("git.exec", { attributes: {
|
|
37439
|
+
"git.command": input.command,
|
|
37440
|
+
"git.subcommand": input.args[0] ?? ""
|
|
37441
|
+
} }));
|
|
37448
37442
|
const runGit = (directory, args) => runCommand({
|
|
37449
37443
|
command: "git",
|
|
37450
37444
|
args,
|
|
@@ -37472,7 +37466,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37472
37466
|
]);
|
|
37473
37467
|
if (candidates.status !== 0) return null;
|
|
37474
37468
|
return trimOrNull(candidates.stdout.split("\n")[0] ?? "");
|
|
37475
|
-
});
|
|
37469
|
+
}).pipe(withSpan("Git.defaultBranch"));
|
|
37476
37470
|
const branchExists = (directory, branch) => runGit(directory, [
|
|
37477
37471
|
"rev-parse",
|
|
37478
37472
|
"--verify",
|
|
@@ -37519,7 +37513,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37519
37513
|
const result = resultOption.value;
|
|
37520
37514
|
if (result.status !== 0) return null;
|
|
37521
37515
|
return parseGithubViewerPermission(result.stdout);
|
|
37522
|
-
}).pipe(catch_$1(() => succeed$2(null)));
|
|
37516
|
+
}).pipe(catch_$1(() => succeed$2(null)), withSpan("Git.githubViewerPermission"));
|
|
37523
37517
|
/**
|
|
37524
37518
|
* Resolves a `--diff A..B` / `A...B` commit range into a changed-file
|
|
37525
37519
|
* selection. Each endpoint is validated with `isSafeGitRevision`
|
|
@@ -37633,7 +37627,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37633
37627
|
changedFiles: splitNullSeparated(diff.stdout),
|
|
37634
37628
|
isCurrentChanges: false
|
|
37635
37629
|
};
|
|
37636
|
-
}),
|
|
37630
|
+
}).pipe(withSpan("Git.diffSelection")),
|
|
37637
37631
|
stagedFilePaths: (directory) => runGit(directory, [
|
|
37638
37632
|
"diff",
|
|
37639
37633
|
"--cached",
|
|
@@ -37675,7 +37669,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37675
37669
|
status: result.status,
|
|
37676
37670
|
stdout: result.stdout
|
|
37677
37671
|
};
|
|
37678
|
-
}),
|
|
37672
|
+
}).pipe(withSpan("Git.grep")),
|
|
37679
37673
|
changedLineRanges: ({ directory, baseRef, cached, files }) => gen(function* () {
|
|
37680
37674
|
if (files.length === 0) return [];
|
|
37681
37675
|
if (baseRef !== void 0 && !isSafeGitRevision(baseRef)) return null;
|
|
@@ -37691,7 +37685,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37691
37685
|
]);
|
|
37692
37686
|
if (result.status !== 0) return null;
|
|
37693
37687
|
return parseChangedLineRanges(result.stdout);
|
|
37694
|
-
})
|
|
37688
|
+
}).pipe(withSpan("Git.changedLineRanges"))
|
|
37695
37689
|
});
|
|
37696
37690
|
})).pipe(provide$2(layer$2.pipe(provide$2(mergeAll$1(layer$1, layer)))));
|
|
37697
37691
|
/**
|
|
@@ -37906,7 +37900,7 @@ const neutralizeDisableDirectives = async (rootDirectory, includePaths) => {
|
|
|
37906
37900
|
for (const [absolutePath, originalContent] of originalContents) try {
|
|
37907
37901
|
NFS.writeFileSync(absolutePath, originalContent);
|
|
37908
37902
|
} catch (error) {
|
|
37909
|
-
process.stderr.write(`[react-doctor] Failed to restore inline disable directives in ${absolutePath}: ${
|
|
37903
|
+
process.stderr.write(`[react-doctor] Failed to restore inline disable directives in ${absolutePath}: ${messageFromUnknown(error)}\n[react-doctor] Run: git checkout -- ${absolutePath}\n`);
|
|
37910
37904
|
}
|
|
37911
37905
|
};
|
|
37912
37906
|
const onExit = () => restore();
|
|
@@ -38012,7 +38006,7 @@ const resolveUserPlugin = (spec, configSourceDirectory) => {
|
|
|
38012
38006
|
try {
|
|
38013
38007
|
resolvedSpecifier = isRelative ? Path.resolve(configSourceDirectory, spec) : candidateRequire.resolve(spec);
|
|
38014
38008
|
} catch (error) {
|
|
38015
|
-
warnConfigIssue(`config.plugins entry "${spec}" could not be resolved from ${configSourceDirectory}: ${
|
|
38009
|
+
warnConfigIssue(`config.plugins entry "${spec}" could not be resolved from ${configSourceDirectory}: ${messageFromUnknown(error)}`);
|
|
38016
38010
|
return null;
|
|
38017
38011
|
}
|
|
38018
38012
|
const { name, ruleNames } = readPluginShape(resolvedSpecifier, (target) => candidateRequire(target));
|
|
@@ -38084,8 +38078,8 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
38084
38078
|
}
|
|
38085
38079
|
return enabled;
|
|
38086
38080
|
};
|
|
38087
|
-
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [] }) => {
|
|
38088
|
-
const reactHooksJsPlugin = resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
|
|
38081
|
+
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false }) => {
|
|
38082
|
+
const reactHooksJsPlugin = disableReactHooksJsPlugin ? null : resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
|
|
38089
38083
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
38090
38084
|
const jsPlugins = [];
|
|
38091
38085
|
if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
|
|
@@ -38145,7 +38139,6 @@ const resolveOxlintBinary = () => {
|
|
|
38145
38139
|
return Path.join(oxlintPackageDirectory, "bin", "oxlint");
|
|
38146
38140
|
};
|
|
38147
38141
|
const resolvePluginPath = () => esmRequire.resolve("oxlint-plugin-react-doctor");
|
|
38148
|
-
const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
|
|
38149
38142
|
const resolveTsConfigRelativePath = (rootDirectory) => {
|
|
38150
38143
|
for (const filename of TSCONFIG_FILENAMES) if (NFS.existsSync(Path.join(rootDirectory, filename))) return `./${filename}`;
|
|
38151
38144
|
return null;
|
|
@@ -38517,7 +38510,7 @@ const scopeContainsNonImportBinding = (node, scopeNode, identifierName) => {
|
|
|
38517
38510
|
const isIdentifierShadowedByLocalBinding = (identifier, sourceFile) => {
|
|
38518
38511
|
let currentNode = identifier.parent;
|
|
38519
38512
|
while (currentNode) {
|
|
38520
|
-
if (
|
|
38513
|
+
if (isScopeBoundary(currentNode)) {
|
|
38521
38514
|
if (scopeContainsNonImportBinding(currentNode, currentNode, identifier.text)) return true;
|
|
38522
38515
|
}
|
|
38523
38516
|
if (currentNode === sourceFile) return false;
|
|
@@ -38608,11 +38601,10 @@ const findResolutionInScope = (scopeNode, identifierName, reactImportBindings, s
|
|
|
38608
38601
|
});
|
|
38609
38602
|
return resolution;
|
|
38610
38603
|
};
|
|
38611
|
-
const isScopeNode = isScopeBoundary;
|
|
38612
38604
|
const resolveIdentifierBinding = (identifier, reactImportBindings, sourceFile, visitedDeclarations = /* @__PURE__ */ new Set()) => {
|
|
38613
38605
|
let currentNode = identifier.parent;
|
|
38614
38606
|
while (currentNode) {
|
|
38615
|
-
if (
|
|
38607
|
+
if (isScopeBoundary(currentNode)) {
|
|
38616
38608
|
const resolution = findResolutionInScope(currentNode, identifier.text, reactImportBindings, sourceFile, visitedDeclarations);
|
|
38617
38609
|
if (resolution) return resolution;
|
|
38618
38610
|
}
|
|
@@ -38782,9 +38774,9 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
38782
38774
|
try {
|
|
38783
38775
|
parsed = JSON.parse(sanitizedStdout);
|
|
38784
38776
|
} catch {
|
|
38785
|
-
throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0,
|
|
38777
|
+
throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
38786
38778
|
}
|
|
38787
|
-
if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0,
|
|
38779
|
+
if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
38788
38780
|
const minifiedFileCache = /* @__PURE__ */ new Map();
|
|
38789
38781
|
const isMinifiedDiagnosticFile = (filename) => {
|
|
38790
38782
|
const absolutePath = Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
|
|
@@ -38860,7 +38852,7 @@ const spawnOxlint = (args, rootDirectory, nodeBinaryPath, spawnTimeoutMs = OXLIN
|
|
|
38860
38852
|
child.kill("SIGKILL");
|
|
38861
38853
|
reject(new ReactDoctorError({ reason: new OxlintBatchExceeded({
|
|
38862
38854
|
kind: "timeout",
|
|
38863
|
-
detail: `${spawnTimeoutMs /
|
|
38855
|
+
detail: `${spawnTimeoutMs / MILLISECONDS_PER_SECOND}s budget exceeded`
|
|
38864
38856
|
}) }));
|
|
38865
38857
|
}, spawnTimeoutMs);
|
|
38866
38858
|
timeoutHandle.unref?.();
|
|
@@ -39075,6 +39067,28 @@ const writeOxlintConfig = (configPath, configToWrite) => {
|
|
|
39075
39067
|
NFS.closeSync(fileHandle);
|
|
39076
39068
|
}
|
|
39077
39069
|
};
|
|
39070
|
+
const REACT_HOOKS_JS_DROP_PREFIX = "React Compiler rules (react-hooks-js/*) skipped — eslint-plugin-react-hooks failed to load in this environment";
|
|
39071
|
+
/**
|
|
39072
|
+
* Detects an oxlint config-load crash caused by the optional
|
|
39073
|
+
* `react-hooks-js` (eslint-plugin-react-hooks) React Compiler plugin and
|
|
39074
|
+
* builds the partial-failure note for it; returns `null` when the failure
|
|
39075
|
+
* was anything else.
|
|
39076
|
+
*
|
|
39077
|
+
* oxlint prints a framed error to stdout (not stderr) and exits non-zero
|
|
39078
|
+
* when a `jsPlugins` entry can't be imported; that non-JSON stdout
|
|
39079
|
+
* surfaces as `OxlintOutputUnparseable`. Because oxlint fails the WHOLE
|
|
39080
|
+
* config load on it, leaving the plugin in would drop every curated
|
|
39081
|
+
* react-doctor diagnostic too — so the caller retries with the plugin
|
|
39082
|
+
* stripped (issue #833). Both markers sit at the start of oxlint's
|
|
39083
|
+
* message, so they survive the `preview` slice even for deep pnpm paths.
|
|
39084
|
+
*/
|
|
39085
|
+
const reactHooksJsPluginDropNote = (error) => {
|
|
39086
|
+
if (!(error instanceof ReactDoctorError) || error.reason._tag !== "OxlintOutputUnparseable") return null;
|
|
39087
|
+
const { preview } = error.reason;
|
|
39088
|
+
if (!preview.includes("Failed to load JS plugin") || !preview.includes("eslint-plugin-react-hooks")) return null;
|
|
39089
|
+
const underlyingReason = preview.match(/Error:[^\n]*/)?.[0]?.trim();
|
|
39090
|
+
return `${REACT_HOOKS_JS_DROP_PREFIX}${underlyingReason ? `: ${underlyingReason}` : ""}. Other rules ran normally.`;
|
|
39091
|
+
};
|
|
39078
39092
|
/**
|
|
39079
39093
|
* The oxlint runner. Composed of three pieces in `runners/oxlint/`:
|
|
39080
39094
|
*
|
|
@@ -39102,15 +39116,16 @@ const runOxlint = async (options) => {
|
|
|
39102
39116
|
const pluginPath = resolvePluginPath();
|
|
39103
39117
|
const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
|
|
39104
39118
|
const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
|
|
39105
|
-
const buildConfig = (
|
|
39119
|
+
const buildConfig = (overrides) => createOxlintConfig({
|
|
39106
39120
|
pluginPath,
|
|
39107
39121
|
project,
|
|
39108
39122
|
customRulesOnly,
|
|
39109
|
-
extendsPaths:
|
|
39123
|
+
extendsPaths: overrides.extendsPaths,
|
|
39110
39124
|
ignoredTags,
|
|
39111
39125
|
serverAuthFunctionNames,
|
|
39112
39126
|
severityControls,
|
|
39113
|
-
userPlugins
|
|
39127
|
+
userPlugins,
|
|
39128
|
+
disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin
|
|
39114
39129
|
});
|
|
39115
39130
|
const restoreDisableDirectives = respectInlineDisables ? () => {} : await neutralizeDisableDirectives(rootDirectory, includePaths);
|
|
39116
39131
|
const configDirectory = NFS.mkdtempSync(Path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
|
|
@@ -39146,12 +39161,22 @@ const runOxlint = async (options) => {
|
|
|
39146
39161
|
outputMaxBytes,
|
|
39147
39162
|
concurrency: options.concurrency
|
|
39148
39163
|
});
|
|
39149
|
-
writeOxlintConfig(configPath, buildConfig(extendsPaths));
|
|
39164
|
+
writeOxlintConfig(configPath, buildConfig({ extendsPaths }));
|
|
39150
39165
|
try {
|
|
39151
39166
|
return await runBatches();
|
|
39152
39167
|
} catch (error) {
|
|
39168
|
+
const reactHooksJsDropNote = reactHooksJsPluginDropNote(error);
|
|
39169
|
+
if (reactHooksJsDropNote !== null) {
|
|
39170
|
+
writeOxlintConfig(configPath, buildConfig({
|
|
39171
|
+
extendsPaths,
|
|
39172
|
+
disableReactHooksJsPlugin: true
|
|
39173
|
+
}));
|
|
39174
|
+
const diagnostics = await runBatches();
|
|
39175
|
+
onPartialFailure?.(reactHooksJsDropNote);
|
|
39176
|
+
return diagnostics;
|
|
39177
|
+
}
|
|
39153
39178
|
if (extendsPaths.length === 0) throw error;
|
|
39154
|
-
writeOxlintConfig(configPath, buildConfig([]));
|
|
39179
|
+
writeOxlintConfig(configPath, buildConfig({ extendsPaths: [] }));
|
|
39155
39180
|
return await runBatches();
|
|
39156
39181
|
}
|
|
39157
39182
|
} finally {
|
|
@@ -39949,7 +39974,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
39949
39974
|
}))))))));
|
|
39950
39975
|
const deadCodeFailureState = yield* get$2(deadCodeFailure);
|
|
39951
39976
|
const scanElapsedMilliseconds = Date.now() - scanStartTime;
|
|
39952
|
-
const scanElapsedSeconds = (scanElapsedMilliseconds /
|
|
39977
|
+
const scanElapsedSeconds = (scanElapsedMilliseconds / MILLISECONDS_PER_SECOND).toFixed(1);
|
|
39953
39978
|
if (!lintFailureState.didFail) if (deadCodeFailureState.didFail) yield* scanProgress.fail(DEAD_CODE_FAIL_TEXT);
|
|
39954
39979
|
else if (input.suppressScanSummary) yield* scanProgress.stop();
|
|
39955
39980
|
else yield* scanProgress.succeed(`Scanned ${scannedFilesLabel} in ${scanElapsedSeconds}s${workerCountSuffix}`);
|
|
@@ -40163,7 +40188,7 @@ const materializeSourceTree = (input) => gen(function* () {
|
|
|
40163
40188
|
static layerNode = effect(StagedFiles, gen(function* () {
|
|
40164
40189
|
const git = yield* Git;
|
|
40165
40190
|
return StagedFiles.of({
|
|
40166
|
-
discoverSourceFiles: (directory) => git.stagedFilePaths(directory).pipe(map$3((entries) => entries.filter(isLintableSourceFile))),
|
|
40191
|
+
discoverSourceFiles: (directory) => git.stagedFilePaths(directory).pipe(map$3((entries) => entries.filter(isLintableSourceFile)), withSpan("StagedFiles.discoverSourceFiles")),
|
|
40167
40192
|
materialize: ({ directory, stagedFiles, tempDirectory }) => materializeSourceTree({
|
|
40168
40193
|
directory,
|
|
40169
40194
|
files: stagedFiles,
|
|
@@ -40173,7 +40198,7 @@ const materializeSourceTree = (input) => gen(function* () {
|
|
|
40173
40198
|
tempDirectory: tree.tempDirectory,
|
|
40174
40199
|
stagedFiles: tree.materializedFiles,
|
|
40175
40200
|
cleanup: tree.cleanup
|
|
40176
|
-
})))
|
|
40201
|
+
})), withSpan("StagedFiles.materialize"))
|
|
40177
40202
|
});
|
|
40178
40203
|
}));
|
|
40179
40204
|
/**
|
|
@@ -40305,6 +40330,7 @@ const buildJsonReport = (input) => {
|
|
|
40305
40330
|
score: result.score,
|
|
40306
40331
|
skippedChecks: result.skippedChecks,
|
|
40307
40332
|
...result.skippedCheckReasons ? { skippedCheckReasons: result.skippedCheckReasons } : {},
|
|
40333
|
+
...typeof result.scannedFileCount === "number" ? { scannedFileCount: result.scannedFileCount } : {},
|
|
40308
40334
|
elapsedMilliseconds: result.elapsedMilliseconds
|
|
40309
40335
|
}));
|
|
40310
40336
|
const flattenedDiagnostics = projects.flatMap((entry) => entry.diagnostics);
|
|
@@ -40571,4 +40597,4 @@ const toJsonReport = (result, options) => buildJsonReport({
|
|
|
40571
40597
|
export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
|
|
40572
40598
|
|
|
40573
40599
|
//# sourceMappingURL=index.js.map
|
|
40574
|
-
//# debugId=
|
|
40600
|
+
//# debugId=efaa91ed-3659-50a5-b802-51753472b2d6
|