react-doctor 0.8.1-dev.fc1b3a3 → 0.8.1
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/README.md +4 -14
- package/dist/cli.js +209 -1129
- package/dist/index.d.ts +15 -38
- package/dist/index.js +99 -546
- package/dist/lsp.js +99 -546
- package/dist/skills/react-doctor/SKILL.md +0 -5
- package/package.json +4 -4
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]="941df082-c8b4-5084-baae-33ec22d4e55f")}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";
|
|
@@ -36022,6 +36022,44 @@ var AmbiguousProjectError = class extends Error {
|
|
|
36022
36022
|
}
|
|
36023
36023
|
};
|
|
36024
36024
|
const isProjectDiscoveryError = (value) => value instanceof ProjectNotFoundError || value instanceof NoReactDependencyError || value instanceof PackageJsonNotFoundError || value instanceof NotADirectoryError || value instanceof AmbiguousProjectError;
|
|
36025
|
+
const isErrnoException = (error) => error instanceof Error && "code" in error;
|
|
36026
|
+
const IGNORABLE_READDIR_ERROR_CODES = new Set([
|
|
36027
|
+
"EACCES",
|
|
36028
|
+
"EPERM",
|
|
36029
|
+
"ENOENT",
|
|
36030
|
+
"ENOTDIR",
|
|
36031
|
+
"EINVAL",
|
|
36032
|
+
"ELOOP",
|
|
36033
|
+
"ENAMETOOLONG"
|
|
36034
|
+
]);
|
|
36035
|
+
const isIgnorableReaddirError = (error) => isErrnoException(error) && typeof error.code === "string" && IGNORABLE_READDIR_ERROR_CODES.has(error.code);
|
|
36036
|
+
const readDirectoryEntries = (directoryPath) => {
|
|
36037
|
+
try {
|
|
36038
|
+
return NFS.readdirSync(directoryPath, { withFileTypes: true });
|
|
36039
|
+
} catch (error) {
|
|
36040
|
+
if (isIgnorableReaddirError(error)) return [];
|
|
36041
|
+
throw error;
|
|
36042
|
+
}
|
|
36043
|
+
};
|
|
36044
|
+
const isFile = (filePath) => {
|
|
36045
|
+
try {
|
|
36046
|
+
return NFS.statSync(filePath).isFile();
|
|
36047
|
+
} catch {
|
|
36048
|
+
return false;
|
|
36049
|
+
}
|
|
36050
|
+
};
|
|
36051
|
+
const isDirectory = (directoryPath) => {
|
|
36052
|
+
try {
|
|
36053
|
+
return NFS.statSync(directoryPath).isDirectory();
|
|
36054
|
+
} catch {
|
|
36055
|
+
return false;
|
|
36056
|
+
}
|
|
36057
|
+
};
|
|
36058
|
+
const isPlainObject = (value) => {
|
|
36059
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
36060
|
+
const prototype = Object.getPrototypeOf(value);
|
|
36061
|
+
return prototype === null || prototype === Object.prototype;
|
|
36062
|
+
};
|
|
36025
36063
|
const SOURCE_FILE_PATTERN = /\.(tsx?|jsx?|mts|mjs)$/;
|
|
36026
36064
|
const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
|
|
36027
36065
|
const GENERATED_SOURCE_DIRECTORY_PATTERN = /(?:^|\/)__generated__\//;
|
|
@@ -36214,44 +36252,6 @@ const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
|
|
|
36214
36252
|
const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
|
|
36215
36253
|
const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
|
|
36216
36254
|
const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
|
|
36217
|
-
const isErrnoException = (error) => error instanceof Error && "code" in error;
|
|
36218
|
-
const IGNORABLE_READDIR_ERROR_CODES = new Set([
|
|
36219
|
-
"EACCES",
|
|
36220
|
-
"EPERM",
|
|
36221
|
-
"ENOENT",
|
|
36222
|
-
"ENOTDIR",
|
|
36223
|
-
"EINVAL",
|
|
36224
|
-
"ELOOP",
|
|
36225
|
-
"ENAMETOOLONG"
|
|
36226
|
-
]);
|
|
36227
|
-
const isIgnorableReaddirError = (error) => isErrnoException(error) && typeof error.code === "string" && IGNORABLE_READDIR_ERROR_CODES.has(error.code);
|
|
36228
|
-
const readDirectoryEntries = (directoryPath) => {
|
|
36229
|
-
try {
|
|
36230
|
-
return NFS.readdirSync(directoryPath, { withFileTypes: true });
|
|
36231
|
-
} catch (error) {
|
|
36232
|
-
if (isIgnorableReaddirError(error)) return [];
|
|
36233
|
-
throw error;
|
|
36234
|
-
}
|
|
36235
|
-
};
|
|
36236
|
-
const isFile = (filePath) => {
|
|
36237
|
-
try {
|
|
36238
|
-
return NFS.statSync(filePath).isFile();
|
|
36239
|
-
} catch {
|
|
36240
|
-
return false;
|
|
36241
|
-
}
|
|
36242
|
-
};
|
|
36243
|
-
const isDirectory = (directoryPath) => {
|
|
36244
|
-
try {
|
|
36245
|
-
return NFS.statSync(directoryPath).isDirectory();
|
|
36246
|
-
} catch {
|
|
36247
|
-
return false;
|
|
36248
|
-
}
|
|
36249
|
-
};
|
|
36250
|
-
const isPlainObject = (value) => {
|
|
36251
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
36252
|
-
const prototype = Object.getPrototypeOf(value);
|
|
36253
|
-
return prototype === null || prototype === Object.prototype;
|
|
36254
|
-
};
|
|
36255
36255
|
const lastSourceMappingUrl = (fileContent) => {
|
|
36256
36256
|
const lastReference = [...fileContent.matchAll(/\/\/# sourceMappingURL=(\S+)/g)].at(-1);
|
|
36257
36257
|
return lastReference ? lastReference[1] : null;
|
|
@@ -36571,10 +36571,10 @@ const FALLBACK_TSCONFIG_FILENAMES = ["tsconfig.app.json", "tsconfig.build.json"]
|
|
|
36571
36571
|
const FRAMEWORK_PACKAGES = {
|
|
36572
36572
|
next: "nextjs",
|
|
36573
36573
|
"@tanstack/react-start": "tanstack-start",
|
|
36574
|
-
"@remix-run/react": "remix",
|
|
36575
|
-
gatsby: "gatsby",
|
|
36576
36574
|
vite: "vite",
|
|
36577
36575
|
"react-scripts": "cra",
|
|
36576
|
+
"@remix-run/react": "remix",
|
|
36577
|
+
gatsby: "gatsby",
|
|
36578
36578
|
expo: "expo",
|
|
36579
36579
|
"react-native": "react-native"
|
|
36580
36580
|
};
|
|
@@ -36598,17 +36598,11 @@ const NEXT_CONFIG_FILENAMES = [
|
|
|
36598
36598
|
];
|
|
36599
36599
|
const BABEL_CONFIG_FILENAMES = [
|
|
36600
36600
|
".babelrc",
|
|
36601
|
-
".babelrc.js",
|
|
36602
36601
|
".babelrc.json",
|
|
36603
|
-
".babelrc.cjs",
|
|
36604
|
-
".babelrc.mjs",
|
|
36605
|
-
".babelrc.cts",
|
|
36606
36602
|
"babel.config.js",
|
|
36607
36603
|
"babel.config.json",
|
|
36608
36604
|
"babel.config.cjs",
|
|
36609
|
-
"babel.config.mjs"
|
|
36610
|
-
"babel.config.ts",
|
|
36611
|
-
"babel.config.cts"
|
|
36605
|
+
"babel.config.mjs"
|
|
36612
36606
|
];
|
|
36613
36607
|
const VITE_CONFIG_FILENAMES = [
|
|
36614
36608
|
"vite.config.js",
|
|
@@ -36620,28 +36614,12 @@ const VITE_CONFIG_FILENAMES = [
|
|
|
36620
36614
|
"vitest.config.ts",
|
|
36621
36615
|
"vitest.config.js"
|
|
36622
36616
|
];
|
|
36623
|
-
const RSBUILD_CONFIG_FILENAMES = [
|
|
36624
|
-
"rsbuild.config.ts",
|
|
36625
|
-
"rsbuild.config.js",
|
|
36626
|
-
"rsbuild.config.mts",
|
|
36627
|
-
"rsbuild.config.mjs",
|
|
36628
|
-
"rsbuild.config.cts",
|
|
36629
|
-
"rsbuild.config.cjs"
|
|
36630
|
-
];
|
|
36631
|
-
const RSPACK_CONFIG_FILENAMES = [
|
|
36632
|
-
"rspack.config.ts",
|
|
36633
|
-
"rspack.config.js",
|
|
36634
|
-
"rspack.config.mts",
|
|
36635
|
-
"rspack.config.mjs",
|
|
36636
|
-
"rspack.config.cts",
|
|
36637
|
-
"rspack.config.cjs"
|
|
36638
|
-
];
|
|
36639
36617
|
const EXPO_APP_CONFIG_FILENAMES = [
|
|
36640
36618
|
"app.json",
|
|
36641
36619
|
"app.config.js",
|
|
36642
36620
|
"app.config.ts"
|
|
36643
36621
|
];
|
|
36644
|
-
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["']/;
|
|
36645
36623
|
const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
|
|
36646
36624
|
const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
|
|
36647
36625
|
const hasCompilerPackage = (packageJson, compilerPackages) => {
|
|
@@ -36676,8 +36654,6 @@ const detectReactCompiler = (directory, packageJson) => {
|
|
|
36676
36654
|
if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;
|
|
36677
36655
|
if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;
|
|
36678
36656
|
if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;
|
|
36679
|
-
if (hasCompilerInConfigFiles(directory, RSBUILD_CONFIG_FILENAMES)) return true;
|
|
36680
|
-
if (hasCompilerInConfigFiles(directory, RSPACK_CONFIG_FILENAMES)) return true;
|
|
36681
36657
|
if (hasCompilerInConfigFiles(directory, EXPO_APP_CONFIG_FILENAMES)) return true;
|
|
36682
36658
|
return hasCompilerPackageInAncestors(directory, REACT_COMPILER_TRANSFORM_PACKAGES);
|
|
36683
36659
|
};
|
|
@@ -36819,16 +36795,6 @@ const getLowestDependencyMajor = (version) => {
|
|
|
36819
36795
|
}
|
|
36820
36796
|
return lowestMajor;
|
|
36821
36797
|
};
|
|
36822
|
-
const getDependencyMajorWithinSupportedRange = (version, latestSupportedMajor) => {
|
|
36823
|
-
const normalizedVersion = normalizeDependencyVersion(version);
|
|
36824
|
-
if (normalizedVersion === null) return null;
|
|
36825
|
-
const validRange = import_semver.validRange(normalizedVersion);
|
|
36826
|
-
if (validRange === null) return null;
|
|
36827
|
-
const minimumVersion = import_semver.minVersion(validRange);
|
|
36828
|
-
if (minimumVersion === null || minimumVersion.major > latestSupportedMajor) return null;
|
|
36829
|
-
if (import_semver.intersects(validRange, `>=${latestSupportedMajor + 1}.0.0`)) return null;
|
|
36830
|
-
return minimumVersion.major;
|
|
36831
|
-
};
|
|
36832
36798
|
const isConcreteDependencyVersion = (version) => {
|
|
36833
36799
|
const normalizedVersion = normalizeDependencyVersion(version);
|
|
36834
36800
|
return normalizedVersion !== null && /\d/.test(normalizedVersion);
|
|
@@ -36872,9 +36838,9 @@ const parseReactMajorMinor = (reactVersion) => {
|
|
|
36872
36838
|
};
|
|
36873
36839
|
};
|
|
36874
36840
|
const parseLowerBoundVersion = (versionSpec) => import_semver.validRange(versionSpec) !== null ? import_semver.minVersion(versionSpec) : import_semver.coerce(versionSpec);
|
|
36875
|
-
const
|
|
36876
|
-
if (typeof
|
|
36877
|
-
const trimmed =
|
|
36841
|
+
const parseTailwindMajorMinor = (tailwindVersion) => {
|
|
36842
|
+
if (typeof tailwindVersion !== "string") return null;
|
|
36843
|
+
const trimmed = tailwindVersion.trim();
|
|
36878
36844
|
if (trimmed.length === 0) return null;
|
|
36879
36845
|
const lowerBound = parseLowerBoundVersion(trimmed);
|
|
36880
36846
|
if (lowerBound === null || lowerBound.major <= 0) return null;
|
|
@@ -36883,7 +36849,6 @@ const parseDependencyMajorMinor = (dependencyVersion) => {
|
|
|
36883
36849
|
minor: lowerBound.minor
|
|
36884
36850
|
};
|
|
36885
36851
|
};
|
|
36886
|
-
const parseTailwindMajorMinor = (tailwindVersion) => parseDependencyMajorMinor(tailwindVersion);
|
|
36887
36852
|
const hasUpperBoundOnlyPeerRange = (range) => {
|
|
36888
36853
|
if (typeof range !== "string") return false;
|
|
36889
36854
|
const normalizedRange = normalizeDependencyVersion(range);
|
|
@@ -37136,6 +37101,19 @@ const getPreactVersion = (packageJson) => {
|
|
|
37136
37101
|
...packageJson.devDependencies
|
|
37137
37102
|
}.preact ?? null;
|
|
37138
37103
|
};
|
|
37104
|
+
const TANSTACK_QUERY_PACKAGES = new Set([
|
|
37105
|
+
"@tanstack/react-query",
|
|
37106
|
+
"@tanstack/query-core",
|
|
37107
|
+
"react-query"
|
|
37108
|
+
]);
|
|
37109
|
+
const hasTanStackQuery = (packageJson) => {
|
|
37110
|
+
const allDependencies = {
|
|
37111
|
+
...packageJson.peerDependencies,
|
|
37112
|
+
...packageJson.dependencies,
|
|
37113
|
+
...packageJson.devDependencies
|
|
37114
|
+
};
|
|
37115
|
+
return Object.keys(allDependencies).some((packageName) => TANSTACK_QUERY_PACKAGES.has(packageName));
|
|
37116
|
+
};
|
|
37139
37117
|
const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, version }) => {
|
|
37140
37118
|
if (version === null || !isCatalogReference(version)) return version;
|
|
37141
37119
|
const catalogName = extractCatalogName(version);
|
|
@@ -37338,60 +37316,7 @@ const listWorkspacePackages = (rootDirectory) => {
|
|
|
37338
37316
|
}
|
|
37339
37317
|
return packages;
|
|
37340
37318
|
};
|
|
37341
|
-
const getPreferredDependencyVersion = ({ packageJson, packageNames }) => {
|
|
37342
|
-
const allDependencies = {
|
|
37343
|
-
...packageJson.devDependencies,
|
|
37344
|
-
...packageJson.peerDependencies,
|
|
37345
|
-
...packageJson.dependencies
|
|
37346
|
-
};
|
|
37347
|
-
for (const packageName of packageNames) {
|
|
37348
|
-
const version = allDependencies[packageName];
|
|
37349
|
-
if (version !== void 0) return version;
|
|
37350
|
-
}
|
|
37351
|
-
return null;
|
|
37352
|
-
};
|
|
37353
|
-
const TANSTACK_REACT_QUERY_PACKAGES = ["@tanstack/react-query", "react-query"];
|
|
37354
|
-
const getTanStackQueryVersion = (packageJson) => {
|
|
37355
|
-
return getPreferredDependencyVersion({
|
|
37356
|
-
packageJson,
|
|
37357
|
-
packageNames: TANSTACK_REACT_QUERY_PACKAGES
|
|
37358
|
-
});
|
|
37359
|
-
};
|
|
37360
|
-
const STYLED_COMPONENTS_PACKAGES = ["styled-components"];
|
|
37361
|
-
const getStyledComponentsVersion = (packageJson) => {
|
|
37362
|
-
return getPreferredDependencyVersion({
|
|
37363
|
-
packageJson,
|
|
37364
|
-
packageNames: STYLED_COMPONENTS_PACKAGES
|
|
37365
|
-
});
|
|
37366
|
-
};
|
|
37367
|
-
const I18N_PACKAGES = [
|
|
37368
|
-
"i18next",
|
|
37369
|
-
"react-i18next",
|
|
37370
|
-
"next-i18next",
|
|
37371
|
-
"react-intl",
|
|
37372
|
-
"next-intl",
|
|
37373
|
-
"use-intl",
|
|
37374
|
-
"@formatjs/intl",
|
|
37375
|
-
"@lingui/core",
|
|
37376
|
-
"@lingui/react",
|
|
37377
|
-
"typesafe-i18n",
|
|
37378
|
-
"@tolgee/react",
|
|
37379
|
-
"react-intl-universal"
|
|
37380
|
-
];
|
|
37381
|
-
const hasI18nDependency = (packageJson) => {
|
|
37382
|
-
const allDependencies = {
|
|
37383
|
-
...packageJson.peerDependencies,
|
|
37384
|
-
...packageJson.dependencies,
|
|
37385
|
-
...packageJson.devDependencies,
|
|
37386
|
-
...packageJson.optionalDependencies
|
|
37387
|
-
};
|
|
37388
|
-
return I18N_PACKAGES.some((packageName) => allDependencies[packageName] !== void 0);
|
|
37389
|
-
};
|
|
37390
37319
|
const REANIMATED_DEPENDENCY_NAME = "react-native-reanimated";
|
|
37391
|
-
const MOBX_REACT_PACKAGE_NAME = "mobx-react";
|
|
37392
|
-
const MOBX_REACT_LITE_PACKAGE_NAME = "mobx-react-lite";
|
|
37393
|
-
const MOBX_STATE_TREE_PACKAGE_NAME = "mobx-state-tree";
|
|
37394
|
-
const MOBX_REACT_OBSERVER_PACKAGE_NAME = "mobx-react-observer";
|
|
37395
37320
|
const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
|
|
37396
37321
|
const resolveWorkspaceDependencyVersion = ({ concreteVersion, packageName, rootDirectory, rootPackageJson, sections, workspaceDirectory, workspacePackageJson }) => {
|
|
37397
37322
|
const dependencyDeclaration = getDependencyDeclaration({
|
|
@@ -37410,62 +37335,7 @@ const shouldReplaceReactVersion = (currentVersion, nextVersion) => {
|
|
|
37410
37335
|
if (nextMajor === null) return false;
|
|
37411
37336
|
return nextMajor < currentMajor;
|
|
37412
37337
|
};
|
|
37413
|
-
const
|
|
37414
|
-
if (currentFact.version === null) return true;
|
|
37415
|
-
if (nextFact.version === null) return false;
|
|
37416
|
-
const currentMajor = getLowestDependencyMajor(currentFact.version);
|
|
37417
|
-
const nextMajor = getLowestDependencyMajor(nextFact.version);
|
|
37418
|
-
if (currentMajor === null) return false;
|
|
37419
|
-
if (nextMajor === null) return true;
|
|
37420
|
-
if (currentMajor > latestSupportedMajor) return false;
|
|
37421
|
-
if (nextMajor > latestSupportedMajor) return true;
|
|
37422
|
-
return nextMajor < currentMajor;
|
|
37423
|
-
};
|
|
37424
|
-
const shouldReplaceStyledComponentsVersion = (currentVersion, nextVersion) => {
|
|
37425
|
-
if (!currentVersion) return true;
|
|
37426
|
-
const currentMajor = getLowestDependencyMajor(currentVersion);
|
|
37427
|
-
const nextMajor = getLowestDependencyMajor(nextVersion);
|
|
37428
|
-
if (currentMajor === null) return nextMajor !== null && nextMajor < 6;
|
|
37429
|
-
if (nextMajor === null) return currentMajor >= 6;
|
|
37430
|
-
return nextMajor < currentMajor;
|
|
37431
|
-
};
|
|
37432
|
-
const selectOldestDependencyVersion = (currentVersion, nextVersion) => {
|
|
37433
|
-
if (currentVersion === null || nextVersion === null) return null;
|
|
37434
|
-
const current = parseDependencyMajorMinor(currentVersion);
|
|
37435
|
-
const next = parseDependencyMajorMinor(nextVersion);
|
|
37436
|
-
if (current === null) return currentVersion;
|
|
37437
|
-
if (next === null) return nextVersion;
|
|
37438
|
-
if (next.major !== current.major) return next.major < current.major ? nextVersion : currentVersion;
|
|
37439
|
-
return next.minor < current.minor ? nextVersion : currentVersion;
|
|
37440
|
-
};
|
|
37441
|
-
const shouldReplaceMobxFact = (currentFact, nextFact) => {
|
|
37442
|
-
if (currentFact.sourceDirectory === null) return true;
|
|
37443
|
-
if (currentFact.version === null) return false;
|
|
37444
|
-
if (nextFact.version === null) return true;
|
|
37445
|
-
const currentMajor = getDependencyMajorWithinSupportedRange(currentFact.version, 6);
|
|
37446
|
-
const nextMajor = getDependencyMajorWithinSupportedRange(nextFact.version, 6);
|
|
37447
|
-
if (currentMajor === null) return false;
|
|
37448
|
-
if (nextMajor === null) return true;
|
|
37449
|
-
return selectOldestDependencyVersion(currentFact.version, nextFact.version) === nextFact.version;
|
|
37450
|
-
};
|
|
37451
|
-
const collectBindingVersion = (facts, packageJson, directory, packageName) => {
|
|
37452
|
-
const version = getDependencySpec(packageJson, packageName);
|
|
37453
|
-
if (version === null) return;
|
|
37454
|
-
const resolvedVersion = resolveCatalogBackedDependencyVersion({
|
|
37455
|
-
rootDirectory: directory,
|
|
37456
|
-
rootPackageJson: packageJson,
|
|
37457
|
-
packageName,
|
|
37458
|
-
version
|
|
37459
|
-
});
|
|
37460
|
-
if (packageName === MOBX_REACT_PACKAGE_NAME) {
|
|
37461
|
-
facts.mobxReactVersion = facts.hasMobxReact ? selectOldestDependencyVersion(facts.mobxReactVersion, resolvedVersion) : resolvedVersion;
|
|
37462
|
-
facts.hasMobxReact = true;
|
|
37463
|
-
return;
|
|
37464
|
-
}
|
|
37465
|
-
facts.mobxReactLiteVersion = facts.hasMobxReactLite ? selectOldestDependencyVersion(facts.mobxReactLiteVersion, resolvedVersion) : resolvedVersion;
|
|
37466
|
-
facts.hasMobxReactLite = true;
|
|
37467
|
-
};
|
|
37468
|
-
const evaluateManifestFacts = (facts, packageJson, directory, rootDirectory, rootPackageJson) => {
|
|
37338
|
+
const evaluateManifestFacts = (facts, packageJson, directory) => {
|
|
37469
37339
|
if (facts.expo.version === null) {
|
|
37470
37340
|
const spec = getDependencySpec(packageJson, "expo");
|
|
37471
37341
|
if (spec !== null) facts.expo = {
|
|
@@ -37487,74 +37357,13 @@ const evaluateManifestFacts = (facts, packageJson, directory, rootDirectory, roo
|
|
|
37487
37357
|
sourceDirectory: directory
|
|
37488
37358
|
};
|
|
37489
37359
|
}
|
|
37490
|
-
const mobxSpec = getDependencySpec(packageJson, "mobx");
|
|
37491
|
-
if (mobxSpec !== null) {
|
|
37492
|
-
const nextMobxFact = {
|
|
37493
|
-
version: resolveCatalogBackedDependencyVersion({
|
|
37494
|
-
rootDirectory: directory,
|
|
37495
|
-
rootPackageJson: packageJson,
|
|
37496
|
-
packageName: "mobx",
|
|
37497
|
-
version: mobxSpec
|
|
37498
|
-
}),
|
|
37499
|
-
sourceDirectory: directory
|
|
37500
|
-
};
|
|
37501
|
-
if (shouldReplaceMobxFact(facts.mobx, nextMobxFact)) facts.mobx = nextMobxFact;
|
|
37502
|
-
}
|
|
37503
|
-
collectBindingVersion(facts, packageJson, directory, MOBX_REACT_PACKAGE_NAME);
|
|
37504
|
-
collectBindingVersion(facts, packageJson, directory, MOBX_REACT_LITE_PACKAGE_NAME);
|
|
37505
|
-
facts.hasMobxStateTree = facts.hasMobxStateTree || getDependencySpec(packageJson, MOBX_STATE_TREE_PACKAGE_NAME) !== null;
|
|
37506
|
-
facts.hasMobxReactObserver = facts.hasMobxReactObserver || getDependencySpec(packageJson, MOBX_REACT_OBSERVER_PACKAGE_NAME) !== null;
|
|
37507
|
-
const zustandSpec = getDependencySpec(packageJson, "zustand");
|
|
37508
|
-
if (zustandSpec !== null) {
|
|
37509
|
-
const nextZustandFact = {
|
|
37510
|
-
version: resolveCatalogBackedDependencyVersion({
|
|
37511
|
-
rootDirectory: directory,
|
|
37512
|
-
rootPackageJson: packageJson,
|
|
37513
|
-
packageName: "zustand",
|
|
37514
|
-
version: zustandSpec
|
|
37515
|
-
}),
|
|
37516
|
-
sourceDirectory: directory
|
|
37517
|
-
};
|
|
37518
|
-
if (shouldReplaceSupportedDependencyFact(facts.zustand, nextZustandFact, 5)) facts.zustand = nextZustandFact;
|
|
37519
|
-
}
|
|
37520
37360
|
if (facts.reanimatedVersion === null) {
|
|
37521
37361
|
const spec = getDependencySpec(packageJson, REANIMATED_DEPENDENCY_NAME);
|
|
37522
37362
|
if (spec !== null) facts.reanimatedVersion = spec;
|
|
37523
37363
|
}
|
|
37524
|
-
if (facts.valtioVersion === null) {
|
|
37525
|
-
const spec = getDependencySpec(packageJson, "valtio");
|
|
37526
|
-
if (spec !== null) facts.valtioVersion = spec;
|
|
37527
|
-
}
|
|
37528
|
-
facts.tanstackQueryVersion ??= getTanStackQueryVersion(packageJson);
|
|
37529
|
-
const styledComponentsVersion = resolveCatalogBackedDependencyVersion({
|
|
37530
|
-
rootDirectory: directory,
|
|
37531
|
-
rootPackageJson: packageJson,
|
|
37532
|
-
packageName: "styled-components",
|
|
37533
|
-
version: getStyledComponentsVersion(packageJson)
|
|
37534
|
-
});
|
|
37535
|
-
if (styledComponentsVersion && shouldReplaceStyledComponentsVersion(facts.styledComponentsVersion, styledComponentsVersion)) facts.styledComponentsVersion = styledComponentsVersion;
|
|
37536
|
-
facts.hasI18nLibrary = facts.hasI18nLibrary || hasI18nDependency(packageJson);
|
|
37537
37364
|
facts.hasReactNativeAwarePackage = facts.hasReactNativeAwarePackage || isPackageJsonReactNativeAware(packageJson);
|
|
37538
37365
|
facts.hasReanimatedAwarePackage = facts.hasReanimatedAwarePackage || isPackageJsonReanimatedAware(packageJson);
|
|
37539
37366
|
facts.hasSsrDependency = facts.hasSsrDependency || isPackageJsonSsrAware(packageJson);
|
|
37540
|
-
const remotionSpec = getDependencySpec(packageJson, "remotion");
|
|
37541
|
-
if (remotionSpec !== null) {
|
|
37542
|
-
facts.hasRemotionDependency = true;
|
|
37543
|
-
const resolvedRemotionVersion = resolveCatalogBackedDependencyVersion({
|
|
37544
|
-
rootDirectory,
|
|
37545
|
-
rootPackageJson,
|
|
37546
|
-
packageName: "remotion",
|
|
37547
|
-
version: remotionSpec
|
|
37548
|
-
});
|
|
37549
|
-
const remotionMajorVersion = resolvedRemotionVersion === null ? null : getLowestDependencyMajor(resolvedRemotionVersion);
|
|
37550
|
-
if (remotionMajorVersion === null) {
|
|
37551
|
-
facts.hasUnknownRemotionVersion = true;
|
|
37552
|
-
facts.remotionVersion = null;
|
|
37553
|
-
} else if (!facts.hasUnknownRemotionVersion) {
|
|
37554
|
-
const currentRemotionMajorVersion = facts.remotionVersion === null ? null : getLowestDependencyMajor(facts.remotionVersion);
|
|
37555
|
-
if (currentRemotionMajorVersion === null || remotionMajorVersion < currentRemotionMajorVersion) facts.remotionVersion = resolvedRemotionVersion;
|
|
37556
|
-
}
|
|
37557
|
-
}
|
|
37558
37367
|
};
|
|
37559
37368
|
const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGroup }) => {
|
|
37560
37369
|
const facts = {
|
|
@@ -37574,33 +37383,12 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
|
|
|
37574
37383
|
version: null,
|
|
37575
37384
|
sourceDirectory: null
|
|
37576
37385
|
},
|
|
37577
|
-
valtioVersion: null,
|
|
37578
|
-
mobx: {
|
|
37579
|
-
version: null,
|
|
37580
|
-
sourceDirectory: null
|
|
37581
|
-
},
|
|
37582
|
-
hasMobxReact: false,
|
|
37583
|
-
mobxReactVersion: null,
|
|
37584
|
-
hasMobxReactLite: false,
|
|
37585
|
-
mobxReactLiteVersion: null,
|
|
37586
|
-
hasMobxStateTree: false,
|
|
37587
|
-
hasMobxReactObserver: false,
|
|
37588
|
-
zustand: {
|
|
37589
|
-
version: null,
|
|
37590
|
-
sourceDirectory: null
|
|
37591
|
-
},
|
|
37592
|
-
tanstackQueryVersion: null,
|
|
37593
|
-
styledComponentsVersion: null,
|
|
37594
|
-
hasI18nLibrary: false,
|
|
37595
37386
|
hasReactNativeAwarePackage: false,
|
|
37596
37387
|
hasReanimatedAwarePackage: false,
|
|
37597
37388
|
hasSsrDependency: false,
|
|
37598
|
-
hasRemotionDependency: false,
|
|
37599
|
-
hasUnknownRemotionVersion: false,
|
|
37600
|
-
remotionVersion: null,
|
|
37601
37389
|
reanimatedVersion: null
|
|
37602
37390
|
};
|
|
37603
|
-
evaluateManifestFacts(facts, rootPackageJson, rootDirectory
|
|
37391
|
+
evaluateManifestFacts(facts, rootPackageJson, rootDirectory);
|
|
37604
37392
|
let isReactGroupSettled = !collectReactGroup;
|
|
37605
37393
|
const visitedDirectories = /* @__PURE__ */ new Set();
|
|
37606
37394
|
for (const pattern of getWorkspacePatterns(rootDirectory, rootPackageJson)) {
|
|
@@ -37609,7 +37397,7 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
|
|
|
37609
37397
|
if (visitedDirectories.has(workspaceDirectory)) continue;
|
|
37610
37398
|
visitedDirectories.add(workspaceDirectory);
|
|
37611
37399
|
const workspacePackageJson = readPackageJson$1(Path.join(workspaceDirectory, "package.json"));
|
|
37612
|
-
evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory
|
|
37400
|
+
evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory);
|
|
37613
37401
|
const info = extractDependencyInfo(workspacePackageJson);
|
|
37614
37402
|
if (info.framework !== "unknown" && frameworkMergeRank(info.framework) < frameworkMergeRank(facts.framework)) facts.framework = info.framework;
|
|
37615
37403
|
if (isReactGroupSettled) continue;
|
|
@@ -37830,29 +37618,11 @@ const discoverProjectWithoutPackageJson = (directory) => {
|
|
|
37830
37618
|
tailwindVersion: null,
|
|
37831
37619
|
zodVersion: null,
|
|
37832
37620
|
zodMajorVersion: null,
|
|
37833
|
-
mobxVersion: null,
|
|
37834
|
-
mobxMajorVersion: null,
|
|
37835
|
-
hasMobxReact: false,
|
|
37836
|
-
mobxReactVersion: null,
|
|
37837
|
-
hasMobxReactLite: false,
|
|
37838
|
-
mobxReactLiteVersion: null,
|
|
37839
|
-
hasMobxStateTree: false,
|
|
37840
|
-
hasMobxReactObserver: false,
|
|
37841
|
-
zustandVersion: null,
|
|
37842
|
-
zustandMajorVersion: null,
|
|
37843
37621
|
framework: "unknown",
|
|
37844
37622
|
hasTypeScript: hasOwnTsConfig,
|
|
37845
37623
|
hasReactCompiler: false,
|
|
37846
37624
|
hasReactCompilerLintPlugin: false,
|
|
37847
37625
|
hasTanStackQuery: false,
|
|
37848
|
-
valtioVersion: null,
|
|
37849
|
-
valtioMajorVersion: null,
|
|
37850
|
-
hasRemotion: false,
|
|
37851
|
-
remotionVersion: null,
|
|
37852
|
-
remotionMajorVersion: null,
|
|
37853
|
-
hasI18nLibrary: false,
|
|
37854
|
-
tanstackQueryVersion: null,
|
|
37855
|
-
styledComponentsVersion: null,
|
|
37856
37626
|
hasSsrDependency: false,
|
|
37857
37627
|
preactVersion: null,
|
|
37858
37628
|
preactMajorVersion: null,
|
|
@@ -37951,12 +37721,6 @@ const discoverProject = (directory) => {
|
|
|
37951
37721
|
packageName: SHOPIFY_FLASH_LIST_PACKAGE_NAME,
|
|
37952
37722
|
version: workspaceFacts.shopifyFlashList.version
|
|
37953
37723
|
}) : null;
|
|
37954
|
-
const zustandVersion = resolveCatalogBackedDependencyVersion({
|
|
37955
|
-
rootDirectory: directory,
|
|
37956
|
-
rootPackageJson: packageJson,
|
|
37957
|
-
packageName: "zustand",
|
|
37958
|
-
version: workspaceFacts.zustand.version
|
|
37959
|
-
});
|
|
37960
37724
|
const hasReanimated = hasReactNativeWorkspace && workspaceFacts.hasReanimatedAwarePackage;
|
|
37961
37725
|
const reanimatedVersion = hasReanimated ? workspaceFacts.reanimatedVersion : null;
|
|
37962
37726
|
const nextjsVersion = framework === "nextjs" ? resolveCatalogBackedDependencyVersion({
|
|
@@ -37965,21 +37729,7 @@ const discoverProject = (directory) => {
|
|
|
37965
37729
|
packageName: "next",
|
|
37966
37730
|
version: workspaceFacts.next.version
|
|
37967
37731
|
}) : null;
|
|
37968
|
-
const valtioVersion = resolveCatalogBackedDependencyVersion({
|
|
37969
|
-
rootDirectory: directory,
|
|
37970
|
-
rootPackageJson: packageJson,
|
|
37971
|
-
packageName: "valtio",
|
|
37972
|
-
version: workspaceFacts.valtioVersion
|
|
37973
|
-
});
|
|
37974
|
-
const mobxVersion = resolveCatalogBackedDependencyVersion({
|
|
37975
|
-
rootDirectory: directory,
|
|
37976
|
-
rootPackageJson: packageJson,
|
|
37977
|
-
packageName: "mobx",
|
|
37978
|
-
version: workspaceFacts.mobx.version
|
|
37979
|
-
});
|
|
37980
37732
|
const preactVersion = getPreactVersion(packageJson);
|
|
37981
|
-
const remotionVersion = workspaceFacts.remotionVersion;
|
|
37982
|
-
const tanstackQueryVersion = getTanStackQueryVersion(packageJson) ?? workspaceFacts.tanstackQueryVersion;
|
|
37983
37733
|
const isPreES2023Target = hasTypeScript && detectPreES2023Target(directory);
|
|
37984
37734
|
const projectInfo = {
|
|
37985
37735
|
rootDirectory: directory,
|
|
@@ -37989,29 +37739,11 @@ const discoverProject = (directory) => {
|
|
|
37989
37739
|
tailwindVersion,
|
|
37990
37740
|
zodVersion,
|
|
37991
37741
|
zodMajorVersion: zodVersion === null ? null : getLowestDependencyMajor(zodVersion),
|
|
37992
|
-
mobxVersion,
|
|
37993
|
-
mobxMajorVersion: mobxVersion === null ? null : getDependencyMajorWithinSupportedRange(mobxVersion, 6),
|
|
37994
|
-
hasMobxReact: workspaceFacts.hasMobxReact,
|
|
37995
|
-
mobxReactVersion: workspaceFacts.mobxReactVersion,
|
|
37996
|
-
hasMobxReactLite: workspaceFacts.hasMobxReactLite,
|
|
37997
|
-
mobxReactLiteVersion: workspaceFacts.mobxReactLiteVersion,
|
|
37998
|
-
hasMobxStateTree: workspaceFacts.hasMobxStateTree,
|
|
37999
|
-
hasMobxReactObserver: workspaceFacts.hasMobxReactObserver,
|
|
38000
|
-
zustandVersion,
|
|
38001
|
-
zustandMajorVersion: zustandVersion === null ? null : getLowestDependencyMajor(zustandVersion),
|
|
38002
37742
|
framework,
|
|
38003
37743
|
hasTypeScript,
|
|
38004
37744
|
hasReactCompiler: detectReactCompiler(directory, packageJson),
|
|
38005
37745
|
hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
|
|
38006
|
-
hasTanStackQuery:
|
|
38007
|
-
hasI18nLibrary: workspaceFacts.hasI18nLibrary,
|
|
38008
|
-
tanstackQueryVersion,
|
|
38009
|
-
styledComponentsVersion: workspaceFacts.styledComponentsVersion,
|
|
38010
|
-
valtioVersion,
|
|
38011
|
-
valtioMajorVersion: valtioVersion === null ? null : getLowestDependencyMajor(valtioVersion),
|
|
38012
|
-
hasRemotion: workspaceFacts.hasRemotionDependency,
|
|
38013
|
-
remotionVersion,
|
|
38014
|
-
remotionMajorVersion: remotionVersion === null ? null : getLowestDependencyMajor(remotionVersion),
|
|
37746
|
+
hasTanStackQuery: hasTanStackQuery(packageJson),
|
|
38015
37747
|
hasSsrDependency: workspaceFacts.hasSsrDependency,
|
|
38016
37748
|
preactVersion,
|
|
38017
37749
|
preactMajorVersion: parseReactMajor(preactVersion),
|
|
@@ -38245,6 +37977,7 @@ const LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY = {
|
|
|
38245
37977
|
"react/jsx-no-new-function-as-prop": "react-doctor/jsx-no-new-function-as-prop",
|
|
38246
37978
|
"react/jsx-no-new-object-as-prop": "react-doctor/jsx-no-new-object-as-prop",
|
|
38247
37979
|
"react/jsx-no-script-url": "react-doctor/jsx-no-script-url",
|
|
37980
|
+
"react/jsx-no-target-blank": "react-doctor/jsx-no-target-blank",
|
|
38248
37981
|
"react/jsx-no-undef": "react-doctor/jsx-no-undef",
|
|
38249
37982
|
"react/jsx-no-useless-fragment": "react-doctor/jsx-no-useless-fragment",
|
|
38250
37983
|
"react/jsx-pascal-case": "react-doctor/jsx-pascal-case",
|
|
@@ -40566,25 +40299,9 @@ const BABEL_CONFIG_FILE_NAMES = [
|
|
|
40566
40299
|
".babelrc.json"
|
|
40567
40300
|
];
|
|
40568
40301
|
const LEGACY_PRESET_SPEC = "module:metro-react-native-babel-preset";
|
|
40569
|
-
const LEGACY_PRESET_PACKAGE = "metro-react-native-babel-preset";
|
|
40570
|
-
const REACT_NATIVE_PACKAGE = "react-native";
|
|
40571
|
-
const PRESET_RENAME_MINIMUM_REACT_NATIVE_VERSION = "0.73.0";
|
|
40572
|
-
const LEGACY_PRESET_REFERENCE = new RegExp(`['"]${LEGACY_PRESET_SPEC}['"]`);
|
|
40573
40302
|
const MODERN_PRESET_REFERENCE = new RegExp(`['"]module:@react-native/babel-preset['"]`);
|
|
40574
40303
|
const ENABLE_BABEL_RUNTIME_VERSION = /enableBabelRuntime["']?\s*:\s*['"]/;
|
|
40575
|
-
const isReactNativeVersionAtLeastPresetRename = (rootDirectory, packageJson) => {
|
|
40576
|
-
const installedReactNativeManifestPath = Path.join(rootDirectory, "node_modules", REACT_NATIVE_PACKAGE, "package.json");
|
|
40577
|
-
const reactNativeVersionSpec = (isFile(installedReactNativeManifestPath) ? readPackageJson$1(installedReactNativeManifestPath).version : void 0) ?? getDependencySpec(packageJson, REACT_NATIVE_PACKAGE);
|
|
40578
|
-
if (reactNativeVersionSpec === null || reactNativeVersionSpec === void 0) return false;
|
|
40579
|
-
const normalizedVersionRange = import_semver.validRange(reactNativeVersionSpec);
|
|
40580
|
-
if (normalizedVersionRange === null) return false;
|
|
40581
|
-
const minimumVersion = import_semver.minVersion(normalizedVersionRange);
|
|
40582
|
-
return minimumVersion !== null && import_semver.gte(minimumVersion, PRESET_RENAME_MINIMUM_REACT_NATIVE_VERSION);
|
|
40583
|
-
};
|
|
40584
|
-
const canResolveLegacyPreset = (rootDirectory, packageJson) => getDependencySpec(packageJson, LEGACY_PRESET_PACKAGE) !== null || isFile(Path.join(rootDirectory, "node_modules", LEGACY_PRESET_PACKAGE, "package.json"));
|
|
40585
40304
|
const checkReactNativeMetroBabelPreset = (rootDirectory) => {
|
|
40586
|
-
const packageJson = readPackageJson$1(Path.join(rootDirectory, "package.json"));
|
|
40587
|
-
const shouldReportLegacyPreset = isReactNativeVersionAtLeastPresetRename(rootDirectory, packageJson) && !canResolveLegacyPreset(rootDirectory, packageJson);
|
|
40588
40305
|
for (const fileName of BABEL_CONFIG_FILE_NAMES) {
|
|
40589
40306
|
const filePath = Path.join(rootDirectory, fileName);
|
|
40590
40307
|
if (!isFile(filePath)) continue;
|
|
@@ -40594,7 +40311,7 @@ const checkReactNativeMetroBabelPreset = (rootDirectory) => {
|
|
|
40594
40311
|
} catch {
|
|
40595
40312
|
continue;
|
|
40596
40313
|
}
|
|
40597
|
-
if (
|
|
40314
|
+
if (contents.includes(LEGACY_PRESET_SPEC)) return [buildReactNativeDiagnostic({
|
|
40598
40315
|
filePath: fileName,
|
|
40599
40316
|
rule: "rn-no-metro-babel-preset",
|
|
40600
40317
|
severity: "error",
|
|
@@ -40617,6 +40334,12 @@ const checkReactNativeProject = (rootDirectory, project) => {
|
|
|
40617
40334
|
return [...checkReactNativeMetroBabelPreset(rootDirectory), ...checkReactNativeLibraryDependencies(rootDirectory)];
|
|
40618
40335
|
};
|
|
40619
40336
|
const RULE_KEY = "no-vulnerable-react-server-components";
|
|
40337
|
+
const DEPENDENCY_SECTIONS = [
|
|
40338
|
+
"dependencies",
|
|
40339
|
+
"devDependencies",
|
|
40340
|
+
"peerDependencies",
|
|
40341
|
+
"optionalDependencies"
|
|
40342
|
+
];
|
|
40620
40343
|
const REACT_RSC_ADVISORIES_BY_MINOR = {
|
|
40621
40344
|
"19.0": {
|
|
40622
40345
|
rceFixedVersion: "19.0.1",
|
|
@@ -40663,13 +40386,20 @@ const enumerateWorkspaceDirectories = (workspaceRoot) => {
|
|
|
40663
40386
|
for (const pattern of patterns) for (const directory of resolveWorkspaceDirectories(workspaceRoot, pattern)) directories.add(directory);
|
|
40664
40387
|
return [...directories];
|
|
40665
40388
|
};
|
|
40389
|
+
const readDeclaredSpec = (packageJson, packageName) => {
|
|
40390
|
+
for (const section of DEPENDENCY_SECTIONS) {
|
|
40391
|
+
const spec = packageJson[section]?.[packageName];
|
|
40392
|
+
if (typeof spec === "string") return spec;
|
|
40393
|
+
}
|
|
40394
|
+
return null;
|
|
40395
|
+
};
|
|
40666
40396
|
const resolveVersionInDirectory = (directory, packageName, declaredSpecOverride) => {
|
|
40667
40397
|
const manifestPath = Path.join(directory, "node_modules", packageName, "package.json");
|
|
40668
40398
|
if (isFile(manifestPath)) {
|
|
40669
40399
|
const installedVersion = import_semver.valid(readPackageJson$1(manifestPath).version ?? null);
|
|
40670
40400
|
if (installedVersion !== null) return installedVersion;
|
|
40671
40401
|
}
|
|
40672
|
-
const candidateSpecs = [
|
|
40402
|
+
const candidateSpecs = [readDeclaredSpec(readPackageJson$1(Path.join(directory, "package.json")), packageName), declaredSpecOverride];
|
|
40673
40403
|
for (const spec of candidateSpecs) {
|
|
40674
40404
|
const pinnedVersion = spec === null ? null : import_semver.valid(spec);
|
|
40675
40405
|
if (pinnedVersion !== null) return pinnedVersion;
|
|
@@ -41337,68 +41067,21 @@ const buildCapabilities = (project) => {
|
|
|
41337
41067
|
if (CLIENT_ONLY_FRAMEWORKS.has(project.framework)) capabilities.add("client-only");
|
|
41338
41068
|
if (project.isStaticExport) capabilities.add("nextjs:static-export");
|
|
41339
41069
|
if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 15) capabilities.add("nextjs:15");
|
|
41340
|
-
if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 16) capabilities.add("nextjs:16");
|
|
41341
41070
|
addMajorLadder(capabilities, "react", project.reactMajorVersion, 17, 30);
|
|
41342
41071
|
if (project.reactMajorVersion !== null && project.reactMajorVersion >= 19 && isMajorMinorAtLeast(parseReactMajorMinor(project.reactVersion), {
|
|
41343
41072
|
major: 19,
|
|
41344
41073
|
minor: 2
|
|
41345
41074
|
})) capabilities.add("react:19.2");
|
|
41346
|
-
if (project.tailwindVersion !== null)
|
|
41347
|
-
|
|
41348
|
-
|
|
41349
|
-
|
|
41350
|
-
|
|
41351
|
-
minor: 4
|
|
41352
|
-
})) capabilities.add("tailwind:3.4");
|
|
41353
|
-
if (tailwindVersion !== null && isMajorMinorAtLeast(tailwindVersion, {
|
|
41354
|
-
major: 4,
|
|
41355
|
-
minor: 0
|
|
41356
|
-
})) capabilities.add("tailwind:4");
|
|
41357
|
-
}
|
|
41075
|
+
if (project.tailwindVersion !== null) capabilities.add("tailwind");
|
|
41076
|
+
if (project.tailwindVersion !== null && isMajorMinorAtLeast(parseTailwindMajorMinor(project.tailwindVersion), {
|
|
41077
|
+
major: 3,
|
|
41078
|
+
minor: 4
|
|
41079
|
+
})) capabilities.add("tailwind:3.4");
|
|
41358
41080
|
if (project.zodVersion !== null) capabilities.add("zod");
|
|
41359
41081
|
if (project.zodMajorVersion !== null && project.zodMajorVersion >= 4) capabilities.add("zod:4");
|
|
41360
|
-
if (project.mobxVersion !== void 0 && project.mobxVersion !== null || project.hasMobxReact === true || project.hasMobxReactLite === true || project.hasMobxStateTree === true || project.hasMobxReactObserver === true) capabilities.add("mobx");
|
|
41361
|
-
if (project.hasMobxReact === true) capabilities.add("mobx-react");
|
|
41362
|
-
if (project.hasMobxReactLite === true) capabilities.add("mobx-react-lite");
|
|
41363
|
-
if (project.hasMobxReact === true || project.hasMobxReactLite === true) capabilities.add("mobx-react-binding");
|
|
41364
|
-
const mobxReactVersion = parseDependencyMajorMinor(project.mobxReactVersion);
|
|
41365
|
-
const mobxReactLiteVersion = parseDependencyMajorMinor(project.mobxReactLiteVersion);
|
|
41366
|
-
const hasMobxReactObserverMemoGuard = mobxReactVersion !== null && isMajorMinorAtLeast(mobxReactVersion, {
|
|
41367
|
-
major: 7,
|
|
41368
|
-
minor: 3
|
|
41369
|
-
});
|
|
41370
|
-
const hasMobxReactLiteObserverMemoGuard = mobxReactLiteVersion !== null && isMajorMinorAtLeast(mobxReactLiteVersion, {
|
|
41371
|
-
major: 3,
|
|
41372
|
-
minor: 3
|
|
41373
|
-
});
|
|
41374
|
-
if (hasMobxReactObserverMemoGuard) capabilities.add("mobx-react-observer-memo-guard");
|
|
41375
|
-
if (hasMobxReactLiteObserverMemoGuard) capabilities.add("mobx-react-lite-observer-memo-guard");
|
|
41376
|
-
if (hasMobxReactObserverMemoGuard || hasMobxReactLiteObserverMemoGuard) capabilities.add("mobx-react-binding-observer-memo-guard");
|
|
41377
|
-
if (project.hasMobxStateTree === true) capabilities.add("mobx-state-tree");
|
|
41378
|
-
if (project.hasMobxReactObserver === true) capabilities.add("mobx-react-observer");
|
|
41379
|
-
if (project.mobxMajorVersion !== void 0 && project.mobxMajorVersion !== null && project.mobxMajorVersion >= 4 && project.mobxMajorVersion <= 6) addMajorLadder(capabilities, "mobx", project.mobxMajorVersion, 4, 6);
|
|
41380
|
-
const mobxVersion = parseDependencyMajorMinor(project.mobxVersion);
|
|
41381
|
-
if (project.mobxMajorVersion === 6 && mobxVersion !== null && isMajorMinorAtLeast(mobxVersion, {
|
|
41382
|
-
major: 6,
|
|
41383
|
-
minor: 10
|
|
41384
|
-
})) capabilities.add("mobx:6.10");
|
|
41385
|
-
if (project.zustandVersion !== void 0 && project.zustandVersion !== null) capabilities.add("zustand");
|
|
41386
|
-
if (project.zustandMajorVersion !== void 0 && project.zustandMajorVersion !== null && project.zustandMajorVersion >= 1 && project.zustandMajorVersion <= 5) addMajorLadder(capabilities, "zustand", project.zustandMajorVersion, 1, 5);
|
|
41387
41082
|
if (project.isPreES2023Target) capabilities.add("pre-es2023");
|
|
41388
41083
|
if (project.hasReactCompiler) capabilities.add("react-compiler");
|
|
41389
|
-
if (
|
|
41390
|
-
if (project.styledComponentsVersion) {
|
|
41391
|
-
capabilities.add("styled-components");
|
|
41392
|
-
const styledComponentsMajor = getLowestDependencyMajor(project.styledComponentsVersion);
|
|
41393
|
-
if (styledComponentsMajor !== null && styledComponentsMajor >= 6) capabilities.add("styled-components:6");
|
|
41394
|
-
}
|
|
41395
|
-
if (project.hasI18nLibrary) capabilities.add("i18n");
|
|
41396
|
-
if (project.valtioVersion !== null) capabilities.add("valtio");
|
|
41397
|
-
addMajorLadder(capabilities, "valtio", project.valtioMajorVersion, 1, 10);
|
|
41398
|
-
if (project.hasRemotion) {
|
|
41399
|
-
capabilities.add("remotion");
|
|
41400
|
-
addMajorLadder(capabilities, "remotion", project.remotionMajorVersion ?? null, 4, 30);
|
|
41401
|
-
}
|
|
41084
|
+
if (project.hasTanStackQuery) capabilities.add("tanstack-query");
|
|
41402
41085
|
if (project.hasTypeScript) capabilities.add("typescript");
|
|
41403
41086
|
if (project.preactVersion !== null) capabilities.add("preact");
|
|
41404
41087
|
addMajorLadder(capabilities, "preact", project.preactMajorVersion, 10, 20);
|
|
@@ -41413,7 +41096,7 @@ const getCapabilities = (project) => {
|
|
|
41413
41096
|
capabilitiesByProject.set(project, capabilities);
|
|
41414
41097
|
return capabilities;
|
|
41415
41098
|
};
|
|
41416
|
-
const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen
|
|
41099
|
+
const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen) => {
|
|
41417
41100
|
if (requires) {
|
|
41418
41101
|
for (const capability of requires) if (!capabilities.has(capability)) return false;
|
|
41419
41102
|
}
|
|
@@ -41424,29 +41107,20 @@ const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhe
|
|
|
41424
41107
|
if (tags) {
|
|
41425
41108
|
for (const tag of tags) if (ignoredTags.has(tag)) return false;
|
|
41426
41109
|
}
|
|
41427
|
-
if (includedTags && includedTags.size > 0) {
|
|
41428
|
-
if (!tags?.some((tag) => includedTags.has(tag))) return false;
|
|
41429
|
-
}
|
|
41430
41110
|
return true;
|
|
41431
41111
|
};
|
|
41432
|
-
const shouldEnableRuleByDefaultStatus = (options) => options.defaultEnabled !== false || options.hasExplicitOverride === true || options.includeTagDefaults && options.hasIncludedTags;
|
|
41433
41112
|
const yieldToEventLoop = () => new Promise((resolve) => {
|
|
41434
41113
|
setImmediate(resolve);
|
|
41435
41114
|
});
|
|
41436
41115
|
const createSecurityScanSession = (rootDirectory, options) => {
|
|
41437
41116
|
const capabilities = options.project ? getCapabilities(options.project) : /* @__PURE__ */ new Set();
|
|
41438
41117
|
const ignoredTags = options.ignoredTags ?? /* @__PURE__ */ new Set();
|
|
41439
|
-
const includedTags = options.includedTags ?? /* @__PURE__ */ new Set();
|
|
41440
41118
|
const enabledScanRules = REACT_DOCTOR_RULES.flatMap((entry) => {
|
|
41441
41119
|
const rule = entry.rule;
|
|
41442
41120
|
const scan = rule.scan;
|
|
41443
41121
|
if (typeof scan !== "function") return [];
|
|
41444
|
-
if (
|
|
41445
|
-
|
|
41446
|
-
includeTagDefaults: options.includeTagDefaults === true,
|
|
41447
|
-
hasIncludedTags: includedTags.size > 0
|
|
41448
|
-
})) return [];
|
|
41449
|
-
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen, includedTags)) return [];
|
|
41122
|
+
if (rule.defaultEnabled === false) return [];
|
|
41123
|
+
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) return [];
|
|
41450
41124
|
return [{
|
|
41451
41125
|
entry,
|
|
41452
41126
|
scan,
|
|
@@ -42660,35 +42334,6 @@ const parseGithubViewerPermission = (stdout) => {
|
|
|
42660
42334
|
return /^[A-Z_]+$/.test(value) ? value.toLowerCase() : null;
|
|
42661
42335
|
};
|
|
42662
42336
|
const splitNullSeparated = (value) => value.split("\0").filter((entry) => entry.length > 0);
|
|
42663
|
-
const parseBaselineDiffPlan = (value) => {
|
|
42664
|
-
const entries = splitNullSeparated(value);
|
|
42665
|
-
const baseFiles = /* @__PURE__ */ new Set();
|
|
42666
|
-
const headFiles = /* @__PURE__ */ new Set();
|
|
42667
|
-
for (let entryIndex = 0; entryIndex < entries.length; entryIndex += 2) {
|
|
42668
|
-
const status = entries[entryIndex];
|
|
42669
|
-
const filePath = entries[entryIndex + 1];
|
|
42670
|
-
if (status === void 0 || filePath === void 0 || status.length !== 1) return null;
|
|
42671
|
-
if (status === "A") {
|
|
42672
|
-
headFiles.add(filePath);
|
|
42673
|
-
continue;
|
|
42674
|
-
}
|
|
42675
|
-
if (status === "D") {
|
|
42676
|
-
baseFiles.add(filePath);
|
|
42677
|
-
continue;
|
|
42678
|
-
}
|
|
42679
|
-
if (status === "M" || status === "T") {
|
|
42680
|
-
baseFiles.add(filePath);
|
|
42681
|
-
headFiles.add(filePath);
|
|
42682
|
-
continue;
|
|
42683
|
-
}
|
|
42684
|
-
return null;
|
|
42685
|
-
}
|
|
42686
|
-
return {
|
|
42687
|
-
baseFiles: [...baseFiles],
|
|
42688
|
-
headFiles: [...headFiles],
|
|
42689
|
-
untrackedFiles: []
|
|
42690
|
-
};
|
|
42691
|
-
};
|
|
42692
42337
|
const UNTRACKED_FILE_LAST_LINE = Number.MAX_SAFE_INTEGER;
|
|
42693
42338
|
/**
|
|
42694
42339
|
* `Git` wraps every `git`-via-subprocess call react-doctor makes
|
|
@@ -42891,45 +42536,6 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
42891
42536
|
githubViewerPermission,
|
|
42892
42537
|
branchExists,
|
|
42893
42538
|
mergeBase,
|
|
42894
|
-
baselineDiffPlan: (input) => {
|
|
42895
|
-
if (!isSafeGitRevision(input.ref)) return succeed$2(null);
|
|
42896
|
-
return gen(function* () {
|
|
42897
|
-
const unmerged = yield* runGit(input.directory, [
|
|
42898
|
-
"diff",
|
|
42899
|
-
"--no-ext-diff",
|
|
42900
|
-
"-z",
|
|
42901
|
-
"--name-only",
|
|
42902
|
-
"--diff-filter=U",
|
|
42903
|
-
"--relative"
|
|
42904
|
-
]);
|
|
42905
|
-
if (unmerged.status !== 0 || unmerged.stdout.length > 0) return null;
|
|
42906
|
-
const result = yield* runGit(input.directory, [
|
|
42907
|
-
"diff",
|
|
42908
|
-
"--no-ext-diff",
|
|
42909
|
-
"--no-textconv",
|
|
42910
|
-
"--no-renames",
|
|
42911
|
-
"-z",
|
|
42912
|
-
"--name-status",
|
|
42913
|
-
"--relative",
|
|
42914
|
-
input.ref
|
|
42915
|
-
]);
|
|
42916
|
-
if (result.status !== 0) return null;
|
|
42917
|
-
const plan = parseBaselineDiffPlan(result.stdout);
|
|
42918
|
-
if (plan === null) return null;
|
|
42919
|
-
const untracked = yield* runGit(input.directory, [
|
|
42920
|
-
"ls-files",
|
|
42921
|
-
"--others",
|
|
42922
|
-
"--exclude-standard",
|
|
42923
|
-
"-z"
|
|
42924
|
-
]);
|
|
42925
|
-
if (untracked.status !== 0) return null;
|
|
42926
|
-
return {
|
|
42927
|
-
baseFiles: plan.baseFiles,
|
|
42928
|
-
headFiles: plan.headFiles,
|
|
42929
|
-
untrackedFiles: splitNullSeparated(untracked.stdout)
|
|
42930
|
-
};
|
|
42931
|
-
}).pipe(catch_$1(() => succeed$2(null)), withSpan("Git.baselineDiffPlan"));
|
|
42932
|
-
},
|
|
42933
42539
|
diffSelection: ({ directory, explicitBaseBranch, includeUntracked = false }) => gen(function* () {
|
|
42934
42540
|
if (explicitBaseBranch !== void 0 && explicitBaseBranch.trim().length === 0) return yield* fail$4(new ReactDoctorError({ reason: new GitBaseBranchInvalid({ detail: "Diff base branch cannot be empty." }) }));
|
|
42935
42541
|
if (explicitBaseBranch !== void 0) {
|
|
@@ -43079,7 +42685,6 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
43079
42685
|
githubViewerPermission: () => succeed$2(snapshot.githubViewerPermission ?? null),
|
|
43080
42686
|
branchExists: (_directory, branch) => succeed$2(snapshot.branchExists?.get(branch) ?? false),
|
|
43081
42687
|
mergeBase: ({ ref }) => succeed$2(snapshot.mergeBase?.get(ref) ?? null),
|
|
43082
|
-
baselineDiffPlan: () => succeed$2(snapshot.baselineDiffPlan ?? null),
|
|
43083
42688
|
diffSelection: () => succeed$2(snapshot.diffSelection ?? null),
|
|
43084
42689
|
stagedFilePaths: () => succeed$2(snapshot.stagedFiles ?? []),
|
|
43085
42690
|
showStagedContent: (_directory, relativePath) => succeed$2(snapshot.stagedContent?.get(relativePath) ?? null),
|
|
@@ -43448,9 +43053,8 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
43448
43053
|
}
|
|
43449
43054
|
return enabled;
|
|
43450
43055
|
};
|
|
43451
|
-
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(),
|
|
43452
|
-
const
|
|
43453
|
-
const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" || hasIncludedTags ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
|
|
43056
|
+
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
|
|
43057
|
+
const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
|
|
43454
43058
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
43455
43059
|
const jsPlugins = [];
|
|
43456
43060
|
if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
|
|
@@ -43465,14 +43069,9 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
43465
43069
|
if (rule.scan !== void 0) continue;
|
|
43466
43070
|
if (customRulesOnly && registryEntry.originallyExternal) continue;
|
|
43467
43071
|
if (rule.framework !== "global" && !rule.requires) continue;
|
|
43468
|
-
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen
|
|
43072
|
+
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) continue;
|
|
43469
43073
|
const explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey: registryEntry.key }, severityControls);
|
|
43470
|
-
if (
|
|
43471
|
-
defaultEnabled: rule.defaultEnabled,
|
|
43472
|
-
includeTagDefaults,
|
|
43473
|
-
hasIncludedTags,
|
|
43474
|
-
hasExplicitOverride: explicitRuleOverride !== void 0
|
|
43475
|
-
})) continue;
|
|
43074
|
+
if (rule.defaultEnabled === false && explicitRuleOverride === void 0) continue;
|
|
43476
43075
|
const severity = resolveRuleSeverityOverride({
|
|
43477
43076
|
ruleKey: registryEntry.key,
|
|
43478
43077
|
category: rule.category
|
|
@@ -43481,7 +43080,7 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
43481
43080
|
enabledReactDoctorRules[registryEntry.key] = severity;
|
|
43482
43081
|
}
|
|
43483
43082
|
const userPluginRules = {};
|
|
43484
|
-
if (ruleSelection !== "sidecar"
|
|
43083
|
+
if (ruleSelection !== "sidecar") for (const userPlugin of userPlugins) {
|
|
43485
43084
|
Object.assign(userPluginRules, buildUserPluginRules(userPlugin, severityControls));
|
|
43486
43085
|
jsPlugins.push(userPlugin.entry);
|
|
43487
43086
|
}
|
|
@@ -43698,19 +43297,6 @@ const createSidecarLintCache = (cacheDirectory, rulesetHash) => {
|
|
|
43698
43297
|
}
|
|
43699
43298
|
};
|
|
43700
43299
|
};
|
|
43701
|
-
const fingerprintCacheByFilePath = /* @__PURE__ */ new Map();
|
|
43702
|
-
const fingerprintFileContents = (filePath, fingerprintLength) => {
|
|
43703
|
-
const fileStats = NFS.statSync(filePath, { bigint: true });
|
|
43704
|
-
const cachedFingerprint = fingerprintCacheByFilePath.get(filePath);
|
|
43705
|
-
if (cachedFingerprint?.modifiedTimeNanoseconds === fileStats.mtimeNs && cachedFingerprint.sizeBytes === fileStats.size) return cachedFingerprint.fingerprint;
|
|
43706
|
-
const fingerprint = crypto.createHash("sha256").update(NFS.readFileSync(filePath)).digest("hex").slice(0, fingerprintLength);
|
|
43707
|
-
fingerprintCacheByFilePath.set(filePath, {
|
|
43708
|
-
fingerprint,
|
|
43709
|
-
modifiedTimeNanoseconds: fileStats.mtimeNs,
|
|
43710
|
-
sizeBytes: fileStats.size
|
|
43711
|
-
});
|
|
43712
|
-
return fingerprint;
|
|
43713
|
-
};
|
|
43714
43300
|
const bundledRequire$3 = createRequire(import.meta.url);
|
|
43715
43301
|
const childNodeVersionByBinaryPath = /* @__PURE__ */ new Map();
|
|
43716
43302
|
const resolveChildNodeVersion = (nodeBinaryPath) => {
|
|
@@ -43734,13 +43320,6 @@ const TOOLCHAIN_PACKAGE_SPECIFIERS$1 = [
|
|
|
43734
43320
|
"oxlint-plugin-react-doctor/package.json",
|
|
43735
43321
|
"eslint-plugin-react-hooks/package.json"
|
|
43736
43322
|
];
|
|
43737
|
-
const resolvePluginFingerprint = () => {
|
|
43738
|
-
try {
|
|
43739
|
-
return fingerprintFileContents(bundledRequire$3.resolve("oxlint-plugin-react-doctor"), 16);
|
|
43740
|
-
} catch {
|
|
43741
|
-
return "unresolved";
|
|
43742
|
-
}
|
|
43743
|
-
};
|
|
43744
43323
|
const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
|
|
43745
43324
|
const versions = [`node=${resolveChildNodeVersion(nodeBinaryPath)}`];
|
|
43746
43325
|
for (const specifier of TOOLCHAIN_PACKAGE_SPECIFIERS$1) try {
|
|
@@ -43750,7 +43329,6 @@ const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
|
|
|
43750
43329
|
} catch {
|
|
43751
43330
|
versions.push(`${specifier}=missing`);
|
|
43752
43331
|
}
|
|
43753
|
-
versions.push(`oxlint-plugin-react-doctor#fingerprint=${resolvePluginFingerprint()}`);
|
|
43754
43332
|
return versions;
|
|
43755
43333
|
};
|
|
43756
43334
|
const esmRequire = createRequire(import.meta.url);
|
|
@@ -44444,17 +44022,12 @@ const REACT_ERROR_BOUNDARY_MESSAGE = "This try/catch cannot catch errors thrown
|
|
|
44444
44022
|
const REACT_COMPILER_IMPACT = "This component misses React Compiler's automatic memoization & re-renders more than it should";
|
|
44445
44023
|
const REACT_COMPILER_ACTION = "Rewrite the flagged code so the compiler can optimize it.";
|
|
44446
44024
|
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`.";
|
|
44447
|
-
const SET_STATE_IN_EFFECT_ACTION = "Prefer deriving or initializing the value before render. If the effect must read a browser API after mount, treat this as advisory or suppress it with `// react-doctor-disable-next-line react-hooks-js/set-state-in-effect`.";
|
|
44448
44025
|
const REACT_COMPILER_GENERIC_MESSAGE = `${REACT_COMPILER_IMPACT}. ${REACT_COMPILER_ACTION}`;
|
|
44449
44026
|
const buildReactCompilerMessage = (reasonSummary, action = REACT_COMPILER_ACTION) => {
|
|
44450
44027
|
const normalizedSummary = reasonSummary.replace(TRAILING_PERIOD_PATTERN, "");
|
|
44451
44028
|
if (!normalizedSummary) return `${REACT_COMPILER_IMPACT}. ${action}`;
|
|
44452
44029
|
return `${REACT_COMPILER_IMPACT}: ${normalizedSummary}. ${action}`;
|
|
44453
44030
|
};
|
|
44454
|
-
const buildSetStateInEffectMessage = (reasonSummary) => {
|
|
44455
|
-
const normalizedSummary = reasonSummary.replace(TRAILING_PERIOD_PATTERN, "");
|
|
44456
|
-
return `This synchronous effect update causes an extra render${normalizedSummary ? `: ${normalizedSummary}` : ""}. ${SET_STATE_IN_EFFECT_ACTION}`;
|
|
44457
|
-
};
|
|
44458
44031
|
const PLUGIN_CATEGORY_MAP = {
|
|
44459
44032
|
react: "Bugs",
|
|
44460
44033
|
"react-hooks": "Bugs",
|
|
@@ -44512,10 +44085,6 @@ const resolveCleanedDiagnostic = (message, help, plugin, rule, project) => {
|
|
|
44512
44085
|
message: REACT_ERROR_BOUNDARY_MESSAGE,
|
|
44513
44086
|
help: reasonDetail || help
|
|
44514
44087
|
};
|
|
44515
|
-
if (rule === "set-state-in-effect") return {
|
|
44516
|
-
message: buildSetStateInEffectMessage(reasonSummary.trim()),
|
|
44517
|
-
help: reasonDetail || help
|
|
44518
|
-
};
|
|
44519
44088
|
return {
|
|
44520
44089
|
message: buildReactCompilerMessage(reasonSummary.trim(), rule === "incompatible-library" ? REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION : REACT_COMPILER_ACTION),
|
|
44521
44090
|
help: appendReanimatedSharedValueHint(reasonDetail || help, rule, project)
|
|
@@ -45226,7 +44795,7 @@ const reactHooksJsPluginDropNote = (error) => {
|
|
|
45226
44795
|
* 6. always restore disable directives + clean up the temp dir
|
|
45227
44796
|
*/
|
|
45228
44797
|
const runOxlint = async (options) => {
|
|
45229
|
-
const { rootDirectory, project, includePaths, nodeBinaryPath = process.execPath, customRulesOnly = false, respectInlineDisables = true, adoptExistingLintConfig = true, ignoredTags = /* @__PURE__ */ new Set(),
|
|
44798
|
+
const { rootDirectory, project, includePaths, nodeBinaryPath = process.execPath, customRulesOnly = false, respectInlineDisables = true, adoptExistingLintConfig = true, ignoredTags = /* @__PURE__ */ new Set(), userConfig, configSourceDirectory = rootDirectory, onPartialFailure, onFileCoverage, perFileLintCacheEnabled = false, sidecarLintCacheEnabled = false, onCacheStats, onSidecarStats, spawnTimeoutMs, outputMaxBytes, lintBatchOrdering = "cost" } = options;
|
|
45230
44799
|
const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
|
|
45231
44800
|
const severityControls = buildRuleSeverityControls(userConfig);
|
|
45232
44801
|
validateRuleRegistration();
|
|
@@ -45240,15 +44809,13 @@ const runOxlint = async (options) => {
|
|
|
45240
44809
|
}
|
|
45241
44810
|
const pluginPath = resolvePluginPath();
|
|
45242
44811
|
const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
|
|
45243
|
-
const userPlugins =
|
|
44812
|
+
const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
|
|
45244
44813
|
const buildConfig = (overrides) => createOxlintConfig({
|
|
45245
44814
|
pluginPath,
|
|
45246
44815
|
project,
|
|
45247
44816
|
customRulesOnly,
|
|
45248
44817
|
extendsPaths: overrides.extendsPaths,
|
|
45249
44818
|
ignoredTags,
|
|
45250
|
-
includedTags,
|
|
45251
|
-
includeTagDefaults,
|
|
45252
44819
|
serverAuthFunctionNames,
|
|
45253
44820
|
severityControls,
|
|
45254
44821
|
userPlugins,
|
|
@@ -45637,8 +45204,6 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
|
|
|
45637
45204
|
respectInlineDisables: input.respectInlineDisables,
|
|
45638
45205
|
adoptExistingLintConfig: input.adoptExistingLintConfig,
|
|
45639
45206
|
ignoredTags: input.ignoredTags,
|
|
45640
|
-
includedTags: input.includedTags,
|
|
45641
|
-
includeTagDefaults: input.includeTagDefaults,
|
|
45642
45207
|
userConfig: input.userConfig ?? null,
|
|
45643
45208
|
configSourceDirectory: input.configSourceDirectory,
|
|
45644
45209
|
onPartialFailure: (reason) => {
|
|
@@ -46487,9 +46052,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
46487
46052
|
const securityScanFailedRef = yield* make$13(false);
|
|
46488
46053
|
const securityScanFiber = yield* forkChild(runCollect(applyPerElementPipeline(isDiffMode ? empty$4 : unwrap(tryPromise(() => checkSecurityScanCooperative(scanDirectory, {
|
|
46489
46054
|
project,
|
|
46490
|
-
ignoredTags: input.ignoredTags
|
|
46491
|
-
includedTags: input.includedTags,
|
|
46492
|
-
includeTagDefaults: input.includeTagDefaults
|
|
46055
|
+
ignoredTags: input.ignoredTags
|
|
46493
46056
|
})).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)), catch_$1(() => set(securityScanFailedRef, true).pipe(as(empty$4))))))).pipe(withSpan("SecurityScan.run")));
|
|
46494
46057
|
const shouldRunSupplyChain = !isDiffMode || (input.supplyChainManifestChanged ?? false);
|
|
46495
46058
|
const supplyChainOverlapTimeout = yield* SupplyChainOverlapTimeoutMs;
|
|
@@ -46580,8 +46143,6 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
46580
46143
|
respectInlineDisables: input.respectInlineDisables,
|
|
46581
46144
|
adoptExistingLintConfig: input.adoptExistingLintConfig,
|
|
46582
46145
|
ignoredTags: input.ignoredTags,
|
|
46583
|
-
includedTags: input.includedTags,
|
|
46584
|
-
includeTagDefaults: input.includeTagDefaults,
|
|
46585
46146
|
userConfig: resolvedConfig.config ?? void 0,
|
|
46586
46147
|
configSourceDirectory: resolvedConfig.configSourceDirectory ?? void 0,
|
|
46587
46148
|
onFileProgress: (scannedFileCount, totalFileCount) => {
|
|
@@ -46860,19 +46421,12 @@ const isPathInsideDirectory = (childAbsolutePath, parentAbsolutePath) => {
|
|
|
46860
46421
|
*/
|
|
46861
46422
|
const materializeSourceTree = (input) => gen(function* () {
|
|
46862
46423
|
const materializedFiles = [];
|
|
46863
|
-
const unmaterializedFiles = [];
|
|
46864
46424
|
const resolvedTempDirectory = path.resolve(input.tempDirectory);
|
|
46865
46425
|
for (const relativePath of input.files) {
|
|
46866
46426
|
const content = yield* input.readContent(relativePath).pipe(orElseSucceed(() => null));
|
|
46867
|
-
if (content === null)
|
|
46868
|
-
unmaterializedFiles.push(relativePath);
|
|
46869
|
-
continue;
|
|
46870
|
-
}
|
|
46427
|
+
if (content === null) continue;
|
|
46871
46428
|
const candidateTargetPath = path.resolve(resolvedTempDirectory, relativePath);
|
|
46872
|
-
if (!isPathInsideDirectory(candidateTargetPath, resolvedTempDirectory))
|
|
46873
|
-
unmaterializedFiles.push(relativePath);
|
|
46874
|
-
continue;
|
|
46875
|
-
}
|
|
46429
|
+
if (!isPathInsideDirectory(candidateTargetPath, resolvedTempDirectory)) continue;
|
|
46876
46430
|
yield* sync(() => {
|
|
46877
46431
|
fs.mkdirSync(path.dirname(candidateTargetPath), { recursive: true });
|
|
46878
46432
|
fs.writeFileSync(candidateTargetPath, content);
|
|
@@ -46889,7 +46443,6 @@ const materializeSourceTree = (input) => gen(function* () {
|
|
|
46889
46443
|
return {
|
|
46890
46444
|
tempDirectory: input.tempDirectory,
|
|
46891
46445
|
materializedFiles,
|
|
46892
|
-
unmaterializedFiles,
|
|
46893
46446
|
cleanup: () => {
|
|
46894
46447
|
try {
|
|
46895
46448
|
fs.rmSync(input.tempDirectory, {
|
|
@@ -47159,80 +46712,54 @@ const buildSkippedChecks = (input) => {
|
|
|
47159
46712
|
skippedCheckReasons
|
|
47160
46713
|
};
|
|
47161
46714
|
};
|
|
47162
|
-
const
|
|
47163
|
-
const normalizeEvidence = (evidence) => evidence.replace(/\s+/g, " ").trim();
|
|
47164
|
-
const getDiagnosticMatchKeys = (diagnostic, evidence) => {
|
|
46715
|
+
const fingerprintDiagnostic = (diagnostic, lineText) => {
|
|
47165
46716
|
const ruleKey = `${diagnostic.plugin}/${diagnostic.rule}`;
|
|
47166
|
-
const
|
|
47167
|
-
|
|
47168
|
-
|
|
47169
|
-
|
|
47170
|
-
|
|
47171
|
-
|
|
47172
|
-
|
|
47173
|
-
|
|
47174
|
-
|
|
47175
|
-
|
|
47176
|
-
|
|
47177
|
-
|
|
47178
|
-
|
|
47179
|
-
|
|
47180
|
-
|
|
47181
|
-
|
|
47182
|
-
|
|
47183
|
-
|
|
47184
|
-
|
|
47185
|
-
|
|
47186
|
-
|
|
47187
|
-
|
|
47188
|
-
|
|
47189
|
-
|
|
47190
|
-
|
|
47191
|
-
|
|
47192
|
-
*
|
|
47193
|
-
* evidence. Stable identities combine plugin/rule, the diagnostic message,
|
|
47194
|
-
* and normalized diagnosed source, so unchanged findings can move across
|
|
47195
|
-
* files while changed constructs or messages remain new. Cardinality is
|
|
47196
|
-
* retained for identical findings. Diagnostics explicitly marked
|
|
47197
|
-
* `matchByOccurrence` may fall back to same-file plugin/rule/message matching
|
|
47198
|
-
* after same-file strict evidence matching. Cross-file evidence matching runs
|
|
47199
|
-
* last so a copy cannot consume a reformatted local occurrence. Unreadable
|
|
47200
|
-
* evidence uses the same conservative fallback rather than matching across
|
|
47201
|
-
* files without proof.
|
|
46717
|
+
const snippet = lineText === null || diagnostic.matchByOccurrence ? "" : createHash("sha1").update(lineText.trim()).digest("hex");
|
|
46718
|
+
return `${diagnostic.filePath}\u0000${ruleKey}\u0000${snippet}`;
|
|
46719
|
+
};
|
|
46720
|
+
/**
|
|
46721
|
+
* Diffs a head scan against a base scan to isolate the diagnostics a change
|
|
46722
|
+
* introduced (and count the ones it resolved). Matching is a multiset over a
|
|
46723
|
+
* position-independent fingerprint — `(filePath, plugin/rule, hash(flagged
|
|
46724
|
+
* line text))` — so inserting lines above an existing issue doesn't make it
|
|
46725
|
+
* look new, while a genuinely new occurrence (new line text, or one more of
|
|
46726
|
+
* the same) surfaces. Identical repeated findings are matched by count.
|
|
46727
|
+
*
|
|
46728
|
+
* Diagnostics carrying `matchByOccurrence` (resolved at diagnostic creation:
|
|
46729
|
+
* every Accessibility-category finding, plus rules opting in via their
|
|
46730
|
+
* `matchByOccurrence` metadata flag) drop the line-text snippet and match by
|
|
46731
|
+
* `(filePath, plugin/rule)` occurrence count alone. Their identity is the
|
|
46732
|
+
* flagged element, not the line's text, so editing the line (reindentation,
|
|
46733
|
+
* prettier reflow, collapsing a multi-line JSX element) doesn't reclassify a
|
|
46734
|
+
* pre-existing finding as new — while one MORE occurrence of the same rule in
|
|
46735
|
+
* the file still surfaces. Expression-level rules keep the line-text snippet:
|
|
46736
|
+
* there the flagged expression IS the finding, so changed text means new +
|
|
46737
|
+
* fixed.
|
|
46738
|
+
*
|
|
46739
|
+
* v1 limitation: the fingerprint keys on the head-relative `filePath`, and base
|
|
46740
|
+
* content is read at that same path. A file renamed by the change therefore has
|
|
46741
|
+
* no base match, so its pre-existing findings are reported as new. This
|
|
46742
|
+
* over-reports (never hides a real issue) and is rare; rename-aware base
|
|
46743
|
+
* resolution is a follow-up.
|
|
47202
46744
|
*/
|
|
47203
46745
|
const computeDiagnosticDelta = (input) => {
|
|
47204
|
-
const
|
|
47205
|
-
const
|
|
47206
|
-
|
|
47207
|
-
|
|
47208
|
-
|
|
47209
|
-
|
|
47210
|
-
|
|
47211
|
-
|
|
47212
|
-
|
|
47213
|
-
|
|
47214
|
-
|
|
47215
|
-
|
|
47216
|
-
|
|
47217
|
-
|
|
47218
|
-
if (matchedHeadDiagnosticIndexes.has(candidate.diagnosticIndex)) continue;
|
|
47219
|
-
const baseDiagnosticIndex = takeMatchingDiagnosticIndex(baseBuckets, getKey(candidate), matchedBaseDiagnosticIndexes);
|
|
47220
|
-
if (baseDiagnosticIndex === null) continue;
|
|
47221
|
-
matchedHeadDiagnosticIndexes.add(candidate.diagnosticIndex);
|
|
47222
|
-
matchedBaseDiagnosticIndexes.add(baseDiagnosticIndex);
|
|
47223
|
-
onMatch?.(candidate.diagnosticIndex, baseDiagnosticIndex);
|
|
47224
|
-
}
|
|
47225
|
-
};
|
|
47226
|
-
matchCandidates(baseBySameFileStableEvidence, (candidate) => candidate.sameFileStableEvidenceKey);
|
|
47227
|
-
matchCandidates(baseBySameFileFallback, (candidate) => candidate.sameFileFallbackKey);
|
|
47228
|
-
let crossFileMatchCount = 0;
|
|
47229
|
-
matchCandidates(baseByStableEvidence, (candidate) => candidate.stableEvidenceKey, (head, base) => {
|
|
47230
|
-
if (input.headDiagnostics[head]?.filePath !== input.baseDiagnostics[base]?.filePath) crossFileMatchCount += 1;
|
|
47231
|
-
});
|
|
46746
|
+
const unmatchedBaseByFingerprint = /* @__PURE__ */ new Map();
|
|
46747
|
+
for (const diagnostic of input.baseDiagnostics) {
|
|
46748
|
+
const key = fingerprintDiagnostic(diagnostic, input.readBaseLine(diagnostic.filePath, diagnostic.line));
|
|
46749
|
+
unmatchedBaseByFingerprint.set(key, (unmatchedBaseByFingerprint.get(key) ?? 0) + 1);
|
|
46750
|
+
}
|
|
46751
|
+
const newDiagnostics = [];
|
|
46752
|
+
for (const diagnostic of input.headDiagnostics) {
|
|
46753
|
+
const key = fingerprintDiagnostic(diagnostic, input.readHeadLine(diagnostic.filePath, diagnostic.line));
|
|
46754
|
+
const availableMatches = unmatchedBaseByFingerprint.get(key) ?? 0;
|
|
46755
|
+
if (availableMatches > 0) unmatchedBaseByFingerprint.set(key, availableMatches - 1);
|
|
46756
|
+
else newDiagnostics.push(diagnostic);
|
|
46757
|
+
}
|
|
46758
|
+
let fixedCount = 0;
|
|
46759
|
+
for (const remaining of unmatchedBaseByFingerprint.values()) fixedCount += remaining;
|
|
47232
46760
|
return {
|
|
47233
|
-
newDiagnostics
|
|
47234
|
-
fixedCount
|
|
47235
|
-
crossFileMatchCount
|
|
46761
|
+
newDiagnostics,
|
|
46762
|
+
fixedCount
|
|
47236
46763
|
};
|
|
47237
46764
|
};
|
|
47238
46765
|
/**
|
|
@@ -47264,12 +46791,6 @@ const getDiffInfo = (directory, explicitBaseBranch, includeUntracked) => runProm
|
|
|
47264
46791
|
};
|
|
47265
46792
|
}).pipe(provide(Git.layerNode)));
|
|
47266
46793
|
const filterSourceFiles = (filePaths) => filePaths.filter(isLintableSourceFile);
|
|
47267
|
-
const getBaselineDiffPlan = (directory, ref) => runPromise(gen(function* () {
|
|
47268
|
-
return yield* (yield* Git).baselineDiffPlan({
|
|
47269
|
-
directory,
|
|
47270
|
-
ref
|
|
47271
|
-
});
|
|
47272
|
-
}).pipe(provide(Git.layerNode)));
|
|
47273
46794
|
/**
|
|
47274
46795
|
* Programmatic façade over `Git.changedLineRanges` (the `lines` scope). Diffs
|
|
47275
46796
|
* `files` with `--unified=0` against `baseRef` (or the index when `cached`),
|
|
@@ -47726,7 +47247,7 @@ const makeNoopConsole = () => ({
|
|
|
47726
47247
|
});
|
|
47727
47248
|
//#endregion
|
|
47728
47249
|
//#region src/cli/utils/version.ts
|
|
47729
|
-
const VERSION = "0.8.1
|
|
47250
|
+
const VERSION = "0.8.1";
|
|
47730
47251
|
//#endregion
|
|
47731
47252
|
//#region src/cli/utils/json-mode.ts
|
|
47732
47253
|
let context = null;
|
|
@@ -47813,11 +47334,7 @@ const getRunId = () => {
|
|
|
47813
47334
|
};
|
|
47814
47335
|
//#endregion
|
|
47815
47336
|
//#region src/cli/utils/build-run-context.ts
|
|
47816
|
-
const ROOT_SUBCOMMANDS = new Set([
|
|
47817
|
-
"design",
|
|
47818
|
-
"install",
|
|
47819
|
-
"setup"
|
|
47820
|
-
]);
|
|
47337
|
+
const ROOT_SUBCOMMANDS = new Set(["install", "setup"]);
|
|
47821
47338
|
const detectInvokedVia = () => {
|
|
47822
47339
|
const userAgent = process.env.npm_config_user_agent;
|
|
47823
47340
|
if (!userAgent) return "unknown";
|
|
@@ -47901,9 +47418,7 @@ const buildSentryProjectContext = (projectInfo) => ({
|
|
|
47901
47418
|
reactMajorVersion: projectInfo.reactMajorVersion,
|
|
47902
47419
|
hasTypeScript: projectInfo.hasTypeScript,
|
|
47903
47420
|
hasReactCompiler: projectInfo.hasReactCompiler,
|
|
47904
|
-
|
|
47905
|
-
mobxVersion: projectInfo.mobxVersion,
|
|
47906
|
-
styledComponentsVersion: projectInfo.styledComponentsVersion,
|
|
47421
|
+
hasTanStackQuery: projectInfo.hasTanStackQuery,
|
|
47907
47422
|
tailwindVersion: projectInfo.tailwindVersion,
|
|
47908
47423
|
zodVersion: projectInfo.zodVersion,
|
|
47909
47424
|
preactVersion: projectInfo.preactVersion,
|
|
@@ -48084,13 +47599,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
|
|
|
48084
47599
|
* uploads source-map artifacts under, so stack frames symbolicate. Honors the
|
|
48085
47600
|
* standard `SENTRY_RELEASE` override.
|
|
48086
47601
|
*/
|
|
48087
|
-
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.8.1
|
|
47602
|
+
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.8.1`;
|
|
48088
47603
|
/**
|
|
48089
47604
|
* Deployment environment shown in Sentry's environment filter. Defaults to
|
|
48090
47605
|
* `production` for tagged releases and `development` for dev/unbuilt versions,
|
|
48091
47606
|
* overridable via the standard `SENTRY_ENVIRONMENT` env var.
|
|
48092
47607
|
*/
|
|
48093
|
-
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.8.1
|
|
47608
|
+
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.8.1") ? "development" : "production");
|
|
48094
47609
|
/**
|
|
48095
47610
|
* Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
|
|
48096
47611
|
* (set to `0` to disable tracing) and falls back to
|
|
@@ -60416,8 +59931,6 @@ const buildScanResultCacheKey = (input) => {
|
|
|
60416
59931
|
warnings: input.options.warnings,
|
|
60417
59932
|
adoptExistingLintConfig: input.options.adoptExistingLintConfig,
|
|
60418
59933
|
ignoredTags: [...input.options.ignoredTags].sort(),
|
|
60419
|
-
includedTags: [...input.options.includedTags].sort(),
|
|
60420
|
-
includeTagDefaults: input.options.includeTagDefaults,
|
|
60421
59934
|
concurrency: input.options.concurrency,
|
|
60422
59935
|
lintBatchOrdering: resolveLintBatchOrdering(),
|
|
60423
59936
|
baselineRef: input.options.baseline?.ref,
|
|
@@ -60715,7 +60228,6 @@ const buildOutcomeAttributes = (input) => {
|
|
|
60715
60228
|
new: summary.totalDiagnosticCount,
|
|
60716
60229
|
fixed: result.baselineDelta.fixedCount,
|
|
60717
60230
|
baseTotal: result.baselineDelta.baseTotalCount,
|
|
60718
|
-
crossFileMatches: result.baselineDelta.crossFileMatchCount ?? null,
|
|
60719
60231
|
degraded: false
|
|
60720
60232
|
}));
|
|
60721
60233
|
else if (input.gateExempt) attributes["baseline.degraded"] = true;
|
|
@@ -60829,49 +60341,28 @@ const diagnosticIntersectsLineRanges = (diagnostic, lineRanges) => {
|
|
|
60829
60341
|
return lineRanges.some(([rangeStartLine, rangeEndLine]) => diagnostic.line <= rangeEndLine && diagnosticEndLine >= rangeStartLine);
|
|
60830
60342
|
};
|
|
60831
60343
|
//#endregion
|
|
60832
|
-
//#region src/cli/utils/is-materializable-git-source.ts
|
|
60833
|
-
const GIT_LFS_POINTER_HEADER = "version https://git-lfs.github.com/spec/v1";
|
|
60834
|
-
const isMaterializableGitSource = (content) => !content.includes("\0") && !content.startsWith(GIT_LFS_POINTER_HEADER);
|
|
60835
|
-
//#endregion
|
|
60836
60344
|
//#region src/cli/utils/materialize-baseline-files.ts
|
|
60837
60345
|
/**
|
|
60838
|
-
* Materializes the
|
|
60839
|
-
* `
|
|
60840
|
-
*
|
|
60841
|
-
*
|
|
60842
|
-
*
|
|
60843
|
-
*
|
|
60346
|
+
* Materializes the `ref` version of `files` into `tempDirectory` (via
|
|
60347
|
+
* `git show <ref>:<path>`), mirroring the project layout + head's config files
|
|
60348
|
+
* so the base lints under the same rules as head. Reuses the shared,
|
|
60349
|
+
* zip-slip-guarded `materializeSourceTree`. Per-file read misses (e.g. a file
|
|
60350
|
+
* the PR added, absent at base) are skipped, which is exactly what we want:
|
|
60351
|
+
* a brand-new file has no base counterpart, so all its findings are "new".
|
|
60844
60352
|
*/
|
|
60845
60353
|
const materializeBaselineFiles = (input) => runPromise(gen(function* () {
|
|
60846
60354
|
const git = yield* Git;
|
|
60847
|
-
|
|
60355
|
+
return yield* materializeSourceTree({
|
|
60848
60356
|
directory: input.directory,
|
|
60849
|
-
|
|
60850
|
-
});
|
|
60851
|
-
const baseFiles = input.baseFiles ?? diffPlan?.baseFiles;
|
|
60852
|
-
const headFiles = input.headFiles ?? diffPlan?.headFiles;
|
|
60853
|
-
const untrackedFiles = diffPlan?.untrackedFiles ?? [];
|
|
60854
|
-
if (baseFiles === void 0 || headFiles === void 0) return null;
|
|
60855
|
-
const files = [...new Set([...input.files, ...baseFiles])];
|
|
60856
|
-
const tree = yield* materializeSourceTree({
|
|
60857
|
-
directory: input.directory,
|
|
60858
|
-
files,
|
|
60357
|
+
files: input.files,
|
|
60859
60358
|
tempDirectory: input.tempDirectory,
|
|
60860
60359
|
readContent: (relativePath) => git.showRefContent({
|
|
60861
60360
|
directory: input.directory,
|
|
60862
60361
|
ref: input.ref,
|
|
60863
60362
|
relativePath,
|
|
60864
60363
|
options: { maxBufferBytes: GIT_SHOW_MAX_BUFFER_BYTES }
|
|
60865
|
-
})
|
|
60364
|
+
})
|
|
60866
60365
|
});
|
|
60867
|
-
const materializedFiles = new Set(tree.materializedFiles);
|
|
60868
|
-
return {
|
|
60869
|
-
...tree,
|
|
60870
|
-
baseFiles,
|
|
60871
|
-
headFiles,
|
|
60872
|
-
isComplete: baseFiles.every((filePath) => materializedFiles.has(filePath)),
|
|
60873
|
-
untrackedFiles
|
|
60874
|
-
};
|
|
60875
60366
|
}).pipe(provide(Git.layerNode)));
|
|
60876
60367
|
/**
|
|
60877
60368
|
* Resolves the commit a baseline scan should read base content from — the
|
|
@@ -60894,8 +60385,8 @@ const resolveMergeBaseRef = async (directory, ref) => {
|
|
|
60894
60385
|
//#region src/cli/utils/read-source-line.ts
|
|
60895
60386
|
/**
|
|
60896
60387
|
* Builds a cached `(filePath, line) -> source text` reader rooted at
|
|
60897
|
-
* `rootDirectory`, used
|
|
60898
|
-
*
|
|
60388
|
+
* `rootDirectory`, used to fingerprint a diagnostic by the content of its
|
|
60389
|
+
* flagged line (see `computeDiagnosticDelta`). Wraps core's
|
|
60899
60390
|
* `createNodeReadFileLinesSync` with per-file memoization + 1-indexed line
|
|
60900
60391
|
* lookup; unreadable files / out-of-range lines return `null`.
|
|
60901
60392
|
*/
|
|
@@ -60910,342 +60401,10 @@ const createSourceLineReader = (rootDirectory) => {
|
|
|
60910
60401
|
};
|
|
60911
60402
|
};
|
|
60912
60403
|
//#endregion
|
|
60913
|
-
//#region src/cli/utils/read-diagnostic-evidence.ts
|
|
60914
|
-
const SOURCE_EXTENSIONS = [
|
|
60915
|
-
".ts",
|
|
60916
|
-
".tsx",
|
|
60917
|
-
".js",
|
|
60918
|
-
".jsx",
|
|
60919
|
-
".mts",
|
|
60920
|
-
".cts",
|
|
60921
|
-
".mjs",
|
|
60922
|
-
".cjs"
|
|
60923
|
-
];
|
|
60924
|
-
const COMPONENT_WRAPPER_NAMES = new Set(["memo", "forwardRef"]);
|
|
60925
|
-
const getScriptKind = (filePath) => {
|
|
60926
|
-
const extension = path.extname(filePath).toLowerCase();
|
|
60927
|
-
if (extension === ".tsx") return ts.ScriptKind.TSX;
|
|
60928
|
-
if (extension === ".jsx") return ts.ScriptKind.JSX;
|
|
60929
|
-
if (extension === ".js" || extension === ".mjs" || extension === ".cjs") return ts.ScriptKind.JS;
|
|
60930
|
-
return ts.ScriptKind.TS;
|
|
60931
|
-
};
|
|
60932
|
-
const resolveSafeSourcePath = (rootDirectory, filePath) => {
|
|
60933
|
-
try {
|
|
60934
|
-
const resolvedRootDirectory = fs.realpathSync(rootDirectory);
|
|
60935
|
-
const absolutePath = path.resolve(resolvedRootDirectory, filePath);
|
|
60936
|
-
const relativePath = path.relative(resolvedRootDirectory, absolutePath);
|
|
60937
|
-
if (relativePath.length === 0 || relativePath === ".." || relativePath.startsWith(`..${path.sep}`) || path.isAbsolute(relativePath)) return null;
|
|
60938
|
-
const stats = fs.lstatSync(absolutePath);
|
|
60939
|
-
if (!stats.isFile() || stats.isSymbolicLink()) return null;
|
|
60940
|
-
const realPath = fs.realpathSync(absolutePath);
|
|
60941
|
-
const realRelativePath = path.relative(resolvedRootDirectory, realPath);
|
|
60942
|
-
return realRelativePath !== ".." && !realRelativePath.startsWith(`..${path.sep}`) && !path.isAbsolute(realRelativePath) ? realPath : null;
|
|
60943
|
-
} catch {
|
|
60944
|
-
return null;
|
|
60945
|
-
}
|
|
60946
|
-
};
|
|
60947
|
-
const readSourceRecord = (rootDirectory, filePath, state) => {
|
|
60948
|
-
const normalizedFilePath = filePath.replace(/\\/g, "/");
|
|
60949
|
-
if (state.recordByFilePath.has(normalizedFilePath)) return state.recordByFilePath.get(normalizedFilePath) ?? null;
|
|
60950
|
-
const absolutePath = resolveSafeSourcePath(rootDirectory, normalizedFilePath);
|
|
60951
|
-
if (absolutePath === null) {
|
|
60952
|
-
state.recordByFilePath.set(normalizedFilePath, null);
|
|
60953
|
-
return null;
|
|
60954
|
-
}
|
|
60955
|
-
try {
|
|
60956
|
-
const sourceText = fs.readFileSync(absolutePath, "utf-8");
|
|
60957
|
-
const record = {
|
|
60958
|
-
absolutePath,
|
|
60959
|
-
filePath: normalizedFilePath,
|
|
60960
|
-
sourceFile: ts.createSourceFile(absolutePath, sourceText, ts.ScriptTarget.Latest, true, getScriptKind(absolutePath)),
|
|
60961
|
-
sourceText
|
|
60962
|
-
};
|
|
60963
|
-
state.recordByFilePath.set(normalizedFilePath, record);
|
|
60964
|
-
return record;
|
|
60965
|
-
} catch {
|
|
60966
|
-
state.recordByFilePath.set(normalizedFilePath, null);
|
|
60967
|
-
return null;
|
|
60968
|
-
}
|
|
60969
|
-
};
|
|
60970
|
-
const listSourceRecords = (rootDirectory, state) => {
|
|
60971
|
-
if (state.sourceRecords !== null) return state.sourceRecords;
|
|
60972
|
-
state.sourceRecords = listSourceFiles(rootDirectory).flatMap((filePath) => {
|
|
60973
|
-
const record = readSourceRecord(rootDirectory, filePath, state);
|
|
60974
|
-
return record === null ? [] : [record];
|
|
60975
|
-
});
|
|
60976
|
-
return state.sourceRecords;
|
|
60977
|
-
};
|
|
60978
|
-
const unwrapExpression = (expression) => {
|
|
60979
|
-
let currentExpression = expression;
|
|
60980
|
-
while (ts.isParenthesizedExpression(currentExpression) || ts.isAsExpression(currentExpression) || ts.isTypeAssertionExpression(currentExpression) || ts.isNonNullExpression(currentExpression) || ts.isSatisfiesExpression(currentExpression)) currentExpression = currentExpression.expression;
|
|
60981
|
-
return currentExpression;
|
|
60982
|
-
};
|
|
60983
|
-
const getCalleeName = (expression) => {
|
|
60984
|
-
const unwrappedExpression = unwrapExpression(expression);
|
|
60985
|
-
if (ts.isIdentifier(unwrappedExpression)) return unwrappedExpression.text;
|
|
60986
|
-
if (ts.isPropertyAccessExpression(unwrappedExpression)) return unwrappedExpression.name.text;
|
|
60987
|
-
return null;
|
|
60988
|
-
};
|
|
60989
|
-
const isComponentWrapperCall = (node) => {
|
|
60990
|
-
const wrapperName = getCalleeName(node.expression);
|
|
60991
|
-
return wrapperName !== null && COMPONENT_WRAPPER_NAMES.has(wrapperName);
|
|
60992
|
-
};
|
|
60993
|
-
const getFunctionName = (node) => {
|
|
60994
|
-
if (ts.isFunctionDeclaration(node) && node.name !== void 0) return node.name.text;
|
|
60995
|
-
if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) {
|
|
60996
|
-
let componentExpression = node;
|
|
60997
|
-
while (true) {
|
|
60998
|
-
const parent = componentExpression.parent;
|
|
60999
|
-
if (ts.isParenthesizedExpression(parent) || ts.isAsExpression(parent) || ts.isTypeAssertionExpression(parent) || ts.isNonNullExpression(parent) || ts.isSatisfiesExpression(parent)) {
|
|
61000
|
-
componentExpression = parent;
|
|
61001
|
-
continue;
|
|
61002
|
-
}
|
|
61003
|
-
if (ts.isCallExpression(parent) && parent.arguments[0] === componentExpression && isComponentWrapperCall(parent)) {
|
|
61004
|
-
componentExpression = parent;
|
|
61005
|
-
continue;
|
|
61006
|
-
}
|
|
61007
|
-
if (ts.isVariableDeclaration(parent) && ts.isIdentifier(parent.name)) return parent.name.text;
|
|
61008
|
-
return node.name?.text ?? null;
|
|
61009
|
-
}
|
|
61010
|
-
}
|
|
61011
|
-
return null;
|
|
61012
|
-
};
|
|
61013
|
-
const isComponentFunction = (node) => ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node);
|
|
61014
|
-
const isDefaultExportedComponent = (record, node, componentName) => {
|
|
61015
|
-
if (ts.canHaveModifiers(node) && ts.getModifiers(node)?.some((modifier) => modifier.kind === ts.SyntaxKind.DefaultKeyword)) return true;
|
|
61016
|
-
return record.sourceFile.statements.some((statement) => ts.isExportAssignment(statement) && ts.isIdentifier(statement.expression) && statement.expression.text === componentName);
|
|
61017
|
-
};
|
|
61018
|
-
const findEnclosingComponent = (record, diagnostic) => {
|
|
61019
|
-
if (!Number.isInteger(diagnostic.line) || diagnostic.line < 1) return null;
|
|
61020
|
-
const lineIndex = diagnostic.line - 1;
|
|
61021
|
-
const lineStarts = record.sourceFile.getLineStarts();
|
|
61022
|
-
const lineStart = lineStarts[lineIndex];
|
|
61023
|
-
if (lineStart === void 0) return null;
|
|
61024
|
-
const nextLineStart = lineStarts[lineIndex + 1] ?? record.sourceFile.end;
|
|
61025
|
-
const lineEnd = Math.max(lineStart, nextLineStart - 1);
|
|
61026
|
-
const columnIndex = Number.isInteger(diagnostic.column) ? Math.max(0, diagnostic.column - 1) : 0;
|
|
61027
|
-
const diagnosticPosition = Math.min(lineStart + columnIndex, lineEnd);
|
|
61028
|
-
let component = null;
|
|
61029
|
-
let componentWidth = Number.POSITIVE_INFINITY;
|
|
61030
|
-
const visit = (node) => {
|
|
61031
|
-
if (diagnosticPosition < node.getStart(record.sourceFile) || diagnosticPosition > node.end) return;
|
|
61032
|
-
if (isComponentFunction(node)) {
|
|
61033
|
-
const name = getFunctionName(node);
|
|
61034
|
-
const width = node.end - node.getStart(record.sourceFile);
|
|
61035
|
-
if (name !== null && /^[A-Z]/.test(name) && width < componentWidth) {
|
|
61036
|
-
component = {
|
|
61037
|
-
isDefaultExport: isDefaultExportedComponent(record, node, name),
|
|
61038
|
-
name,
|
|
61039
|
-
node,
|
|
61040
|
-
record
|
|
61041
|
-
};
|
|
61042
|
-
componentWidth = width;
|
|
61043
|
-
}
|
|
61044
|
-
}
|
|
61045
|
-
ts.forEachChild(node, visit);
|
|
61046
|
-
};
|
|
61047
|
-
visit(record.sourceFile);
|
|
61048
|
-
return component;
|
|
61049
|
-
};
|
|
61050
|
-
const moduleSpecifierTargetsComponent = (callerRecord, moduleSpecifier, componentRecord) => {
|
|
61051
|
-
if (!moduleSpecifier.startsWith(".")) return false;
|
|
61052
|
-
const unresolvedPath = path.resolve(path.dirname(callerRecord.absolutePath), moduleSpecifier);
|
|
61053
|
-
const specifiedExtension = path.extname(unresolvedPath).toLowerCase();
|
|
61054
|
-
const sourcePathWithoutExtension = SOURCE_EXTENSIONS.includes(specifiedExtension) ? unresolvedPath.slice(0, -specifiedExtension.length) : unresolvedPath;
|
|
61055
|
-
return [
|
|
61056
|
-
unresolvedPath,
|
|
61057
|
-
...SOURCE_EXTENSIONS.map((extension) => `${sourcePathWithoutExtension}${extension}`),
|
|
61058
|
-
...sourcePathWithoutExtension === unresolvedPath ? SOURCE_EXTENSIONS.map((extension) => path.join(unresolvedPath, `index${extension}`)) : []
|
|
61059
|
-
].includes(componentRecord.absolutePath);
|
|
61060
|
-
};
|
|
61061
|
-
const getComponentTagNames = (record, component) => {
|
|
61062
|
-
if (record.absolutePath === component.record.absolutePath) return new Set([component.name]);
|
|
61063
|
-
const tagNames = /* @__PURE__ */ new Set();
|
|
61064
|
-
for (const statement of record.sourceFile.statements) {
|
|
61065
|
-
if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier) || !moduleSpecifierTargetsComponent(record, statement.moduleSpecifier.text, component.record)) continue;
|
|
61066
|
-
const importClause = statement.importClause;
|
|
61067
|
-
if (component.isDefaultExport && importClause?.name !== void 0) tagNames.add(importClause.name.text);
|
|
61068
|
-
const namedBindings = importClause?.namedBindings;
|
|
61069
|
-
if (namedBindings !== void 0 && ts.isNamedImports(namedBindings)) {
|
|
61070
|
-
for (const element of namedBindings.elements) if ((element.propertyName?.text ?? element.name.text) === component.name) tagNames.add(element.name.text);
|
|
61071
|
-
}
|
|
61072
|
-
}
|
|
61073
|
-
return tagNames;
|
|
61074
|
-
};
|
|
61075
|
-
const getTransparentCall = (functionNode) => {
|
|
61076
|
-
if (functionNode.body === void 0) return null;
|
|
61077
|
-
if (!ts.isBlock(functionNode.body)) {
|
|
61078
|
-
const expression = unwrapExpression(functionNode.body);
|
|
61079
|
-
return ts.isCallExpression(expression) ? expression : null;
|
|
61080
|
-
}
|
|
61081
|
-
if (functionNode.body.statements.length !== 1) return null;
|
|
61082
|
-
const statement = functionNode.body.statements[0];
|
|
61083
|
-
if (statement === void 0) return null;
|
|
61084
|
-
const expression = ts.isExpressionStatement(statement) || ts.isReturnStatement(statement) ? statement.expression : void 0;
|
|
61085
|
-
if (expression === void 0) return null;
|
|
61086
|
-
const unwrappedExpression = unwrapExpression(expression);
|
|
61087
|
-
return ts.isCallExpression(unwrappedExpression) ? unwrappedExpression : null;
|
|
61088
|
-
};
|
|
61089
|
-
const resolveTransparentTarget = (functionNode) => {
|
|
61090
|
-
const call = getTransparentCall(functionNode);
|
|
61091
|
-
if (call === null) return null;
|
|
61092
|
-
const target = unwrapExpression(call.expression);
|
|
61093
|
-
if (!ts.isIdentifier(target) || call.arguments.length !== functionNode.parameters.length) return null;
|
|
61094
|
-
for (const [parameterIndex, parameter] of functionNode.parameters.entries()) {
|
|
61095
|
-
const argument = call.arguments[parameterIndex];
|
|
61096
|
-
const unwrappedArgument = argument === void 0 ? null : unwrapExpression(argument);
|
|
61097
|
-
if (!ts.isIdentifier(parameter.name) || unwrappedArgument === null || !ts.isIdentifier(unwrappedArgument) || unwrappedArgument.text !== parameter.name.text) return null;
|
|
61098
|
-
}
|
|
61099
|
-
return target.text;
|
|
61100
|
-
};
|
|
61101
|
-
const getForwardingFunction = (declaration) => {
|
|
61102
|
-
if (ts.isFunctionDeclaration(declaration)) return declaration;
|
|
61103
|
-
if (!ts.isVariableDeclaration(declaration) || declaration.initializer === void 0) return null;
|
|
61104
|
-
const initializer = unwrapExpression(declaration.initializer);
|
|
61105
|
-
if (ts.isArrowFunction(initializer) || ts.isFunctionExpression(initializer)) return initializer;
|
|
61106
|
-
if (ts.isCallExpression(initializer) && getCalleeName(initializer.expression) === "useCallback") {
|
|
61107
|
-
const callback = initializer.arguments[0];
|
|
61108
|
-
if (callback !== void 0 && (ts.isArrowFunction(callback) || ts.isFunctionExpression(callback))) return callback;
|
|
61109
|
-
}
|
|
61110
|
-
return null;
|
|
61111
|
-
};
|
|
61112
|
-
const getDeclaredBindingName = (node) => {
|
|
61113
|
-
if ((ts.isVariableDeclaration(node) || ts.isParameter(node) || ts.isBindingElement(node) || ts.isFunctionDeclaration(node)) && node.name !== void 0 && ts.isIdentifier(node.name)) return node.name.text;
|
|
61114
|
-
if (ts.isImportClause(node)) return node.name?.text ?? null;
|
|
61115
|
-
if (ts.isImportSpecifier(node) || ts.isNamespaceImport(node)) return node.name.text;
|
|
61116
|
-
return null;
|
|
61117
|
-
};
|
|
61118
|
-
const findBindingScope = (node) => {
|
|
61119
|
-
let currentNode = node;
|
|
61120
|
-
while (currentNode !== void 0) {
|
|
61121
|
-
if (ts.isParameter(currentNode) && ts.isFunctionLike(currentNode.parent)) return currentNode.parent;
|
|
61122
|
-
if (ts.isBlock(currentNode) || ts.isModuleBlock(currentNode) || ts.isSourceFile(currentNode)) return currentNode;
|
|
61123
|
-
currentNode = currentNode.parent;
|
|
61124
|
-
}
|
|
61125
|
-
return node.getSourceFile();
|
|
61126
|
-
};
|
|
61127
|
-
const findBindingDeclaration = (record, binding) => {
|
|
61128
|
-
const usagePosition = binding.getStart(record.sourceFile);
|
|
61129
|
-
const candidates = [];
|
|
61130
|
-
const visit = (node) => {
|
|
61131
|
-
if (getDeclaredBindingName(node) === binding.text) {
|
|
61132
|
-
const scope = findBindingScope(node);
|
|
61133
|
-
const isVisibleScope = usagePosition >= scope.getStart(record.sourceFile) && usagePosition <= scope.end;
|
|
61134
|
-
const isVisibleDeclaration = ts.isFunctionDeclaration(node) || ts.isParameter(node) || ts.isBindingElement(node) || ts.isImportClause(node) || ts.isImportSpecifier(node) || ts.isNamespaceImport(node) || node.getStart(record.sourceFile) < usagePosition;
|
|
61135
|
-
if (isVisibleScope && isVisibleDeclaration) candidates.push({
|
|
61136
|
-
declaration: node,
|
|
61137
|
-
scope
|
|
61138
|
-
});
|
|
61139
|
-
}
|
|
61140
|
-
ts.forEachChild(node, visit);
|
|
61141
|
-
};
|
|
61142
|
-
visit(record.sourceFile);
|
|
61143
|
-
let nearestCandidate = null;
|
|
61144
|
-
let nearestScopeWidth = Number.POSITIVE_INFINITY;
|
|
61145
|
-
let isNearestScopeAmbiguous = false;
|
|
61146
|
-
for (const candidate of candidates) {
|
|
61147
|
-
const scopeWidth = candidate.scope.end - candidate.scope.getStart(record.sourceFile);
|
|
61148
|
-
if (scopeWidth < nearestScopeWidth) {
|
|
61149
|
-
nearestCandidate = candidate;
|
|
61150
|
-
nearestScopeWidth = scopeWidth;
|
|
61151
|
-
isNearestScopeAmbiguous = false;
|
|
61152
|
-
} else if (scopeWidth === nearestScopeWidth) isNearestScopeAmbiguous = true;
|
|
61153
|
-
}
|
|
61154
|
-
if (isNearestScopeAmbiguous) return null;
|
|
61155
|
-
const declaration = nearestCandidate?.declaration;
|
|
61156
|
-
return declaration !== void 0 && (ts.isVariableDeclaration(declaration) || ts.isFunctionDeclaration(declaration)) ? declaration : null;
|
|
61157
|
-
};
|
|
61158
|
-
const resolveHandlerBinding = (record, binding) => {
|
|
61159
|
-
const declaration = findBindingDeclaration(record, binding);
|
|
61160
|
-
if (declaration === null) return binding.text;
|
|
61161
|
-
const forwardingFunction = getForwardingFunction(declaration);
|
|
61162
|
-
const target = forwardingFunction === null ? null : resolveTransparentTarget(forwardingFunction);
|
|
61163
|
-
return target === null || target === binding.text ? binding.text : target;
|
|
61164
|
-
};
|
|
61165
|
-
const getJsxTagName = (node) => ts.isIdentifier(node.tagName) ? node.tagName.text : null;
|
|
61166
|
-
const getHandlerBinding = (node, propName) => {
|
|
61167
|
-
for (const property of node.attributes.properties) {
|
|
61168
|
-
if (!ts.isJsxAttribute(property) || property.name.getText() !== propName) continue;
|
|
61169
|
-
const initializer = property.initializer;
|
|
61170
|
-
if (initializer === void 0 || !ts.isJsxExpression(initializer)) return null;
|
|
61171
|
-
if (initializer.expression === void 0) return null;
|
|
61172
|
-
const expression = unwrapExpression(initializer.expression);
|
|
61173
|
-
return ts.isIdentifier(expression) ? expression : null;
|
|
61174
|
-
}
|
|
61175
|
-
return null;
|
|
61176
|
-
};
|
|
61177
|
-
const getForwardedHandlerAliases = (rootDirectory, component, propNames, state) => {
|
|
61178
|
-
const cacheKey = `${component.record.filePath}\0${component.name}\0${[...propNames].sort().join("\0")}`;
|
|
61179
|
-
const cachedAliases = state.aliasesByComponent.get(cacheKey);
|
|
61180
|
-
if (cachedAliases !== void 0) return cachedAliases;
|
|
61181
|
-
const bindingsByPropName = /* @__PURE__ */ new Map();
|
|
61182
|
-
const unresolvedPropNames = /* @__PURE__ */ new Set();
|
|
61183
|
-
let callsiteCount = 0;
|
|
61184
|
-
for (const record of listSourceRecords(rootDirectory, state)) {
|
|
61185
|
-
const tagNames = getComponentTagNames(record, component);
|
|
61186
|
-
if (tagNames.size === 0) continue;
|
|
61187
|
-
const visit = (node) => {
|
|
61188
|
-
if (record === component.record && node === component.node) return;
|
|
61189
|
-
if (ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) {
|
|
61190
|
-
const tagName = getJsxTagName(node);
|
|
61191
|
-
if (tagName !== null && tagNames.has(tagName)) {
|
|
61192
|
-
callsiteCount += 1;
|
|
61193
|
-
for (const propName of propNames) {
|
|
61194
|
-
const binding = getHandlerBinding(node, propName);
|
|
61195
|
-
if (binding === null) {
|
|
61196
|
-
unresolvedPropNames.add(propName);
|
|
61197
|
-
continue;
|
|
61198
|
-
}
|
|
61199
|
-
const bindings = bindingsByPropName.get(propName) ?? /* @__PURE__ */ new Set();
|
|
61200
|
-
bindings.add(resolveHandlerBinding(record, binding));
|
|
61201
|
-
bindingsByPropName.set(propName, bindings);
|
|
61202
|
-
}
|
|
61203
|
-
}
|
|
61204
|
-
}
|
|
61205
|
-
ts.forEachChild(node, visit);
|
|
61206
|
-
};
|
|
61207
|
-
visit(record.sourceFile);
|
|
61208
|
-
}
|
|
61209
|
-
const aliases = /* @__PURE__ */ new Map();
|
|
61210
|
-
if (callsiteCount > 0) for (const [propName, bindings] of bindingsByPropName) {
|
|
61211
|
-
if (bindings.size !== 1 || unresolvedPropNames.has(propName)) continue;
|
|
61212
|
-
const [bindingName] = bindings;
|
|
61213
|
-
if (bindingName !== void 0) aliases.set(propName, bindingName);
|
|
61214
|
-
}
|
|
61215
|
-
state.aliasesByComponent.set(cacheKey, aliases);
|
|
61216
|
-
return aliases;
|
|
61217
|
-
};
|
|
61218
|
-
const normalizeForwardedHandlers = (evidence, aliases) => {
|
|
61219
|
-
let normalizedEvidence = evidence;
|
|
61220
|
-
for (const [propName, bindingName] of aliases) normalizedEvidence = normalizedEvidence.replace(new RegExp(`\\{\\s*${propName}\\s*\\}`, "g"), `{${bindingName}}`).replace(new RegExp(`=>\\s*${propName}\\s*\\(`, "g"), `=> ${bindingName}(`);
|
|
61221
|
-
return normalizedEvidence;
|
|
61222
|
-
};
|
|
61223
|
-
const createDiagnosticEvidenceReader = (rootDirectory, options = {}) => {
|
|
61224
|
-
const state = {
|
|
61225
|
-
aliasesByComponent: /* @__PURE__ */ new Map(),
|
|
61226
|
-
recordByFilePath: /* @__PURE__ */ new Map(),
|
|
61227
|
-
sourceRecords: null
|
|
61228
|
-
};
|
|
61229
|
-
return (diagnostic) => {
|
|
61230
|
-
const record = readSourceRecord(rootDirectory, diagnostic.filePath, state);
|
|
61231
|
-
if (record === null || !Number.isInteger(diagnostic.line)) return null;
|
|
61232
|
-
const sourceLines = record.sourceText.split(/\r?\n/);
|
|
61233
|
-
const startLineIndex = Math.max(0, diagnostic.line - 1);
|
|
61234
|
-
const endLineIndex = Math.max(startLineIndex, (diagnostic.endLine ?? diagnostic.line) - 1);
|
|
61235
|
-
const evidence = sourceLines.slice(startLineIndex, endLineIndex + 1).join("\n");
|
|
61236
|
-
if (!options.resolveForwardedHandlers) return evidence;
|
|
61237
|
-
const propNames = new Set(evidence.match(/\bon[A-Z]\w*\b/g) ?? []);
|
|
61238
|
-
if (propNames.size === 0) return evidence;
|
|
61239
|
-
const component = findEnclosingComponent(record, diagnostic);
|
|
61240
|
-
if (component === null) return evidence;
|
|
61241
|
-
return normalizeForwardedHandlers(evidence, getForwardedHandlerAliases(rootDirectory, component, propNames, state));
|
|
61242
|
-
};
|
|
61243
|
-
};
|
|
61244
|
-
//#endregion
|
|
61245
60404
|
//#region src/cli/utils/build-no-score-message.ts
|
|
61246
60405
|
const ENTERPRISE_CONTACT_HINT = `Want something custom to your company? Contact us at ${ENTERPRISE_CONTACT_URL}.`;
|
|
61247
|
-
const buildNoScoreMessage = (isScoreDisabled
|
|
61248
|
-
return `${isScoreDisabled ?
|
|
60406
|
+
const buildNoScoreMessage = (isScoreDisabled) => {
|
|
60407
|
+
return `${isScoreDisabled ? "Score disabled by --no-score." : "Score unavailable (could not reach the score API)."} ${ENTERPRISE_CONTACT_HINT}`;
|
|
61249
60408
|
};
|
|
61250
60409
|
//#endregion
|
|
61251
60410
|
//#region src/cli/utils/render-agent-guidance.ts
|
|
@@ -62370,47 +61529,40 @@ const buildChangedLineMatcher = (directory, changedLineRanges) => {
|
|
|
62370
61529
|
return diagnosticIntersectsLineRanges(diagnostic, ranges);
|
|
62371
61530
|
};
|
|
62372
61531
|
};
|
|
62373
|
-
const buildIgnoredTags = (userConfig
|
|
61532
|
+
const buildIgnoredTags = (userConfig) => {
|
|
62374
61533
|
const tags = /* @__PURE__ */ new Set();
|
|
62375
61534
|
if (userConfig?.ignore?.tags) for (const tag of userConfig.ignore.tags) tags.add(tag);
|
|
62376
|
-
for (const tag of includedTags) tags.delete(tag);
|
|
62377
61535
|
return tags;
|
|
62378
61536
|
};
|
|
62379
|
-
const mergeInspectOptions = (inputOptions, userConfig) => {
|
|
62380
|
-
|
|
62381
|
-
|
|
62382
|
-
|
|
62383
|
-
|
|
62384
|
-
|
|
62385
|
-
|
|
62386
|
-
|
|
62387
|
-
|
|
62388
|
-
|
|
62389
|
-
|
|
62390
|
-
|
|
62391
|
-
|
|
62392
|
-
|
|
62393
|
-
|
|
62394
|
-
|
|
62395
|
-
|
|
62396
|
-
|
|
62397
|
-
|
|
62398
|
-
|
|
62399
|
-
|
|
62400
|
-
|
|
62401
|
-
|
|
62402
|
-
|
|
62403
|
-
|
|
62404
|
-
|
|
62405
|
-
|
|
62406
|
-
|
|
62407
|
-
|
|
62408
|
-
maxDurationMs: inputOptions.maxDurationMs ?? null,
|
|
62409
|
-
baseline: inputOptions.baseline ?? null,
|
|
62410
|
-
changedLineRanges: inputOptions.changedLineRanges ?? null,
|
|
62411
|
-
supplyChainManifestChanged: inputOptions.supplyChainManifestChanged ?? false
|
|
62412
|
-
};
|
|
62413
|
-
};
|
|
61537
|
+
const mergeInspectOptions = (inputOptions, userConfig) => ({
|
|
61538
|
+
lint: inputOptions.lint ?? userConfig?.lint ?? true,
|
|
61539
|
+
deadCode: inputOptions.deadCode ?? userConfig?.deadCode ?? true,
|
|
61540
|
+
supplyChain: inputOptions.supplyChain ?? userConfig?.supplyChain?.enabled ?? true,
|
|
61541
|
+
verbose: inputOptions.verbose ?? userConfig?.verbose ?? false,
|
|
61542
|
+
outputDirectory: inputOptions.outputDirectory || null,
|
|
61543
|
+
scoreOnly: inputOptions.scoreOnly ?? false,
|
|
61544
|
+
noScore: inputOptions.noScore ?? userConfig?.noScore ?? false,
|
|
61545
|
+
isCi: inputOptions.isCi ?? false,
|
|
61546
|
+
isCiOrCodingAgentEnvironment: isCiOrCodingAgentEnvironment(),
|
|
61547
|
+
isNonInteractiveEnvironment: isNonInteractiveEnvironment(),
|
|
61548
|
+
silent: inputOptions.silent ?? false,
|
|
61549
|
+
includePaths: inputOptions.includePaths ?? [],
|
|
61550
|
+
customRulesOnly: userConfig?.customRulesOnly ?? false,
|
|
61551
|
+
share: userConfig?.share ?? true,
|
|
61552
|
+
respectInlineDisables: inputOptions.respectInlineDisables ?? userConfig?.respectInlineDisables ?? true,
|
|
61553
|
+
warnings: inputOptions.warnings ?? userConfig?.warnings ?? true,
|
|
61554
|
+
categoryFilters: new Set(resolveCliCategories(inputOptions.categoryFilters) ?? []),
|
|
61555
|
+
adoptExistingLintConfig: userConfig?.adoptExistingLintConfig ?? true,
|
|
61556
|
+
ignoredTags: buildIgnoredTags(userConfig),
|
|
61557
|
+
outputSurface: inputOptions.outputSurface ?? "cli",
|
|
61558
|
+
suppressRendering: inputOptions.suppressRendering ?? false,
|
|
61559
|
+
concurrentScan: inputOptions.concurrentScan ?? false,
|
|
61560
|
+
concurrency: inputOptions.concurrency,
|
|
61561
|
+
maxDurationMs: inputOptions.maxDurationMs ?? null,
|
|
61562
|
+
baseline: inputOptions.baseline ?? null,
|
|
61563
|
+
changedLineRanges: inputOptions.changedLineRanges ?? null,
|
|
61564
|
+
supplyChainManifestChanged: inputOptions.supplyChainManifestChanged ?? false
|
|
61565
|
+
});
|
|
62414
61566
|
const deriveScope = (options) => {
|
|
62415
61567
|
if (options.baseline) return "changed";
|
|
62416
61568
|
if (options.changedLineRanges !== null) return "lines";
|
|
@@ -62492,8 +61644,6 @@ const runBaselineComparison = async (params) => {
|
|
|
62492
61644
|
directory: params.directory,
|
|
62493
61645
|
ref: params.baselineRef,
|
|
62494
61646
|
files: params.options.includePaths,
|
|
62495
|
-
baseFiles: params.baseFiles,
|
|
62496
|
-
headFiles: params.headFiles,
|
|
62497
61647
|
tempDirectory
|
|
62498
61648
|
}).catch((error) => {
|
|
62499
61649
|
rmSync(tempDirectory, {
|
|
@@ -62502,24 +61652,7 @@ const runBaselineComparison = async (params) => {
|
|
|
62502
61652
|
});
|
|
62503
61653
|
throw error;
|
|
62504
61654
|
});
|
|
62505
|
-
if (snapshot === null) {
|
|
62506
|
-
rmSync(tempDirectory, {
|
|
62507
|
-
recursive: true,
|
|
62508
|
-
force: true
|
|
62509
|
-
});
|
|
62510
|
-
return null;
|
|
62511
|
-
}
|
|
62512
61655
|
try {
|
|
62513
|
-
if (!snapshot.isComplete) return null;
|
|
62514
|
-
const analyzedHeadFiles = new Set(params.headAnalyzedFiles.map(toForwardSlashes));
|
|
62515
|
-
const baseFiles = new Set(snapshot.baseFiles.map(toForwardSlashes));
|
|
62516
|
-
const trackedHeadFiles = new Set(snapshot.headFiles.map(toForwardSlashes));
|
|
62517
|
-
const expectedHeadFiles = new Set(trackedHeadFiles);
|
|
62518
|
-
for (const filePath of params.options.includePaths) {
|
|
62519
|
-
const normalizedFilePath = toForwardSlashes(filePath);
|
|
62520
|
-
if (!baseFiles.has(normalizedFilePath)) expectedHeadFiles.add(normalizedFilePath);
|
|
62521
|
-
}
|
|
62522
|
-
if (filterSourceFiles([...expectedHeadFiles]).some((filePath) => !analyzedHeadFiles.has(filePath))) return null;
|
|
62523
61656
|
const baseLayers = buildRuntimeLayers({
|
|
62524
61657
|
directory: snapshot.tempDirectory,
|
|
62525
61658
|
hasConfigOverride: true,
|
|
@@ -62535,14 +61668,12 @@ const runBaselineComparison = async (params) => {
|
|
|
62535
61668
|
});
|
|
62536
61669
|
const baseOutput = await runPromise(restoreLegacyThrow(runInspect({
|
|
62537
61670
|
directory: snapshot.tempDirectory,
|
|
62538
|
-
includePaths:
|
|
61671
|
+
includePaths: params.options.includePaths,
|
|
62539
61672
|
customRulesOnly: params.options.customRulesOnly,
|
|
62540
61673
|
respectInlineDisables: params.options.respectInlineDisables,
|
|
62541
61674
|
warnings: params.options.warnings,
|
|
62542
61675
|
adoptExistingLintConfig: params.options.adoptExistingLintConfig,
|
|
62543
61676
|
ignoredTags: params.options.ignoredTags,
|
|
62544
|
-
includedTags: params.options.includedTags,
|
|
62545
|
-
includeTagDefaults: params.options.includeTagDefaults,
|
|
62546
61677
|
nodeBinaryPath: params.resolvedNodeBinaryPath ?? void 0,
|
|
62547
61678
|
runDeadCode: false,
|
|
62548
61679
|
isCi: params.options.isCi,
|
|
@@ -62554,22 +61685,18 @@ const runBaselineComparison = async (params) => {
|
|
|
62554
61685
|
deadlineEpochMs: params.deadlineEpochMs ?? void 0
|
|
62555
61686
|
}, {}).pipe(provide(baseLayers), provideService$2(PerFileLintCacheEnabled, false), provideService$2(SidecarLintCacheEnabled, false), provideService$2(Console, silentConsole))));
|
|
62556
61687
|
if (baseOutput.didLintFail || countIncompleteLintFiles(baseOutput.lintPartialFailures) > 0) return null;
|
|
62557
|
-
const hasUnscannedUntrackedSourceFiles = filterSourceFiles(snapshot.untrackedFiles.map(toForwardSlashes)).some((filePath) => !analyzedHeadFiles.has(filePath));
|
|
62558
61688
|
const delta = computeDiagnosticDelta({
|
|
62559
61689
|
headDiagnostics: params.headDiagnostics,
|
|
62560
61690
|
baseDiagnostics: baseOutput.diagnostics,
|
|
62561
61691
|
readHeadLine: createSourceLineReader(params.directory),
|
|
62562
|
-
readBaseLine: createSourceLineReader(snapshot.tempDirectory)
|
|
62563
|
-
readHeadEvidence: createDiagnosticEvidenceReader(params.directory, { resolveForwardedHandlers: true }),
|
|
62564
|
-
readBaseEvidence: createDiagnosticEvidenceReader(snapshot.tempDirectory)
|
|
61692
|
+
readBaseLine: createSourceLineReader(snapshot.tempDirectory)
|
|
62565
61693
|
});
|
|
62566
61694
|
return {
|
|
62567
61695
|
displayDiagnostics: delta.newDiagnostics,
|
|
62568
61696
|
baselineDelta: {
|
|
62569
61697
|
baseRef: params.baselineRef,
|
|
62570
|
-
fixedCount:
|
|
62571
|
-
baseTotalCount: baseOutput.diagnostics.length
|
|
62572
|
-
crossFileMatchCount: delta.crossFileMatchCount
|
|
61698
|
+
fixedCount: delta.fixedCount,
|
|
61699
|
+
baseTotalCount: baseOutput.diagnostics.length
|
|
62573
61700
|
}
|
|
62574
61701
|
};
|
|
62575
61702
|
} finally {
|
|
@@ -62636,8 +61763,6 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
|
|
|
62636
61763
|
warnings: options.warnings,
|
|
62637
61764
|
adoptExistingLintConfig: options.adoptExistingLintConfig,
|
|
62638
61765
|
ignoredTags: options.ignoredTags,
|
|
62639
|
-
includedTags: options.includedTags,
|
|
62640
|
-
includeTagDefaults: options.includeTagDefaults,
|
|
62641
61766
|
nodeBinaryPath: resolvedNodeBinaryPath ?? void 0,
|
|
62642
61767
|
runDeadCode: options.deadCode,
|
|
62643
61768
|
isCi: options.isCi,
|
|
@@ -62678,9 +61803,6 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
|
|
|
62678
61803
|
headDiagnostics: output.diagnostics,
|
|
62679
61804
|
resolvedNodeBinaryPath,
|
|
62680
61805
|
baselineRef: options.baseline.ref,
|
|
62681
|
-
baseFiles: options.baseline.baseFiles,
|
|
62682
|
-
headFiles: options.baseline.headFiles,
|
|
62683
|
-
headAnalyzedFiles: output.analyzedFiles,
|
|
62684
61806
|
deadlineEpochMs
|
|
62685
61807
|
});
|
|
62686
61808
|
if (comparison) {
|
|
@@ -62826,7 +61948,7 @@ const finalizeAndRender = (input) => gen(function* () {
|
|
|
62826
61948
|
securityScanFailed
|
|
62827
61949
|
});
|
|
62828
61950
|
const hasSkippedChecks = skippedChecks.length > 0;
|
|
62829
|
-
const noScoreMessage = buildNoScoreMessage(options.noScore
|
|
61951
|
+
const noScoreMessage = buildNoScoreMessage(options.noScore);
|
|
62830
61952
|
const buildResult = () => ({
|
|
62831
61953
|
diagnostics: [...diagnostics],
|
|
62832
61954
|
score,
|
|
@@ -64931,25 +64053,21 @@ const resolveParallelFlag = (parallel) => parallel === false ? 1 : void 0;
|
|
|
64931
64053
|
*/
|
|
64932
64054
|
const resolveCliInspectOptions = (flags, userConfig) => {
|
|
64933
64055
|
const wantsWarningGate = pickBlockingLevel(flags, userConfig) === "warning";
|
|
64934
|
-
const isDesignScan = flags.design === true;
|
|
64935
64056
|
return {
|
|
64936
64057
|
lint: flags.lint,
|
|
64937
|
-
deadCode:
|
|
64938
|
-
supplyChain:
|
|
64058
|
+
deadCode: flags.deadCode,
|
|
64059
|
+
supplyChain: flags.supplyChain,
|
|
64939
64060
|
verbose: flags.verbose,
|
|
64940
64061
|
outputDirectory: flags.outputDir,
|
|
64941
64062
|
respectInlineDisables: flags.respectInlineDisables === false ? false : void 0,
|
|
64942
64063
|
warnings: wantsWarningGate ? true : flags.warnings,
|
|
64943
64064
|
scoreOnly: flags.score === true,
|
|
64944
|
-
noScore:
|
|
64065
|
+
noScore: flags.score === false || flags.telemetry === false ? true : void 0,
|
|
64945
64066
|
isCi: isCiEnvironment(),
|
|
64946
64067
|
silent: Boolean(flags.json),
|
|
64947
64068
|
concurrency: resolveParallelFlag(flags.parallel),
|
|
64948
64069
|
maxDurationMs: resolveMaxDurationFlag(flags.maxDuration),
|
|
64949
|
-
categoryFilters: resolveCliCategories(flags.category)
|
|
64950
|
-
includedTags: isDesignScan ? new Set(["design"]) : void 0,
|
|
64951
|
-
includeTagDefaults: isDesignScan ? true : void 0,
|
|
64952
|
-
scoreDisabledMessage: isDesignScan ? "Design scans do not affect the React health score." : void 0
|
|
64070
|
+
categoryFilters: resolveCliCategories(flags.category)
|
|
64953
64071
|
};
|
|
64954
64072
|
};
|
|
64955
64073
|
//#endregion
|
|
@@ -64969,25 +64087,20 @@ const resolveProjectRelativeDirectory = (rootDirectory, projectDirectory) => {
|
|
|
64969
64087
|
return relativeProjectDirectory;
|
|
64970
64088
|
};
|
|
64971
64089
|
//#endregion
|
|
64972
|
-
//#region src/cli/utils/resolve-project-
|
|
64973
|
-
const
|
|
64090
|
+
//#region src/cli/utils/resolve-project-diff-include-paths.ts
|
|
64091
|
+
const resolveProjectDiffIncludePaths = (rootDirectory, projectDirectory, diffInfo) => {
|
|
64974
64092
|
const relativeProjectDirectory = resolveProjectRelativeDirectory(rootDirectory, projectDirectory);
|
|
64975
64093
|
if (relativeProjectDirectory === null) return [];
|
|
64976
|
-
const
|
|
64977
|
-
if (relativeProjectDirectory.length === 0) return
|
|
64094
|
+
const changedSourceFiles = filterSourceFiles(diffInfo.changedFiles);
|
|
64095
|
+
if (relativeProjectDirectory.length === 0) return changedSourceFiles;
|
|
64978
64096
|
const projectPrefix = `${relativeProjectDirectory}/`;
|
|
64979
|
-
return
|
|
64097
|
+
return changedSourceFiles.flatMap((filePath) => {
|
|
64980
64098
|
const normalizedFilePath = toForwardSlashes(filePath);
|
|
64981
64099
|
if (!normalizedFilePath.startsWith(projectPrefix)) return [];
|
|
64982
64100
|
const projectRelativePath = normalizedFilePath.slice(projectPrefix.length);
|
|
64983
64101
|
return projectRelativePath.length > 0 ? [projectRelativePath] : [];
|
|
64984
64102
|
});
|
|
64985
64103
|
};
|
|
64986
|
-
//#endregion
|
|
64987
|
-
//#region src/cli/utils/resolve-project-diff-include-paths.ts
|
|
64988
|
-
const resolveProjectDiffIncludePaths = (rootDirectory, projectDirectory, diffInfo) => {
|
|
64989
|
-
return resolveProjectSourceFilePaths(rootDirectory, projectDirectory, diffInfo.changedFiles);
|
|
64990
|
-
};
|
|
64991
64104
|
/**
|
|
64992
64105
|
* Re-keys repo-relative changed line ranges (from `getChangedLineRanges`) to
|
|
64993
64106
|
* the scanned project, mirroring `resolveProjectDiffIncludePaths`'s boundary
|
|
@@ -65367,7 +64480,7 @@ const maybeMigrateLegacyConfig = async (requestedDirectory, { isQuiet, isStaged
|
|
|
65367
64480
|
if (!(!isQuiet && !isStaged && process.stdout.isTTY === true && !isCiOrCodingAgentEnvironment())) return;
|
|
65368
64481
|
await runProjectMigrations(requestedDirectory);
|
|
65369
64482
|
};
|
|
65370
|
-
const inspectAction = async (directory, flags
|
|
64483
|
+
const inspectAction = async (directory, flags) => {
|
|
65371
64484
|
const isScoreOnly = Boolean(flags.score);
|
|
65372
64485
|
const isJsonMode = Boolean(flags.json);
|
|
65373
64486
|
const isQuiet = isScoreOnly || isJsonMode;
|
|
@@ -65381,7 +64494,7 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
|
|
|
65381
64494
|
});
|
|
65382
64495
|
if (flags.jsonOut) recordCount(METRIC.jsonOutUsed, 1);
|
|
65383
64496
|
}
|
|
65384
|
-
recordCount(METRIC.cliInvoked, 1, { command:
|
|
64497
|
+
recordCount(METRIC.cliInvoked, 1, { command: "inspect" });
|
|
65385
64498
|
try {
|
|
65386
64499
|
validateModeFlags(flags);
|
|
65387
64500
|
if (flags.staged) setJsonReportMode("staged");
|
|
@@ -65526,7 +64639,6 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
|
|
|
65526
64639
|
const isDiffMode = scope !== "full";
|
|
65527
64640
|
const comparisonBaseRef = isDiffMode && diffInfo && !diffInfo.isCurrentChanges ? diffInfo.baseSha ? await resolveMergeBaseRef(resolvedDirectory, diffInfo.baseSha) : diffInfo.diffBaseRef ?? await resolveMergeBaseRef(resolvedDirectory, diffInfo.baseBranch) : null;
|
|
65528
64641
|
const baselineRef = scope === "changed" ? comparisonBaseRef : null;
|
|
65529
|
-
const baselineDiffPlan = baselineRef === null ? null : await getBaselineDiffPlan(resolvedDirectory, baselineRef);
|
|
65530
64642
|
const linesBaseRef = diffInfo?.isCurrentChanges ? "HEAD" : comparisonBaseRef;
|
|
65531
64643
|
const changedLineRanges = scope === "lines" && diffInfo !== null && (diffInfo.isCurrentChanges || linesBaseRef !== null) && diffInfo !== null ? await getChangedLineRanges({
|
|
65532
64644
|
directory: resolvedDirectory,
|
|
@@ -65557,13 +64669,10 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
|
|
|
65557
64669
|
const supplyChainEnabled = flags.supplyChain ?? projectConfig?.supplyChain?.enabled !== false;
|
|
65558
64670
|
let includePaths;
|
|
65559
64671
|
let supplyChainManifestChanged = false;
|
|
65560
|
-
const projectBaselineBaseFiles = baselineDiffPlan === null ? null : resolveProjectSourceFilePaths(resolvedDirectory, scanDirectory, baselineDiffPlan.baseFiles);
|
|
65561
|
-
const projectBaselineHeadFiles = baselineDiffPlan === null ? null : resolveProjectSourceFilePaths(resolvedDirectory, scanDirectory, baselineDiffPlan.headFiles);
|
|
65562
64672
|
if (isDiffMode) {
|
|
65563
64673
|
const changedSourceFiles = diffInfo === null ? [] : resolveProjectDiffIncludePaths(resolvedDirectory, scanDirectory, diffInfo);
|
|
65564
64674
|
supplyChainManifestChanged = supplyChainEnabled && diffInfo !== null && projectManifestChanged(resolvedDirectory, scanDirectory, diffInfo);
|
|
65565
|
-
|
|
65566
|
-
if (changedSourceFiles.length === 0 && !supplyChainManifestChanged && !hasBaselineOnlyFiles) {
|
|
64675
|
+
if (changedSourceFiles.length === 0 && !supplyChainManifestChanged) {
|
|
65567
64676
|
if (!isQuiet) {
|
|
65568
64677
|
cliLogger.dim(`No changed source files in ${scanDirectory}, skipping.`);
|
|
65569
64678
|
cliLogger.break();
|
|
@@ -65571,7 +64680,6 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
|
|
|
65571
64680
|
return null;
|
|
65572
64681
|
}
|
|
65573
64682
|
includePaths = [...changedSourceFiles];
|
|
65574
|
-
if (includePaths.length === 0 && hasBaselineOnlyFiles) includePaths.push(...projectBaselineBaseFiles ?? []);
|
|
65575
64683
|
if (supplyChainManifestChanged) includePaths.push("package.json");
|
|
65576
64684
|
}
|
|
65577
64685
|
if (!isQuiet && !isMultiProject) cliLogger.dim(" ");
|
|
@@ -65583,11 +64691,7 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
|
|
|
65583
64691
|
configSourceDirectory: projectConfigSourceDirectory ?? void 0,
|
|
65584
64692
|
suppressRendering: isMultiProject,
|
|
65585
64693
|
concurrentScan: isMultiProject,
|
|
65586
|
-
baseline: baselineRef
|
|
65587
|
-
ref: baselineRef,
|
|
65588
|
-
baseFiles: projectBaselineBaseFiles,
|
|
65589
|
-
headFiles: projectBaselineHeadFiles
|
|
65590
|
-
} : void 0,
|
|
64694
|
+
baseline: baselineRef ? { ref: baselineRef } : void 0,
|
|
65591
64695
|
changedLineRanges: scope === "lines" && changedLineRanges !== null ? resolveProjectChangedLineRanges(resolvedDirectory, scanDirectory, changedLineRanges) : void 0,
|
|
65592
64696
|
supplyChainManifestChanged
|
|
65593
64697
|
});
|
|
@@ -65693,13 +64797,6 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
|
|
|
65693
64797
|
}
|
|
65694
64798
|
};
|
|
65695
64799
|
//#endregion
|
|
65696
|
-
//#region src/cli/commands/design.ts
|
|
65697
|
-
const designAction = async (directory, flags) => inspectAction(directory, {
|
|
65698
|
-
...flags,
|
|
65699
|
-
design: true,
|
|
65700
|
-
lint: flags.lint ?? true
|
|
65701
|
-
}, "design");
|
|
65702
|
-
//#endregion
|
|
65703
64800
|
//#region src/cli/commands/install.ts
|
|
65704
64801
|
const installAction = async (options, command) => {
|
|
65705
64802
|
recordCount(METRIC.cliInvoked, 1, { command: "install" });
|
|
@@ -66536,7 +65633,6 @@ const INSTALL_FLAG_SPEC = {
|
|
|
66536
65633
|
shortOptionsWithRequiredValues: new Set(["-c"])
|
|
66537
65634
|
};
|
|
66538
65635
|
const COMMAND_FLAG_SPECS = new Map([
|
|
66539
|
-
["design", ROOT_FLAG_SPEC],
|
|
66540
65636
|
["install", INSTALL_FLAG_SPEC],
|
|
66541
65637
|
["setup", INSTALL_FLAG_SPEC],
|
|
66542
65638
|
["version", {
|
|
@@ -66693,7 +65789,6 @@ ${formatExampleLines([
|
|
|
66693
65789
|
["react-doctor --scope changed --base main", "scan only new issues vs. main"],
|
|
66694
65790
|
["react-doctor --project modules/a,modules/b", "score each module separately (names or paths)"],
|
|
66695
65791
|
["react-doctor --staged", "scan staged files (pre-commit hook)"],
|
|
66696
|
-
["react-doctor design", "run the focused UI design audit"],
|
|
66697
65792
|
["react-doctor --category Security", "show only one diagnostic category"],
|
|
66698
65793
|
["react-doctor --blocking warning", "fail CI on warnings too (default: error)"],
|
|
66699
65794
|
["react-doctor --json > report.json", "write a machine-readable report"],
|
|
@@ -66727,20 +65822,6 @@ ${highlighter.dim("Managing CI:")}
|
|
|
66727
65822
|
${highlighter.dim("Learn more:")}
|
|
66728
65823
|
${highlighter.info(CANONICAL_GITHUB_URL)}
|
|
66729
65824
|
`;
|
|
66730
|
-
const renderDesignHelpEpilog = () => `
|
|
66731
|
-
${highlighter.dim("Examples:")}
|
|
66732
|
-
${formatExampleLines([
|
|
66733
|
-
["react-doctor design", "audit UI design in the current project"],
|
|
66734
|
-
["react-doctor design ./apps/web", "audit one application"],
|
|
66735
|
-
["react-doctor design --verbose", "show every design finding"],
|
|
66736
|
-
["react-doctor design --json", "write a design-only JSON report"]
|
|
66737
|
-
])}
|
|
66738
|
-
|
|
66739
|
-
${highlighter.dim("Scope:")}
|
|
66740
|
-
Runs only rules tagged ${highlighter.info("design")}, including focused rules that stay opt-in during a general health scan.
|
|
66741
|
-
Dead-code, supply-chain, external lint-config, custom-plugin, and health-score passes are skipped.
|
|
66742
|
-
Standard scan flags such as ${highlighter.info("--scope")}, ${highlighter.info("--project")}, ${highlighter.info("--verbose")}, and ${highlighter.info("--json")} still work.
|
|
66743
|
-
`;
|
|
66744
65825
|
const renderCiHelpEpilog = () => `
|
|
66745
65826
|
${highlighter.dim("Examples:")}
|
|
66746
65827
|
${formatExampleLines([
|
|
@@ -66762,7 +65843,6 @@ ${highlighter.dim("Learn more:")}
|
|
|
66762
65843
|
const collectCategoryOption = (value, previousValues) => [...previousValues ?? [], value];
|
|
66763
65844
|
const program = new Command().name("react-doctor").description("Diagnose React codebase health").version(VERSION, "-v, --version", "display the version number").argument("[directory]", "project directory to scan", ".").option("--lint", "enable linting").option("--no-lint", "skip linting").option("--dead-code", "enable dead-code analysis (default)").option("--no-dead-code", "skip dead-code analysis (unused files / exports / dependencies, circular imports)").option("--supply-chain", "enable the dependency supply-chain scan (default)").option("--no-supply-chain", "skip the dependency supply-chain scan (Socket.dev dependency health checks)").option("--verbose", "show every rule and per-file details (default shows top 3 rules)").option("--debug", "force a Sentry trace and print its id at the end (paste it into a bug report)").option("--output-dir <dir>", "directory for the full diagnostics dump (default: a temp folder)").option("--score", "output only the score").option("--json", "output a single structured JSON report (suppresses other output)").option("--json-compact", "with --json, emit compact JSON (no indentation)").option("--json-out <path>", "with --json, write the report to a file instead of stdout").option("-y, --yes", "skip prompts, scan all workspace projects").option("--no-parallel", "lint serially with one worker (default: parallel across CPU cores; set the worker count with REACT_DOCTOR_PARALLEL)").option("--project <name>", "select projects: workspace names or directory paths (comma-separated for multiple); overrides the `projects` config field").option("--scope <value>", "how much supported JS/TS source to scan/report: full (default), files, changed (only new issues vs base), or lines (issues whose source spans touch changed lines)").option("--base <ref>", "base git ref for files/changed/lines scope (auto-detected when omitted)").option("--include-untracked", "with --scope files/changed/lines, also scan ordinary untracked files (respects .gitignore)").addOption(new Option("--diff [base]", "[deprecated] alias for --scope changed (pass `false` to force a full scan)").hideHelp()).addOption(new Option("--changed-files-from <file>", "scan source files listed in a newline-delimited changed-files file").hideHelp()).option("--no-score", "skip the score API, the share URL, and crash reporting").addOption(new Option("--category <category>", "only show diagnostics in a category (repeatable; e.g. Security)").argParser(collectCategoryOption)).option("--no-telemetry", "alias for --no-score (skip the score API, share URL, and crash reporting)").option("--staged", "scan only staged (git index) files for pre-commit hooks").option("--max-duration <seconds>", "scan time budget for the whole run, shared across workspace projects: past it, remaining lint batches and dead-code are skipped and partial results are reported (skipped files are listed in the JSON report)").option("--blocking <level>", "severity that fails CI: error (default), warning, or none (advisory)").addOption(new Option("--fail-on <level>", "[deprecated] alias for --blocking <level>").hideHelp()).option("--no-respect-inline-disables", "audit mode: neutralize inline lint suppressions before scanning").option("--warnings", "show warning-severity diagnostics (default)").option("--no-warnings", "hide warning-severity diagnostics (errors only)").option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").addHelpText("after", renderRootHelpEpilog);
|
|
66764
65845
|
program.action(inspectAction);
|
|
66765
|
-
program.command("design [directory]").description("Run only the focused UI design diagnostics").addHelpText("after", renderDesignHelpEpilog).action((directory, _options, command) => designAction(directory ?? ".", command.optsWithGlobals()));
|
|
66766
65846
|
program.command("why <location>").description("Explain why a rule fired (or why a suppression didn't apply) at a file:line").option("--project <name>", "select projects: workspace names or directory paths (comma-separated for multiple)").option("-c, --cwd <cwd>", "working directory", process.cwd()).option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").action((location, options) => whyAction(location, options));
|
|
66767
65847
|
program.command("install").alias("setup").description("Install the react-doctor skill into your coding agents and optional git hook").option("-y, --yes", "skip prompts, install for all detected agents").option("--dry-run", "show what would be installed without writing files").option("--agent-hooks", "install native non-blocking agent hooks for Claude Code and Cursor").option("-c, --cwd <cwd>", "working directory", process.cwd()).option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").addHelpText("after", renderInstallHelpEpilog).action(installAction);
|
|
66768
65848
|
const providerOption = ["--provider <name>", "ci provider: github-actions or gitlab-ci (auto-detected by default)"];
|
|
@@ -66811,4 +65891,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
|
|
|
66811
65891
|
export {};
|
|
66812
65892
|
|
|
66813
65893
|
//# sourceMappingURL=cli.js.map
|
|
66814
|
-
//# debugId=
|
|
65894
|
+
//# debugId=941df082-c8b4-5084-baae-33ec22d4e55f
|