react-doctor 0.5.6-dev.15238de → 0.5.6-dev.424d8f9
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 +61 -25
- package/dist/index.d.ts +4 -3
- package/dist/index.js +52 -16
- package/dist/lsp.js +52 -16
- package/package.json +2 -2
package/dist/cli.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]="fc691f8f-4aa6-5f96-8491-8e4e53439952")}catch(e){}}();
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import * as NodeChildProcess from "node:child_process";
|
|
5
5
|
import { execFile, execFileSync, spawn, spawnSync } from "node:child_process";
|
|
@@ -39692,10 +39692,15 @@ const buildCapabilities = (project) => {
|
|
|
39692
39692
|
}
|
|
39693
39693
|
if (project.tailwindVersion !== null) {
|
|
39694
39694
|
capabilities.add("tailwind");
|
|
39695
|
-
|
|
39695
|
+
const tailwind = parseTailwindMajorMinor(project.tailwindVersion);
|
|
39696
|
+
if (isTailwindAtLeast(tailwind, {
|
|
39696
39697
|
major: 3,
|
|
39697
39698
|
minor: 4
|
|
39698
39699
|
})) capabilities.add("tailwind:3.4");
|
|
39700
|
+
if (tailwind !== null && isTailwindAtLeast(tailwind, {
|
|
39701
|
+
major: 4,
|
|
39702
|
+
minor: 0
|
|
39703
|
+
})) capabilities.add("tailwind:4");
|
|
39699
39704
|
}
|
|
39700
39705
|
if (project.zodVersion !== null) {
|
|
39701
39706
|
capabilities.add("zod");
|
|
@@ -39986,12 +39991,11 @@ const collectKnipPatterns = (rootDirectory, settingName) => {
|
|
|
39986
39991
|
if (!config) return [];
|
|
39987
39992
|
return [...normalizePatternList(config[settingName]), ...collectKnipWorkspacePatterns(config.workspaces, settingName)];
|
|
39988
39993
|
};
|
|
39989
|
-
const collectDeadCodeIgnorePatterns = (rootDirectory
|
|
39994
|
+
const collectDeadCodeIgnorePatterns = (rootDirectory) => {
|
|
39990
39995
|
const seen = /* @__PURE__ */ new Set();
|
|
39991
39996
|
const sources = [
|
|
39992
39997
|
readIgnoreFile(path.join(rootDirectory, ".gitignore")),
|
|
39993
39998
|
collectIgnorePatterns(rootDirectory),
|
|
39994
|
-
userConfig?.ignore?.files ?? [],
|
|
39995
39999
|
collectKnipPatterns(rootDirectory, "ignore")
|
|
39996
40000
|
];
|
|
39997
40001
|
for (const source of sources) for (const pattern of source) seen.add(pattern);
|
|
@@ -40269,11 +40273,10 @@ const runDeadCodeWorkerWithTimeout = (handle, timeoutMs) => new Promise((resolve
|
|
|
40269
40273
|
});
|
|
40270
40274
|
});
|
|
40271
40275
|
const checkDeadCode = async (options) => {
|
|
40272
|
-
const { userConfig } = options;
|
|
40273
40276
|
const rootDirectory = toCanonicalPath(options.rootDirectory);
|
|
40274
40277
|
if (!NFS.existsSync(Path.join(rootDirectory, "package.json"))) return [];
|
|
40275
40278
|
const entryPatterns = collectDeadCodeEntryPatterns(rootDirectory);
|
|
40276
|
-
const ignorePatterns = collectDeadCodeIgnorePatterns(rootDirectory
|
|
40279
|
+
const ignorePatterns = collectDeadCodeIgnorePatterns(rootDirectory);
|
|
40277
40280
|
const result = parseDeadCodeWorkerResult(await runDeadCodeWorkerWithTimeout((options.createWorker ?? createDeadCodeWorker)({
|
|
40278
40281
|
rootDirectory,
|
|
40279
40282
|
entryPatterns,
|
|
@@ -41322,8 +41325,8 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
41322
41325
|
}
|
|
41323
41326
|
return enabled;
|
|
41324
41327
|
};
|
|
41325
|
-
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [] }) => {
|
|
41326
|
-
const reactHooksJsPlugin = resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
|
|
41328
|
+
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false }) => {
|
|
41329
|
+
const reactHooksJsPlugin = disableReactHooksJsPlugin ? null : resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
|
|
41327
41330
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
41328
41331
|
const jsPlugins = [];
|
|
41329
41332
|
if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
|
|
@@ -42020,9 +42023,9 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
42020
42023
|
try {
|
|
42021
42024
|
parsed = JSON.parse(sanitizedStdout);
|
|
42022
42025
|
} catch {
|
|
42023
|
-
throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0,
|
|
42026
|
+
throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
42024
42027
|
}
|
|
42025
|
-
if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0,
|
|
42028
|
+
if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
42026
42029
|
const minifiedFileCache = /* @__PURE__ */ new Map();
|
|
42027
42030
|
const isMinifiedDiagnosticFile = (filename) => {
|
|
42028
42031
|
const absolutePath = Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
|
|
@@ -42313,6 +42316,28 @@ const writeOxlintConfig = (configPath, configToWrite) => {
|
|
|
42313
42316
|
NFS.closeSync(fileHandle);
|
|
42314
42317
|
}
|
|
42315
42318
|
};
|
|
42319
|
+
const REACT_HOOKS_JS_DROP_PREFIX = "React Compiler rules (react-hooks-js/*) skipped — eslint-plugin-react-hooks failed to load in this environment";
|
|
42320
|
+
/**
|
|
42321
|
+
* Detects an oxlint config-load crash caused by the optional
|
|
42322
|
+
* `react-hooks-js` (eslint-plugin-react-hooks) React Compiler plugin and
|
|
42323
|
+
* builds the partial-failure note for it; returns `null` when the failure
|
|
42324
|
+
* was anything else.
|
|
42325
|
+
*
|
|
42326
|
+
* oxlint prints a framed error to stdout (not stderr) and exits non-zero
|
|
42327
|
+
* when a `jsPlugins` entry can't be imported; that non-JSON stdout
|
|
42328
|
+
* surfaces as `OxlintOutputUnparseable`. Because oxlint fails the WHOLE
|
|
42329
|
+
* config load on it, leaving the plugin in would drop every curated
|
|
42330
|
+
* react-doctor diagnostic too — so the caller retries with the plugin
|
|
42331
|
+
* stripped (issue #833). Both markers sit at the start of oxlint's
|
|
42332
|
+
* message, so they survive the `preview` slice even for deep pnpm paths.
|
|
42333
|
+
*/
|
|
42334
|
+
const reactHooksJsPluginDropNote = (error) => {
|
|
42335
|
+
if (!(error instanceof ReactDoctorError) || error.reason._tag !== "OxlintOutputUnparseable") return null;
|
|
42336
|
+
const { preview } = error.reason;
|
|
42337
|
+
if (!preview.includes("Failed to load JS plugin") || !preview.includes("eslint-plugin-react-hooks")) return null;
|
|
42338
|
+
const underlyingReason = preview.match(/Error:[^\n]*/)?.[0]?.trim();
|
|
42339
|
+
return `${REACT_HOOKS_JS_DROP_PREFIX}${underlyingReason ? `: ${underlyingReason}` : ""}. Other rules ran normally.`;
|
|
42340
|
+
};
|
|
42316
42341
|
/**
|
|
42317
42342
|
* The oxlint runner. Composed of three pieces in `runners/oxlint/`:
|
|
42318
42343
|
*
|
|
@@ -42340,15 +42365,16 @@ const runOxlint = async (options) => {
|
|
|
42340
42365
|
const pluginPath = resolvePluginPath();
|
|
42341
42366
|
const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
|
|
42342
42367
|
const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
|
|
42343
|
-
const buildConfig = (
|
|
42368
|
+
const buildConfig = (overrides) => createOxlintConfig({
|
|
42344
42369
|
pluginPath,
|
|
42345
42370
|
project,
|
|
42346
42371
|
customRulesOnly,
|
|
42347
|
-
extendsPaths:
|
|
42372
|
+
extendsPaths: overrides.extendsPaths,
|
|
42348
42373
|
ignoredTags,
|
|
42349
42374
|
serverAuthFunctionNames,
|
|
42350
42375
|
severityControls,
|
|
42351
|
-
userPlugins
|
|
42376
|
+
userPlugins,
|
|
42377
|
+
disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin
|
|
42352
42378
|
});
|
|
42353
42379
|
const restoreDisableDirectives = respectInlineDisables ? () => {} : await neutralizeDisableDirectives(rootDirectory, includePaths);
|
|
42354
42380
|
const configDirectory = NFS.mkdtempSync(Path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
|
|
@@ -42384,12 +42410,22 @@ const runOxlint = async (options) => {
|
|
|
42384
42410
|
outputMaxBytes,
|
|
42385
42411
|
concurrency: options.concurrency
|
|
42386
42412
|
});
|
|
42387
|
-
writeOxlintConfig(configPath, buildConfig(extendsPaths));
|
|
42413
|
+
writeOxlintConfig(configPath, buildConfig({ extendsPaths }));
|
|
42388
42414
|
try {
|
|
42389
42415
|
return await runBatches();
|
|
42390
42416
|
} catch (error) {
|
|
42417
|
+
const reactHooksJsDropNote = reactHooksJsPluginDropNote(error);
|
|
42418
|
+
if (reactHooksJsDropNote !== null) {
|
|
42419
|
+
writeOxlintConfig(configPath, buildConfig({
|
|
42420
|
+
extendsPaths,
|
|
42421
|
+
disableReactHooksJsPlugin: true
|
|
42422
|
+
}));
|
|
42423
|
+
const diagnostics = await runBatches();
|
|
42424
|
+
onPartialFailure?.(reactHooksJsDropNote);
|
|
42425
|
+
return diagnostics;
|
|
42426
|
+
}
|
|
42391
42427
|
if (extendsPaths.length === 0) throw error;
|
|
42392
|
-
writeOxlintConfig(configPath, buildConfig([]));
|
|
42428
|
+
writeOxlintConfig(configPath, buildConfig({ extendsPaths: [] }));
|
|
42393
42429
|
return await runBatches();
|
|
42394
42430
|
}
|
|
42395
42431
|
} finally {
|
|
@@ -43972,7 +44008,7 @@ const makeNoopConsole = () => ({
|
|
|
43972
44008
|
});
|
|
43973
44009
|
//#endregion
|
|
43974
44010
|
//#region src/cli/utils/version.ts
|
|
43975
|
-
const VERSION = "0.5.6-dev.
|
|
44011
|
+
const VERSION = "0.5.6-dev.424d8f9";
|
|
43976
44012
|
//#endregion
|
|
43977
44013
|
//#region src/cli/utils/json-mode.ts
|
|
43978
44014
|
let context = null;
|
|
@@ -44330,13 +44366,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
|
|
|
44330
44366
|
* uploads source-map artifacts under, so stack frames symbolicate. Honors the
|
|
44331
44367
|
* standard `SENTRY_RELEASE` override.
|
|
44332
44368
|
*/
|
|
44333
|
-
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.5.6-dev.
|
|
44369
|
+
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.5.6-dev.424d8f9`;
|
|
44334
44370
|
/**
|
|
44335
44371
|
* Deployment environment shown in Sentry's environment filter. Defaults to
|
|
44336
44372
|
* `production` for tagged releases and `development` for dev/unbuilt versions,
|
|
44337
44373
|
* overridable via the standard `SENTRY_ENVIRONMENT` env var.
|
|
44338
44374
|
*/
|
|
44339
|
-
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.5.6-dev.
|
|
44375
|
+
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.5.6-dev.424d8f9") ? "development" : "production");
|
|
44340
44376
|
/**
|
|
44341
44377
|
* Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
|
|
44342
44378
|
* (set to `0` to disable tracing) and falls back to
|
|
@@ -48118,7 +48154,7 @@ const AGENT_GUIDANCE_LINES = [
|
|
|
48118
48154
|
"Investigate deeply where relevant: race conditions, security-sensitive flows, state propagation, multi-file refactors, and downstream dependency chains.",
|
|
48119
48155
|
"Ignore pure style preferences, theoretical issues without real impact, missing features, and unrelated pre-existing code.",
|
|
48120
48156
|
"Start with high-confidence fixes that preserve behavior. Leave low-confidence or product-dependent changes as notes.",
|
|
48121
|
-
"Run `npx react-doctor@latest --verbose --
|
|
48157
|
+
"Run `npx react-doctor@latest --verbose --scope changed` before and after changes, plus relevant tests after each focused batch.",
|
|
48122
48158
|
"When available, spawn subagents or isolated worktrees for independent rule families, then review and merge only the best safe fixes.",
|
|
48123
48159
|
"Split unrelated, broad, or behavior-changing work into separate PRs/branches instead of one large cleanup.",
|
|
48124
48160
|
"For confirmed issues that cannot be fixed now, create GitHub issues with the rule, file/line, confidence, impact, and proposed fix.",
|
|
@@ -50760,22 +50796,22 @@ const buildAgentHookScript = () => [
|
|
|
50760
50796
|
"",
|
|
50761
50797
|
"run_react_doctor() {",
|
|
50762
50798
|
" if [ -x ./node_modules/.bin/react-doctor ]; then",
|
|
50763
|
-
" ./node_modules/.bin/react-doctor --verbose --
|
|
50799
|
+
" ./node_modules/.bin/react-doctor --verbose --scope changed --blocking warning --no-score",
|
|
50764
50800
|
" return",
|
|
50765
50801
|
" fi",
|
|
50766
50802
|
"",
|
|
50767
50803
|
" if command -v react-doctor >/dev/null 2>&1; then",
|
|
50768
|
-
" react-doctor --verbose --
|
|
50804
|
+
" react-doctor --verbose --scope changed --blocking warning --no-score",
|
|
50769
50805
|
" return",
|
|
50770
50806
|
" fi",
|
|
50771
50807
|
"",
|
|
50772
50808
|
" if command -v pnpm >/dev/null 2>&1; then",
|
|
50773
|
-
" pnpm dlx react-doctor@latest --verbose --
|
|
50809
|
+
" pnpm dlx react-doctor@latest --verbose --scope changed --blocking warning --no-score",
|
|
50774
50810
|
" return",
|
|
50775
50811
|
" fi",
|
|
50776
50812
|
"",
|
|
50777
50813
|
" if command -v npx >/dev/null 2>&1; then",
|
|
50778
|
-
" npx --yes react-doctor@latest --verbose --
|
|
50814
|
+
" npx --yes react-doctor@latest --verbose --scope changed --blocking warning --no-score",
|
|
50779
50815
|
" return",
|
|
50780
50816
|
" fi",
|
|
50781
50817
|
"",
|
|
@@ -53872,7 +53908,7 @@ ${highlighter.dim("Examples:")}
|
|
|
53872
53908
|
${formatExampleLines([
|
|
53873
53909
|
["react-doctor", "scan the current project"],
|
|
53874
53910
|
["react-doctor ./apps/web", "scan a specific directory"],
|
|
53875
|
-
["react-doctor --
|
|
53911
|
+
["react-doctor --scope changed --base main", "scan only new issues vs. main"],
|
|
53876
53912
|
["react-doctor --project modules/a,modules/b", "score each module separately (names or paths)"],
|
|
53877
53913
|
["react-doctor --staged", "scan staged files (pre-commit hook)"],
|
|
53878
53914
|
["react-doctor --category Security", "show only one diagnostic category"],
|
|
@@ -53948,4 +53984,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
|
|
|
53948
53984
|
export {};
|
|
53949
53985
|
|
|
53950
53986
|
//# sourceMappingURL=cli.js.map
|
|
53951
|
-
//# debugId=
|
|
53987
|
+
//# debugId=fc691f8f-4aa6-5f96-8491-8e4e53439952
|
package/dist/index.d.ts
CHANGED
|
@@ -9280,9 +9280,10 @@ interface ReactDoctorConfig {
|
|
|
9280
9280
|
* list, user-provided names are treated as distinctive and never
|
|
9281
9281
|
* subject to receiver-object disambiguation.
|
|
9282
9282
|
*
|
|
9283
|
-
*
|
|
9284
|
-
*
|
|
9285
|
-
*
|
|
9283
|
+
* Common guard conventions are already recognized automatically
|
|
9284
|
+
* (`requireAdmin`, `ensureSignedIn`, `getCurrentUser`, `hasRole`, …),
|
|
9285
|
+
* so this is only needed for domain-specific guards whose names carry
|
|
9286
|
+
* no auth noun — e.g. a project-local `requireWorkspaceMember`.
|
|
9286
9287
|
*/
|
|
9287
9288
|
serverAuthFunctionNames?: string[];
|
|
9288
9289
|
/**
|
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]="3b9fafb6-a936-52a2-96df-a26760fdafc1")}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";
|
|
@@ -36472,10 +36472,15 @@ const buildCapabilities = (project) => {
|
|
|
36472
36472
|
}
|
|
36473
36473
|
if (project.tailwindVersion !== null) {
|
|
36474
36474
|
capabilities.add("tailwind");
|
|
36475
|
-
|
|
36475
|
+
const tailwind = parseTailwindMajorMinor(project.tailwindVersion);
|
|
36476
|
+
if (isTailwindAtLeast(tailwind, {
|
|
36476
36477
|
major: 3,
|
|
36477
36478
|
minor: 4
|
|
36478
36479
|
})) capabilities.add("tailwind:3.4");
|
|
36480
|
+
if (tailwind !== null && isTailwindAtLeast(tailwind, {
|
|
36481
|
+
major: 4,
|
|
36482
|
+
minor: 0
|
|
36483
|
+
})) capabilities.add("tailwind:4");
|
|
36479
36484
|
}
|
|
36480
36485
|
if (project.zodVersion !== null) {
|
|
36481
36486
|
capabilities.add("zod");
|
|
@@ -36750,12 +36755,11 @@ const collectKnipPatterns = (rootDirectory, settingName) => {
|
|
|
36750
36755
|
if (!config) return [];
|
|
36751
36756
|
return [...normalizePatternList(config[settingName]), ...collectKnipWorkspacePatterns(config.workspaces, settingName)];
|
|
36752
36757
|
};
|
|
36753
|
-
const collectDeadCodeIgnorePatterns = (rootDirectory
|
|
36758
|
+
const collectDeadCodeIgnorePatterns = (rootDirectory) => {
|
|
36754
36759
|
const seen = /* @__PURE__ */ new Set();
|
|
36755
36760
|
const sources = [
|
|
36756
36761
|
readIgnoreFile(path.join(rootDirectory, ".gitignore")),
|
|
36757
36762
|
collectIgnorePatterns(rootDirectory),
|
|
36758
|
-
userConfig?.ignore?.files ?? [],
|
|
36759
36763
|
collectKnipPatterns(rootDirectory, "ignore")
|
|
36760
36764
|
];
|
|
36761
36765
|
for (const source of sources) for (const pattern of source) seen.add(pattern);
|
|
@@ -37033,11 +37037,10 @@ const runDeadCodeWorkerWithTimeout = (handle, timeoutMs) => new Promise((resolve
|
|
|
37033
37037
|
});
|
|
37034
37038
|
});
|
|
37035
37039
|
const checkDeadCode = async (options) => {
|
|
37036
|
-
const { userConfig } = options;
|
|
37037
37040
|
const rootDirectory = toCanonicalPath(options.rootDirectory);
|
|
37038
37041
|
if (!NFS.existsSync(Path.join(rootDirectory, "package.json"))) return [];
|
|
37039
37042
|
const entryPatterns = collectDeadCodeEntryPatterns(rootDirectory);
|
|
37040
|
-
const ignorePatterns = collectDeadCodeIgnorePatterns(rootDirectory
|
|
37043
|
+
const ignorePatterns = collectDeadCodeIgnorePatterns(rootDirectory);
|
|
37041
37044
|
const result = parseDeadCodeWorkerResult(await runDeadCodeWorkerWithTimeout((options.createWorker ?? createDeadCodeWorker)({
|
|
37042
37045
|
rootDirectory,
|
|
37043
37046
|
entryPatterns,
|
|
@@ -38086,8 +38089,8 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
38086
38089
|
}
|
|
38087
38090
|
return enabled;
|
|
38088
38091
|
};
|
|
38089
|
-
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [] }) => {
|
|
38090
|
-
const reactHooksJsPlugin = resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
|
|
38092
|
+
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false }) => {
|
|
38093
|
+
const reactHooksJsPlugin = disableReactHooksJsPlugin ? null : resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
|
|
38091
38094
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
38092
38095
|
const jsPlugins = [];
|
|
38093
38096
|
if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
|
|
@@ -38784,9 +38787,9 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
38784
38787
|
try {
|
|
38785
38788
|
parsed = JSON.parse(sanitizedStdout);
|
|
38786
38789
|
} catch {
|
|
38787
|
-
throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0,
|
|
38790
|
+
throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
38788
38791
|
}
|
|
38789
|
-
if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0,
|
|
38792
|
+
if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
38790
38793
|
const minifiedFileCache = /* @__PURE__ */ new Map();
|
|
38791
38794
|
const isMinifiedDiagnosticFile = (filename) => {
|
|
38792
38795
|
const absolutePath = Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
|
|
@@ -39077,6 +39080,28 @@ const writeOxlintConfig = (configPath, configToWrite) => {
|
|
|
39077
39080
|
NFS.closeSync(fileHandle);
|
|
39078
39081
|
}
|
|
39079
39082
|
};
|
|
39083
|
+
const REACT_HOOKS_JS_DROP_PREFIX = "React Compiler rules (react-hooks-js/*) skipped — eslint-plugin-react-hooks failed to load in this environment";
|
|
39084
|
+
/**
|
|
39085
|
+
* Detects an oxlint config-load crash caused by the optional
|
|
39086
|
+
* `react-hooks-js` (eslint-plugin-react-hooks) React Compiler plugin and
|
|
39087
|
+
* builds the partial-failure note for it; returns `null` when the failure
|
|
39088
|
+
* was anything else.
|
|
39089
|
+
*
|
|
39090
|
+
* oxlint prints a framed error to stdout (not stderr) and exits non-zero
|
|
39091
|
+
* when a `jsPlugins` entry can't be imported; that non-JSON stdout
|
|
39092
|
+
* surfaces as `OxlintOutputUnparseable`. Because oxlint fails the WHOLE
|
|
39093
|
+
* config load on it, leaving the plugin in would drop every curated
|
|
39094
|
+
* react-doctor diagnostic too — so the caller retries with the plugin
|
|
39095
|
+
* stripped (issue #833). Both markers sit at the start of oxlint's
|
|
39096
|
+
* message, so they survive the `preview` slice even for deep pnpm paths.
|
|
39097
|
+
*/
|
|
39098
|
+
const reactHooksJsPluginDropNote = (error) => {
|
|
39099
|
+
if (!(error instanceof ReactDoctorError) || error.reason._tag !== "OxlintOutputUnparseable") return null;
|
|
39100
|
+
const { preview } = error.reason;
|
|
39101
|
+
if (!preview.includes("Failed to load JS plugin") || !preview.includes("eslint-plugin-react-hooks")) return null;
|
|
39102
|
+
const underlyingReason = preview.match(/Error:[^\n]*/)?.[0]?.trim();
|
|
39103
|
+
return `${REACT_HOOKS_JS_DROP_PREFIX}${underlyingReason ? `: ${underlyingReason}` : ""}. Other rules ran normally.`;
|
|
39104
|
+
};
|
|
39080
39105
|
/**
|
|
39081
39106
|
* The oxlint runner. Composed of three pieces in `runners/oxlint/`:
|
|
39082
39107
|
*
|
|
@@ -39104,15 +39129,16 @@ const runOxlint = async (options) => {
|
|
|
39104
39129
|
const pluginPath = resolvePluginPath();
|
|
39105
39130
|
const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
|
|
39106
39131
|
const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
|
|
39107
|
-
const buildConfig = (
|
|
39132
|
+
const buildConfig = (overrides) => createOxlintConfig({
|
|
39108
39133
|
pluginPath,
|
|
39109
39134
|
project,
|
|
39110
39135
|
customRulesOnly,
|
|
39111
|
-
extendsPaths:
|
|
39136
|
+
extendsPaths: overrides.extendsPaths,
|
|
39112
39137
|
ignoredTags,
|
|
39113
39138
|
serverAuthFunctionNames,
|
|
39114
39139
|
severityControls,
|
|
39115
|
-
userPlugins
|
|
39140
|
+
userPlugins,
|
|
39141
|
+
disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin
|
|
39116
39142
|
});
|
|
39117
39143
|
const restoreDisableDirectives = respectInlineDisables ? () => {} : await neutralizeDisableDirectives(rootDirectory, includePaths);
|
|
39118
39144
|
const configDirectory = NFS.mkdtempSync(Path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
|
|
@@ -39148,12 +39174,22 @@ const runOxlint = async (options) => {
|
|
|
39148
39174
|
outputMaxBytes,
|
|
39149
39175
|
concurrency: options.concurrency
|
|
39150
39176
|
});
|
|
39151
|
-
writeOxlintConfig(configPath, buildConfig(extendsPaths));
|
|
39177
|
+
writeOxlintConfig(configPath, buildConfig({ extendsPaths }));
|
|
39152
39178
|
try {
|
|
39153
39179
|
return await runBatches();
|
|
39154
39180
|
} catch (error) {
|
|
39181
|
+
const reactHooksJsDropNote = reactHooksJsPluginDropNote(error);
|
|
39182
|
+
if (reactHooksJsDropNote !== null) {
|
|
39183
|
+
writeOxlintConfig(configPath, buildConfig({
|
|
39184
|
+
extendsPaths,
|
|
39185
|
+
disableReactHooksJsPlugin: true
|
|
39186
|
+
}));
|
|
39187
|
+
const diagnostics = await runBatches();
|
|
39188
|
+
onPartialFailure?.(reactHooksJsDropNote);
|
|
39189
|
+
return diagnostics;
|
|
39190
|
+
}
|
|
39155
39191
|
if (extendsPaths.length === 0) throw error;
|
|
39156
|
-
writeOxlintConfig(configPath, buildConfig([]));
|
|
39192
|
+
writeOxlintConfig(configPath, buildConfig({ extendsPaths: [] }));
|
|
39157
39193
|
return await runBatches();
|
|
39158
39194
|
}
|
|
39159
39195
|
} finally {
|
|
@@ -40573,4 +40609,4 @@ const toJsonReport = (result, options) => buildJsonReport({
|
|
|
40573
40609
|
export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
|
|
40574
40610
|
|
|
40575
40611
|
//# sourceMappingURL=index.js.map
|
|
40576
|
-
//# debugId=
|
|
40612
|
+
//# debugId=3b9fafb6-a936-52a2-96df-a26760fdafc1
|
package/dist/lsp.js
CHANGED
|
@@ -36458,10 +36458,15 @@ const buildCapabilities = (project) => {
|
|
|
36458
36458
|
}
|
|
36459
36459
|
if (project.tailwindVersion !== null) {
|
|
36460
36460
|
capabilities.add("tailwind");
|
|
36461
|
-
|
|
36461
|
+
const tailwind = parseTailwindMajorMinor(project.tailwindVersion);
|
|
36462
|
+
if (isTailwindAtLeast(tailwind, {
|
|
36462
36463
|
major: 3,
|
|
36463
36464
|
minor: 4
|
|
36464
36465
|
})) capabilities.add("tailwind:3.4");
|
|
36466
|
+
if (tailwind !== null && isTailwindAtLeast(tailwind, {
|
|
36467
|
+
major: 4,
|
|
36468
|
+
minor: 0
|
|
36469
|
+
})) capabilities.add("tailwind:4");
|
|
36465
36470
|
}
|
|
36466
36471
|
if (project.zodVersion !== null) {
|
|
36467
36472
|
capabilities.add("zod");
|
|
@@ -36736,12 +36741,11 @@ const collectKnipPatterns = (rootDirectory, settingName) => {
|
|
|
36736
36741
|
if (!config) return [];
|
|
36737
36742
|
return [...normalizePatternList(config[settingName]), ...collectKnipWorkspacePatterns(config.workspaces, settingName)];
|
|
36738
36743
|
};
|
|
36739
|
-
const collectDeadCodeIgnorePatterns = (rootDirectory
|
|
36744
|
+
const collectDeadCodeIgnorePatterns = (rootDirectory) => {
|
|
36740
36745
|
const seen = /* @__PURE__ */ new Set();
|
|
36741
36746
|
const sources = [
|
|
36742
36747
|
readIgnoreFile(path.join(rootDirectory, ".gitignore")),
|
|
36743
36748
|
collectIgnorePatterns(rootDirectory),
|
|
36744
|
-
userConfig?.ignore?.files ?? [],
|
|
36745
36749
|
collectKnipPatterns(rootDirectory, "ignore")
|
|
36746
36750
|
];
|
|
36747
36751
|
for (const source of sources) for (const pattern of source) seen.add(pattern);
|
|
@@ -37019,11 +37023,10 @@ const runDeadCodeWorkerWithTimeout = (handle, timeoutMs) => new Promise((resolve
|
|
|
37019
37023
|
});
|
|
37020
37024
|
});
|
|
37021
37025
|
const checkDeadCode = async (options) => {
|
|
37022
|
-
const { userConfig } = options;
|
|
37023
37026
|
const rootDirectory = toCanonicalPath(options.rootDirectory);
|
|
37024
37027
|
if (!NFS.existsSync(Path.join(rootDirectory, "package.json"))) return [];
|
|
37025
37028
|
const entryPatterns = collectDeadCodeEntryPatterns(rootDirectory);
|
|
37026
|
-
const ignorePatterns = collectDeadCodeIgnorePatterns(rootDirectory
|
|
37029
|
+
const ignorePatterns = collectDeadCodeIgnorePatterns(rootDirectory);
|
|
37027
37030
|
const result = parseDeadCodeWorkerResult(await runDeadCodeWorkerWithTimeout((options.createWorker ?? createDeadCodeWorker)({
|
|
37028
37031
|
rootDirectory,
|
|
37029
37032
|
entryPatterns,
|
|
@@ -38072,8 +38075,8 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
38072
38075
|
}
|
|
38073
38076
|
return enabled;
|
|
38074
38077
|
};
|
|
38075
|
-
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [] }) => {
|
|
38076
|
-
const reactHooksJsPlugin = resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
|
|
38078
|
+
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false }) => {
|
|
38079
|
+
const reactHooksJsPlugin = disableReactHooksJsPlugin ? null : resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
|
|
38077
38080
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
38078
38081
|
const jsPlugins = [];
|
|
38079
38082
|
if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
|
|
@@ -38770,9 +38773,9 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
38770
38773
|
try {
|
|
38771
38774
|
parsed = JSON.parse(sanitizedStdout);
|
|
38772
38775
|
} catch {
|
|
38773
|
-
throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0,
|
|
38776
|
+
throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
38774
38777
|
}
|
|
38775
|
-
if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0,
|
|
38778
|
+
if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
38776
38779
|
const minifiedFileCache = /* @__PURE__ */ new Map();
|
|
38777
38780
|
const isMinifiedDiagnosticFile = (filename) => {
|
|
38778
38781
|
const absolutePath = Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
|
|
@@ -39063,6 +39066,28 @@ const writeOxlintConfig = (configPath, configToWrite) => {
|
|
|
39063
39066
|
NFS.closeSync(fileHandle);
|
|
39064
39067
|
}
|
|
39065
39068
|
};
|
|
39069
|
+
const REACT_HOOKS_JS_DROP_PREFIX = "React Compiler rules (react-hooks-js/*) skipped — eslint-plugin-react-hooks failed to load in this environment";
|
|
39070
|
+
/**
|
|
39071
|
+
* Detects an oxlint config-load crash caused by the optional
|
|
39072
|
+
* `react-hooks-js` (eslint-plugin-react-hooks) React Compiler plugin and
|
|
39073
|
+
* builds the partial-failure note for it; returns `null` when the failure
|
|
39074
|
+
* was anything else.
|
|
39075
|
+
*
|
|
39076
|
+
* oxlint prints a framed error to stdout (not stderr) and exits non-zero
|
|
39077
|
+
* when a `jsPlugins` entry can't be imported; that non-JSON stdout
|
|
39078
|
+
* surfaces as `OxlintOutputUnparseable`. Because oxlint fails the WHOLE
|
|
39079
|
+
* config load on it, leaving the plugin in would drop every curated
|
|
39080
|
+
* react-doctor diagnostic too — so the caller retries with the plugin
|
|
39081
|
+
* stripped (issue #833). Both markers sit at the start of oxlint's
|
|
39082
|
+
* message, so they survive the `preview` slice even for deep pnpm paths.
|
|
39083
|
+
*/
|
|
39084
|
+
const reactHooksJsPluginDropNote = (error) => {
|
|
39085
|
+
if (!(error instanceof ReactDoctorError) || error.reason._tag !== "OxlintOutputUnparseable") return null;
|
|
39086
|
+
const { preview } = error.reason;
|
|
39087
|
+
if (!preview.includes("Failed to load JS plugin") || !preview.includes("eslint-plugin-react-hooks")) return null;
|
|
39088
|
+
const underlyingReason = preview.match(/Error:[^\n]*/)?.[0]?.trim();
|
|
39089
|
+
return `${REACT_HOOKS_JS_DROP_PREFIX}${underlyingReason ? `: ${underlyingReason}` : ""}. Other rules ran normally.`;
|
|
39090
|
+
};
|
|
39066
39091
|
/**
|
|
39067
39092
|
* The oxlint runner. Composed of three pieces in `runners/oxlint/`:
|
|
39068
39093
|
*
|
|
@@ -39090,15 +39115,16 @@ const runOxlint = async (options) => {
|
|
|
39090
39115
|
const pluginPath = resolvePluginPath();
|
|
39091
39116
|
const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
|
|
39092
39117
|
const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
|
|
39093
|
-
const buildConfig = (
|
|
39118
|
+
const buildConfig = (overrides) => createOxlintConfig({
|
|
39094
39119
|
pluginPath,
|
|
39095
39120
|
project,
|
|
39096
39121
|
customRulesOnly,
|
|
39097
|
-
extendsPaths:
|
|
39122
|
+
extendsPaths: overrides.extendsPaths,
|
|
39098
39123
|
ignoredTags,
|
|
39099
39124
|
serverAuthFunctionNames,
|
|
39100
39125
|
severityControls,
|
|
39101
|
-
userPlugins
|
|
39126
|
+
userPlugins,
|
|
39127
|
+
disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin
|
|
39102
39128
|
});
|
|
39103
39129
|
const restoreDisableDirectives = respectInlineDisables ? () => {} : await neutralizeDisableDirectives(rootDirectory, includePaths);
|
|
39104
39130
|
const configDirectory = NFS.mkdtempSync(Path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
|
|
@@ -39134,12 +39160,22 @@ const runOxlint = async (options) => {
|
|
|
39134
39160
|
outputMaxBytes,
|
|
39135
39161
|
concurrency: options.concurrency
|
|
39136
39162
|
});
|
|
39137
|
-
writeOxlintConfig(configPath, buildConfig(extendsPaths));
|
|
39163
|
+
writeOxlintConfig(configPath, buildConfig({ extendsPaths }));
|
|
39138
39164
|
try {
|
|
39139
39165
|
return await runBatches();
|
|
39140
39166
|
} catch (error) {
|
|
39167
|
+
const reactHooksJsDropNote = reactHooksJsPluginDropNote(error);
|
|
39168
|
+
if (reactHooksJsDropNote !== null) {
|
|
39169
|
+
writeOxlintConfig(configPath, buildConfig({
|
|
39170
|
+
extendsPaths,
|
|
39171
|
+
disableReactHooksJsPlugin: true
|
|
39172
|
+
}));
|
|
39173
|
+
const diagnostics = await runBatches();
|
|
39174
|
+
onPartialFailure?.(reactHooksJsDropNote);
|
|
39175
|
+
return diagnostics;
|
|
39176
|
+
}
|
|
39141
39177
|
if (extendsPaths.length === 0) throw error;
|
|
39142
|
-
writeOxlintConfig(configPath, buildConfig([]));
|
|
39178
|
+
writeOxlintConfig(configPath, buildConfig({ extendsPaths: [] }));
|
|
39143
39179
|
return await runBatches();
|
|
39144
39180
|
}
|
|
39145
39181
|
} finally {
|
|
@@ -42358,5 +42394,5 @@ const startLanguageServer = () => {
|
|
|
42358
42394
|
};
|
|
42359
42395
|
//#endregion
|
|
42360
42396
|
export { startLanguageServer };
|
|
42361
|
-
!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]="
|
|
42362
|
-
//# debugId=
|
|
42397
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="90262051-3b30-5292-8128-962466deb4ac")}catch(e){}}();
|
|
42398
|
+
//# debugId=90262051-3b30-5292-8128-962466deb4ac
|
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.424d8f9",
|
|
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.424d8f9"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@types/babel__code-frame": "^7.27.0",
|