react-doctor 0.7.9-dev.9aa98b9 → 0.7.9-dev.a16e452
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 +54 -47
- package/dist/index.d.ts +1 -0
- package/dist/index.js +51 -27
- package/dist/lsp.js +51 -44
- 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]="5c4df375-a5c4-57d2-9076-4e54cbb8f3bd")}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";
|
|
@@ -36532,11 +36532,8 @@ const frameworkMergeRank = (framework) => {
|
|
|
36532
36532
|
if (framework === "unknown") return 3;
|
|
36533
36533
|
return MOBILE_FRAMEWORKS.has(framework) ? 2 : 1;
|
|
36534
36534
|
};
|
|
36535
|
-
const
|
|
36536
|
-
|
|
36537
|
-
"react-compiler-runtime",
|
|
36538
|
-
"eslint-plugin-react-compiler"
|
|
36539
|
-
]);
|
|
36535
|
+
const REACT_COMPILER_TRANSFORM_PACKAGES = new Set(["babel-plugin-react-compiler", "react-compiler-runtime"]);
|
|
36536
|
+
const REACT_COMPILER_LINT_PACKAGES = new Set(["eslint-plugin-react-compiler"]);
|
|
36540
36537
|
const NEXT_CONFIG_FILENAMES = [
|
|
36541
36538
|
"next.config.js",
|
|
36542
36539
|
"next.config.mjs",
|
|
@@ -36566,16 +36563,29 @@ const EXPO_APP_CONFIG_FILENAMES = [
|
|
|
36566
36563
|
"app.config.js",
|
|
36567
36564
|
"app.config.ts"
|
|
36568
36565
|
];
|
|
36569
|
-
const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|
|
|
36566
|
+
const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|["']react-compiler["']/;
|
|
36570
36567
|
const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
|
|
36571
36568
|
const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
|
|
36572
|
-
const hasCompilerPackage = (packageJson) => {
|
|
36569
|
+
const hasCompilerPackage = (packageJson, compilerPackages) => {
|
|
36573
36570
|
const allDependencies = {
|
|
36574
36571
|
...packageJson.peerDependencies,
|
|
36575
36572
|
...packageJson.dependencies,
|
|
36576
36573
|
...packageJson.devDependencies
|
|
36577
36574
|
};
|
|
36578
|
-
return Object.keys(allDependencies).some((packageName) =>
|
|
36575
|
+
return Object.keys(allDependencies).some((packageName) => compilerPackages.has(packageName));
|
|
36576
|
+
};
|
|
36577
|
+
const hasCompilerPackageInAncestors = (directory, compilerPackages) => {
|
|
36578
|
+
if (isProjectBoundary(directory)) return false;
|
|
36579
|
+
let ancestorDirectory = Path.dirname(directory);
|
|
36580
|
+
while (ancestorDirectory !== Path.dirname(ancestorDirectory)) {
|
|
36581
|
+
const ancestorPackagePath = Path.join(ancestorDirectory, "package.json");
|
|
36582
|
+
if (isFile(ancestorPackagePath)) {
|
|
36583
|
+
if (hasCompilerPackage(readPackageJson$1(ancestorPackagePath), compilerPackages)) return true;
|
|
36584
|
+
}
|
|
36585
|
+
if (isProjectBoundary(ancestorDirectory)) return false;
|
|
36586
|
+
ancestorDirectory = Path.dirname(ancestorDirectory);
|
|
36587
|
+
}
|
|
36588
|
+
return false;
|
|
36579
36589
|
};
|
|
36580
36590
|
const hasCompilerInConfigFile = (filePath) => {
|
|
36581
36591
|
if (!isFile(filePath)) return false;
|
|
@@ -36584,23 +36594,14 @@ const hasCompilerInConfigFile = (filePath) => {
|
|
|
36584
36594
|
};
|
|
36585
36595
|
const hasCompilerInConfigFiles = (directory, filenames) => filenames.some((filename) => hasCompilerInConfigFile(Path.join(directory, filename)));
|
|
36586
36596
|
const detectReactCompiler = (directory, packageJson) => {
|
|
36587
|
-
if (hasCompilerPackage(packageJson)) return true;
|
|
36597
|
+
if (hasCompilerPackage(packageJson, REACT_COMPILER_TRANSFORM_PACKAGES)) return true;
|
|
36588
36598
|
if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;
|
|
36589
36599
|
if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;
|
|
36590
36600
|
if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;
|
|
36591
36601
|
if (hasCompilerInConfigFiles(directory, EXPO_APP_CONFIG_FILENAMES)) return true;
|
|
36592
|
-
|
|
36593
|
-
let ancestorDirectory = Path.dirname(directory);
|
|
36594
|
-
while (ancestorDirectory !== Path.dirname(ancestorDirectory)) {
|
|
36595
|
-
const ancestorPackagePath = Path.join(ancestorDirectory, "package.json");
|
|
36596
|
-
if (isFile(ancestorPackagePath)) {
|
|
36597
|
-
if (hasCompilerPackage(readPackageJson$1(ancestorPackagePath))) return true;
|
|
36598
|
-
}
|
|
36599
|
-
if (isProjectBoundary(ancestorDirectory)) return false;
|
|
36600
|
-
ancestorDirectory = Path.dirname(ancestorDirectory);
|
|
36601
|
-
}
|
|
36602
|
-
return false;
|
|
36602
|
+
return hasCompilerPackageInAncestors(directory, REACT_COMPILER_TRANSFORM_PACKAGES);
|
|
36603
36603
|
};
|
|
36604
|
+
const detectReactCompilerLintPlugin = (directory, packageJson) => hasCompilerPackage(packageJson, REACT_COMPILER_LINT_PACKAGES) || hasCompilerPackageInAncestors(directory, REACT_COMPILER_LINT_PACKAGES);
|
|
36604
36605
|
const detectNextjsStaticExport = (directory) => NEXT_CONFIG_FILENAMES.some((filename) => {
|
|
36605
36606
|
const filePath = Path.join(directory, filename);
|
|
36606
36607
|
return isFile(filePath) && STATIC_EXPORT_OUTPUT_PATTERN.test(NFS.readFileSync(filePath, "utf-8"));
|
|
@@ -37564,6 +37565,7 @@ const discoverProjectWithoutPackageJson = (directory) => {
|
|
|
37564
37565
|
framework: "unknown",
|
|
37565
37566
|
hasTypeScript: hasOwnTsConfig,
|
|
37566
37567
|
hasReactCompiler: false,
|
|
37568
|
+
hasReactCompilerLintPlugin: false,
|
|
37567
37569
|
hasTanStackQuery: false,
|
|
37568
37570
|
hasSsrDependency: false,
|
|
37569
37571
|
preactVersion: null,
|
|
@@ -37684,6 +37686,7 @@ const discoverProject = (directory) => {
|
|
|
37684
37686
|
framework,
|
|
37685
37687
|
hasTypeScript,
|
|
37686
37688
|
hasReactCompiler: detectReactCompiler(directory, packageJson),
|
|
37689
|
+
hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
|
|
37687
37690
|
hasTanStackQuery: hasTanStackQuery(packageJson),
|
|
37688
37691
|
hasSsrDependency: workspaceFacts.hasSsrDependency,
|
|
37689
37692
|
preactVersion,
|
|
@@ -42963,7 +42966,7 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
42963
42966
|
return enabled;
|
|
42964
42967
|
};
|
|
42965
42968
|
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
|
|
42966
|
-
const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
|
|
42969
|
+
const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
|
|
42967
42970
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
42968
42971
|
const jsPlugins = [];
|
|
42969
42972
|
if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
|
|
@@ -43926,6 +43929,8 @@ const LEADING_SEVERITY_LABEL_PATTERN = /^(?:Error|Warning):\s*/;
|
|
|
43926
43929
|
const TRAILING_PERIOD_PATTERN = /\.$/;
|
|
43927
43930
|
const REACT_COMPILER_TITLE = "React Compiler can't optimize this";
|
|
43928
43931
|
const REACT_COMPILER_TODO_TITLE = "React Compiler doesn't support this syntax";
|
|
43932
|
+
const REACT_ERROR_BOUNDARY_TITLE = "JSX render errors need an Error Boundary";
|
|
43933
|
+
const REACT_ERROR_BOUNDARY_MESSAGE = "This try/catch cannot catch errors thrown while the JSX child renders. Use an Error Boundary instead.";
|
|
43929
43934
|
const REACT_COMPILER_IMPACT = "This component misses React Compiler's automatic memoization & re-renders more than it should";
|
|
43930
43935
|
const REACT_COMPILER_ACTION = "Rewrite the flagged code so the compiler can optimize it.";
|
|
43931
43936
|
const REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION = "It's how the library works, not a bug in your code. Memoize values you pass from it into other memoized components, or suppress it with `// react-doctor-disable-next-line react-hooks-js/incompatible-library`.";
|
|
@@ -43969,6 +43974,7 @@ const getRuleCategory = (ruleName) => reactDoctorPlugin.rules[ruleName]?.categor
|
|
|
43969
43974
|
const getRuleTitle = (ruleName) => reactDoctorPlugin.rules[ruleName]?.title;
|
|
43970
43975
|
const resolveDiagnosticTitle = (plugin, rule) => {
|
|
43971
43976
|
if (plugin !== "react-hooks-js") return getRuleTitle(rule);
|
|
43977
|
+
if (rule === "error-boundaries") return REACT_ERROR_BOUNDARY_TITLE;
|
|
43972
43978
|
return rule === "todo" ? REACT_COMPILER_TODO_TITLE : REACT_COMPILER_TITLE;
|
|
43973
43979
|
};
|
|
43974
43980
|
const cleanDiagnosticMessage = (message, help, plugin, rule, project) => {
|
|
@@ -43987,6 +43993,10 @@ const resolveCleanedDiagnostic = (message, help, plugin, rule, project) => {
|
|
|
43987
43993
|
};
|
|
43988
43994
|
const [reasonSummary = "", ...reasonDetailLines] = bailoutReason.split("\n");
|
|
43989
43995
|
const reasonDetail = reasonDetailLines.join("\n").trim();
|
|
43996
|
+
if (rule === "error-boundaries") return {
|
|
43997
|
+
message: REACT_ERROR_BOUNDARY_MESSAGE,
|
|
43998
|
+
help: reasonDetail || help
|
|
43999
|
+
};
|
|
43990
44000
|
return {
|
|
43991
44001
|
message: buildReactCompilerMessage(reasonSummary.trim(), rule === "incompatible-library" ? REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION : REACT_COMPILER_ACTION),
|
|
43992
44002
|
help: appendReanimatedSharedValueHint(reasonDetail || help, rule, project)
|
|
@@ -44008,7 +44018,10 @@ const parseRuleCode = (code) => {
|
|
|
44008
44018
|
rule: match[2]
|
|
44009
44019
|
};
|
|
44010
44020
|
};
|
|
44011
|
-
const resolveDiagnosticCategory = (plugin, rule) =>
|
|
44021
|
+
const resolveDiagnosticCategory = (plugin, rule) => {
|
|
44022
|
+
if (plugin === "react-hooks-js" && rule === "error-boundaries") return "Bugs";
|
|
44023
|
+
return getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
|
|
44024
|
+
};
|
|
44012
44025
|
const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORIES.has(category) || Boolean(reactDoctorPlugin.rules[rule]?.matchByOccurrence);
|
|
44013
44026
|
/**
|
|
44014
44027
|
* Maps oxlint's non-primary labels (`labels[1..]`) into related source
|
|
@@ -44821,7 +44834,7 @@ const runOxlint = async (options) => {
|
|
|
44821
44834
|
};
|
|
44822
44835
|
}
|
|
44823
44836
|
};
|
|
44824
|
-
if (perFileLintCacheEnabled && !project.hasReactCompiler && extendsPaths.length === 0 && userPlugins.length === 0) {
|
|
44837
|
+
if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0) {
|
|
44825
44838
|
const rulesetHash = computeRulesetHash({
|
|
44826
44839
|
config: buildConfig({
|
|
44827
44840
|
extendsPaths: [],
|
|
@@ -45263,6 +45276,14 @@ var Reporter = class Reporter extends Service()("react-doctor/Reporter") {
|
|
|
45263
45276
|
});
|
|
45264
45277
|
}));
|
|
45265
45278
|
};
|
|
45279
|
+
const HOME_DIRECTORY = os.homedir();
|
|
45280
|
+
const USER_HOME_PATTERNS = [/[A-Za-z]:[\\/]Users[\\/][^\\/]+/gi, /(?:\/Users\/|\/home\/)[^/\\]+/gi];
|
|
45281
|
+
const scrubSensitivePaths = (text) => {
|
|
45282
|
+
let scrubbed = text;
|
|
45283
|
+
if (HOME_DIRECTORY.length > 1) scrubbed = scrubbed.split(HOME_DIRECTORY).join("~");
|
|
45284
|
+
for (const pattern of USER_HOME_PATTERNS) scrubbed = scrubbed.replace(pattern, "~");
|
|
45285
|
+
return scrubbed;
|
|
45286
|
+
};
|
|
45266
45287
|
const ScoreApiResponseSchema = Struct({
|
|
45267
45288
|
score: Number$1,
|
|
45268
45289
|
label: String$1,
|
|
@@ -45277,7 +45298,10 @@ const ScoreApiResponseSchema = Struct({
|
|
|
45277
45298
|
})))
|
|
45278
45299
|
});
|
|
45279
45300
|
const parseScoreResult = (value) => getOrNull(decodeUnknownOption(ScoreApiResponseSchema)(value));
|
|
45280
|
-
const
|
|
45301
|
+
const sanitizeScoreDiagnostics = (diagnostics) => diagnostics.map(({ filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => ({
|
|
45302
|
+
...rest,
|
|
45303
|
+
filePath: redactSensitiveText(scrubSensitivePaths(filePath))
|
|
45304
|
+
}));
|
|
45281
45305
|
const isAbortError = (error) => error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
|
|
45282
45306
|
const describeFailure = (error) => {
|
|
45283
45307
|
if (isAbortError(error)) return `timed out after ${FETCH_TIMEOUT_MS / 1e3}s`;
|
|
@@ -45290,7 +45314,7 @@ const calculateScore = async (diagnostics, options = {}) => {
|
|
|
45290
45314
|
const requestUrl = options.isCi ? `${SCORE_API_URL}?ci=1` : SCORE_API_URL;
|
|
45291
45315
|
try {
|
|
45292
45316
|
const compressedBody = gzipSync(JSON.stringify({
|
|
45293
|
-
diagnostics:
|
|
45317
|
+
diagnostics: sanitizeScoreDiagnostics(diagnostics),
|
|
45294
45318
|
...options.metadata?.repo ? { repo: options.metadata.repo } : {},
|
|
45295
45319
|
...options.metadata?.sha ? { sha: options.metadata.sha } : {},
|
|
45296
45320
|
...options.metadata?.framework ? { framework: options.metadata.framework } : {},
|
|
@@ -47135,7 +47159,7 @@ const makeNoopConsole = () => ({
|
|
|
47135
47159
|
});
|
|
47136
47160
|
//#endregion
|
|
47137
47161
|
//#region src/cli/utils/version.ts
|
|
47138
|
-
const VERSION = "0.7.9-dev.
|
|
47162
|
+
const VERSION = "0.7.9-dev.a16e452";
|
|
47139
47163
|
//#endregion
|
|
47140
47164
|
//#region src/cli/utils/json-mode.ts
|
|
47141
47165
|
let context = null;
|
|
@@ -47221,23 +47245,6 @@ const getRunId = () => {
|
|
|
47221
47245
|
return cachedRunId;
|
|
47222
47246
|
};
|
|
47223
47247
|
//#endregion
|
|
47224
|
-
//#region src/cli/utils/scrub-sensitive-text.ts
|
|
47225
|
-
const HOME_DIRECTORY = os.homedir();
|
|
47226
|
-
const USER_HOME_PATTERNS = [/[A-Za-z]:[\\/]Users[\\/][^\\/]+/gi, /(?:\/Users\/|\/home\/)[^/\\]+/gi];
|
|
47227
|
-
/**
|
|
47228
|
-
* Replaces the user's home directory (and generic `/Users|/home|C:\Users\<name>`
|
|
47229
|
-
* roots) with `~` so absolute paths can't be tied back to an individual. Keeps
|
|
47230
|
-
* the path's relative structure intact, which stays useful for debugging while
|
|
47231
|
-
* dropping the personally-identifying prefix. Idempotent — re-running on an
|
|
47232
|
-
* already-scrubbed `~/...` path is a no-op.
|
|
47233
|
-
*/
|
|
47234
|
-
const scrubSensitivePaths = (text) => {
|
|
47235
|
-
let scrubbed = text;
|
|
47236
|
-
if (HOME_DIRECTORY.length > 1) scrubbed = scrubbed.split(HOME_DIRECTORY).join("~");
|
|
47237
|
-
for (const pattern of USER_HOME_PATTERNS) scrubbed = scrubbed.replace(pattern, "~");
|
|
47238
|
-
return scrubbed;
|
|
47239
|
-
};
|
|
47240
|
-
//#endregion
|
|
47241
47248
|
//#region src/cli/utils/build-run-context.ts
|
|
47242
47249
|
const ROOT_SUBCOMMANDS = new Set(["install", "setup"]);
|
|
47243
47250
|
const detectInvokedVia = () => {
|
|
@@ -47504,13 +47511,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
|
|
|
47504
47511
|
* uploads source-map artifacts under, so stack frames symbolicate. Honors the
|
|
47505
47512
|
* standard `SENTRY_RELEASE` override.
|
|
47506
47513
|
*/
|
|
47507
|
-
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.9-dev.
|
|
47514
|
+
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.9-dev.a16e452`;
|
|
47508
47515
|
/**
|
|
47509
47516
|
* Deployment environment shown in Sentry's environment filter. Defaults to
|
|
47510
47517
|
* `production` for tagged releases and `development` for dev/unbuilt versions,
|
|
47511
47518
|
* overridable via the standard `SENTRY_ENVIRONMENT` env var.
|
|
47512
47519
|
*/
|
|
47513
|
-
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.9-dev.
|
|
47520
|
+
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.9-dev.a16e452") ? "development" : "production");
|
|
47514
47521
|
/**
|
|
47515
47522
|
* Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
|
|
47516
47523
|
* (set to `0` to disable tracing) and falls back to
|
|
@@ -65788,4 +65795,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
|
|
|
65788
65795
|
export {};
|
|
65789
65796
|
|
|
65790
65797
|
//# sourceMappingURL=cli.js.map
|
|
65791
|
-
//# debugId=
|
|
65798
|
+
//# debugId=5c4df375-a5c4-57d2-9076-4e54cbb8f3bd
|
package/dist/index.d.ts
CHANGED
|
@@ -9540,6 +9540,7 @@ interface ProjectInfo {
|
|
|
9540
9540
|
framework: Framework;
|
|
9541
9541
|
hasTypeScript: boolean;
|
|
9542
9542
|
hasReactCompiler: boolean;
|
|
9543
|
+
hasReactCompilerLintPlugin?: boolean;
|
|
9543
9544
|
hasTanStackQuery: boolean;
|
|
9544
9545
|
/**
|
|
9545
9546
|
* `true` when the project or a workspace declares a Vite-based SSR runtime
|
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]="526cf949-6544-5cb8-bf6d-3f4d854b6678")}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 reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_DEPENDENCY_COLLECTORS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, FRAMEWORK_TOKENS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, classifySecurityScanFile, collectCrossFileDependencyProbes, resetManifestCaches, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor";
|
|
@@ -33336,11 +33336,8 @@ const frameworkMergeRank = (framework) => {
|
|
|
33336
33336
|
if (framework === "unknown") return 3;
|
|
33337
33337
|
return MOBILE_FRAMEWORKS.has(framework) ? 2 : 1;
|
|
33338
33338
|
};
|
|
33339
|
-
const
|
|
33340
|
-
|
|
33341
|
-
"react-compiler-runtime",
|
|
33342
|
-
"eslint-plugin-react-compiler"
|
|
33343
|
-
]);
|
|
33339
|
+
const REACT_COMPILER_TRANSFORM_PACKAGES = new Set(["babel-plugin-react-compiler", "react-compiler-runtime"]);
|
|
33340
|
+
const REACT_COMPILER_LINT_PACKAGES = new Set(["eslint-plugin-react-compiler"]);
|
|
33344
33341
|
const NEXT_CONFIG_FILENAMES = [
|
|
33345
33342
|
"next.config.js",
|
|
33346
33343
|
"next.config.mjs",
|
|
@@ -33370,16 +33367,29 @@ const EXPO_APP_CONFIG_FILENAMES = [
|
|
|
33370
33367
|
"app.config.js",
|
|
33371
33368
|
"app.config.ts"
|
|
33372
33369
|
];
|
|
33373
|
-
const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|
|
|
33370
|
+
const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|["']react-compiler["']/;
|
|
33374
33371
|
const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
|
|
33375
33372
|
const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
|
|
33376
|
-
const hasCompilerPackage = (packageJson) => {
|
|
33373
|
+
const hasCompilerPackage = (packageJson, compilerPackages) => {
|
|
33377
33374
|
const allDependencies = {
|
|
33378
33375
|
...packageJson.peerDependencies,
|
|
33379
33376
|
...packageJson.dependencies,
|
|
33380
33377
|
...packageJson.devDependencies
|
|
33381
33378
|
};
|
|
33382
|
-
return Object.keys(allDependencies).some((packageName) =>
|
|
33379
|
+
return Object.keys(allDependencies).some((packageName) => compilerPackages.has(packageName));
|
|
33380
|
+
};
|
|
33381
|
+
const hasCompilerPackageInAncestors = (directory, compilerPackages) => {
|
|
33382
|
+
if (isProjectBoundary(directory)) return false;
|
|
33383
|
+
let ancestorDirectory = Path.dirname(directory);
|
|
33384
|
+
while (ancestorDirectory !== Path.dirname(ancestorDirectory)) {
|
|
33385
|
+
const ancestorPackagePath = Path.join(ancestorDirectory, "package.json");
|
|
33386
|
+
if (isFile(ancestorPackagePath)) {
|
|
33387
|
+
if (hasCompilerPackage(readPackageJson(ancestorPackagePath), compilerPackages)) return true;
|
|
33388
|
+
}
|
|
33389
|
+
if (isProjectBoundary(ancestorDirectory)) return false;
|
|
33390
|
+
ancestorDirectory = Path.dirname(ancestorDirectory);
|
|
33391
|
+
}
|
|
33392
|
+
return false;
|
|
33383
33393
|
};
|
|
33384
33394
|
const hasCompilerInConfigFile = (filePath) => {
|
|
33385
33395
|
if (!isFile(filePath)) return false;
|
|
@@ -33388,23 +33398,14 @@ const hasCompilerInConfigFile = (filePath) => {
|
|
|
33388
33398
|
};
|
|
33389
33399
|
const hasCompilerInConfigFiles = (directory, filenames) => filenames.some((filename) => hasCompilerInConfigFile(Path.join(directory, filename)));
|
|
33390
33400
|
const detectReactCompiler = (directory, packageJson) => {
|
|
33391
|
-
if (hasCompilerPackage(packageJson)) return true;
|
|
33401
|
+
if (hasCompilerPackage(packageJson, REACT_COMPILER_TRANSFORM_PACKAGES)) return true;
|
|
33392
33402
|
if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;
|
|
33393
33403
|
if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;
|
|
33394
33404
|
if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;
|
|
33395
33405
|
if (hasCompilerInConfigFiles(directory, EXPO_APP_CONFIG_FILENAMES)) return true;
|
|
33396
|
-
|
|
33397
|
-
let ancestorDirectory = Path.dirname(directory);
|
|
33398
|
-
while (ancestorDirectory !== Path.dirname(ancestorDirectory)) {
|
|
33399
|
-
const ancestorPackagePath = Path.join(ancestorDirectory, "package.json");
|
|
33400
|
-
if (isFile(ancestorPackagePath)) {
|
|
33401
|
-
if (hasCompilerPackage(readPackageJson(ancestorPackagePath))) return true;
|
|
33402
|
-
}
|
|
33403
|
-
if (isProjectBoundary(ancestorDirectory)) return false;
|
|
33404
|
-
ancestorDirectory = Path.dirname(ancestorDirectory);
|
|
33405
|
-
}
|
|
33406
|
-
return false;
|
|
33406
|
+
return hasCompilerPackageInAncestors(directory, REACT_COMPILER_TRANSFORM_PACKAGES);
|
|
33407
33407
|
};
|
|
33408
|
+
const detectReactCompilerLintPlugin = (directory, packageJson) => hasCompilerPackage(packageJson, REACT_COMPILER_LINT_PACKAGES) || hasCompilerPackageInAncestors(directory, REACT_COMPILER_LINT_PACKAGES);
|
|
33408
33409
|
const detectNextjsStaticExport = (directory) => NEXT_CONFIG_FILENAMES.some((filename) => {
|
|
33409
33410
|
const filePath = Path.join(directory, filename);
|
|
33410
33411
|
return isFile(filePath) && STATIC_EXPORT_OUTPUT_PATTERN.test(NFS.readFileSync(filePath, "utf-8"));
|
|
@@ -34371,6 +34372,7 @@ const discoverProjectWithoutPackageJson = (directory) => {
|
|
|
34371
34372
|
framework: "unknown",
|
|
34372
34373
|
hasTypeScript: hasOwnTsConfig,
|
|
34373
34374
|
hasReactCompiler: false,
|
|
34375
|
+
hasReactCompilerLintPlugin: false,
|
|
34374
34376
|
hasTanStackQuery: false,
|
|
34375
34377
|
hasSsrDependency: false,
|
|
34376
34378
|
preactVersion: null,
|
|
@@ -34491,6 +34493,7 @@ const discoverProject = (directory) => {
|
|
|
34491
34493
|
framework,
|
|
34492
34494
|
hasTypeScript,
|
|
34493
34495
|
hasReactCompiler: detectReactCompiler(directory, packageJson),
|
|
34496
|
+
hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
|
|
34494
34497
|
hasTanStackQuery: hasTanStackQuery(packageJson),
|
|
34495
34498
|
hasSsrDependency: workspaceFacts.hasSsrDependency,
|
|
34496
34499
|
preactVersion,
|
|
@@ -39719,7 +39722,7 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
39719
39722
|
return enabled;
|
|
39720
39723
|
};
|
|
39721
39724
|
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
|
|
39722
|
-
const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
|
|
39725
|
+
const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
|
|
39723
39726
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
39724
39727
|
const jsPlugins = [];
|
|
39725
39728
|
if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
|
|
@@ -40682,6 +40685,8 @@ const LEADING_SEVERITY_LABEL_PATTERN = /^(?:Error|Warning):\s*/;
|
|
|
40682
40685
|
const TRAILING_PERIOD_PATTERN = /\.$/;
|
|
40683
40686
|
const REACT_COMPILER_TITLE = "React Compiler can't optimize this";
|
|
40684
40687
|
const REACT_COMPILER_TODO_TITLE = "React Compiler doesn't support this syntax";
|
|
40688
|
+
const REACT_ERROR_BOUNDARY_TITLE = "JSX render errors need an Error Boundary";
|
|
40689
|
+
const REACT_ERROR_BOUNDARY_MESSAGE = "This try/catch cannot catch errors thrown while the JSX child renders. Use an Error Boundary instead.";
|
|
40685
40690
|
const REACT_COMPILER_IMPACT = "This component misses React Compiler's automatic memoization & re-renders more than it should";
|
|
40686
40691
|
const REACT_COMPILER_ACTION = "Rewrite the flagged code so the compiler can optimize it.";
|
|
40687
40692
|
const REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION = "It's how the library works, not a bug in your code. Memoize values you pass from it into other memoized components, or suppress it with `// react-doctor-disable-next-line react-hooks-js/incompatible-library`.";
|
|
@@ -40725,6 +40730,7 @@ const getRuleCategory = (ruleName) => reactDoctorPlugin.rules[ruleName]?.categor
|
|
|
40725
40730
|
const getRuleTitle = (ruleName) => reactDoctorPlugin.rules[ruleName]?.title;
|
|
40726
40731
|
const resolveDiagnosticTitle = (plugin, rule) => {
|
|
40727
40732
|
if (plugin !== "react-hooks-js") return getRuleTitle(rule);
|
|
40733
|
+
if (rule === "error-boundaries") return REACT_ERROR_BOUNDARY_TITLE;
|
|
40728
40734
|
return rule === "todo" ? REACT_COMPILER_TODO_TITLE : REACT_COMPILER_TITLE;
|
|
40729
40735
|
};
|
|
40730
40736
|
const cleanDiagnosticMessage = (message, help, plugin, rule, project) => {
|
|
@@ -40743,6 +40749,10 @@ const resolveCleanedDiagnostic = (message, help, plugin, rule, project) => {
|
|
|
40743
40749
|
};
|
|
40744
40750
|
const [reasonSummary = "", ...reasonDetailLines] = bailoutReason.split("\n");
|
|
40745
40751
|
const reasonDetail = reasonDetailLines.join("\n").trim();
|
|
40752
|
+
if (rule === "error-boundaries") return {
|
|
40753
|
+
message: REACT_ERROR_BOUNDARY_MESSAGE,
|
|
40754
|
+
help: reasonDetail || help
|
|
40755
|
+
};
|
|
40746
40756
|
return {
|
|
40747
40757
|
message: buildReactCompilerMessage(reasonSummary.trim(), rule === "incompatible-library" ? REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION : REACT_COMPILER_ACTION),
|
|
40748
40758
|
help: appendReanimatedSharedValueHint(reasonDetail || help, rule, project)
|
|
@@ -40764,7 +40774,10 @@ const parseRuleCode = (code) => {
|
|
|
40764
40774
|
rule: match[2]
|
|
40765
40775
|
};
|
|
40766
40776
|
};
|
|
40767
|
-
const resolveDiagnosticCategory = (plugin, rule) =>
|
|
40777
|
+
const resolveDiagnosticCategory = (plugin, rule) => {
|
|
40778
|
+
if (plugin === "react-hooks-js" && rule === "error-boundaries") return "Bugs";
|
|
40779
|
+
return getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
|
|
40780
|
+
};
|
|
40768
40781
|
const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORIES.has(category) || Boolean(reactDoctorPlugin.rules[rule]?.matchByOccurrence);
|
|
40769
40782
|
/**
|
|
40770
40783
|
* Maps oxlint's non-primary labels (`labels[1..]`) into related source
|
|
@@ -41577,7 +41590,7 @@ const runOxlint = async (options) => {
|
|
|
41577
41590
|
};
|
|
41578
41591
|
}
|
|
41579
41592
|
};
|
|
41580
|
-
if (perFileLintCacheEnabled && !project.hasReactCompiler && extendsPaths.length === 0 && userPlugins.length === 0) {
|
|
41593
|
+
if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0) {
|
|
41581
41594
|
const rulesetHash = computeRulesetHash({
|
|
41582
41595
|
config: buildConfig({
|
|
41583
41596
|
extendsPaths: [],
|
|
@@ -42019,6 +42032,14 @@ var Reporter = class Reporter extends Service()("react-doctor/Reporter") {
|
|
|
42019
42032
|
});
|
|
42020
42033
|
}));
|
|
42021
42034
|
};
|
|
42035
|
+
const HOME_DIRECTORY = os.homedir();
|
|
42036
|
+
const USER_HOME_PATTERNS = [/[A-Za-z]:[\\/]Users[\\/][^\\/]+/gi, /(?:\/Users\/|\/home\/)[^/\\]+/gi];
|
|
42037
|
+
const scrubSensitivePaths = (text) => {
|
|
42038
|
+
let scrubbed = text;
|
|
42039
|
+
if (HOME_DIRECTORY.length > 1) scrubbed = scrubbed.split(HOME_DIRECTORY).join("~");
|
|
42040
|
+
for (const pattern of USER_HOME_PATTERNS) scrubbed = scrubbed.replace(pattern, "~");
|
|
42041
|
+
return scrubbed;
|
|
42042
|
+
};
|
|
42022
42043
|
const ScoreApiResponseSchema = Struct({
|
|
42023
42044
|
score: Number$1,
|
|
42024
42045
|
label: String$1,
|
|
@@ -42033,7 +42054,10 @@ const ScoreApiResponseSchema = Struct({
|
|
|
42033
42054
|
})))
|
|
42034
42055
|
});
|
|
42035
42056
|
const parseScoreResult = (value) => getOrNull(decodeUnknownOption(ScoreApiResponseSchema)(value));
|
|
42036
|
-
const
|
|
42057
|
+
const sanitizeScoreDiagnostics = (diagnostics) => diagnostics.map(({ filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => ({
|
|
42058
|
+
...rest,
|
|
42059
|
+
filePath: redactSensitiveText(scrubSensitivePaths(filePath))
|
|
42060
|
+
}));
|
|
42037
42061
|
const isAbortError = (error) => error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
|
|
42038
42062
|
const describeFailure = (error) => {
|
|
42039
42063
|
if (isAbortError(error)) return `timed out after ${FETCH_TIMEOUT_MS / 1e3}s`;
|
|
@@ -42046,7 +42070,7 @@ const calculateScore = async (diagnostics, options = {}) => {
|
|
|
42046
42070
|
const requestUrl = options.isCi ? `${SCORE_API_URL}?ci=1` : SCORE_API_URL;
|
|
42047
42071
|
try {
|
|
42048
42072
|
const compressedBody = gzipSync(JSON.stringify({
|
|
42049
|
-
diagnostics:
|
|
42073
|
+
diagnostics: sanitizeScoreDiagnostics(diagnostics),
|
|
42050
42074
|
...options.metadata?.repo ? { repo: options.metadata.repo } : {},
|
|
42051
42075
|
...options.metadata?.sha ? { sha: options.metadata.sha } : {},
|
|
42052
42076
|
...options.metadata?.framework ? { framework: options.metadata.framework } : {},
|
|
@@ -43639,4 +43663,4 @@ const toJsonReport = (result, options) => buildJsonReport({
|
|
|
43639
43663
|
export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
|
|
43640
43664
|
|
|
43641
43665
|
//# sourceMappingURL=index.js.map
|
|
43642
|
-
//# debugId=
|
|
43666
|
+
//# debugId=526cf949-6544-5cb8-bf6d-3f4d854b6678
|
package/dist/lsp.js
CHANGED
|
@@ -33388,11 +33388,8 @@ const frameworkMergeRank = (framework) => {
|
|
|
33388
33388
|
if (framework === "unknown") return 3;
|
|
33389
33389
|
return MOBILE_FRAMEWORKS.has(framework) ? 2 : 1;
|
|
33390
33390
|
};
|
|
33391
|
-
const
|
|
33392
|
-
|
|
33393
|
-
"react-compiler-runtime",
|
|
33394
|
-
"eslint-plugin-react-compiler"
|
|
33395
|
-
]);
|
|
33391
|
+
const REACT_COMPILER_TRANSFORM_PACKAGES = new Set(["babel-plugin-react-compiler", "react-compiler-runtime"]);
|
|
33392
|
+
const REACT_COMPILER_LINT_PACKAGES = new Set(["eslint-plugin-react-compiler"]);
|
|
33396
33393
|
const NEXT_CONFIG_FILENAMES = [
|
|
33397
33394
|
"next.config.js",
|
|
33398
33395
|
"next.config.mjs",
|
|
@@ -33422,16 +33419,29 @@ const EXPO_APP_CONFIG_FILENAMES = [
|
|
|
33422
33419
|
"app.config.js",
|
|
33423
33420
|
"app.config.ts"
|
|
33424
33421
|
];
|
|
33425
|
-
const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|
|
|
33422
|
+
const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|["']react-compiler["']/;
|
|
33426
33423
|
const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
|
|
33427
33424
|
const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
|
|
33428
|
-
const hasCompilerPackage = (packageJson) => {
|
|
33425
|
+
const hasCompilerPackage = (packageJson, compilerPackages) => {
|
|
33429
33426
|
const allDependencies = {
|
|
33430
33427
|
...packageJson.peerDependencies,
|
|
33431
33428
|
...packageJson.dependencies,
|
|
33432
33429
|
...packageJson.devDependencies
|
|
33433
33430
|
};
|
|
33434
|
-
return Object.keys(allDependencies).some((packageName) =>
|
|
33431
|
+
return Object.keys(allDependencies).some((packageName) => compilerPackages.has(packageName));
|
|
33432
|
+
};
|
|
33433
|
+
const hasCompilerPackageInAncestors = (directory, compilerPackages) => {
|
|
33434
|
+
if (isProjectBoundary(directory)) return false;
|
|
33435
|
+
let ancestorDirectory = Path.dirname(directory);
|
|
33436
|
+
while (ancestorDirectory !== Path.dirname(ancestorDirectory)) {
|
|
33437
|
+
const ancestorPackagePath = Path.join(ancestorDirectory, "package.json");
|
|
33438
|
+
if (isFile(ancestorPackagePath)) {
|
|
33439
|
+
if (hasCompilerPackage(readPackageJson(ancestorPackagePath), compilerPackages)) return true;
|
|
33440
|
+
}
|
|
33441
|
+
if (isProjectBoundary(ancestorDirectory)) return false;
|
|
33442
|
+
ancestorDirectory = Path.dirname(ancestorDirectory);
|
|
33443
|
+
}
|
|
33444
|
+
return false;
|
|
33435
33445
|
};
|
|
33436
33446
|
const hasCompilerInConfigFile = (filePath) => {
|
|
33437
33447
|
if (!isFile(filePath)) return false;
|
|
@@ -33440,23 +33450,14 @@ const hasCompilerInConfigFile = (filePath) => {
|
|
|
33440
33450
|
};
|
|
33441
33451
|
const hasCompilerInConfigFiles = (directory, filenames) => filenames.some((filename) => hasCompilerInConfigFile(Path.join(directory, filename)));
|
|
33442
33452
|
const detectReactCompiler = (directory, packageJson) => {
|
|
33443
|
-
if (hasCompilerPackage(packageJson)) return true;
|
|
33453
|
+
if (hasCompilerPackage(packageJson, REACT_COMPILER_TRANSFORM_PACKAGES)) return true;
|
|
33444
33454
|
if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;
|
|
33445
33455
|
if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;
|
|
33446
33456
|
if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;
|
|
33447
33457
|
if (hasCompilerInConfigFiles(directory, EXPO_APP_CONFIG_FILENAMES)) return true;
|
|
33448
|
-
|
|
33449
|
-
let ancestorDirectory = Path.dirname(directory);
|
|
33450
|
-
while (ancestorDirectory !== Path.dirname(ancestorDirectory)) {
|
|
33451
|
-
const ancestorPackagePath = Path.join(ancestorDirectory, "package.json");
|
|
33452
|
-
if (isFile(ancestorPackagePath)) {
|
|
33453
|
-
if (hasCompilerPackage(readPackageJson(ancestorPackagePath))) return true;
|
|
33454
|
-
}
|
|
33455
|
-
if (isProjectBoundary(ancestorDirectory)) return false;
|
|
33456
|
-
ancestorDirectory = Path.dirname(ancestorDirectory);
|
|
33457
|
-
}
|
|
33458
|
-
return false;
|
|
33458
|
+
return hasCompilerPackageInAncestors(directory, REACT_COMPILER_TRANSFORM_PACKAGES);
|
|
33459
33459
|
};
|
|
33460
|
+
const detectReactCompilerLintPlugin = (directory, packageJson) => hasCompilerPackage(packageJson, REACT_COMPILER_LINT_PACKAGES) || hasCompilerPackageInAncestors(directory, REACT_COMPILER_LINT_PACKAGES);
|
|
33460
33461
|
const detectNextjsStaticExport = (directory) => NEXT_CONFIG_FILENAMES.some((filename) => {
|
|
33461
33462
|
const filePath = Path.join(directory, filename);
|
|
33462
33463
|
return isFile(filePath) && STATIC_EXPORT_OUTPUT_PATTERN.test(NFS.readFileSync(filePath, "utf-8"));
|
|
@@ -34423,6 +34424,7 @@ const discoverProjectWithoutPackageJson = (directory) => {
|
|
|
34423
34424
|
framework: "unknown",
|
|
34424
34425
|
hasTypeScript: hasOwnTsConfig,
|
|
34425
34426
|
hasReactCompiler: false,
|
|
34427
|
+
hasReactCompilerLintPlugin: false,
|
|
34426
34428
|
hasTanStackQuery: false,
|
|
34427
34429
|
hasSsrDependency: false,
|
|
34428
34430
|
preactVersion: null,
|
|
@@ -34543,6 +34545,7 @@ const discoverProject = (directory) => {
|
|
|
34543
34545
|
framework,
|
|
34544
34546
|
hasTypeScript,
|
|
34545
34547
|
hasReactCompiler: detectReactCompiler(directory, packageJson),
|
|
34548
|
+
hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
|
|
34546
34549
|
hasTanStackQuery: hasTanStackQuery(packageJson),
|
|
34547
34550
|
hasSsrDependency: workspaceFacts.hasSsrDependency,
|
|
34548
34551
|
preactVersion,
|
|
@@ -39697,7 +39700,7 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
39697
39700
|
return enabled;
|
|
39698
39701
|
};
|
|
39699
39702
|
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
|
|
39700
|
-
const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
|
|
39703
|
+
const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
|
|
39701
39704
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
39702
39705
|
const jsPlugins = [];
|
|
39703
39706
|
if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
|
|
@@ -40660,6 +40663,8 @@ const LEADING_SEVERITY_LABEL_PATTERN = /^(?:Error|Warning):\s*/;
|
|
|
40660
40663
|
const TRAILING_PERIOD_PATTERN = /\.$/;
|
|
40661
40664
|
const REACT_COMPILER_TITLE = "React Compiler can't optimize this";
|
|
40662
40665
|
const REACT_COMPILER_TODO_TITLE = "React Compiler doesn't support this syntax";
|
|
40666
|
+
const REACT_ERROR_BOUNDARY_TITLE = "JSX render errors need an Error Boundary";
|
|
40667
|
+
const REACT_ERROR_BOUNDARY_MESSAGE = "This try/catch cannot catch errors thrown while the JSX child renders. Use an Error Boundary instead.";
|
|
40663
40668
|
const REACT_COMPILER_IMPACT = "This component misses React Compiler's automatic memoization & re-renders more than it should";
|
|
40664
40669
|
const REACT_COMPILER_ACTION = "Rewrite the flagged code so the compiler can optimize it.";
|
|
40665
40670
|
const REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION = "It's how the library works, not a bug in your code. Memoize values you pass from it into other memoized components, or suppress it with `// react-doctor-disable-next-line react-hooks-js/incompatible-library`.";
|
|
@@ -40703,6 +40708,7 @@ const getRuleCategory = (ruleName) => reactDoctorPlugin.rules[ruleName]?.categor
|
|
|
40703
40708
|
const getRuleTitle = (ruleName) => reactDoctorPlugin.rules[ruleName]?.title;
|
|
40704
40709
|
const resolveDiagnosticTitle = (plugin, rule) => {
|
|
40705
40710
|
if (plugin !== "react-hooks-js") return getRuleTitle(rule);
|
|
40711
|
+
if (rule === "error-boundaries") return REACT_ERROR_BOUNDARY_TITLE;
|
|
40706
40712
|
return rule === "todo" ? REACT_COMPILER_TODO_TITLE : REACT_COMPILER_TITLE;
|
|
40707
40713
|
};
|
|
40708
40714
|
const cleanDiagnosticMessage = (message, help, plugin, rule, project) => {
|
|
@@ -40721,6 +40727,10 @@ const resolveCleanedDiagnostic = (message, help, plugin, rule, project) => {
|
|
|
40721
40727
|
};
|
|
40722
40728
|
const [reasonSummary = "", ...reasonDetailLines] = bailoutReason.split("\n");
|
|
40723
40729
|
const reasonDetail = reasonDetailLines.join("\n").trim();
|
|
40730
|
+
if (rule === "error-boundaries") return {
|
|
40731
|
+
message: REACT_ERROR_BOUNDARY_MESSAGE,
|
|
40732
|
+
help: reasonDetail || help
|
|
40733
|
+
};
|
|
40724
40734
|
return {
|
|
40725
40735
|
message: buildReactCompilerMessage(reasonSummary.trim(), rule === "incompatible-library" ? REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION : REACT_COMPILER_ACTION),
|
|
40726
40736
|
help: appendReanimatedSharedValueHint(reasonDetail || help, rule, project)
|
|
@@ -40742,7 +40752,10 @@ const parseRuleCode = (code) => {
|
|
|
40742
40752
|
rule: match[2]
|
|
40743
40753
|
};
|
|
40744
40754
|
};
|
|
40745
|
-
const resolveDiagnosticCategory = (plugin, rule) =>
|
|
40755
|
+
const resolveDiagnosticCategory = (plugin, rule) => {
|
|
40756
|
+
if (plugin === "react-hooks-js" && rule === "error-boundaries") return "Bugs";
|
|
40757
|
+
return getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
|
|
40758
|
+
};
|
|
40746
40759
|
const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORIES.has(category) || Boolean(reactDoctorPlugin.rules[rule]?.matchByOccurrence);
|
|
40747
40760
|
/**
|
|
40748
40761
|
* Maps oxlint's non-primary labels (`labels[1..]`) into related source
|
|
@@ -41555,7 +41568,7 @@ const runOxlint = async (options) => {
|
|
|
41555
41568
|
};
|
|
41556
41569
|
}
|
|
41557
41570
|
};
|
|
41558
|
-
if (perFileLintCacheEnabled && !project.hasReactCompiler && extendsPaths.length === 0 && userPlugins.length === 0) {
|
|
41571
|
+
if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0) {
|
|
41559
41572
|
const rulesetHash = computeRulesetHash({
|
|
41560
41573
|
config: buildConfig({
|
|
41561
41574
|
extendsPaths: [],
|
|
@@ -41997,6 +42010,14 @@ var Reporter = class Reporter extends Service()("react-doctor/Reporter") {
|
|
|
41997
42010
|
});
|
|
41998
42011
|
}));
|
|
41999
42012
|
};
|
|
42013
|
+
const HOME_DIRECTORY = os.homedir();
|
|
42014
|
+
const USER_HOME_PATTERNS = [/[A-Za-z]:[\\/]Users[\\/][^\\/]+/gi, /(?:\/Users\/|\/home\/)[^/\\]+/gi];
|
|
42015
|
+
const scrubSensitivePaths = (text) => {
|
|
42016
|
+
let scrubbed = text;
|
|
42017
|
+
if (HOME_DIRECTORY.length > 1) scrubbed = scrubbed.split(HOME_DIRECTORY).join("~");
|
|
42018
|
+
for (const pattern of USER_HOME_PATTERNS) scrubbed = scrubbed.replace(pattern, "~");
|
|
42019
|
+
return scrubbed;
|
|
42020
|
+
};
|
|
42000
42021
|
const ScoreApiResponseSchema = Struct({
|
|
42001
42022
|
score: Number$1,
|
|
42002
42023
|
label: String$1,
|
|
@@ -42011,7 +42032,10 @@ const ScoreApiResponseSchema = Struct({
|
|
|
42011
42032
|
})))
|
|
42012
42033
|
});
|
|
42013
42034
|
const parseScoreResult = (value) => getOrNull(decodeUnknownOption(ScoreApiResponseSchema)(value));
|
|
42014
|
-
const
|
|
42035
|
+
const sanitizeScoreDiagnostics = (diagnostics) => diagnostics.map(({ filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => ({
|
|
42036
|
+
...rest,
|
|
42037
|
+
filePath: redactSensitiveText(scrubSensitivePaths(filePath))
|
|
42038
|
+
}));
|
|
42015
42039
|
const isAbortError = (error) => error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
|
|
42016
42040
|
const describeFailure = (error) => {
|
|
42017
42041
|
if (isAbortError(error)) return `timed out after ${FETCH_TIMEOUT_MS / 1e3}s`;
|
|
@@ -42024,7 +42048,7 @@ const calculateScore = async (diagnostics, options = {}) => {
|
|
|
42024
42048
|
const requestUrl = options.isCi ? `${SCORE_API_URL}?ci=1` : SCORE_API_URL;
|
|
42025
42049
|
try {
|
|
42026
42050
|
const compressedBody = gzipSync(JSON.stringify({
|
|
42027
|
-
diagnostics:
|
|
42051
|
+
diagnostics: sanitizeScoreDiagnostics(diagnostics),
|
|
42028
42052
|
...options.metadata?.repo ? { repo: options.metadata.repo } : {},
|
|
42029
42053
|
...options.metadata?.sha ? { sha: options.metadata.sha } : {},
|
|
42030
42054
|
...options.metadata?.framework ? { framework: options.metadata.framework } : {},
|
|
@@ -44971,23 +44995,6 @@ const METRIC = {
|
|
|
44971
44995
|
*/
|
|
44972
44996
|
const toCategoryKey = (category) => category.toLowerCase().replace(/[^a-z0-9]+/g, "_");
|
|
44973
44997
|
//#endregion
|
|
44974
|
-
//#region src/cli/utils/scrub-sensitive-text.ts
|
|
44975
|
-
const HOME_DIRECTORY = os.homedir();
|
|
44976
|
-
const USER_HOME_PATTERNS = [/[A-Za-z]:[\\/]Users[\\/][^\\/]+/gi, /(?:\/Users\/|\/home\/)[^/\\]+/gi];
|
|
44977
|
-
/**
|
|
44978
|
-
* Replaces the user's home directory (and generic `/Users|/home|C:\Users\<name>`
|
|
44979
|
-
* roots) with `~` so absolute paths can't be tied back to an individual. Keeps
|
|
44980
|
-
* the path's relative structure intact, which stays useful for debugging while
|
|
44981
|
-
* dropping the personally-identifying prefix. Idempotent — re-running on an
|
|
44982
|
-
* already-scrubbed `~/...` path is a no-op.
|
|
44983
|
-
*/
|
|
44984
|
-
const scrubSensitivePaths = (text) => {
|
|
44985
|
-
let scrubbed = text;
|
|
44986
|
-
if (HOME_DIRECTORY.length > 1) scrubbed = scrubbed.split(HOME_DIRECTORY).join("~");
|
|
44987
|
-
for (const pattern of USER_HOME_PATTERNS) scrubbed = scrubbed.replace(pattern, "~");
|
|
44988
|
-
return scrubbed;
|
|
44989
|
-
};
|
|
44990
|
-
//#endregion
|
|
44991
44998
|
//#region src/cli/utils/anonymize-text.ts
|
|
44992
44999
|
/**
|
|
44993
45000
|
* Free-text fields can carry both a home-directory path (the OS username) and a
|
|
@@ -45276,5 +45283,5 @@ const startLanguageServer = () => {
|
|
|
45276
45283
|
};
|
|
45277
45284
|
//#endregion
|
|
45278
45285
|
export { startLanguageServer };
|
|
45279
|
-
!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]="
|
|
45280
|
-
//# debugId=
|
|
45286
|
+
!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]="3eb1e331-d4d9-517d-a23d-3170e3d3203f")}catch(e){}}();
|
|
45287
|
+
//# debugId=3eb1e331-d4d9-517d-a23d-3170e3d3203f
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-doctor",
|
|
3
|
-
"version": "0.7.9-dev.
|
|
3
|
+
"version": "0.7.9-dev.a16e452",
|
|
4
4
|
"description": "Your agent writes bad React. This catches it",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"accessibility",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"vscode-uri": "^3.1.0",
|
|
67
67
|
"yaml": "^2.9.0",
|
|
68
68
|
"deslop-js": "0.7.9",
|
|
69
|
-
"oxlint-plugin-react-doctor": "0.7.9-dev.
|
|
69
|
+
"oxlint-plugin-react-doctor": "0.7.9-dev.a16e452"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@types/babel__code-frame": "^7.27.0",
|