react-doctor 0.5.6-dev.6b8e756 → 0.5.6-dev.740211c
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 +465 -260
- package/dist/index.d.ts +10 -0
- package/dist/index.js +97 -76
- package/dist/lsp.js +115 -98
- 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
|
}
|
|
@@ -36472,15 +36467,10 @@ const buildCapabilities = (project) => {
|
|
|
36472
36467
|
}
|
|
36473
36468
|
if (project.tailwindVersion !== null) {
|
|
36474
36469
|
capabilities.add("tailwind");
|
|
36475
|
-
|
|
36476
|
-
if (isTailwindAtLeast(tailwind, {
|
|
36470
|
+
if (isTailwindAtLeast(parseTailwindMajorMinor(project.tailwindVersion), {
|
|
36477
36471
|
major: 3,
|
|
36478
36472
|
minor: 4
|
|
36479
36473
|
})) capabilities.add("tailwind:3.4");
|
|
36480
|
-
if (tailwind !== null && isTailwindAtLeast(tailwind, {
|
|
36481
|
-
major: 4,
|
|
36482
|
-
minor: 0
|
|
36483
|
-
})) capabilities.add("tailwind:4");
|
|
36484
36474
|
}
|
|
36485
36475
|
if (project.zodVersion !== null) {
|
|
36486
36476
|
capabilities.add("zod");
|
|
@@ -36669,7 +36659,7 @@ const readIgnoreFile = (filePath) => {
|
|
|
36669
36659
|
try {
|
|
36670
36660
|
content = NFS.readFileSync(filePath, "utf-8");
|
|
36671
36661
|
} catch (error) {
|
|
36672
|
-
const errnoCode = error
|
|
36662
|
+
const errnoCode = isErrnoException(error) ? error.code : void 0;
|
|
36673
36663
|
if (errnoCode && errnoCode !== "ENOENT") runSync(warn$1(`Could not read ignore file ${filePath}: ${errnoCode}`));
|
|
36674
36664
|
return [];
|
|
36675
36665
|
}
|
|
@@ -36710,8 +36700,8 @@ const collectIgnorePatterns = (rootDirectory) => {
|
|
|
36710
36700
|
cachedPatternsByRoot.set(rootDirectory, patterns);
|
|
36711
36701
|
return patterns;
|
|
36712
36702
|
};
|
|
36703
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36713
36704
|
const KNIP_JSON_FILENAME = "knip.json";
|
|
36714
|
-
const isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36715
36705
|
const readJsonFileSafe = (filePath) => {
|
|
36716
36706
|
let rawContents;
|
|
36717
36707
|
try {
|
|
@@ -36727,10 +36717,10 @@ const readJsonFileSafe = (filePath) => {
|
|
|
36727
36717
|
};
|
|
36728
36718
|
const readKnipConfig = (rootDirectory) => {
|
|
36729
36719
|
const knipJson = readJsonFileSafe(path.join(rootDirectory, KNIP_JSON_FILENAME));
|
|
36730
|
-
if (isRecord
|
|
36720
|
+
if (isRecord(knipJson)) return knipJson;
|
|
36731
36721
|
const packageJson = readJsonFileSafe(path.join(rootDirectory, "package.json"));
|
|
36732
|
-
const packageKnipConfig = isRecord
|
|
36733
|
-
return isRecord
|
|
36722
|
+
const packageKnipConfig = isRecord(packageJson) ? packageJson.knip : null;
|
|
36723
|
+
return isRecord(packageKnipConfig) ? packageKnipConfig : null;
|
|
36734
36724
|
};
|
|
36735
36725
|
const normalizePatternList = (value) => {
|
|
36736
36726
|
if (typeof value === "string" && value.length > 0) return [value];
|
|
@@ -36742,10 +36732,10 @@ const prefixWorkspacePatterns = (workspacePattern, patterns) => {
|
|
|
36742
36732
|
return patterns.map((pattern) => pattern.startsWith("!") ? `!${normalizedWorkspacePattern}/${pattern.slice(1)}` : `${normalizedWorkspacePattern}/${pattern}`);
|
|
36743
36733
|
};
|
|
36744
36734
|
const collectKnipWorkspacePatterns = (workspaces, settingName) => {
|
|
36745
|
-
if (!isRecord
|
|
36735
|
+
if (!isRecord(workspaces)) return [];
|
|
36746
36736
|
const patterns = [];
|
|
36747
36737
|
for (const [workspacePattern, workspaceConfig] of Object.entries(workspaces)) {
|
|
36748
|
-
if (!isRecord
|
|
36738
|
+
if (!isRecord(workspaceConfig)) continue;
|
|
36749
36739
|
patterns.push(...prefixWorkspacePatterns(workspacePattern, normalizePatternList(workspaceConfig[settingName])));
|
|
36750
36740
|
}
|
|
36751
36741
|
return patterns;
|
|
@@ -36790,8 +36780,6 @@ const toCanonicalPath = (filePath) => {
|
|
|
36790
36780
|
};
|
|
36791
36781
|
const DEAD_CODE_PLUGIN = "deslop";
|
|
36792
36782
|
const DEAD_CODE_CATEGORY = "Maintainability";
|
|
36793
|
-
const TSCONFIG_FILENAMES$1 = ["tsconfig.json", "tsconfig.base.json"];
|
|
36794
|
-
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36795
36783
|
const DEAD_CODE_WORKER_SCRIPT = `
|
|
36796
36784
|
const inputChunks = [];
|
|
36797
36785
|
process.stdin.on("data", (chunk) => inputChunks.push(chunk));
|
|
@@ -36849,7 +36837,7 @@ process.stdin.on("end", () => {
|
|
|
36849
36837
|
});
|
|
36850
36838
|
`;
|
|
36851
36839
|
const resolveTsConfigPath = (rootDirectory) => {
|
|
36852
|
-
for (const filename of TSCONFIG_FILENAMES
|
|
36840
|
+
for (const filename of TSCONFIG_FILENAMES) {
|
|
36853
36841
|
const candidate = Path.join(rootDirectory, filename);
|
|
36854
36842
|
if (NFS.existsSync(candidate)) return candidate;
|
|
36855
36843
|
}
|
|
@@ -37230,15 +37218,13 @@ var DeadCode = class DeadCode extends Service()("react-doctor/DeadCode") {
|
|
|
37230
37218
|
})()) }));
|
|
37231
37219
|
static layerOf = (diagnostics) => succeed$3(DeadCode, DeadCode.of({ run: () => fromIterable$1(diagnostics) }));
|
|
37232
37220
|
};
|
|
37233
|
-
const createNodeReadFileLinesSync = (rootDirectory) => {
|
|
37234
|
-
|
|
37235
|
-
|
|
37236
|
-
|
|
37237
|
-
|
|
37238
|
-
|
|
37239
|
-
|
|
37240
|
-
}
|
|
37241
|
-
};
|
|
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
|
+
}
|
|
37242
37228
|
};
|
|
37243
37229
|
var Files = class Files extends Service()("react-doctor/Files") {
|
|
37244
37230
|
static layerNode = succeed$3(Files, Files.of({
|
|
@@ -37449,7 +37435,10 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37449
37435
|
directory: input.directory,
|
|
37450
37436
|
cause
|
|
37451
37437
|
}) });
|
|
37452
|
-
})
|
|
37438
|
+
}), withSpan("git.exec", { attributes: {
|
|
37439
|
+
"git.command": input.command,
|
|
37440
|
+
"git.subcommand": input.args[0] ?? ""
|
|
37441
|
+
} }));
|
|
37453
37442
|
const runGit = (directory, args) => runCommand({
|
|
37454
37443
|
command: "git",
|
|
37455
37444
|
args,
|
|
@@ -37477,7 +37466,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37477
37466
|
]);
|
|
37478
37467
|
if (candidates.status !== 0) return null;
|
|
37479
37468
|
return trimOrNull(candidates.stdout.split("\n")[0] ?? "");
|
|
37480
|
-
});
|
|
37469
|
+
}).pipe(withSpan("Git.defaultBranch"));
|
|
37481
37470
|
const branchExists = (directory, branch) => runGit(directory, [
|
|
37482
37471
|
"rev-parse",
|
|
37483
37472
|
"--verify",
|
|
@@ -37524,7 +37513,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37524
37513
|
const result = resultOption.value;
|
|
37525
37514
|
if (result.status !== 0) return null;
|
|
37526
37515
|
return parseGithubViewerPermission(result.stdout);
|
|
37527
|
-
}).pipe(catch_$1(() => succeed$2(null)));
|
|
37516
|
+
}).pipe(catch_$1(() => succeed$2(null)), withSpan("Git.githubViewerPermission"));
|
|
37528
37517
|
/**
|
|
37529
37518
|
* Resolves a `--diff A..B` / `A...B` commit range into a changed-file
|
|
37530
37519
|
* selection. Each endpoint is validated with `isSafeGitRevision`
|
|
@@ -37638,7 +37627,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37638
37627
|
changedFiles: splitNullSeparated(diff.stdout),
|
|
37639
37628
|
isCurrentChanges: false
|
|
37640
37629
|
};
|
|
37641
|
-
}),
|
|
37630
|
+
}).pipe(withSpan("Git.diffSelection")),
|
|
37642
37631
|
stagedFilePaths: (directory) => runGit(directory, [
|
|
37643
37632
|
"diff",
|
|
37644
37633
|
"--cached",
|
|
@@ -37680,7 +37669,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37680
37669
|
status: result.status,
|
|
37681
37670
|
stdout: result.stdout
|
|
37682
37671
|
};
|
|
37683
|
-
}),
|
|
37672
|
+
}).pipe(withSpan("Git.grep")),
|
|
37684
37673
|
changedLineRanges: ({ directory, baseRef, cached, files }) => gen(function* () {
|
|
37685
37674
|
if (files.length === 0) return [];
|
|
37686
37675
|
if (baseRef !== void 0 && !isSafeGitRevision(baseRef)) return null;
|
|
@@ -37696,7 +37685,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
37696
37685
|
]);
|
|
37697
37686
|
if (result.status !== 0) return null;
|
|
37698
37687
|
return parseChangedLineRanges(result.stdout);
|
|
37699
|
-
})
|
|
37688
|
+
}).pipe(withSpan("Git.changedLineRanges"))
|
|
37700
37689
|
});
|
|
37701
37690
|
})).pipe(provide$2(layer$2.pipe(provide$2(mergeAll$1(layer$1, layer)))));
|
|
37702
37691
|
/**
|
|
@@ -37911,7 +37900,7 @@ const neutralizeDisableDirectives = async (rootDirectory, includePaths) => {
|
|
|
37911
37900
|
for (const [absolutePath, originalContent] of originalContents) try {
|
|
37912
37901
|
NFS.writeFileSync(absolutePath, originalContent);
|
|
37913
37902
|
} catch (error) {
|
|
37914
|
-
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`);
|
|
37915
37904
|
}
|
|
37916
37905
|
};
|
|
37917
37906
|
const onExit = () => restore();
|
|
@@ -38017,7 +38006,7 @@ const resolveUserPlugin = (spec, configSourceDirectory) => {
|
|
|
38017
38006
|
try {
|
|
38018
38007
|
resolvedSpecifier = isRelative ? Path.resolve(configSourceDirectory, spec) : candidateRequire.resolve(spec);
|
|
38019
38008
|
} catch (error) {
|
|
38020
|
-
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)}`);
|
|
38021
38010
|
return null;
|
|
38022
38011
|
}
|
|
38023
38012
|
const { name, ruleNames } = readPluginShape(resolvedSpecifier, (target) => candidateRequire(target));
|
|
@@ -38089,8 +38078,8 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
38089
38078
|
}
|
|
38090
38079
|
return enabled;
|
|
38091
38080
|
};
|
|
38092
|
-
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [] }) => {
|
|
38093
|
-
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);
|
|
38094
38083
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
38095
38084
|
const jsPlugins = [];
|
|
38096
38085
|
if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
|
|
@@ -38150,7 +38139,6 @@ const resolveOxlintBinary = () => {
|
|
|
38150
38139
|
return Path.join(oxlintPackageDirectory, "bin", "oxlint");
|
|
38151
38140
|
};
|
|
38152
38141
|
const resolvePluginPath = () => esmRequire.resolve("oxlint-plugin-react-doctor");
|
|
38153
|
-
const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
|
|
38154
38142
|
const resolveTsConfigRelativePath = (rootDirectory) => {
|
|
38155
38143
|
for (const filename of TSCONFIG_FILENAMES) if (NFS.existsSync(Path.join(rootDirectory, filename))) return `./${filename}`;
|
|
38156
38144
|
return null;
|
|
@@ -38522,7 +38510,7 @@ const scopeContainsNonImportBinding = (node, scopeNode, identifierName) => {
|
|
|
38522
38510
|
const isIdentifierShadowedByLocalBinding = (identifier, sourceFile) => {
|
|
38523
38511
|
let currentNode = identifier.parent;
|
|
38524
38512
|
while (currentNode) {
|
|
38525
|
-
if (
|
|
38513
|
+
if (isScopeBoundary(currentNode)) {
|
|
38526
38514
|
if (scopeContainsNonImportBinding(currentNode, currentNode, identifier.text)) return true;
|
|
38527
38515
|
}
|
|
38528
38516
|
if (currentNode === sourceFile) return false;
|
|
@@ -38613,11 +38601,10 @@ const findResolutionInScope = (scopeNode, identifierName, reactImportBindings, s
|
|
|
38613
38601
|
});
|
|
38614
38602
|
return resolution;
|
|
38615
38603
|
};
|
|
38616
|
-
const isScopeNode = isScopeBoundary;
|
|
38617
38604
|
const resolveIdentifierBinding = (identifier, reactImportBindings, sourceFile, visitedDeclarations = /* @__PURE__ */ new Set()) => {
|
|
38618
38605
|
let currentNode = identifier.parent;
|
|
38619
38606
|
while (currentNode) {
|
|
38620
|
-
if (
|
|
38607
|
+
if (isScopeBoundary(currentNode)) {
|
|
38621
38608
|
const resolution = findResolutionInScope(currentNode, identifier.text, reactImportBindings, sourceFile, visitedDeclarations);
|
|
38622
38609
|
if (resolution) return resolution;
|
|
38623
38610
|
}
|
|
@@ -38787,9 +38774,9 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
38787
38774
|
try {
|
|
38788
38775
|
parsed = JSON.parse(sanitizedStdout);
|
|
38789
38776
|
} catch {
|
|
38790
|
-
throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0,
|
|
38777
|
+
throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
38791
38778
|
}
|
|
38792
|
-
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) }) });
|
|
38793
38780
|
const minifiedFileCache = /* @__PURE__ */ new Map();
|
|
38794
38781
|
const isMinifiedDiagnosticFile = (filename) => {
|
|
38795
38782
|
const absolutePath = Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
|
|
@@ -38865,7 +38852,7 @@ const spawnOxlint = (args, rootDirectory, nodeBinaryPath, spawnTimeoutMs = OXLIN
|
|
|
38865
38852
|
child.kill("SIGKILL");
|
|
38866
38853
|
reject(new ReactDoctorError({ reason: new OxlintBatchExceeded({
|
|
38867
38854
|
kind: "timeout",
|
|
38868
|
-
detail: `${spawnTimeoutMs /
|
|
38855
|
+
detail: `${spawnTimeoutMs / MILLISECONDS_PER_SECOND}s budget exceeded`
|
|
38869
38856
|
}) }));
|
|
38870
38857
|
}, spawnTimeoutMs);
|
|
38871
38858
|
timeoutHandle.unref?.();
|
|
@@ -39080,6 +39067,28 @@ const writeOxlintConfig = (configPath, configToWrite) => {
|
|
|
39080
39067
|
NFS.closeSync(fileHandle);
|
|
39081
39068
|
}
|
|
39082
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
|
+
};
|
|
39083
39092
|
/**
|
|
39084
39093
|
* The oxlint runner. Composed of three pieces in `runners/oxlint/`:
|
|
39085
39094
|
*
|
|
@@ -39107,15 +39116,16 @@ const runOxlint = async (options) => {
|
|
|
39107
39116
|
const pluginPath = resolvePluginPath();
|
|
39108
39117
|
const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
|
|
39109
39118
|
const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
|
|
39110
|
-
const buildConfig = (
|
|
39119
|
+
const buildConfig = (overrides) => createOxlintConfig({
|
|
39111
39120
|
pluginPath,
|
|
39112
39121
|
project,
|
|
39113
39122
|
customRulesOnly,
|
|
39114
|
-
extendsPaths:
|
|
39123
|
+
extendsPaths: overrides.extendsPaths,
|
|
39115
39124
|
ignoredTags,
|
|
39116
39125
|
serverAuthFunctionNames,
|
|
39117
39126
|
severityControls,
|
|
39118
|
-
userPlugins
|
|
39127
|
+
userPlugins,
|
|
39128
|
+
disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin
|
|
39119
39129
|
});
|
|
39120
39130
|
const restoreDisableDirectives = respectInlineDisables ? () => {} : await neutralizeDisableDirectives(rootDirectory, includePaths);
|
|
39121
39131
|
const configDirectory = NFS.mkdtempSync(Path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
|
|
@@ -39151,12 +39161,22 @@ const runOxlint = async (options) => {
|
|
|
39151
39161
|
outputMaxBytes,
|
|
39152
39162
|
concurrency: options.concurrency
|
|
39153
39163
|
});
|
|
39154
|
-
writeOxlintConfig(configPath, buildConfig(extendsPaths));
|
|
39164
|
+
writeOxlintConfig(configPath, buildConfig({ extendsPaths }));
|
|
39155
39165
|
try {
|
|
39156
39166
|
return await runBatches();
|
|
39157
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
|
+
}
|
|
39158
39178
|
if (extendsPaths.length === 0) throw error;
|
|
39159
|
-
writeOxlintConfig(configPath, buildConfig([]));
|
|
39179
|
+
writeOxlintConfig(configPath, buildConfig({ extendsPaths: [] }));
|
|
39160
39180
|
return await runBatches();
|
|
39161
39181
|
}
|
|
39162
39182
|
} finally {
|
|
@@ -39954,7 +39974,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
39954
39974
|
}))))))));
|
|
39955
39975
|
const deadCodeFailureState = yield* get$2(deadCodeFailure);
|
|
39956
39976
|
const scanElapsedMilliseconds = Date.now() - scanStartTime;
|
|
39957
|
-
const scanElapsedSeconds = (scanElapsedMilliseconds /
|
|
39977
|
+
const scanElapsedSeconds = (scanElapsedMilliseconds / MILLISECONDS_PER_SECOND).toFixed(1);
|
|
39958
39978
|
if (!lintFailureState.didFail) if (deadCodeFailureState.didFail) yield* scanProgress.fail(DEAD_CODE_FAIL_TEXT);
|
|
39959
39979
|
else if (input.suppressScanSummary) yield* scanProgress.stop();
|
|
39960
39980
|
else yield* scanProgress.succeed(`Scanned ${scannedFilesLabel} in ${scanElapsedSeconds}s${workerCountSuffix}`);
|
|
@@ -40168,7 +40188,7 @@ const materializeSourceTree = (input) => gen(function* () {
|
|
|
40168
40188
|
static layerNode = effect(StagedFiles, gen(function* () {
|
|
40169
40189
|
const git = yield* Git;
|
|
40170
40190
|
return StagedFiles.of({
|
|
40171
|
-
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")),
|
|
40172
40192
|
materialize: ({ directory, stagedFiles, tempDirectory }) => materializeSourceTree({
|
|
40173
40193
|
directory,
|
|
40174
40194
|
files: stagedFiles,
|
|
@@ -40178,7 +40198,7 @@ const materializeSourceTree = (input) => gen(function* () {
|
|
|
40178
40198
|
tempDirectory: tree.tempDirectory,
|
|
40179
40199
|
stagedFiles: tree.materializedFiles,
|
|
40180
40200
|
cleanup: tree.cleanup
|
|
40181
|
-
})))
|
|
40201
|
+
})), withSpan("StagedFiles.materialize"))
|
|
40182
40202
|
});
|
|
40183
40203
|
}));
|
|
40184
40204
|
/**
|
|
@@ -40310,6 +40330,7 @@ const buildJsonReport = (input) => {
|
|
|
40310
40330
|
score: result.score,
|
|
40311
40331
|
skippedChecks: result.skippedChecks,
|
|
40312
40332
|
...result.skippedCheckReasons ? { skippedCheckReasons: result.skippedCheckReasons } : {},
|
|
40333
|
+
...typeof result.scannedFileCount === "number" ? { scannedFileCount: result.scannedFileCount } : {},
|
|
40313
40334
|
elapsedMilliseconds: result.elapsedMilliseconds
|
|
40314
40335
|
}));
|
|
40315
40336
|
const flattenedDiagnostics = projects.flatMap((entry) => entry.diagnostics);
|
|
@@ -40576,4 +40597,4 @@ const toJsonReport = (result, options) => buildJsonReport({
|
|
|
40576
40597
|
export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
|
|
40577
40598
|
|
|
40578
40599
|
//# sourceMappingURL=index.js.map
|
|
40579
|
-
//# debugId=
|
|
40600
|
+
//# debugId=efaa91ed-3659-50a5-b802-51753472b2d6
|