react-doctor 0.5.6-dev.eafac9d → 0.5.6-dev.ed0258c
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 +363 -204
- package/dist/index.js +59 -30
- package/dist/lsp.js +65 -41
- package/package.json +3 -3
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]="36898527-7b70-58ed-8b5b-19ca48903764")}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";
|
|
@@ -33620,6 +33620,11 @@ const ES_TARGET_YEAR_BY_NAME = {
|
|
|
33620
33620
|
esnext: 9999
|
|
33621
33621
|
};
|
|
33622
33622
|
/**
|
|
33623
|
+
* tsconfig filenames probed when resolving a project's TypeScript
|
|
33624
|
+
* compiler options — the root config first, then a monorepo base config.
|
|
33625
|
+
*/
|
|
33626
|
+
const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
|
|
33627
|
+
/**
|
|
33623
33628
|
* Project-config files that `StagedFiles.materialize` copies into
|
|
33624
33629
|
* the temp directory alongside staged sources so oxlint resolves
|
|
33625
33630
|
* `tsconfig` / `package.json` / lint configs the same way it would
|
|
@@ -36472,15 +36477,10 @@ const buildCapabilities = (project) => {
|
|
|
36472
36477
|
}
|
|
36473
36478
|
if (project.tailwindVersion !== null) {
|
|
36474
36479
|
capabilities.add("tailwind");
|
|
36475
|
-
|
|
36476
|
-
if (isTailwindAtLeast(tailwind, {
|
|
36480
|
+
if (isTailwindAtLeast(parseTailwindMajorMinor(project.tailwindVersion), {
|
|
36477
36481
|
major: 3,
|
|
36478
36482
|
minor: 4
|
|
36479
36483
|
})) capabilities.add("tailwind:3.4");
|
|
36480
|
-
if (tailwind !== null && isTailwindAtLeast(tailwind, {
|
|
36481
|
-
major: 4,
|
|
36482
|
-
minor: 0
|
|
36483
|
-
})) capabilities.add("tailwind:4");
|
|
36484
36484
|
}
|
|
36485
36485
|
if (project.zodVersion !== null) {
|
|
36486
36486
|
capabilities.add("zod");
|
|
@@ -36710,8 +36710,8 @@ const collectIgnorePatterns = (rootDirectory) => {
|
|
|
36710
36710
|
cachedPatternsByRoot.set(rootDirectory, patterns);
|
|
36711
36711
|
return patterns;
|
|
36712
36712
|
};
|
|
36713
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36713
36714
|
const KNIP_JSON_FILENAME = "knip.json";
|
|
36714
|
-
const isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36715
36715
|
const readJsonFileSafe = (filePath) => {
|
|
36716
36716
|
let rawContents;
|
|
36717
36717
|
try {
|
|
@@ -36727,10 +36727,10 @@ const readJsonFileSafe = (filePath) => {
|
|
|
36727
36727
|
};
|
|
36728
36728
|
const readKnipConfig = (rootDirectory) => {
|
|
36729
36729
|
const knipJson = readJsonFileSafe(path.join(rootDirectory, KNIP_JSON_FILENAME));
|
|
36730
|
-
if (isRecord
|
|
36730
|
+
if (isRecord(knipJson)) return knipJson;
|
|
36731
36731
|
const packageJson = readJsonFileSafe(path.join(rootDirectory, "package.json"));
|
|
36732
|
-
const packageKnipConfig = isRecord
|
|
36733
|
-
return isRecord
|
|
36732
|
+
const packageKnipConfig = isRecord(packageJson) ? packageJson.knip : null;
|
|
36733
|
+
return isRecord(packageKnipConfig) ? packageKnipConfig : null;
|
|
36734
36734
|
};
|
|
36735
36735
|
const normalizePatternList = (value) => {
|
|
36736
36736
|
if (typeof value === "string" && value.length > 0) return [value];
|
|
@@ -36742,10 +36742,10 @@ const prefixWorkspacePatterns = (workspacePattern, patterns) => {
|
|
|
36742
36742
|
return patterns.map((pattern) => pattern.startsWith("!") ? `!${normalizedWorkspacePattern}/${pattern.slice(1)}` : `${normalizedWorkspacePattern}/${pattern}`);
|
|
36743
36743
|
};
|
|
36744
36744
|
const collectKnipWorkspacePatterns = (workspaces, settingName) => {
|
|
36745
|
-
if (!isRecord
|
|
36745
|
+
if (!isRecord(workspaces)) return [];
|
|
36746
36746
|
const patterns = [];
|
|
36747
36747
|
for (const [workspacePattern, workspaceConfig] of Object.entries(workspaces)) {
|
|
36748
|
-
if (!isRecord
|
|
36748
|
+
if (!isRecord(workspaceConfig)) continue;
|
|
36749
36749
|
patterns.push(...prefixWorkspacePatterns(workspacePattern, normalizePatternList(workspaceConfig[settingName])));
|
|
36750
36750
|
}
|
|
36751
36751
|
return patterns;
|
|
@@ -36790,8 +36790,6 @@ const toCanonicalPath = (filePath) => {
|
|
|
36790
36790
|
};
|
|
36791
36791
|
const DEAD_CODE_PLUGIN = "deslop";
|
|
36792
36792
|
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
36793
|
const DEAD_CODE_WORKER_SCRIPT = `
|
|
36796
36794
|
const inputChunks = [];
|
|
36797
36795
|
process.stdin.on("data", (chunk) => inputChunks.push(chunk));
|
|
@@ -36849,7 +36847,7 @@ process.stdin.on("end", () => {
|
|
|
36849
36847
|
});
|
|
36850
36848
|
`;
|
|
36851
36849
|
const resolveTsConfigPath = (rootDirectory) => {
|
|
36852
|
-
for (const filename of TSCONFIG_FILENAMES
|
|
36850
|
+
for (const filename of TSCONFIG_FILENAMES) {
|
|
36853
36851
|
const candidate = Path.join(rootDirectory, filename);
|
|
36854
36852
|
if (NFS.existsSync(candidate)) return candidate;
|
|
36855
36853
|
}
|
|
@@ -38089,8 +38087,8 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
38089
38087
|
}
|
|
38090
38088
|
return enabled;
|
|
38091
38089
|
};
|
|
38092
|
-
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [] }) => {
|
|
38093
|
-
const reactHooksJsPlugin = resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
|
|
38090
|
+
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false }) => {
|
|
38091
|
+
const reactHooksJsPlugin = disableReactHooksJsPlugin ? null : resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
|
|
38094
38092
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
38095
38093
|
const jsPlugins = [];
|
|
38096
38094
|
if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
|
|
@@ -38150,7 +38148,6 @@ const resolveOxlintBinary = () => {
|
|
|
38150
38148
|
return Path.join(oxlintPackageDirectory, "bin", "oxlint");
|
|
38151
38149
|
};
|
|
38152
38150
|
const resolvePluginPath = () => esmRequire.resolve("oxlint-plugin-react-doctor");
|
|
38153
|
-
const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
|
|
38154
38151
|
const resolveTsConfigRelativePath = (rootDirectory) => {
|
|
38155
38152
|
for (const filename of TSCONFIG_FILENAMES) if (NFS.existsSync(Path.join(rootDirectory, filename))) return `./${filename}`;
|
|
38156
38153
|
return null;
|
|
@@ -38522,7 +38519,7 @@ const scopeContainsNonImportBinding = (node, scopeNode, identifierName) => {
|
|
|
38522
38519
|
const isIdentifierShadowedByLocalBinding = (identifier, sourceFile) => {
|
|
38523
38520
|
let currentNode = identifier.parent;
|
|
38524
38521
|
while (currentNode) {
|
|
38525
|
-
if (
|
|
38522
|
+
if (isScopeBoundary(currentNode)) {
|
|
38526
38523
|
if (scopeContainsNonImportBinding(currentNode, currentNode, identifier.text)) return true;
|
|
38527
38524
|
}
|
|
38528
38525
|
if (currentNode === sourceFile) return false;
|
|
@@ -38613,11 +38610,10 @@ const findResolutionInScope = (scopeNode, identifierName, reactImportBindings, s
|
|
|
38613
38610
|
});
|
|
38614
38611
|
return resolution;
|
|
38615
38612
|
};
|
|
38616
|
-
const isScopeNode = isScopeBoundary;
|
|
38617
38613
|
const resolveIdentifierBinding = (identifier, reactImportBindings, sourceFile, visitedDeclarations = /* @__PURE__ */ new Set()) => {
|
|
38618
38614
|
let currentNode = identifier.parent;
|
|
38619
38615
|
while (currentNode) {
|
|
38620
|
-
if (
|
|
38616
|
+
if (isScopeBoundary(currentNode)) {
|
|
38621
38617
|
const resolution = findResolutionInScope(currentNode, identifier.text, reactImportBindings, sourceFile, visitedDeclarations);
|
|
38622
38618
|
if (resolution) return resolution;
|
|
38623
38619
|
}
|
|
@@ -38787,9 +38783,9 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
38787
38783
|
try {
|
|
38788
38784
|
parsed = JSON.parse(sanitizedStdout);
|
|
38789
38785
|
} catch {
|
|
38790
|
-
throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0,
|
|
38786
|
+
throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
38791
38787
|
}
|
|
38792
|
-
if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0,
|
|
38788
|
+
if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
38793
38789
|
const minifiedFileCache = /* @__PURE__ */ new Map();
|
|
38794
38790
|
const isMinifiedDiagnosticFile = (filename) => {
|
|
38795
38791
|
const absolutePath = Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
|
|
@@ -39080,6 +39076,28 @@ const writeOxlintConfig = (configPath, configToWrite) => {
|
|
|
39080
39076
|
NFS.closeSync(fileHandle);
|
|
39081
39077
|
}
|
|
39082
39078
|
};
|
|
39079
|
+
const REACT_HOOKS_JS_DROP_PREFIX = "React Compiler rules (react-hooks-js/*) skipped — eslint-plugin-react-hooks failed to load in this environment";
|
|
39080
|
+
/**
|
|
39081
|
+
* Detects an oxlint config-load crash caused by the optional
|
|
39082
|
+
* `react-hooks-js` (eslint-plugin-react-hooks) React Compiler plugin and
|
|
39083
|
+
* builds the partial-failure note for it; returns `null` when the failure
|
|
39084
|
+
* was anything else.
|
|
39085
|
+
*
|
|
39086
|
+
* oxlint prints a framed error to stdout (not stderr) and exits non-zero
|
|
39087
|
+
* when a `jsPlugins` entry can't be imported; that non-JSON stdout
|
|
39088
|
+
* surfaces as `OxlintOutputUnparseable`. Because oxlint fails the WHOLE
|
|
39089
|
+
* config load on it, leaving the plugin in would drop every curated
|
|
39090
|
+
* react-doctor diagnostic too — so the caller retries with the plugin
|
|
39091
|
+
* stripped (issue #833). Both markers sit at the start of oxlint's
|
|
39092
|
+
* message, so they survive the `preview` slice even for deep pnpm paths.
|
|
39093
|
+
*/
|
|
39094
|
+
const reactHooksJsPluginDropNote = (error) => {
|
|
39095
|
+
if (!(error instanceof ReactDoctorError) || error.reason._tag !== "OxlintOutputUnparseable") return null;
|
|
39096
|
+
const { preview } = error.reason;
|
|
39097
|
+
if (!preview.includes("Failed to load JS plugin") || !preview.includes("eslint-plugin-react-hooks")) return null;
|
|
39098
|
+
const underlyingReason = preview.match(/Error:[^\n]*/)?.[0]?.trim();
|
|
39099
|
+
return `${REACT_HOOKS_JS_DROP_PREFIX}${underlyingReason ? `: ${underlyingReason}` : ""}. Other rules ran normally.`;
|
|
39100
|
+
};
|
|
39083
39101
|
/**
|
|
39084
39102
|
* The oxlint runner. Composed of three pieces in `runners/oxlint/`:
|
|
39085
39103
|
*
|
|
@@ -39107,15 +39125,16 @@ const runOxlint = async (options) => {
|
|
|
39107
39125
|
const pluginPath = resolvePluginPath();
|
|
39108
39126
|
const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
|
|
39109
39127
|
const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
|
|
39110
|
-
const buildConfig = (
|
|
39128
|
+
const buildConfig = (overrides) => createOxlintConfig({
|
|
39111
39129
|
pluginPath,
|
|
39112
39130
|
project,
|
|
39113
39131
|
customRulesOnly,
|
|
39114
|
-
extendsPaths:
|
|
39132
|
+
extendsPaths: overrides.extendsPaths,
|
|
39115
39133
|
ignoredTags,
|
|
39116
39134
|
serverAuthFunctionNames,
|
|
39117
39135
|
severityControls,
|
|
39118
|
-
userPlugins
|
|
39136
|
+
userPlugins,
|
|
39137
|
+
disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin
|
|
39119
39138
|
});
|
|
39120
39139
|
const restoreDisableDirectives = respectInlineDisables ? () => {} : await neutralizeDisableDirectives(rootDirectory, includePaths);
|
|
39121
39140
|
const configDirectory = NFS.mkdtempSync(Path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
|
|
@@ -39151,12 +39170,22 @@ const runOxlint = async (options) => {
|
|
|
39151
39170
|
outputMaxBytes,
|
|
39152
39171
|
concurrency: options.concurrency
|
|
39153
39172
|
});
|
|
39154
|
-
writeOxlintConfig(configPath, buildConfig(extendsPaths));
|
|
39173
|
+
writeOxlintConfig(configPath, buildConfig({ extendsPaths }));
|
|
39155
39174
|
try {
|
|
39156
39175
|
return await runBatches();
|
|
39157
39176
|
} catch (error) {
|
|
39177
|
+
const reactHooksJsDropNote = reactHooksJsPluginDropNote(error);
|
|
39178
|
+
if (reactHooksJsDropNote !== null) {
|
|
39179
|
+
writeOxlintConfig(configPath, buildConfig({
|
|
39180
|
+
extendsPaths,
|
|
39181
|
+
disableReactHooksJsPlugin: true
|
|
39182
|
+
}));
|
|
39183
|
+
const diagnostics = await runBatches();
|
|
39184
|
+
onPartialFailure?.(reactHooksJsDropNote);
|
|
39185
|
+
return diagnostics;
|
|
39186
|
+
}
|
|
39158
39187
|
if (extendsPaths.length === 0) throw error;
|
|
39159
|
-
writeOxlintConfig(configPath, buildConfig([]));
|
|
39188
|
+
writeOxlintConfig(configPath, buildConfig({ extendsPaths: [] }));
|
|
39160
39189
|
return await runBatches();
|
|
39161
39190
|
}
|
|
39162
39191
|
} finally {
|
|
@@ -40576,4 +40605,4 @@ const toJsonReport = (result, options) => buildJsonReport({
|
|
|
40576
40605
|
export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
|
|
40577
40606
|
|
|
40578
40607
|
//# sourceMappingURL=index.js.map
|
|
40579
|
-
//# debugId=
|
|
40608
|
+
//# debugId=36898527-7b70-58ed-8b5b-19ca48903764
|
package/dist/lsp.js
CHANGED
|
@@ -33657,6 +33657,11 @@ const ES_TARGET_YEAR_BY_NAME = {
|
|
|
33657
33657
|
esnext: 9999
|
|
33658
33658
|
};
|
|
33659
33659
|
/**
|
|
33660
|
+
* tsconfig filenames probed when resolving a project's TypeScript
|
|
33661
|
+
* compiler options — the root config first, then a monorepo base config.
|
|
33662
|
+
*/
|
|
33663
|
+
const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
|
|
33664
|
+
/**
|
|
33660
33665
|
* Project-config files that `StagedFiles.materialize` copies into
|
|
33661
33666
|
* the temp directory alongside staged sources so oxlint resolves
|
|
33662
33667
|
* `tsconfig` / `package.json` / lint configs the same way it would
|
|
@@ -36458,15 +36463,10 @@ const buildCapabilities = (project) => {
|
|
|
36458
36463
|
}
|
|
36459
36464
|
if (project.tailwindVersion !== null) {
|
|
36460
36465
|
capabilities.add("tailwind");
|
|
36461
|
-
|
|
36462
|
-
if (isTailwindAtLeast(tailwind, {
|
|
36466
|
+
if (isTailwindAtLeast(parseTailwindMajorMinor(project.tailwindVersion), {
|
|
36463
36467
|
major: 3,
|
|
36464
36468
|
minor: 4
|
|
36465
36469
|
})) capabilities.add("tailwind:3.4");
|
|
36466
|
-
if (tailwind !== null && isTailwindAtLeast(tailwind, {
|
|
36467
|
-
major: 4,
|
|
36468
|
-
minor: 0
|
|
36469
|
-
})) capabilities.add("tailwind:4");
|
|
36470
36470
|
}
|
|
36471
36471
|
if (project.zodVersion !== null) {
|
|
36472
36472
|
capabilities.add("zod");
|
|
@@ -36696,8 +36696,8 @@ const collectIgnorePatterns = (rootDirectory) => {
|
|
|
36696
36696
|
cachedPatternsByRoot.set(rootDirectory, patterns);
|
|
36697
36697
|
return patterns;
|
|
36698
36698
|
};
|
|
36699
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36699
36700
|
const KNIP_JSON_FILENAME = "knip.json";
|
|
36700
|
-
const isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36701
36701
|
const readJsonFileSafe = (filePath) => {
|
|
36702
36702
|
let rawContents;
|
|
36703
36703
|
try {
|
|
@@ -36713,10 +36713,10 @@ const readJsonFileSafe = (filePath) => {
|
|
|
36713
36713
|
};
|
|
36714
36714
|
const readKnipConfig = (rootDirectory) => {
|
|
36715
36715
|
const knipJson = readJsonFileSafe(path.join(rootDirectory, KNIP_JSON_FILENAME));
|
|
36716
|
-
if (isRecord
|
|
36716
|
+
if (isRecord(knipJson)) return knipJson;
|
|
36717
36717
|
const packageJson = readJsonFileSafe(path.join(rootDirectory, "package.json"));
|
|
36718
|
-
const packageKnipConfig = isRecord
|
|
36719
|
-
return isRecord
|
|
36718
|
+
const packageKnipConfig = isRecord(packageJson) ? packageJson.knip : null;
|
|
36719
|
+
return isRecord(packageKnipConfig) ? packageKnipConfig : null;
|
|
36720
36720
|
};
|
|
36721
36721
|
const normalizePatternList = (value) => {
|
|
36722
36722
|
if (typeof value === "string" && value.length > 0) return [value];
|
|
@@ -36728,10 +36728,10 @@ const prefixWorkspacePatterns = (workspacePattern, patterns) => {
|
|
|
36728
36728
|
return patterns.map((pattern) => pattern.startsWith("!") ? `!${normalizedWorkspacePattern}/${pattern.slice(1)}` : `${normalizedWorkspacePattern}/${pattern}`);
|
|
36729
36729
|
};
|
|
36730
36730
|
const collectKnipWorkspacePatterns = (workspaces, settingName) => {
|
|
36731
|
-
if (!isRecord
|
|
36731
|
+
if (!isRecord(workspaces)) return [];
|
|
36732
36732
|
const patterns = [];
|
|
36733
36733
|
for (const [workspacePattern, workspaceConfig] of Object.entries(workspaces)) {
|
|
36734
|
-
if (!isRecord
|
|
36734
|
+
if (!isRecord(workspaceConfig)) continue;
|
|
36735
36735
|
patterns.push(...prefixWorkspacePatterns(workspacePattern, normalizePatternList(workspaceConfig[settingName])));
|
|
36736
36736
|
}
|
|
36737
36737
|
return patterns;
|
|
@@ -36776,8 +36776,6 @@ const toCanonicalPath = (filePath) => {
|
|
|
36776
36776
|
};
|
|
36777
36777
|
const DEAD_CODE_PLUGIN = "deslop";
|
|
36778
36778
|
const DEAD_CODE_CATEGORY = "Maintainability";
|
|
36779
|
-
const TSCONFIG_FILENAMES$1 = ["tsconfig.json", "tsconfig.base.json"];
|
|
36780
|
-
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36781
36779
|
const DEAD_CODE_WORKER_SCRIPT = `
|
|
36782
36780
|
const inputChunks = [];
|
|
36783
36781
|
process.stdin.on("data", (chunk) => inputChunks.push(chunk));
|
|
@@ -36835,7 +36833,7 @@ process.stdin.on("end", () => {
|
|
|
36835
36833
|
});
|
|
36836
36834
|
`;
|
|
36837
36835
|
const resolveTsConfigPath = (rootDirectory) => {
|
|
36838
|
-
for (const filename of TSCONFIG_FILENAMES
|
|
36836
|
+
for (const filename of TSCONFIG_FILENAMES) {
|
|
36839
36837
|
const candidate = Path.join(rootDirectory, filename);
|
|
36840
36838
|
if (NFS.existsSync(candidate)) return candidate;
|
|
36841
36839
|
}
|
|
@@ -38075,8 +38073,8 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
38075
38073
|
}
|
|
38076
38074
|
return enabled;
|
|
38077
38075
|
};
|
|
38078
|
-
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [] }) => {
|
|
38079
|
-
const reactHooksJsPlugin = resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
|
|
38076
|
+
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false }) => {
|
|
38077
|
+
const reactHooksJsPlugin = disableReactHooksJsPlugin ? null : resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
|
|
38080
38078
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
38081
38079
|
const jsPlugins = [];
|
|
38082
38080
|
if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
|
|
@@ -38136,7 +38134,6 @@ const resolveOxlintBinary = () => {
|
|
|
38136
38134
|
return Path.join(oxlintPackageDirectory, "bin", "oxlint");
|
|
38137
38135
|
};
|
|
38138
38136
|
const resolvePluginPath = () => esmRequire.resolve("oxlint-plugin-react-doctor");
|
|
38139
|
-
const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
|
|
38140
38137
|
const resolveTsConfigRelativePath = (rootDirectory) => {
|
|
38141
38138
|
for (const filename of TSCONFIG_FILENAMES) if (NFS.existsSync(Path.join(rootDirectory, filename))) return `./${filename}`;
|
|
38142
38139
|
return null;
|
|
@@ -38508,7 +38505,7 @@ const scopeContainsNonImportBinding = (node, scopeNode, identifierName) => {
|
|
|
38508
38505
|
const isIdentifierShadowedByLocalBinding = (identifier, sourceFile) => {
|
|
38509
38506
|
let currentNode = identifier.parent;
|
|
38510
38507
|
while (currentNode) {
|
|
38511
|
-
if (
|
|
38508
|
+
if (isScopeBoundary(currentNode)) {
|
|
38512
38509
|
if (scopeContainsNonImportBinding(currentNode, currentNode, identifier.text)) return true;
|
|
38513
38510
|
}
|
|
38514
38511
|
if (currentNode === sourceFile) return false;
|
|
@@ -38599,11 +38596,10 @@ const findResolutionInScope = (scopeNode, identifierName, reactImportBindings, s
|
|
|
38599
38596
|
});
|
|
38600
38597
|
return resolution;
|
|
38601
38598
|
};
|
|
38602
|
-
const isScopeNode = isScopeBoundary;
|
|
38603
38599
|
const resolveIdentifierBinding = (identifier, reactImportBindings, sourceFile, visitedDeclarations = /* @__PURE__ */ new Set()) => {
|
|
38604
38600
|
let currentNode = identifier.parent;
|
|
38605
38601
|
while (currentNode) {
|
|
38606
|
-
if (
|
|
38602
|
+
if (isScopeBoundary(currentNode)) {
|
|
38607
38603
|
const resolution = findResolutionInScope(currentNode, identifier.text, reactImportBindings, sourceFile, visitedDeclarations);
|
|
38608
38604
|
if (resolution) return resolution;
|
|
38609
38605
|
}
|
|
@@ -38773,9 +38769,9 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
38773
38769
|
try {
|
|
38774
38770
|
parsed = JSON.parse(sanitizedStdout);
|
|
38775
38771
|
} catch {
|
|
38776
|
-
throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0,
|
|
38772
|
+
throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
38777
38773
|
}
|
|
38778
|
-
if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0,
|
|
38774
|
+
if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
38779
38775
|
const minifiedFileCache = /* @__PURE__ */ new Map();
|
|
38780
38776
|
const isMinifiedDiagnosticFile = (filename) => {
|
|
38781
38777
|
const absolutePath = Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
|
|
@@ -39066,6 +39062,28 @@ const writeOxlintConfig = (configPath, configToWrite) => {
|
|
|
39066
39062
|
NFS.closeSync(fileHandle);
|
|
39067
39063
|
}
|
|
39068
39064
|
};
|
|
39065
|
+
const REACT_HOOKS_JS_DROP_PREFIX = "React Compiler rules (react-hooks-js/*) skipped — eslint-plugin-react-hooks failed to load in this environment";
|
|
39066
|
+
/**
|
|
39067
|
+
* Detects an oxlint config-load crash caused by the optional
|
|
39068
|
+
* `react-hooks-js` (eslint-plugin-react-hooks) React Compiler plugin and
|
|
39069
|
+
* builds the partial-failure note for it; returns `null` when the failure
|
|
39070
|
+
* was anything else.
|
|
39071
|
+
*
|
|
39072
|
+
* oxlint prints a framed error to stdout (not stderr) and exits non-zero
|
|
39073
|
+
* when a `jsPlugins` entry can't be imported; that non-JSON stdout
|
|
39074
|
+
* surfaces as `OxlintOutputUnparseable`. Because oxlint fails the WHOLE
|
|
39075
|
+
* config load on it, leaving the plugin in would drop every curated
|
|
39076
|
+
* react-doctor diagnostic too — so the caller retries with the plugin
|
|
39077
|
+
* stripped (issue #833). Both markers sit at the start of oxlint's
|
|
39078
|
+
* message, so they survive the `preview` slice even for deep pnpm paths.
|
|
39079
|
+
*/
|
|
39080
|
+
const reactHooksJsPluginDropNote = (error) => {
|
|
39081
|
+
if (!(error instanceof ReactDoctorError) || error.reason._tag !== "OxlintOutputUnparseable") return null;
|
|
39082
|
+
const { preview } = error.reason;
|
|
39083
|
+
if (!preview.includes("Failed to load JS plugin") || !preview.includes("eslint-plugin-react-hooks")) return null;
|
|
39084
|
+
const underlyingReason = preview.match(/Error:[^\n]*/)?.[0]?.trim();
|
|
39085
|
+
return `${REACT_HOOKS_JS_DROP_PREFIX}${underlyingReason ? `: ${underlyingReason}` : ""}. Other rules ran normally.`;
|
|
39086
|
+
};
|
|
39069
39087
|
/**
|
|
39070
39088
|
* The oxlint runner. Composed of three pieces in `runners/oxlint/`:
|
|
39071
39089
|
*
|
|
@@ -39093,15 +39111,16 @@ const runOxlint = async (options) => {
|
|
|
39093
39111
|
const pluginPath = resolvePluginPath();
|
|
39094
39112
|
const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
|
|
39095
39113
|
const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
|
|
39096
|
-
const buildConfig = (
|
|
39114
|
+
const buildConfig = (overrides) => createOxlintConfig({
|
|
39097
39115
|
pluginPath,
|
|
39098
39116
|
project,
|
|
39099
39117
|
customRulesOnly,
|
|
39100
|
-
extendsPaths:
|
|
39118
|
+
extendsPaths: overrides.extendsPaths,
|
|
39101
39119
|
ignoredTags,
|
|
39102
39120
|
serverAuthFunctionNames,
|
|
39103
39121
|
severityControls,
|
|
39104
|
-
userPlugins
|
|
39122
|
+
userPlugins,
|
|
39123
|
+
disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin
|
|
39105
39124
|
});
|
|
39106
39125
|
const restoreDisableDirectives = respectInlineDisables ? () => {} : await neutralizeDisableDirectives(rootDirectory, includePaths);
|
|
39107
39126
|
const configDirectory = NFS.mkdtempSync(Path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
|
|
@@ -39137,12 +39156,22 @@ const runOxlint = async (options) => {
|
|
|
39137
39156
|
outputMaxBytes,
|
|
39138
39157
|
concurrency: options.concurrency
|
|
39139
39158
|
});
|
|
39140
|
-
writeOxlintConfig(configPath, buildConfig(extendsPaths));
|
|
39159
|
+
writeOxlintConfig(configPath, buildConfig({ extendsPaths }));
|
|
39141
39160
|
try {
|
|
39142
39161
|
return await runBatches();
|
|
39143
39162
|
} catch (error) {
|
|
39163
|
+
const reactHooksJsDropNote = reactHooksJsPluginDropNote(error);
|
|
39164
|
+
if (reactHooksJsDropNote !== null) {
|
|
39165
|
+
writeOxlintConfig(configPath, buildConfig({
|
|
39166
|
+
extendsPaths,
|
|
39167
|
+
disableReactHooksJsPlugin: true
|
|
39168
|
+
}));
|
|
39169
|
+
const diagnostics = await runBatches();
|
|
39170
|
+
onPartialFailure?.(reactHooksJsDropNote);
|
|
39171
|
+
return diagnostics;
|
|
39172
|
+
}
|
|
39144
39173
|
if (extendsPaths.length === 0) throw error;
|
|
39145
|
-
writeOxlintConfig(configPath, buildConfig([]));
|
|
39174
|
+
writeOxlintConfig(configPath, buildConfig({ extendsPaths: [] }));
|
|
39146
39175
|
return await runBatches();
|
|
39147
39176
|
}
|
|
39148
39177
|
} finally {
|
|
@@ -40974,6 +41003,11 @@ const createProjectGraph = (options) => {
|
|
|
40974
41003
|
}
|
|
40975
41004
|
};
|
|
40976
41005
|
};
|
|
41006
|
+
const toProjectRelative = (projectDirectory, filePath) => {
|
|
41007
|
+
const relative = Path.relative(projectDirectory, filePath).replace(/\\/g, "/");
|
|
41008
|
+
if (relative.length === 0 || relative.startsWith("../") || Path.isAbsolute(relative)) return null;
|
|
41009
|
+
return relative;
|
|
41010
|
+
};
|
|
40977
41011
|
const resolveCacheFilePath = (projectDirectory) => {
|
|
40978
41012
|
const nodeModules = path.join(projectDirectory, "node_modules");
|
|
40979
41013
|
if (fs.existsSync(nodeModules)) return path.join(nodeModules, ".cache", "react-doctor", "lint-cache.json");
|
|
@@ -41034,11 +41068,6 @@ const createLintCache = (input) => {
|
|
|
41034
41068
|
};
|
|
41035
41069
|
const OVERLAY_TEMP_PREFIX = "react-doctor-lsp-";
|
|
41036
41070
|
const OVERLAY_CONFIG_FILENAMES = [...new Set([...STAGED_FILES_PROJECT_CONFIG_FILENAMES, ...ADOPTABLE_LINT_CONFIG_FILENAMES])];
|
|
41037
|
-
const toProjectRelative$1 = (projectDirectory, filePath) => {
|
|
41038
|
-
const relative = path.relative(projectDirectory, filePath).replace(/\\/g, "/");
|
|
41039
|
-
if (relative.length === 0 || relative.startsWith("../") || path.isAbsolute(relative)) return null;
|
|
41040
|
-
return relative;
|
|
41041
|
-
};
|
|
41042
41071
|
/**
|
|
41043
41072
|
* Writes the live (possibly unsaved) content of the target files into a
|
|
41044
41073
|
* throwaway temp tree that mirrors the project, alongside the well-known
|
|
@@ -41052,7 +41081,7 @@ const materializeOverlay = (input) => {
|
|
|
41052
41081
|
const relativePaths = [];
|
|
41053
41082
|
try {
|
|
41054
41083
|
for (const filePath of input.files) {
|
|
41055
|
-
const relative = toProjectRelative
|
|
41084
|
+
const relative = toProjectRelative(input.projectDirectory, filePath);
|
|
41056
41085
|
if (relative === null) continue;
|
|
41057
41086
|
const content = input.readText(filePath);
|
|
41058
41087
|
if (content === null) continue;
|
|
@@ -41100,11 +41129,6 @@ const materializeOverlay = (input) => {
|
|
|
41100
41129
|
throw error;
|
|
41101
41130
|
}
|
|
41102
41131
|
};
|
|
41103
|
-
const toProjectRelative = (projectDirectory, filePath) => {
|
|
41104
|
-
const relative = path.relative(projectDirectory, filePath).replace(/\\/g, "/");
|
|
41105
|
-
if (relative.length === 0 || relative.startsWith("../") || path.isAbsolute(relative)) return null;
|
|
41106
|
-
return relative;
|
|
41107
|
-
};
|
|
41108
41132
|
/**
|
|
41109
41133
|
* Resolves a diagnostic's (possibly relative, possibly overlay-temp)
|
|
41110
41134
|
* file path back to the canonical absolute path inside the real project.
|
|
@@ -42361,5 +42385,5 @@ const startLanguageServer = () => {
|
|
|
42361
42385
|
};
|
|
42362
42386
|
//#endregion
|
|
42363
42387
|
export { startLanguageServer };
|
|
42364
|
-
!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]="
|
|
42365
|
-
//# debugId=
|
|
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]="42683a4c-8da1-5155-bf9c-b9a69b9718e6")}catch(e){}}();
|
|
42389
|
+
//# debugId=42683a4c-8da1-5155-bf9c-b9a69b9718e6
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-doctor",
|
|
3
|
-
"version": "0.5.6-dev.
|
|
3
|
+
"version": "0.5.6-dev.ed0258c",
|
|
4
4
|
"description": "Your agent writes bad React. This catches it",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"accessibility",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"vscode-languageserver": "^9.0.1",
|
|
65
65
|
"vscode-languageserver-textdocument": "^1.0.12",
|
|
66
66
|
"vscode-uri": "^3.1.0",
|
|
67
|
-
"oxlint-plugin-react-doctor": "0.5.6-dev.
|
|
67
|
+
"oxlint-plugin-react-doctor": "0.5.6-dev.ed0258c"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@types/babel__code-frame": "^7.27.0",
|
|
@@ -72,8 +72,8 @@
|
|
|
72
72
|
"@xterm/headless": "^6.0.0",
|
|
73
73
|
"commander": "^14.0.3",
|
|
74
74
|
"ora": "^9.4.0",
|
|
75
|
-
"@react-doctor/core": "0.5.6",
|
|
76
75
|
"@react-doctor/api": "0.5.6",
|
|
76
|
+
"@react-doctor/core": "0.5.6",
|
|
77
77
|
"@react-doctor/language-server": "0.5.6"
|
|
78
78
|
},
|
|
79
79
|
"engines": {
|