react-doctor 0.7.9-dev.d8a20e0 → 0.7.9-dev.e5a5f73
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 +115 -52
- package/dist/index.d.ts +1 -0
- package/dist/index.js +112 -32
- package/dist/lsp.js +112 -49
- 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]="6f05eada-46fe-5b24-92d8-15fa92a38b00")}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";
|
|
@@ -36252,6 +36252,53 @@ const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
|
|
|
36252
36252
|
const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
|
|
36253
36253
|
const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
|
|
36254
36254
|
const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
|
|
36255
|
+
const lastSourceMappingUrl = (fileContent) => {
|
|
36256
|
+
const lastReference = [...fileContent.matchAll(/\/\/# sourceMappingURL=(\S+)/g)].at(-1);
|
|
36257
|
+
return lastReference ? lastReference[1] : null;
|
|
36258
|
+
};
|
|
36259
|
+
const mapTargetsSource = (mapContent, input) => {
|
|
36260
|
+
const parsedMap = JSON.parse(mapContent);
|
|
36261
|
+
if (typeof parsedMap !== "object" || parsedMap === null) return false;
|
|
36262
|
+
const { file, sources } = parsedMap;
|
|
36263
|
+
if (file !== input.expectedFile) return false;
|
|
36264
|
+
if (!Array.isArray(sources) || sources.length !== 1 || typeof sources[0] !== "string") return false;
|
|
36265
|
+
return Path.posix.normalize(Path.posix.join(input.mapDirectory, sources[0])) === input.sourcePath;
|
|
36266
|
+
};
|
|
36267
|
+
const quartetProvesEmit = (stem, sourcePath, readFileText) => {
|
|
36268
|
+
try {
|
|
36269
|
+
const emitBaseName = Path.posix.basename(stem);
|
|
36270
|
+
const mapDirectory = Path.posix.dirname(stem);
|
|
36271
|
+
return lastSourceMappingUrl(readFileText(`${stem}.js`)) === `${emitBaseName}.js.map` && lastSourceMappingUrl(readFileText(`${stem}.d.ts`)) === `${emitBaseName}.d.ts.map` && mapTargetsSource(readFileText(`${stem}.js.map`), {
|
|
36272
|
+
expectedFile: `${emitBaseName}.js`,
|
|
36273
|
+
mapDirectory,
|
|
36274
|
+
sourcePath
|
|
36275
|
+
}) && mapTargetsSource(readFileText(`${stem}.d.ts.map`), {
|
|
36276
|
+
expectedFile: `${emitBaseName}.d.ts`,
|
|
36277
|
+
mapDirectory,
|
|
36278
|
+
sourcePath
|
|
36279
|
+
});
|
|
36280
|
+
} catch {
|
|
36281
|
+
return false;
|
|
36282
|
+
}
|
|
36283
|
+
};
|
|
36284
|
+
const collectTypeScriptEmitDuplicateJsPaths = (input) => {
|
|
36285
|
+
const untracked = new Set(input.untrackedPaths);
|
|
36286
|
+
const duplicateJsPaths = /* @__PURE__ */ new Set();
|
|
36287
|
+
for (const jsPath of untracked) {
|
|
36288
|
+
if (!jsPath.endsWith(".js")) continue;
|
|
36289
|
+
const stem = jsPath.slice(0, -3);
|
|
36290
|
+
if (![
|
|
36291
|
+
jsPath,
|
|
36292
|
+
`${stem}.js.map`,
|
|
36293
|
+
`${stem}.d.ts`,
|
|
36294
|
+
`${stem}.d.ts.map`
|
|
36295
|
+
].every((emitPath) => untracked.has(emitPath) && !input.trackedPaths.has(emitPath))) continue;
|
|
36296
|
+
const sourcePath = [`${stem}.ts`, `${stem}.tsx`].find((candidatePath) => input.trackedPaths.has(candidatePath));
|
|
36297
|
+
if (!sourcePath) continue;
|
|
36298
|
+
if (quartetProvesEmit(stem, sourcePath, input.readFileText)) duplicateJsPaths.add(jsPath);
|
|
36299
|
+
}
|
|
36300
|
+
return duplicateJsPaths;
|
|
36301
|
+
};
|
|
36255
36302
|
const isIgnoredDirectoryName = (directoryName) => IGNORED_DIRECTORIES.has(directoryName) || directoryName.startsWith(".") && !SCANNED_DOT_DIRECTORIES.has(directoryName);
|
|
36256
36303
|
const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => isIgnoredDirectoryName(segment));
|
|
36257
36304
|
const isLintableSourceFile = (filePath) => SOURCE_FILE_PATTERN.test(filePath) && !GENERATED_BUNDLE_FILE_PATTERN.test(filePath) && !GENERATED_SOURCE_DIRECTORY_PATTERN.test(filePath);
|
|
@@ -36319,20 +36366,29 @@ const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
|
|
|
36319
36366
|
}
|
|
36320
36367
|
return entries;
|
|
36321
36368
|
};
|
|
36322
|
-
const
|
|
36369
|
+
const gitLsFiles = (rootDirectory, flags) => {
|
|
36323
36370
|
const result = spawnSync("git", [
|
|
36324
36371
|
"ls-files",
|
|
36325
36372
|
"-z",
|
|
36326
|
-
|
|
36327
|
-
"--others",
|
|
36328
|
-
"--exclude-standard"
|
|
36373
|
+
...flags
|
|
36329
36374
|
], {
|
|
36330
36375
|
cwd: rootDirectory,
|
|
36331
36376
|
encoding: "utf-8",
|
|
36332
36377
|
maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
|
|
36333
36378
|
});
|
|
36334
36379
|
if (result.error || result.status !== 0) return null;
|
|
36335
|
-
return result.stdout.split("\0").filter((filePath) => filePath.length > 0
|
|
36380
|
+
return result.stdout.split("\0").filter((filePath) => filePath.length > 0);
|
|
36381
|
+
};
|
|
36382
|
+
const listSourceFilesViaGit = (rootDirectory) => {
|
|
36383
|
+
const trackedPaths = gitLsFiles(rootDirectory, ["--cached"]);
|
|
36384
|
+
const untrackedPaths = gitLsFiles(rootDirectory, ["--others", "--exclude-standard"]);
|
|
36385
|
+
if (trackedPaths === null || untrackedPaths === null) return null;
|
|
36386
|
+
const emitDuplicateJsPaths = collectTypeScriptEmitDuplicateJsPaths({
|
|
36387
|
+
trackedPaths: new Set(trackedPaths),
|
|
36388
|
+
untrackedPaths,
|
|
36389
|
+
readFileText: (relativePath) => NFS.readFileSync(Path.resolve(rootDirectory, relativePath), "utf-8")
|
|
36390
|
+
});
|
|
36391
|
+
return [...trackedPaths, ...untrackedPaths].filter((filePath) => isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath) && !emitDuplicateJsPaths.has(filePath));
|
|
36336
36392
|
};
|
|
36337
36393
|
const listSourceFilesViaFilesystem = (rootDirectory) => {
|
|
36338
36394
|
const filePaths = [];
|
|
@@ -36532,11 +36588,8 @@ const frameworkMergeRank = (framework) => {
|
|
|
36532
36588
|
if (framework === "unknown") return 3;
|
|
36533
36589
|
return MOBILE_FRAMEWORKS.has(framework) ? 2 : 1;
|
|
36534
36590
|
};
|
|
36535
|
-
const
|
|
36536
|
-
|
|
36537
|
-
"react-compiler-runtime",
|
|
36538
|
-
"eslint-plugin-react-compiler"
|
|
36539
|
-
]);
|
|
36591
|
+
const REACT_COMPILER_TRANSFORM_PACKAGES = new Set(["babel-plugin-react-compiler", "react-compiler-runtime"]);
|
|
36592
|
+
const REACT_COMPILER_LINT_PACKAGES = new Set(["eslint-plugin-react-compiler"]);
|
|
36540
36593
|
const NEXT_CONFIG_FILENAMES = [
|
|
36541
36594
|
"next.config.js",
|
|
36542
36595
|
"next.config.mjs",
|
|
@@ -36566,16 +36619,29 @@ const EXPO_APP_CONFIG_FILENAMES = [
|
|
|
36566
36619
|
"app.config.js",
|
|
36567
36620
|
"app.config.ts"
|
|
36568
36621
|
];
|
|
36569
|
-
const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|
|
|
36622
|
+
const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|["']react-compiler["']/;
|
|
36570
36623
|
const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
|
|
36571
36624
|
const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
|
|
36572
|
-
const hasCompilerPackage = (packageJson) => {
|
|
36625
|
+
const hasCompilerPackage = (packageJson, compilerPackages) => {
|
|
36573
36626
|
const allDependencies = {
|
|
36574
36627
|
...packageJson.peerDependencies,
|
|
36575
36628
|
...packageJson.dependencies,
|
|
36576
36629
|
...packageJson.devDependencies
|
|
36577
36630
|
};
|
|
36578
|
-
return Object.keys(allDependencies).some((packageName) =>
|
|
36631
|
+
return Object.keys(allDependencies).some((packageName) => compilerPackages.has(packageName));
|
|
36632
|
+
};
|
|
36633
|
+
const hasCompilerPackageInAncestors = (directory, compilerPackages) => {
|
|
36634
|
+
if (isProjectBoundary(directory)) return false;
|
|
36635
|
+
let ancestorDirectory = Path.dirname(directory);
|
|
36636
|
+
while (ancestorDirectory !== Path.dirname(ancestorDirectory)) {
|
|
36637
|
+
const ancestorPackagePath = Path.join(ancestorDirectory, "package.json");
|
|
36638
|
+
if (isFile(ancestorPackagePath)) {
|
|
36639
|
+
if (hasCompilerPackage(readPackageJson$1(ancestorPackagePath), compilerPackages)) return true;
|
|
36640
|
+
}
|
|
36641
|
+
if (isProjectBoundary(ancestorDirectory)) return false;
|
|
36642
|
+
ancestorDirectory = Path.dirname(ancestorDirectory);
|
|
36643
|
+
}
|
|
36644
|
+
return false;
|
|
36579
36645
|
};
|
|
36580
36646
|
const hasCompilerInConfigFile = (filePath) => {
|
|
36581
36647
|
if (!isFile(filePath)) return false;
|
|
@@ -36584,23 +36650,14 @@ const hasCompilerInConfigFile = (filePath) => {
|
|
|
36584
36650
|
};
|
|
36585
36651
|
const hasCompilerInConfigFiles = (directory, filenames) => filenames.some((filename) => hasCompilerInConfigFile(Path.join(directory, filename)));
|
|
36586
36652
|
const detectReactCompiler = (directory, packageJson) => {
|
|
36587
|
-
if (hasCompilerPackage(packageJson)) return true;
|
|
36653
|
+
if (hasCompilerPackage(packageJson, REACT_COMPILER_TRANSFORM_PACKAGES)) return true;
|
|
36588
36654
|
if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;
|
|
36589
36655
|
if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;
|
|
36590
36656
|
if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;
|
|
36591
36657
|
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;
|
|
36658
|
+
return hasCompilerPackageInAncestors(directory, REACT_COMPILER_TRANSFORM_PACKAGES);
|
|
36603
36659
|
};
|
|
36660
|
+
const detectReactCompilerLintPlugin = (directory, packageJson) => hasCompilerPackage(packageJson, REACT_COMPILER_LINT_PACKAGES) || hasCompilerPackageInAncestors(directory, REACT_COMPILER_LINT_PACKAGES);
|
|
36604
36661
|
const detectNextjsStaticExport = (directory) => NEXT_CONFIG_FILENAMES.some((filename) => {
|
|
36605
36662
|
const filePath = Path.join(directory, filename);
|
|
36606
36663
|
return isFile(filePath) && STATIC_EXPORT_OUTPUT_PATTERN.test(NFS.readFileSync(filePath, "utf-8"));
|
|
@@ -37564,6 +37621,7 @@ const discoverProjectWithoutPackageJson = (directory) => {
|
|
|
37564
37621
|
framework: "unknown",
|
|
37565
37622
|
hasTypeScript: hasOwnTsConfig,
|
|
37566
37623
|
hasReactCompiler: false,
|
|
37624
|
+
hasReactCompilerLintPlugin: false,
|
|
37567
37625
|
hasTanStackQuery: false,
|
|
37568
37626
|
hasSsrDependency: false,
|
|
37569
37627
|
preactVersion: null,
|
|
@@ -37684,6 +37742,7 @@ const discoverProject = (directory) => {
|
|
|
37684
37742
|
framework,
|
|
37685
37743
|
hasTypeScript,
|
|
37686
37744
|
hasReactCompiler: detectReactCompiler(directory, packageJson),
|
|
37745
|
+
hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
|
|
37687
37746
|
hasTanStackQuery: hasTanStackQuery(packageJson),
|
|
37688
37747
|
hasSsrDependency: workspaceFacts.hasSsrDependency,
|
|
37689
37748
|
preactVersion,
|
|
@@ -42963,7 +43022,7 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
42963
43022
|
return enabled;
|
|
42964
43023
|
};
|
|
42965
43024
|
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);
|
|
43025
|
+
const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
|
|
42967
43026
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
42968
43027
|
const jsPlugins = [];
|
|
42969
43028
|
if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
|
|
@@ -43926,6 +43985,8 @@ const LEADING_SEVERITY_LABEL_PATTERN = /^(?:Error|Warning):\s*/;
|
|
|
43926
43985
|
const TRAILING_PERIOD_PATTERN = /\.$/;
|
|
43927
43986
|
const REACT_COMPILER_TITLE = "React Compiler can't optimize this";
|
|
43928
43987
|
const REACT_COMPILER_TODO_TITLE = "React Compiler doesn't support this syntax";
|
|
43988
|
+
const REACT_ERROR_BOUNDARY_TITLE = "JSX render errors need an Error Boundary";
|
|
43989
|
+
const REACT_ERROR_BOUNDARY_MESSAGE = "This try/catch cannot catch errors thrown while the JSX child renders. Use an Error Boundary instead.";
|
|
43929
43990
|
const REACT_COMPILER_IMPACT = "This component misses React Compiler's automatic memoization & re-renders more than it should";
|
|
43930
43991
|
const REACT_COMPILER_ACTION = "Rewrite the flagged code so the compiler can optimize it.";
|
|
43931
43992
|
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 +44030,7 @@ const getRuleCategory = (ruleName) => reactDoctorPlugin.rules[ruleName]?.categor
|
|
|
43969
44030
|
const getRuleTitle = (ruleName) => reactDoctorPlugin.rules[ruleName]?.title;
|
|
43970
44031
|
const resolveDiagnosticTitle = (plugin, rule) => {
|
|
43971
44032
|
if (plugin !== "react-hooks-js") return getRuleTitle(rule);
|
|
44033
|
+
if (rule === "error-boundaries") return REACT_ERROR_BOUNDARY_TITLE;
|
|
43972
44034
|
return rule === "todo" ? REACT_COMPILER_TODO_TITLE : REACT_COMPILER_TITLE;
|
|
43973
44035
|
};
|
|
43974
44036
|
const cleanDiagnosticMessage = (message, help, plugin, rule, project) => {
|
|
@@ -43987,6 +44049,10 @@ const resolveCleanedDiagnostic = (message, help, plugin, rule, project) => {
|
|
|
43987
44049
|
};
|
|
43988
44050
|
const [reasonSummary = "", ...reasonDetailLines] = bailoutReason.split("\n");
|
|
43989
44051
|
const reasonDetail = reasonDetailLines.join("\n").trim();
|
|
44052
|
+
if (rule === "error-boundaries") return {
|
|
44053
|
+
message: REACT_ERROR_BOUNDARY_MESSAGE,
|
|
44054
|
+
help: reasonDetail || help
|
|
44055
|
+
};
|
|
43990
44056
|
return {
|
|
43991
44057
|
message: buildReactCompilerMessage(reasonSummary.trim(), rule === "incompatible-library" ? REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION : REACT_COMPILER_ACTION),
|
|
43992
44058
|
help: appendReanimatedSharedValueHint(reasonDetail || help, rule, project)
|
|
@@ -44008,7 +44074,10 @@ const parseRuleCode = (code) => {
|
|
|
44008
44074
|
rule: match[2]
|
|
44009
44075
|
};
|
|
44010
44076
|
};
|
|
44011
|
-
const resolveDiagnosticCategory = (plugin, rule) =>
|
|
44077
|
+
const resolveDiagnosticCategory = (plugin, rule) => {
|
|
44078
|
+
if (plugin === "react-hooks-js" && rule === "error-boundaries") return "Bugs";
|
|
44079
|
+
return getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
|
|
44080
|
+
};
|
|
44012
44081
|
const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORIES.has(category) || Boolean(reactDoctorPlugin.rules[rule]?.matchByOccurrence);
|
|
44013
44082
|
/**
|
|
44014
44083
|
* Maps oxlint's non-primary labels (`labels[1..]`) into related source
|
|
@@ -44821,7 +44890,7 @@ const runOxlint = async (options) => {
|
|
|
44821
44890
|
};
|
|
44822
44891
|
}
|
|
44823
44892
|
};
|
|
44824
|
-
if (perFileLintCacheEnabled && !project.hasReactCompiler && extendsPaths.length === 0 && userPlugins.length === 0) {
|
|
44893
|
+
if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0) {
|
|
44825
44894
|
const rulesetHash = computeRulesetHash({
|
|
44826
44895
|
config: buildConfig({
|
|
44827
44896
|
extendsPaths: [],
|
|
@@ -45263,6 +45332,14 @@ var Reporter = class Reporter extends Service()("react-doctor/Reporter") {
|
|
|
45263
45332
|
});
|
|
45264
45333
|
}));
|
|
45265
45334
|
};
|
|
45335
|
+
const HOME_DIRECTORY = os.homedir();
|
|
45336
|
+
const USER_HOME_PATTERNS = [/[A-Za-z]:[\\/]Users[\\/][^\\/]+/gi, /(?:\/Users\/|\/home\/)[^/\\]+/gi];
|
|
45337
|
+
const scrubSensitivePaths = (text) => {
|
|
45338
|
+
let scrubbed = text;
|
|
45339
|
+
if (HOME_DIRECTORY.length > 1) scrubbed = scrubbed.split(HOME_DIRECTORY).join("~");
|
|
45340
|
+
for (const pattern of USER_HOME_PATTERNS) scrubbed = scrubbed.replace(pattern, "~");
|
|
45341
|
+
return scrubbed;
|
|
45342
|
+
};
|
|
45266
45343
|
const ScoreApiResponseSchema = Struct({
|
|
45267
45344
|
score: Number$1,
|
|
45268
45345
|
label: String$1,
|
|
@@ -45277,7 +45354,10 @@ const ScoreApiResponseSchema = Struct({
|
|
|
45277
45354
|
})))
|
|
45278
45355
|
});
|
|
45279
45356
|
const parseScoreResult = (value) => getOrNull(decodeUnknownOption(ScoreApiResponseSchema)(value));
|
|
45280
|
-
const
|
|
45357
|
+
const sanitizeScoreDiagnostics = (diagnostics) => diagnostics.map(({ filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => ({
|
|
45358
|
+
...rest,
|
|
45359
|
+
filePath: redactSensitiveText(scrubSensitivePaths(filePath))
|
|
45360
|
+
}));
|
|
45281
45361
|
const isAbortError = (error) => error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
|
|
45282
45362
|
const describeFailure = (error) => {
|
|
45283
45363
|
if (isAbortError(error)) return `timed out after ${FETCH_TIMEOUT_MS / 1e3}s`;
|
|
@@ -45290,7 +45370,7 @@ const calculateScore = async (diagnostics, options = {}) => {
|
|
|
45290
45370
|
const requestUrl = options.isCi ? `${SCORE_API_URL}?ci=1` : SCORE_API_URL;
|
|
45291
45371
|
try {
|
|
45292
45372
|
const compressedBody = gzipSync(JSON.stringify({
|
|
45293
|
-
diagnostics:
|
|
45373
|
+
diagnostics: sanitizeScoreDiagnostics(diagnostics),
|
|
45294
45374
|
...options.metadata?.repo ? { repo: options.metadata.repo } : {},
|
|
45295
45375
|
...options.metadata?.sha ? { sha: options.metadata.sha } : {},
|
|
45296
45376
|
...options.metadata?.framework ? { framework: options.metadata.framework } : {},
|
|
@@ -47135,7 +47215,7 @@ const makeNoopConsole = () => ({
|
|
|
47135
47215
|
});
|
|
47136
47216
|
//#endregion
|
|
47137
47217
|
//#region src/cli/utils/version.ts
|
|
47138
|
-
const VERSION = "0.7.9-dev.
|
|
47218
|
+
const VERSION = "0.7.9-dev.e5a5f73";
|
|
47139
47219
|
//#endregion
|
|
47140
47220
|
//#region src/cli/utils/json-mode.ts
|
|
47141
47221
|
let context = null;
|
|
@@ -47221,23 +47301,6 @@ const getRunId = () => {
|
|
|
47221
47301
|
return cachedRunId;
|
|
47222
47302
|
};
|
|
47223
47303
|
//#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
47304
|
//#region src/cli/utils/build-run-context.ts
|
|
47242
47305
|
const ROOT_SUBCOMMANDS = new Set(["install", "setup"]);
|
|
47243
47306
|
const detectInvokedVia = () => {
|
|
@@ -47504,13 +47567,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
|
|
|
47504
47567
|
* uploads source-map artifacts under, so stack frames symbolicate. Honors the
|
|
47505
47568
|
* standard `SENTRY_RELEASE` override.
|
|
47506
47569
|
*/
|
|
47507
|
-
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.9-dev.
|
|
47570
|
+
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.9-dev.e5a5f73`;
|
|
47508
47571
|
/**
|
|
47509
47572
|
* Deployment environment shown in Sentry's environment filter. Defaults to
|
|
47510
47573
|
* `production` for tagged releases and `development` for dev/unbuilt versions,
|
|
47511
47574
|
* overridable via the standard `SENTRY_ENVIRONMENT` env var.
|
|
47512
47575
|
*/
|
|
47513
|
-
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.9-dev.
|
|
47576
|
+
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.9-dev.e5a5f73") ? "development" : "production");
|
|
47514
47577
|
/**
|
|
47515
47578
|
* Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
|
|
47516
47579
|
* (set to `0` to disable tracing) and falls back to
|
|
@@ -65788,4 +65851,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
|
|
|
65788
65851
|
export {};
|
|
65789
65852
|
|
|
65790
65853
|
//# sourceMappingURL=cli.js.map
|
|
65791
|
-
//# debugId=
|
|
65854
|
+
//# debugId=6f05eada-46fe-5b24-92d8-15fa92a38b00
|
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]="28287c1c-b7b6-53b8-9e72-7d28d4f3ca45")}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";
|
|
@@ -33050,6 +33050,53 @@ const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
|
|
|
33050
33050
|
const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
|
|
33051
33051
|
const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
|
|
33052
33052
|
const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
|
|
33053
|
+
const lastSourceMappingUrl = (fileContent) => {
|
|
33054
|
+
const lastReference = [...fileContent.matchAll(/\/\/# sourceMappingURL=(\S+)/g)].at(-1);
|
|
33055
|
+
return lastReference ? lastReference[1] : null;
|
|
33056
|
+
};
|
|
33057
|
+
const mapTargetsSource = (mapContent, input) => {
|
|
33058
|
+
const parsedMap = JSON.parse(mapContent);
|
|
33059
|
+
if (typeof parsedMap !== "object" || parsedMap === null) return false;
|
|
33060
|
+
const { file, sources } = parsedMap;
|
|
33061
|
+
if (file !== input.expectedFile) return false;
|
|
33062
|
+
if (!Array.isArray(sources) || sources.length !== 1 || typeof sources[0] !== "string") return false;
|
|
33063
|
+
return Path.posix.normalize(Path.posix.join(input.mapDirectory, sources[0])) === input.sourcePath;
|
|
33064
|
+
};
|
|
33065
|
+
const quartetProvesEmit = (stem, sourcePath, readFileText) => {
|
|
33066
|
+
try {
|
|
33067
|
+
const emitBaseName = Path.posix.basename(stem);
|
|
33068
|
+
const mapDirectory = Path.posix.dirname(stem);
|
|
33069
|
+
return lastSourceMappingUrl(readFileText(`${stem}.js`)) === `${emitBaseName}.js.map` && lastSourceMappingUrl(readFileText(`${stem}.d.ts`)) === `${emitBaseName}.d.ts.map` && mapTargetsSource(readFileText(`${stem}.js.map`), {
|
|
33070
|
+
expectedFile: `${emitBaseName}.js`,
|
|
33071
|
+
mapDirectory,
|
|
33072
|
+
sourcePath
|
|
33073
|
+
}) && mapTargetsSource(readFileText(`${stem}.d.ts.map`), {
|
|
33074
|
+
expectedFile: `${emitBaseName}.d.ts`,
|
|
33075
|
+
mapDirectory,
|
|
33076
|
+
sourcePath
|
|
33077
|
+
});
|
|
33078
|
+
} catch {
|
|
33079
|
+
return false;
|
|
33080
|
+
}
|
|
33081
|
+
};
|
|
33082
|
+
const collectTypeScriptEmitDuplicateJsPaths = (input) => {
|
|
33083
|
+
const untracked = new Set(input.untrackedPaths);
|
|
33084
|
+
const duplicateJsPaths = /* @__PURE__ */ new Set();
|
|
33085
|
+
for (const jsPath of untracked) {
|
|
33086
|
+
if (!jsPath.endsWith(".js")) continue;
|
|
33087
|
+
const stem = jsPath.slice(0, -3);
|
|
33088
|
+
if (![
|
|
33089
|
+
jsPath,
|
|
33090
|
+
`${stem}.js.map`,
|
|
33091
|
+
`${stem}.d.ts`,
|
|
33092
|
+
`${stem}.d.ts.map`
|
|
33093
|
+
].every((emitPath) => untracked.has(emitPath) && !input.trackedPaths.has(emitPath))) continue;
|
|
33094
|
+
const sourcePath = [`${stem}.ts`, `${stem}.tsx`].find((candidatePath) => input.trackedPaths.has(candidatePath));
|
|
33095
|
+
if (!sourcePath) continue;
|
|
33096
|
+
if (quartetProvesEmit(stem, sourcePath, input.readFileText)) duplicateJsPaths.add(jsPath);
|
|
33097
|
+
}
|
|
33098
|
+
return duplicateJsPaths;
|
|
33099
|
+
};
|
|
33053
33100
|
const isIgnoredDirectoryName = (directoryName) => IGNORED_DIRECTORIES.has(directoryName) || directoryName.startsWith(".") && !SCANNED_DOT_DIRECTORIES.has(directoryName);
|
|
33054
33101
|
const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => isIgnoredDirectoryName(segment));
|
|
33055
33102
|
const isLintableSourceFile = (filePath) => SOURCE_FILE_PATTERN.test(filePath) && !GENERATED_BUNDLE_FILE_PATTERN.test(filePath) && !GENERATED_SOURCE_DIRECTORY_PATTERN.test(filePath);
|
|
@@ -33120,20 +33167,29 @@ const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
|
|
|
33120
33167
|
}
|
|
33121
33168
|
return entries;
|
|
33122
33169
|
};
|
|
33123
|
-
const
|
|
33170
|
+
const gitLsFiles = (rootDirectory, flags) => {
|
|
33124
33171
|
const result = spawnSync("git", [
|
|
33125
33172
|
"ls-files",
|
|
33126
33173
|
"-z",
|
|
33127
|
-
|
|
33128
|
-
"--others",
|
|
33129
|
-
"--exclude-standard"
|
|
33174
|
+
...flags
|
|
33130
33175
|
], {
|
|
33131
33176
|
cwd: rootDirectory,
|
|
33132
33177
|
encoding: "utf-8",
|
|
33133
33178
|
maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
|
|
33134
33179
|
});
|
|
33135
33180
|
if (result.error || result.status !== 0) return null;
|
|
33136
|
-
return result.stdout.split("\0").filter((filePath) => filePath.length > 0
|
|
33181
|
+
return result.stdout.split("\0").filter((filePath) => filePath.length > 0);
|
|
33182
|
+
};
|
|
33183
|
+
const listSourceFilesViaGit = (rootDirectory) => {
|
|
33184
|
+
const trackedPaths = gitLsFiles(rootDirectory, ["--cached"]);
|
|
33185
|
+
const untrackedPaths = gitLsFiles(rootDirectory, ["--others", "--exclude-standard"]);
|
|
33186
|
+
if (trackedPaths === null || untrackedPaths === null) return null;
|
|
33187
|
+
const emitDuplicateJsPaths = collectTypeScriptEmitDuplicateJsPaths({
|
|
33188
|
+
trackedPaths: new Set(trackedPaths),
|
|
33189
|
+
untrackedPaths,
|
|
33190
|
+
readFileText: (relativePath) => NFS.readFileSync(Path.resolve(rootDirectory, relativePath), "utf-8")
|
|
33191
|
+
});
|
|
33192
|
+
return [...trackedPaths, ...untrackedPaths].filter((filePath) => isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath) && !emitDuplicateJsPaths.has(filePath));
|
|
33137
33193
|
};
|
|
33138
33194
|
const listSourceFilesViaFilesystem = (rootDirectory) => {
|
|
33139
33195
|
const filePaths = [];
|
|
@@ -33336,11 +33392,8 @@ const frameworkMergeRank = (framework) => {
|
|
|
33336
33392
|
if (framework === "unknown") return 3;
|
|
33337
33393
|
return MOBILE_FRAMEWORKS.has(framework) ? 2 : 1;
|
|
33338
33394
|
};
|
|
33339
|
-
const
|
|
33340
|
-
|
|
33341
|
-
"react-compiler-runtime",
|
|
33342
|
-
"eslint-plugin-react-compiler"
|
|
33343
|
-
]);
|
|
33395
|
+
const REACT_COMPILER_TRANSFORM_PACKAGES = new Set(["babel-plugin-react-compiler", "react-compiler-runtime"]);
|
|
33396
|
+
const REACT_COMPILER_LINT_PACKAGES = new Set(["eslint-plugin-react-compiler"]);
|
|
33344
33397
|
const NEXT_CONFIG_FILENAMES = [
|
|
33345
33398
|
"next.config.js",
|
|
33346
33399
|
"next.config.mjs",
|
|
@@ -33370,16 +33423,29 @@ const EXPO_APP_CONFIG_FILENAMES = [
|
|
|
33370
33423
|
"app.config.js",
|
|
33371
33424
|
"app.config.ts"
|
|
33372
33425
|
];
|
|
33373
|
-
const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|
|
|
33426
|
+
const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|["']react-compiler["']/;
|
|
33374
33427
|
const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
|
|
33375
33428
|
const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
|
|
33376
|
-
const hasCompilerPackage = (packageJson) => {
|
|
33429
|
+
const hasCompilerPackage = (packageJson, compilerPackages) => {
|
|
33377
33430
|
const allDependencies = {
|
|
33378
33431
|
...packageJson.peerDependencies,
|
|
33379
33432
|
...packageJson.dependencies,
|
|
33380
33433
|
...packageJson.devDependencies
|
|
33381
33434
|
};
|
|
33382
|
-
return Object.keys(allDependencies).some((packageName) =>
|
|
33435
|
+
return Object.keys(allDependencies).some((packageName) => compilerPackages.has(packageName));
|
|
33436
|
+
};
|
|
33437
|
+
const hasCompilerPackageInAncestors = (directory, compilerPackages) => {
|
|
33438
|
+
if (isProjectBoundary(directory)) return false;
|
|
33439
|
+
let ancestorDirectory = Path.dirname(directory);
|
|
33440
|
+
while (ancestorDirectory !== Path.dirname(ancestorDirectory)) {
|
|
33441
|
+
const ancestorPackagePath = Path.join(ancestorDirectory, "package.json");
|
|
33442
|
+
if (isFile(ancestorPackagePath)) {
|
|
33443
|
+
if (hasCompilerPackage(readPackageJson(ancestorPackagePath), compilerPackages)) return true;
|
|
33444
|
+
}
|
|
33445
|
+
if (isProjectBoundary(ancestorDirectory)) return false;
|
|
33446
|
+
ancestorDirectory = Path.dirname(ancestorDirectory);
|
|
33447
|
+
}
|
|
33448
|
+
return false;
|
|
33383
33449
|
};
|
|
33384
33450
|
const hasCompilerInConfigFile = (filePath) => {
|
|
33385
33451
|
if (!isFile(filePath)) return false;
|
|
@@ -33388,23 +33454,14 @@ const hasCompilerInConfigFile = (filePath) => {
|
|
|
33388
33454
|
};
|
|
33389
33455
|
const hasCompilerInConfigFiles = (directory, filenames) => filenames.some((filename) => hasCompilerInConfigFile(Path.join(directory, filename)));
|
|
33390
33456
|
const detectReactCompiler = (directory, packageJson) => {
|
|
33391
|
-
if (hasCompilerPackage(packageJson)) return true;
|
|
33457
|
+
if (hasCompilerPackage(packageJson, REACT_COMPILER_TRANSFORM_PACKAGES)) return true;
|
|
33392
33458
|
if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;
|
|
33393
33459
|
if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;
|
|
33394
33460
|
if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;
|
|
33395
33461
|
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;
|
|
33462
|
+
return hasCompilerPackageInAncestors(directory, REACT_COMPILER_TRANSFORM_PACKAGES);
|
|
33407
33463
|
};
|
|
33464
|
+
const detectReactCompilerLintPlugin = (directory, packageJson) => hasCompilerPackage(packageJson, REACT_COMPILER_LINT_PACKAGES) || hasCompilerPackageInAncestors(directory, REACT_COMPILER_LINT_PACKAGES);
|
|
33408
33465
|
const detectNextjsStaticExport = (directory) => NEXT_CONFIG_FILENAMES.some((filename) => {
|
|
33409
33466
|
const filePath = Path.join(directory, filename);
|
|
33410
33467
|
return isFile(filePath) && STATIC_EXPORT_OUTPUT_PATTERN.test(NFS.readFileSync(filePath, "utf-8"));
|
|
@@ -34371,6 +34428,7 @@ const discoverProjectWithoutPackageJson = (directory) => {
|
|
|
34371
34428
|
framework: "unknown",
|
|
34372
34429
|
hasTypeScript: hasOwnTsConfig,
|
|
34373
34430
|
hasReactCompiler: false,
|
|
34431
|
+
hasReactCompilerLintPlugin: false,
|
|
34374
34432
|
hasTanStackQuery: false,
|
|
34375
34433
|
hasSsrDependency: false,
|
|
34376
34434
|
preactVersion: null,
|
|
@@ -34491,6 +34549,7 @@ const discoverProject = (directory) => {
|
|
|
34491
34549
|
framework,
|
|
34492
34550
|
hasTypeScript,
|
|
34493
34551
|
hasReactCompiler: detectReactCompiler(directory, packageJson),
|
|
34552
|
+
hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
|
|
34494
34553
|
hasTanStackQuery: hasTanStackQuery(packageJson),
|
|
34495
34554
|
hasSsrDependency: workspaceFacts.hasSsrDependency,
|
|
34496
34555
|
preactVersion,
|
|
@@ -39719,7 +39778,7 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
39719
39778
|
return enabled;
|
|
39720
39779
|
};
|
|
39721
39780
|
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);
|
|
39781
|
+
const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
|
|
39723
39782
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
39724
39783
|
const jsPlugins = [];
|
|
39725
39784
|
if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
|
|
@@ -40682,6 +40741,8 @@ const LEADING_SEVERITY_LABEL_PATTERN = /^(?:Error|Warning):\s*/;
|
|
|
40682
40741
|
const TRAILING_PERIOD_PATTERN = /\.$/;
|
|
40683
40742
|
const REACT_COMPILER_TITLE = "React Compiler can't optimize this";
|
|
40684
40743
|
const REACT_COMPILER_TODO_TITLE = "React Compiler doesn't support this syntax";
|
|
40744
|
+
const REACT_ERROR_BOUNDARY_TITLE = "JSX render errors need an Error Boundary";
|
|
40745
|
+
const REACT_ERROR_BOUNDARY_MESSAGE = "This try/catch cannot catch errors thrown while the JSX child renders. Use an Error Boundary instead.";
|
|
40685
40746
|
const REACT_COMPILER_IMPACT = "This component misses React Compiler's automatic memoization & re-renders more than it should";
|
|
40686
40747
|
const REACT_COMPILER_ACTION = "Rewrite the flagged code so the compiler can optimize it.";
|
|
40687
40748
|
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 +40786,7 @@ const getRuleCategory = (ruleName) => reactDoctorPlugin.rules[ruleName]?.categor
|
|
|
40725
40786
|
const getRuleTitle = (ruleName) => reactDoctorPlugin.rules[ruleName]?.title;
|
|
40726
40787
|
const resolveDiagnosticTitle = (plugin, rule) => {
|
|
40727
40788
|
if (plugin !== "react-hooks-js") return getRuleTitle(rule);
|
|
40789
|
+
if (rule === "error-boundaries") return REACT_ERROR_BOUNDARY_TITLE;
|
|
40728
40790
|
return rule === "todo" ? REACT_COMPILER_TODO_TITLE : REACT_COMPILER_TITLE;
|
|
40729
40791
|
};
|
|
40730
40792
|
const cleanDiagnosticMessage = (message, help, plugin, rule, project) => {
|
|
@@ -40743,6 +40805,10 @@ const resolveCleanedDiagnostic = (message, help, plugin, rule, project) => {
|
|
|
40743
40805
|
};
|
|
40744
40806
|
const [reasonSummary = "", ...reasonDetailLines] = bailoutReason.split("\n");
|
|
40745
40807
|
const reasonDetail = reasonDetailLines.join("\n").trim();
|
|
40808
|
+
if (rule === "error-boundaries") return {
|
|
40809
|
+
message: REACT_ERROR_BOUNDARY_MESSAGE,
|
|
40810
|
+
help: reasonDetail || help
|
|
40811
|
+
};
|
|
40746
40812
|
return {
|
|
40747
40813
|
message: buildReactCompilerMessage(reasonSummary.trim(), rule === "incompatible-library" ? REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION : REACT_COMPILER_ACTION),
|
|
40748
40814
|
help: appendReanimatedSharedValueHint(reasonDetail || help, rule, project)
|
|
@@ -40764,7 +40830,10 @@ const parseRuleCode = (code) => {
|
|
|
40764
40830
|
rule: match[2]
|
|
40765
40831
|
};
|
|
40766
40832
|
};
|
|
40767
|
-
const resolveDiagnosticCategory = (plugin, rule) =>
|
|
40833
|
+
const resolveDiagnosticCategory = (plugin, rule) => {
|
|
40834
|
+
if (plugin === "react-hooks-js" && rule === "error-boundaries") return "Bugs";
|
|
40835
|
+
return getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
|
|
40836
|
+
};
|
|
40768
40837
|
const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORIES.has(category) || Boolean(reactDoctorPlugin.rules[rule]?.matchByOccurrence);
|
|
40769
40838
|
/**
|
|
40770
40839
|
* Maps oxlint's non-primary labels (`labels[1..]`) into related source
|
|
@@ -41577,7 +41646,7 @@ const runOxlint = async (options) => {
|
|
|
41577
41646
|
};
|
|
41578
41647
|
}
|
|
41579
41648
|
};
|
|
41580
|
-
if (perFileLintCacheEnabled && !project.hasReactCompiler && extendsPaths.length === 0 && userPlugins.length === 0) {
|
|
41649
|
+
if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0) {
|
|
41581
41650
|
const rulesetHash = computeRulesetHash({
|
|
41582
41651
|
config: buildConfig({
|
|
41583
41652
|
extendsPaths: [],
|
|
@@ -42019,6 +42088,14 @@ var Reporter = class Reporter extends Service()("react-doctor/Reporter") {
|
|
|
42019
42088
|
});
|
|
42020
42089
|
}));
|
|
42021
42090
|
};
|
|
42091
|
+
const HOME_DIRECTORY = os.homedir();
|
|
42092
|
+
const USER_HOME_PATTERNS = [/[A-Za-z]:[\\/]Users[\\/][^\\/]+/gi, /(?:\/Users\/|\/home\/)[^/\\]+/gi];
|
|
42093
|
+
const scrubSensitivePaths = (text) => {
|
|
42094
|
+
let scrubbed = text;
|
|
42095
|
+
if (HOME_DIRECTORY.length > 1) scrubbed = scrubbed.split(HOME_DIRECTORY).join("~");
|
|
42096
|
+
for (const pattern of USER_HOME_PATTERNS) scrubbed = scrubbed.replace(pattern, "~");
|
|
42097
|
+
return scrubbed;
|
|
42098
|
+
};
|
|
42022
42099
|
const ScoreApiResponseSchema = Struct({
|
|
42023
42100
|
score: Number$1,
|
|
42024
42101
|
label: String$1,
|
|
@@ -42033,7 +42110,10 @@ const ScoreApiResponseSchema = Struct({
|
|
|
42033
42110
|
})))
|
|
42034
42111
|
});
|
|
42035
42112
|
const parseScoreResult = (value) => getOrNull(decodeUnknownOption(ScoreApiResponseSchema)(value));
|
|
42036
|
-
const
|
|
42113
|
+
const sanitizeScoreDiagnostics = (diagnostics) => diagnostics.map(({ filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => ({
|
|
42114
|
+
...rest,
|
|
42115
|
+
filePath: redactSensitiveText(scrubSensitivePaths(filePath))
|
|
42116
|
+
}));
|
|
42037
42117
|
const isAbortError = (error) => error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
|
|
42038
42118
|
const describeFailure = (error) => {
|
|
42039
42119
|
if (isAbortError(error)) return `timed out after ${FETCH_TIMEOUT_MS / 1e3}s`;
|
|
@@ -42046,7 +42126,7 @@ const calculateScore = async (diagnostics, options = {}) => {
|
|
|
42046
42126
|
const requestUrl = options.isCi ? `${SCORE_API_URL}?ci=1` : SCORE_API_URL;
|
|
42047
42127
|
try {
|
|
42048
42128
|
const compressedBody = gzipSync(JSON.stringify({
|
|
42049
|
-
diagnostics:
|
|
42129
|
+
diagnostics: sanitizeScoreDiagnostics(diagnostics),
|
|
42050
42130
|
...options.metadata?.repo ? { repo: options.metadata.repo } : {},
|
|
42051
42131
|
...options.metadata?.sha ? { sha: options.metadata.sha } : {},
|
|
42052
42132
|
...options.metadata?.framework ? { framework: options.metadata.framework } : {},
|
|
@@ -43639,4 +43719,4 @@ const toJsonReport = (result, options) => buildJsonReport({
|
|
|
43639
43719
|
export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
|
|
43640
43720
|
|
|
43641
43721
|
//# sourceMappingURL=index.js.map
|
|
43642
|
-
//# debugId=
|
|
43722
|
+
//# debugId=28287c1c-b7b6-53b8-9e72-7d28d4f3ca45
|
package/dist/lsp.js
CHANGED
|
@@ -33102,6 +33102,53 @@ const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
|
|
|
33102
33102
|
const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
|
|
33103
33103
|
const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
|
|
33104
33104
|
const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
|
|
33105
|
+
const lastSourceMappingUrl = (fileContent) => {
|
|
33106
|
+
const lastReference = [...fileContent.matchAll(/\/\/# sourceMappingURL=(\S+)/g)].at(-1);
|
|
33107
|
+
return lastReference ? lastReference[1] : null;
|
|
33108
|
+
};
|
|
33109
|
+
const mapTargetsSource = (mapContent, input) => {
|
|
33110
|
+
const parsedMap = JSON.parse(mapContent);
|
|
33111
|
+
if (typeof parsedMap !== "object" || parsedMap === null) return false;
|
|
33112
|
+
const { file, sources } = parsedMap;
|
|
33113
|
+
if (file !== input.expectedFile) return false;
|
|
33114
|
+
if (!Array.isArray(sources) || sources.length !== 1 || typeof sources[0] !== "string") return false;
|
|
33115
|
+
return Path.posix.normalize(Path.posix.join(input.mapDirectory, sources[0])) === input.sourcePath;
|
|
33116
|
+
};
|
|
33117
|
+
const quartetProvesEmit = (stem, sourcePath, readFileText) => {
|
|
33118
|
+
try {
|
|
33119
|
+
const emitBaseName = Path.posix.basename(stem);
|
|
33120
|
+
const mapDirectory = Path.posix.dirname(stem);
|
|
33121
|
+
return lastSourceMappingUrl(readFileText(`${stem}.js`)) === `${emitBaseName}.js.map` && lastSourceMappingUrl(readFileText(`${stem}.d.ts`)) === `${emitBaseName}.d.ts.map` && mapTargetsSource(readFileText(`${stem}.js.map`), {
|
|
33122
|
+
expectedFile: `${emitBaseName}.js`,
|
|
33123
|
+
mapDirectory,
|
|
33124
|
+
sourcePath
|
|
33125
|
+
}) && mapTargetsSource(readFileText(`${stem}.d.ts.map`), {
|
|
33126
|
+
expectedFile: `${emitBaseName}.d.ts`,
|
|
33127
|
+
mapDirectory,
|
|
33128
|
+
sourcePath
|
|
33129
|
+
});
|
|
33130
|
+
} catch {
|
|
33131
|
+
return false;
|
|
33132
|
+
}
|
|
33133
|
+
};
|
|
33134
|
+
const collectTypeScriptEmitDuplicateJsPaths = (input) => {
|
|
33135
|
+
const untracked = new Set(input.untrackedPaths);
|
|
33136
|
+
const duplicateJsPaths = /* @__PURE__ */ new Set();
|
|
33137
|
+
for (const jsPath of untracked) {
|
|
33138
|
+
if (!jsPath.endsWith(".js")) continue;
|
|
33139
|
+
const stem = jsPath.slice(0, -3);
|
|
33140
|
+
if (![
|
|
33141
|
+
jsPath,
|
|
33142
|
+
`${stem}.js.map`,
|
|
33143
|
+
`${stem}.d.ts`,
|
|
33144
|
+
`${stem}.d.ts.map`
|
|
33145
|
+
].every((emitPath) => untracked.has(emitPath) && !input.trackedPaths.has(emitPath))) continue;
|
|
33146
|
+
const sourcePath = [`${stem}.ts`, `${stem}.tsx`].find((candidatePath) => input.trackedPaths.has(candidatePath));
|
|
33147
|
+
if (!sourcePath) continue;
|
|
33148
|
+
if (quartetProvesEmit(stem, sourcePath, input.readFileText)) duplicateJsPaths.add(jsPath);
|
|
33149
|
+
}
|
|
33150
|
+
return duplicateJsPaths;
|
|
33151
|
+
};
|
|
33105
33152
|
const isIgnoredDirectoryName = (directoryName) => IGNORED_DIRECTORIES.has(directoryName) || directoryName.startsWith(".") && !SCANNED_DOT_DIRECTORIES.has(directoryName);
|
|
33106
33153
|
const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => isIgnoredDirectoryName(segment));
|
|
33107
33154
|
const isLintableSourceFile = (filePath) => SOURCE_FILE_PATTERN.test(filePath) && !GENERATED_BUNDLE_FILE_PATTERN.test(filePath) && !GENERATED_SOURCE_DIRECTORY_PATTERN.test(filePath);
|
|
@@ -33172,20 +33219,29 @@ const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
|
|
|
33172
33219
|
}
|
|
33173
33220
|
return entries;
|
|
33174
33221
|
};
|
|
33175
|
-
const
|
|
33222
|
+
const gitLsFiles = (rootDirectory, flags) => {
|
|
33176
33223
|
const result = spawnSync("git", [
|
|
33177
33224
|
"ls-files",
|
|
33178
33225
|
"-z",
|
|
33179
|
-
|
|
33180
|
-
"--others",
|
|
33181
|
-
"--exclude-standard"
|
|
33226
|
+
...flags
|
|
33182
33227
|
], {
|
|
33183
33228
|
cwd: rootDirectory,
|
|
33184
33229
|
encoding: "utf-8",
|
|
33185
33230
|
maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
|
|
33186
33231
|
});
|
|
33187
33232
|
if (result.error || result.status !== 0) return null;
|
|
33188
|
-
return result.stdout.split("\0").filter((filePath) => filePath.length > 0
|
|
33233
|
+
return result.stdout.split("\0").filter((filePath) => filePath.length > 0);
|
|
33234
|
+
};
|
|
33235
|
+
const listSourceFilesViaGit = (rootDirectory) => {
|
|
33236
|
+
const trackedPaths = gitLsFiles(rootDirectory, ["--cached"]);
|
|
33237
|
+
const untrackedPaths = gitLsFiles(rootDirectory, ["--others", "--exclude-standard"]);
|
|
33238
|
+
if (trackedPaths === null || untrackedPaths === null) return null;
|
|
33239
|
+
const emitDuplicateJsPaths = collectTypeScriptEmitDuplicateJsPaths({
|
|
33240
|
+
trackedPaths: new Set(trackedPaths),
|
|
33241
|
+
untrackedPaths,
|
|
33242
|
+
readFileText: (relativePath) => NFS.readFileSync(Path.resolve(rootDirectory, relativePath), "utf-8")
|
|
33243
|
+
});
|
|
33244
|
+
return [...trackedPaths, ...untrackedPaths].filter((filePath) => isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath) && !emitDuplicateJsPaths.has(filePath));
|
|
33189
33245
|
};
|
|
33190
33246
|
const listSourceFilesViaFilesystem = (rootDirectory) => {
|
|
33191
33247
|
const filePaths = [];
|
|
@@ -33388,11 +33444,8 @@ const frameworkMergeRank = (framework) => {
|
|
|
33388
33444
|
if (framework === "unknown") return 3;
|
|
33389
33445
|
return MOBILE_FRAMEWORKS.has(framework) ? 2 : 1;
|
|
33390
33446
|
};
|
|
33391
|
-
const
|
|
33392
|
-
|
|
33393
|
-
"react-compiler-runtime",
|
|
33394
|
-
"eslint-plugin-react-compiler"
|
|
33395
|
-
]);
|
|
33447
|
+
const REACT_COMPILER_TRANSFORM_PACKAGES = new Set(["babel-plugin-react-compiler", "react-compiler-runtime"]);
|
|
33448
|
+
const REACT_COMPILER_LINT_PACKAGES = new Set(["eslint-plugin-react-compiler"]);
|
|
33396
33449
|
const NEXT_CONFIG_FILENAMES = [
|
|
33397
33450
|
"next.config.js",
|
|
33398
33451
|
"next.config.mjs",
|
|
@@ -33422,16 +33475,29 @@ const EXPO_APP_CONFIG_FILENAMES = [
|
|
|
33422
33475
|
"app.config.js",
|
|
33423
33476
|
"app.config.ts"
|
|
33424
33477
|
];
|
|
33425
|
-
const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|
|
|
33478
|
+
const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|["']react-compiler["']/;
|
|
33426
33479
|
const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
|
|
33427
33480
|
const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
|
|
33428
|
-
const hasCompilerPackage = (packageJson) => {
|
|
33481
|
+
const hasCompilerPackage = (packageJson, compilerPackages) => {
|
|
33429
33482
|
const allDependencies = {
|
|
33430
33483
|
...packageJson.peerDependencies,
|
|
33431
33484
|
...packageJson.dependencies,
|
|
33432
33485
|
...packageJson.devDependencies
|
|
33433
33486
|
};
|
|
33434
|
-
return Object.keys(allDependencies).some((packageName) =>
|
|
33487
|
+
return Object.keys(allDependencies).some((packageName) => compilerPackages.has(packageName));
|
|
33488
|
+
};
|
|
33489
|
+
const hasCompilerPackageInAncestors = (directory, compilerPackages) => {
|
|
33490
|
+
if (isProjectBoundary(directory)) return false;
|
|
33491
|
+
let ancestorDirectory = Path.dirname(directory);
|
|
33492
|
+
while (ancestorDirectory !== Path.dirname(ancestorDirectory)) {
|
|
33493
|
+
const ancestorPackagePath = Path.join(ancestorDirectory, "package.json");
|
|
33494
|
+
if (isFile(ancestorPackagePath)) {
|
|
33495
|
+
if (hasCompilerPackage(readPackageJson(ancestorPackagePath), compilerPackages)) return true;
|
|
33496
|
+
}
|
|
33497
|
+
if (isProjectBoundary(ancestorDirectory)) return false;
|
|
33498
|
+
ancestorDirectory = Path.dirname(ancestorDirectory);
|
|
33499
|
+
}
|
|
33500
|
+
return false;
|
|
33435
33501
|
};
|
|
33436
33502
|
const hasCompilerInConfigFile = (filePath) => {
|
|
33437
33503
|
if (!isFile(filePath)) return false;
|
|
@@ -33440,23 +33506,14 @@ const hasCompilerInConfigFile = (filePath) => {
|
|
|
33440
33506
|
};
|
|
33441
33507
|
const hasCompilerInConfigFiles = (directory, filenames) => filenames.some((filename) => hasCompilerInConfigFile(Path.join(directory, filename)));
|
|
33442
33508
|
const detectReactCompiler = (directory, packageJson) => {
|
|
33443
|
-
if (hasCompilerPackage(packageJson)) return true;
|
|
33509
|
+
if (hasCompilerPackage(packageJson, REACT_COMPILER_TRANSFORM_PACKAGES)) return true;
|
|
33444
33510
|
if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;
|
|
33445
33511
|
if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;
|
|
33446
33512
|
if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;
|
|
33447
33513
|
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;
|
|
33514
|
+
return hasCompilerPackageInAncestors(directory, REACT_COMPILER_TRANSFORM_PACKAGES);
|
|
33459
33515
|
};
|
|
33516
|
+
const detectReactCompilerLintPlugin = (directory, packageJson) => hasCompilerPackage(packageJson, REACT_COMPILER_LINT_PACKAGES) || hasCompilerPackageInAncestors(directory, REACT_COMPILER_LINT_PACKAGES);
|
|
33460
33517
|
const detectNextjsStaticExport = (directory) => NEXT_CONFIG_FILENAMES.some((filename) => {
|
|
33461
33518
|
const filePath = Path.join(directory, filename);
|
|
33462
33519
|
return isFile(filePath) && STATIC_EXPORT_OUTPUT_PATTERN.test(NFS.readFileSync(filePath, "utf-8"));
|
|
@@ -34423,6 +34480,7 @@ const discoverProjectWithoutPackageJson = (directory) => {
|
|
|
34423
34480
|
framework: "unknown",
|
|
34424
34481
|
hasTypeScript: hasOwnTsConfig,
|
|
34425
34482
|
hasReactCompiler: false,
|
|
34483
|
+
hasReactCompilerLintPlugin: false,
|
|
34426
34484
|
hasTanStackQuery: false,
|
|
34427
34485
|
hasSsrDependency: false,
|
|
34428
34486
|
preactVersion: null,
|
|
@@ -34543,6 +34601,7 @@ const discoverProject = (directory) => {
|
|
|
34543
34601
|
framework,
|
|
34544
34602
|
hasTypeScript,
|
|
34545
34603
|
hasReactCompiler: detectReactCompiler(directory, packageJson),
|
|
34604
|
+
hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
|
|
34546
34605
|
hasTanStackQuery: hasTanStackQuery(packageJson),
|
|
34547
34606
|
hasSsrDependency: workspaceFacts.hasSsrDependency,
|
|
34548
34607
|
preactVersion,
|
|
@@ -39697,7 +39756,7 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
39697
39756
|
return enabled;
|
|
39698
39757
|
};
|
|
39699
39758
|
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);
|
|
39759
|
+
const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
|
|
39701
39760
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
39702
39761
|
const jsPlugins = [];
|
|
39703
39762
|
if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
|
|
@@ -40660,6 +40719,8 @@ const LEADING_SEVERITY_LABEL_PATTERN = /^(?:Error|Warning):\s*/;
|
|
|
40660
40719
|
const TRAILING_PERIOD_PATTERN = /\.$/;
|
|
40661
40720
|
const REACT_COMPILER_TITLE = "React Compiler can't optimize this";
|
|
40662
40721
|
const REACT_COMPILER_TODO_TITLE = "React Compiler doesn't support this syntax";
|
|
40722
|
+
const REACT_ERROR_BOUNDARY_TITLE = "JSX render errors need an Error Boundary";
|
|
40723
|
+
const REACT_ERROR_BOUNDARY_MESSAGE = "This try/catch cannot catch errors thrown while the JSX child renders. Use an Error Boundary instead.";
|
|
40663
40724
|
const REACT_COMPILER_IMPACT = "This component misses React Compiler's automatic memoization & re-renders more than it should";
|
|
40664
40725
|
const REACT_COMPILER_ACTION = "Rewrite the flagged code so the compiler can optimize it.";
|
|
40665
40726
|
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 +40764,7 @@ const getRuleCategory = (ruleName) => reactDoctorPlugin.rules[ruleName]?.categor
|
|
|
40703
40764
|
const getRuleTitle = (ruleName) => reactDoctorPlugin.rules[ruleName]?.title;
|
|
40704
40765
|
const resolveDiagnosticTitle = (plugin, rule) => {
|
|
40705
40766
|
if (plugin !== "react-hooks-js") return getRuleTitle(rule);
|
|
40767
|
+
if (rule === "error-boundaries") return REACT_ERROR_BOUNDARY_TITLE;
|
|
40706
40768
|
return rule === "todo" ? REACT_COMPILER_TODO_TITLE : REACT_COMPILER_TITLE;
|
|
40707
40769
|
};
|
|
40708
40770
|
const cleanDiagnosticMessage = (message, help, plugin, rule, project) => {
|
|
@@ -40721,6 +40783,10 @@ const resolveCleanedDiagnostic = (message, help, plugin, rule, project) => {
|
|
|
40721
40783
|
};
|
|
40722
40784
|
const [reasonSummary = "", ...reasonDetailLines] = bailoutReason.split("\n");
|
|
40723
40785
|
const reasonDetail = reasonDetailLines.join("\n").trim();
|
|
40786
|
+
if (rule === "error-boundaries") return {
|
|
40787
|
+
message: REACT_ERROR_BOUNDARY_MESSAGE,
|
|
40788
|
+
help: reasonDetail || help
|
|
40789
|
+
};
|
|
40724
40790
|
return {
|
|
40725
40791
|
message: buildReactCompilerMessage(reasonSummary.trim(), rule === "incompatible-library" ? REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION : REACT_COMPILER_ACTION),
|
|
40726
40792
|
help: appendReanimatedSharedValueHint(reasonDetail || help, rule, project)
|
|
@@ -40742,7 +40808,10 @@ const parseRuleCode = (code) => {
|
|
|
40742
40808
|
rule: match[2]
|
|
40743
40809
|
};
|
|
40744
40810
|
};
|
|
40745
|
-
const resolveDiagnosticCategory = (plugin, rule) =>
|
|
40811
|
+
const resolveDiagnosticCategory = (plugin, rule) => {
|
|
40812
|
+
if (plugin === "react-hooks-js" && rule === "error-boundaries") return "Bugs";
|
|
40813
|
+
return getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
|
|
40814
|
+
};
|
|
40746
40815
|
const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORIES.has(category) || Boolean(reactDoctorPlugin.rules[rule]?.matchByOccurrence);
|
|
40747
40816
|
/**
|
|
40748
40817
|
* Maps oxlint's non-primary labels (`labels[1..]`) into related source
|
|
@@ -41555,7 +41624,7 @@ const runOxlint = async (options) => {
|
|
|
41555
41624
|
};
|
|
41556
41625
|
}
|
|
41557
41626
|
};
|
|
41558
|
-
if (perFileLintCacheEnabled && !project.hasReactCompiler && extendsPaths.length === 0 && userPlugins.length === 0) {
|
|
41627
|
+
if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0) {
|
|
41559
41628
|
const rulesetHash = computeRulesetHash({
|
|
41560
41629
|
config: buildConfig({
|
|
41561
41630
|
extendsPaths: [],
|
|
@@ -41997,6 +42066,14 @@ var Reporter = class Reporter extends Service()("react-doctor/Reporter") {
|
|
|
41997
42066
|
});
|
|
41998
42067
|
}));
|
|
41999
42068
|
};
|
|
42069
|
+
const HOME_DIRECTORY = os.homedir();
|
|
42070
|
+
const USER_HOME_PATTERNS = [/[A-Za-z]:[\\/]Users[\\/][^\\/]+/gi, /(?:\/Users\/|\/home\/)[^/\\]+/gi];
|
|
42071
|
+
const scrubSensitivePaths = (text) => {
|
|
42072
|
+
let scrubbed = text;
|
|
42073
|
+
if (HOME_DIRECTORY.length > 1) scrubbed = scrubbed.split(HOME_DIRECTORY).join("~");
|
|
42074
|
+
for (const pattern of USER_HOME_PATTERNS) scrubbed = scrubbed.replace(pattern, "~");
|
|
42075
|
+
return scrubbed;
|
|
42076
|
+
};
|
|
42000
42077
|
const ScoreApiResponseSchema = Struct({
|
|
42001
42078
|
score: Number$1,
|
|
42002
42079
|
label: String$1,
|
|
@@ -42011,7 +42088,10 @@ const ScoreApiResponseSchema = Struct({
|
|
|
42011
42088
|
})))
|
|
42012
42089
|
});
|
|
42013
42090
|
const parseScoreResult = (value) => getOrNull(decodeUnknownOption(ScoreApiResponseSchema)(value));
|
|
42014
|
-
const
|
|
42091
|
+
const sanitizeScoreDiagnostics = (diagnostics) => diagnostics.map(({ filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => ({
|
|
42092
|
+
...rest,
|
|
42093
|
+
filePath: redactSensitiveText(scrubSensitivePaths(filePath))
|
|
42094
|
+
}));
|
|
42015
42095
|
const isAbortError = (error) => error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
|
|
42016
42096
|
const describeFailure = (error) => {
|
|
42017
42097
|
if (isAbortError(error)) return `timed out after ${FETCH_TIMEOUT_MS / 1e3}s`;
|
|
@@ -42024,7 +42104,7 @@ const calculateScore = async (diagnostics, options = {}) => {
|
|
|
42024
42104
|
const requestUrl = options.isCi ? `${SCORE_API_URL}?ci=1` : SCORE_API_URL;
|
|
42025
42105
|
try {
|
|
42026
42106
|
const compressedBody = gzipSync(JSON.stringify({
|
|
42027
|
-
diagnostics:
|
|
42107
|
+
diagnostics: sanitizeScoreDiagnostics(diagnostics),
|
|
42028
42108
|
...options.metadata?.repo ? { repo: options.metadata.repo } : {},
|
|
42029
42109
|
...options.metadata?.sha ? { sha: options.metadata.sha } : {},
|
|
42030
42110
|
...options.metadata?.framework ? { framework: options.metadata.framework } : {},
|
|
@@ -44971,23 +45051,6 @@ const METRIC = {
|
|
|
44971
45051
|
*/
|
|
44972
45052
|
const toCategoryKey = (category) => category.toLowerCase().replace(/[^a-z0-9]+/g, "_");
|
|
44973
45053
|
//#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
45054
|
//#region src/cli/utils/anonymize-text.ts
|
|
44992
45055
|
/**
|
|
44993
45056
|
* Free-text fields can carry both a home-directory path (the OS username) and a
|
|
@@ -45276,5 +45339,5 @@ const startLanguageServer = () => {
|
|
|
45276
45339
|
};
|
|
45277
45340
|
//#endregion
|
|
45278
45341
|
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=
|
|
45342
|
+
!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]="6c89dec9-5fbe-5a2e-b1fe-6b3954e0e85b")}catch(e){}}();
|
|
45343
|
+
//# debugId=6c89dec9-5fbe-5a2e-b1fe-6b3954e0e85b
|
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.e5a5f73",
|
|
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.e5a5f73"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@types/babel__code-frame": "^7.27.0",
|