react-doctor 0.5.8-dev.80e3093 → 0.5.8-dev.8232e96
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +575 -410
- package/dist/index.d.ts +12 -0
- package/dist/index.js +265 -227
- package/dist/lsp.js +287 -250
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="62cf4740-7938-5db0-8b80-dc81b60af36a")}catch(e){}}();
|
|
3
3
|
import { r as __toESM$1, t as __commonJSMin$1 } from "./chunk-N93fKeF6.js";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import * as NFS from "node:fs";
|
|
@@ -19364,6 +19364,15 @@ var JsonReportV1 = class extends Class("JsonReportV1")({
|
|
|
19364
19364
|
ok: Boolean$1,
|
|
19365
19365
|
directory: String$1,
|
|
19366
19366
|
mode: JsonReportMode,
|
|
19367
|
+
/**
|
|
19368
|
+
* True when a `changed` (compare) run was intended but the base couldn't be
|
|
19369
|
+
* resolved — a shallow CI checkout with no merge base, or a failed base/head
|
|
19370
|
+
* lint. The report then lists every finding in the changed files (mode
|
|
19371
|
+
* downgrades to `diff`, the `baseline` block is dropped, the CI gate is
|
|
19372
|
+
* skipped) rather than only the ones the change introduced. Absent on a
|
|
19373
|
+
* successful `baseline` run (`schemaVersion: 2`) and on non-compare scopes.
|
|
19374
|
+
*/
|
|
19375
|
+
baselineDegraded: optional(Boolean$1),
|
|
19367
19376
|
diff: NullOr(JsonReportDiffInfo),
|
|
19368
19377
|
projects: ArraySchema(JsonReportProjectEntry),
|
|
19369
19378
|
diagnostics: ArraySchema(Diagnostic),
|
|
@@ -32780,12 +32789,31 @@ const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
|
|
|
32780
32789
|
const MINIFIED_SNIFF_BYTES = 65536;
|
|
32781
32790
|
const GIT_LS_FILES_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
|
|
32782
32791
|
const IGNORED_DIRECTORIES = new Set([
|
|
32792
|
+
".angular",
|
|
32793
|
+
".astro",
|
|
32794
|
+
".cache",
|
|
32795
|
+
".contentlayer",
|
|
32796
|
+
".direnv",
|
|
32797
|
+
".docusaurus",
|
|
32798
|
+
".expo",
|
|
32799
|
+
".firebase",
|
|
32783
32800
|
".git",
|
|
32801
|
+
".gradle",
|
|
32802
|
+
".hg",
|
|
32784
32803
|
".next",
|
|
32785
32804
|
".nuxt",
|
|
32805
|
+
".nx",
|
|
32786
32806
|
".output",
|
|
32807
|
+
".parcel-cache",
|
|
32808
|
+
".serverless",
|
|
32787
32809
|
".svelte-kit",
|
|
32810
|
+
".svn",
|
|
32811
|
+
".terraform",
|
|
32788
32812
|
".turbo",
|
|
32813
|
+
".venv",
|
|
32814
|
+
".vercel",
|
|
32815
|
+
".wrangler",
|
|
32816
|
+
".yarn",
|
|
32789
32817
|
"build",
|
|
32790
32818
|
"coverage",
|
|
32791
32819
|
"dist",
|
|
@@ -32793,6 +32821,119 @@ const IGNORED_DIRECTORIES = new Set([
|
|
|
32793
32821
|
"out",
|
|
32794
32822
|
"storybook-static"
|
|
32795
32823
|
]);
|
|
32824
|
+
const JSX_FILE_PATTERN = /\.(tsx|jsx)$/;
|
|
32825
|
+
const MILLISECONDS_PER_SECOND = 1e3;
|
|
32826
|
+
const SCORE_API_URL = "https://www.react.doctor/api/score";
|
|
32827
|
+
const FETCH_TIMEOUT_MS = 1e4;
|
|
32828
|
+
const GITHUB_VIEWER_PERMISSION_TIMEOUT_MS = 2e3;
|
|
32829
|
+
const SPAWN_ARGS_MAX_LENGTH_CHARS = 24e3;
|
|
32830
|
+
const SPAWN_ARGS_MAX_LENGTH_CHARS_POSIX = 15e5;
|
|
32831
|
+
const SPAWN_ARGS_MAX_LENGTH_CHARS_DARWIN = 8e5;
|
|
32832
|
+
const NODE_VERSION_PROBE_TIMEOUT_MS = 5e3;
|
|
32833
|
+
const PER_WORKER_MEM_BUDGET_BYTES = 1024 * 1024 * 1024;
|
|
32834
|
+
const DEFAULT_BRANCH_CANDIDATES = ["main", "master"];
|
|
32835
|
+
const ADOPTABLE_LINT_CONFIG_FILENAMES = [".oxlintrc.json", ".eslintrc.json"];
|
|
32836
|
+
const GIT_SHOW_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
|
|
32837
|
+
const ES_TARGET_YEAR_BY_NAME = {
|
|
32838
|
+
es3: 1999,
|
|
32839
|
+
es5: 2009,
|
|
32840
|
+
es6: 2015,
|
|
32841
|
+
es2015: 2015,
|
|
32842
|
+
es2016: 2016,
|
|
32843
|
+
es2017: 2017,
|
|
32844
|
+
es2018: 2018,
|
|
32845
|
+
es2019: 2019,
|
|
32846
|
+
es2020: 2020,
|
|
32847
|
+
es2021: 2021,
|
|
32848
|
+
es2022: 2022,
|
|
32849
|
+
es2023: 2023,
|
|
32850
|
+
es2024: 2024,
|
|
32851
|
+
es2025: 2025,
|
|
32852
|
+
esnext: 9999
|
|
32853
|
+
};
|
|
32854
|
+
/**
|
|
32855
|
+
* tsconfig filenames probed when resolving a project's TypeScript
|
|
32856
|
+
* compiler options — the root config first, then a monorepo base config.
|
|
32857
|
+
*/
|
|
32858
|
+
const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
|
|
32859
|
+
/**
|
|
32860
|
+
* Project-config files that `StagedFiles.materialize` copies into
|
|
32861
|
+
* the temp directory alongside staged sources so oxlint resolves
|
|
32862
|
+
* `tsconfig` / `package.json` / lint configs the same way it would
|
|
32863
|
+
* in the working tree. Hoisted out of the staged-files helper so
|
|
32864
|
+
* the constant lives next to the rest of the IO budget knobs.
|
|
32865
|
+
*/
|
|
32866
|
+
const STAGED_FILES_PROJECT_CONFIG_FILENAMES = [
|
|
32867
|
+
"tsconfig.json",
|
|
32868
|
+
"tsconfig.base.json",
|
|
32869
|
+
"package.json",
|
|
32870
|
+
"doctor.config.ts",
|
|
32871
|
+
"doctor.config.mts",
|
|
32872
|
+
"doctor.config.cts",
|
|
32873
|
+
"doctor.config.js",
|
|
32874
|
+
"doctor.config.mjs",
|
|
32875
|
+
"doctor.config.cjs",
|
|
32876
|
+
"doctor.config.json",
|
|
32877
|
+
"doctor.config.jsonc",
|
|
32878
|
+
"oxlint.json",
|
|
32879
|
+
".oxlintrc.json"
|
|
32880
|
+
];
|
|
32881
|
+
const OXLINT_OUTPUT_MAX_BYTES = 50 * 1024 * 1024;
|
|
32882
|
+
const OXLINT_SPAWN_TIMEOUT_MS = 6e4;
|
|
32883
|
+
const NODE_COMPILE_CACHE_DIR_NAME = "node-compile-cache";
|
|
32884
|
+
const DEAD_CODE_WORKER_TIMEOUT_MS = 12e4;
|
|
32885
|
+
const OXLINT_SPLIT_TOTAL_BUDGET_MS = 18e4;
|
|
32886
|
+
const DEAD_CODE_PHASE_TIMEOUT_MS = 15e4;
|
|
32887
|
+
const LINT_PHASE_TIMEOUT_MS = 3e5;
|
|
32888
|
+
const SCAN_TOTAL_DEADLINE_MS = 9e5;
|
|
32889
|
+
const DEAD_CODE_WORKER_MAX_OLD_SPACE_MB = 8192;
|
|
32890
|
+
const DEAD_CODE_WORKER_MEM_BUDGET_BYTES = 2 * 1024 * 1024 * 1024;
|
|
32891
|
+
const DEAD_CODE_TIMEOUT_CEILING_MS = 6e5;
|
|
32892
|
+
const DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS = 3e4;
|
|
32893
|
+
const DEAD_CODE_OVERLAP_PARSE_SHARE = .4;
|
|
32894
|
+
const RECOMMENDED_PNPM_MINIMUM_RELEASE_AGE_MINUTES = 10080;
|
|
32895
|
+
const REACT_SERVER_DOM_PACKAGES = [
|
|
32896
|
+
"react-server-dom-webpack",
|
|
32897
|
+
"react-server-dom-parcel",
|
|
32898
|
+
"react-server-dom-turbopack"
|
|
32899
|
+
];
|
|
32900
|
+
const REACT_BLOG_RSC_ADVISORY_URL = "https://react.dev/blog/2025/12/03/critical-security-vulnerability-in-react-server-components";
|
|
32901
|
+
const VERCEL_NEXTJS_SECURITY_RELEASE_URL = "https://vercel.com/changelog/next-js-may-2026-security-release";
|
|
32902
|
+
const DIAGNOSTIC_CATEGORY_BUCKETS = [
|
|
32903
|
+
"Security",
|
|
32904
|
+
"Bugs",
|
|
32905
|
+
"Performance",
|
|
32906
|
+
"Accessibility",
|
|
32907
|
+
"Maintainability"
|
|
32908
|
+
];
|
|
32909
|
+
const APP_ONLY_RULE_KEYS = new Set([
|
|
32910
|
+
"react-hooks-js/static-components",
|
|
32911
|
+
"react-doctor/no-render-prop-children",
|
|
32912
|
+
"react-doctor/prefer-explicit-variants"
|
|
32913
|
+
]);
|
|
32914
|
+
const COMPILER_CLEANUP_BUCKET = "compiler-cleanup";
|
|
32915
|
+
const COMPILER_CLEANUP_RULE_KEYS = new Set(["react-doctor/react-compiler-no-manual-memoization"]);
|
|
32916
|
+
const ROOT_CAUSE_GROUPABLE_RULE_KEYS = new Set([
|
|
32917
|
+
"react-doctor/no-derived-state",
|
|
32918
|
+
"react-doctor/no-derived-state-effect",
|
|
32919
|
+
"react-doctor/no-derived-useState",
|
|
32920
|
+
"react-doctor/no-adjust-state-on-prop-change",
|
|
32921
|
+
"react-doctor/no-reset-all-state-on-prop-change"
|
|
32922
|
+
]);
|
|
32923
|
+
const MAX_GLOB_PATTERN_LENGTH_CHARS = 1024;
|
|
32924
|
+
const CONFIG_CACHE_TTL_MS = 300 * 1e3;
|
|
32925
|
+
const SOCKET_FREE_PURL_API_BASE = "https://firewall-api.socket.dev/purl";
|
|
32926
|
+
const SOCKET_PACKAGE_PAGE_BASE = "https://socket.dev/npm/package";
|
|
32927
|
+
const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
|
|
32928
|
+
const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
|
|
32929
|
+
const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
|
|
32930
|
+
const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
32931
|
+
const SUPPLY_CHAIN_RULE = "low-supply-chain-score";
|
|
32932
|
+
const SUPPLY_CHAIN_CATEGORY = "Security";
|
|
32933
|
+
const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
|
|
32934
|
+
const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
|
|
32935
|
+
const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
|
|
32936
|
+
const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => IGNORED_DIRECTORIES.has(segment));
|
|
32796
32937
|
const isLintableSourceFile = (filePath) => SOURCE_FILE_PATTERN.test(filePath) && !GENERATED_BUNDLE_FILE_PATTERN.test(filePath);
|
|
32797
32938
|
const isMinifiedSource = (absolutePath) => {
|
|
32798
32939
|
let fileDescriptor;
|
|
@@ -32849,23 +32990,38 @@ const readDirectoryEntries = (directoryPath) => {
|
|
|
32849
32990
|
throw error;
|
|
32850
32991
|
}
|
|
32851
32992
|
};
|
|
32852
|
-
|
|
32853
|
-
let count = 0;
|
|
32993
|
+
function* walkSourceTreeFiles(rootDirectory) {
|
|
32854
32994
|
const stack = [rootDirectory];
|
|
32855
32995
|
while (stack.length > 0) {
|
|
32856
32996
|
const currentDirectory = stack.pop();
|
|
32857
|
-
|
|
32858
|
-
for (const entry of
|
|
32997
|
+
if (currentDirectory === void 0) continue;
|
|
32998
|
+
for (const entry of readDirectoryEntries(currentDirectory)) {
|
|
32999
|
+
const absolutePath = Path.join(currentDirectory, entry.name);
|
|
32859
33000
|
if (entry.isDirectory()) {
|
|
32860
|
-
if (!
|
|
33001
|
+
if (!IGNORED_DIRECTORIES.has(entry.name)) stack.push(absolutePath);
|
|
32861
33002
|
continue;
|
|
32862
33003
|
}
|
|
32863
|
-
if (entry.isFile()
|
|
33004
|
+
if (entry.isFile()) yield {
|
|
33005
|
+
absolutePath,
|
|
33006
|
+
name: entry.name
|
|
33007
|
+
};
|
|
32864
33008
|
}
|
|
32865
33009
|
}
|
|
32866
|
-
|
|
33010
|
+
}
|
|
33011
|
+
const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
|
|
33012
|
+
const entries = [];
|
|
33013
|
+
for (const relativePath of relativePaths) {
|
|
33014
|
+
const absolutePath = Path.resolve(rootDirectory, relativePath);
|
|
33015
|
+
const sizeBytes = statSourceFileSize(absolutePath);
|
|
33016
|
+
if (isLargeMinifiedFile(absolutePath, sizeBytes)) continue;
|
|
33017
|
+
entries.push({
|
|
33018
|
+
path: relativePath,
|
|
33019
|
+
sizeBytes: sizeBytes ?? 0
|
|
33020
|
+
});
|
|
33021
|
+
}
|
|
33022
|
+
return entries;
|
|
32867
33023
|
};
|
|
32868
|
-
const
|
|
33024
|
+
const listSourceFilesViaGit = (rootDirectory) => {
|
|
32869
33025
|
const result = spawnSync("git", [
|
|
32870
33026
|
"ls-files",
|
|
32871
33027
|
"-z",
|
|
@@ -32878,9 +33034,16 @@ const countSourceFilesViaGit = (rootDirectory) => {
|
|
|
32878
33034
|
maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
|
|
32879
33035
|
});
|
|
32880
33036
|
if (result.error || result.status !== 0) return null;
|
|
32881
|
-
return result.stdout.split("\0").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath) && !
|
|
33037
|
+
return result.stdout.split("\0").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath));
|
|
32882
33038
|
};
|
|
32883
|
-
const
|
|
33039
|
+
const listSourceFilesViaFilesystem = (rootDirectory) => {
|
|
33040
|
+
const filePaths = [];
|
|
33041
|
+
for (const { absolutePath, name } of walkSourceTreeFiles(rootDirectory)) if (isLintableSourceFile(name)) filePaths.push(Path.relative(rootDirectory, absolutePath).replace(/\\/g, "/"));
|
|
33042
|
+
return filePaths;
|
|
33043
|
+
};
|
|
33044
|
+
const listSourceFilesWithSize = (rootDirectory) => collectSizedSourceFiles(rootDirectory, (listSourceFilesViaGit(rootDirectory) ?? listSourceFilesViaFilesystem(rootDirectory)).sort());
|
|
33045
|
+
const listSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).map((entry) => entry.path);
|
|
33046
|
+
const countSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).length;
|
|
32884
33047
|
const cachedPackageJsons = /* @__PURE__ */ new Map();
|
|
32885
33048
|
const clearPackageJsonCache = () => {
|
|
32886
33049
|
cachedPackageJsons.clear();
|
|
@@ -33689,118 +33852,6 @@ const resolveEffectiveReactMajor = (reactVersion, packageJson) => {
|
|
|
33689
33852
|
if (peerFloor === null) return hasUpperBoundOnlyPeerRange(peerReactRange) ? null : installedReactMajor;
|
|
33690
33853
|
return installedReactMajor !== null ? Math.min(installedReactMajor, peerFloor) : peerFloor;
|
|
33691
33854
|
};
|
|
33692
|
-
const JSX_FILE_PATTERN = /\.(tsx|jsx)$/;
|
|
33693
|
-
const MILLISECONDS_PER_SECOND = 1e3;
|
|
33694
|
-
const SCORE_API_URL = "https://www.react.doctor/api/score";
|
|
33695
|
-
const FETCH_TIMEOUT_MS = 1e4;
|
|
33696
|
-
const GITHUB_VIEWER_PERMISSION_TIMEOUT_MS = 2e3;
|
|
33697
|
-
const SPAWN_ARGS_MAX_LENGTH_CHARS = 24e3;
|
|
33698
|
-
const SPAWN_ARGS_MAX_LENGTH_CHARS_POSIX = 15e5;
|
|
33699
|
-
const SPAWN_ARGS_MAX_LENGTH_CHARS_DARWIN = 8e5;
|
|
33700
|
-
const NODE_VERSION_PROBE_TIMEOUT_MS = 5e3;
|
|
33701
|
-
const PER_WORKER_MEM_BUDGET_BYTES = 1024 * 1024 * 1024;
|
|
33702
|
-
const DEFAULT_BRANCH_CANDIDATES = ["main", "master"];
|
|
33703
|
-
const ADOPTABLE_LINT_CONFIG_FILENAMES = [".oxlintrc.json", ".eslintrc.json"];
|
|
33704
|
-
const GIT_SHOW_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
|
|
33705
|
-
const ES_TARGET_YEAR_BY_NAME = {
|
|
33706
|
-
es3: 1999,
|
|
33707
|
-
es5: 2009,
|
|
33708
|
-
es6: 2015,
|
|
33709
|
-
es2015: 2015,
|
|
33710
|
-
es2016: 2016,
|
|
33711
|
-
es2017: 2017,
|
|
33712
|
-
es2018: 2018,
|
|
33713
|
-
es2019: 2019,
|
|
33714
|
-
es2020: 2020,
|
|
33715
|
-
es2021: 2021,
|
|
33716
|
-
es2022: 2022,
|
|
33717
|
-
es2023: 2023,
|
|
33718
|
-
es2024: 2024,
|
|
33719
|
-
es2025: 2025,
|
|
33720
|
-
esnext: 9999
|
|
33721
|
-
};
|
|
33722
|
-
/**
|
|
33723
|
-
* tsconfig filenames probed when resolving a project's TypeScript
|
|
33724
|
-
* compiler options — the root config first, then a monorepo base config.
|
|
33725
|
-
*/
|
|
33726
|
-
const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
|
|
33727
|
-
/**
|
|
33728
|
-
* Project-config files that `StagedFiles.materialize` copies into
|
|
33729
|
-
* the temp directory alongside staged sources so oxlint resolves
|
|
33730
|
-
* `tsconfig` / `package.json` / lint configs the same way it would
|
|
33731
|
-
* in the working tree. Hoisted out of the staged-files helper so
|
|
33732
|
-
* the constant lives next to the rest of the IO budget knobs.
|
|
33733
|
-
*/
|
|
33734
|
-
const STAGED_FILES_PROJECT_CONFIG_FILENAMES = [
|
|
33735
|
-
"tsconfig.json",
|
|
33736
|
-
"tsconfig.base.json",
|
|
33737
|
-
"package.json",
|
|
33738
|
-
"doctor.config.ts",
|
|
33739
|
-
"doctor.config.mts",
|
|
33740
|
-
"doctor.config.cts",
|
|
33741
|
-
"doctor.config.js",
|
|
33742
|
-
"doctor.config.mjs",
|
|
33743
|
-
"doctor.config.cjs",
|
|
33744
|
-
"doctor.config.json",
|
|
33745
|
-
"doctor.config.jsonc",
|
|
33746
|
-
"oxlint.json",
|
|
33747
|
-
".oxlintrc.json"
|
|
33748
|
-
];
|
|
33749
|
-
const OXLINT_OUTPUT_MAX_BYTES = 50 * 1024 * 1024;
|
|
33750
|
-
const OXLINT_SPAWN_TIMEOUT_MS = 6e4;
|
|
33751
|
-
const NODE_COMPILE_CACHE_DIR_NAME = "node-compile-cache";
|
|
33752
|
-
const DEAD_CODE_WORKER_TIMEOUT_MS = 12e4;
|
|
33753
|
-
const OXLINT_SPLIT_TOTAL_BUDGET_MS = 18e4;
|
|
33754
|
-
const DEAD_CODE_PHASE_TIMEOUT_MS = 15e4;
|
|
33755
|
-
const LINT_PHASE_TIMEOUT_MS = 3e5;
|
|
33756
|
-
const SCAN_TOTAL_DEADLINE_MS = 9e5;
|
|
33757
|
-
const DEAD_CODE_WORKER_MAX_OLD_SPACE_MB = 8192;
|
|
33758
|
-
const DEAD_CODE_WORKER_MEM_BUDGET_BYTES = 2 * 1024 * 1024 * 1024;
|
|
33759
|
-
const DEAD_CODE_TIMEOUT_CEILING_MS = 6e5;
|
|
33760
|
-
const DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS = 3e4;
|
|
33761
|
-
const DEAD_CODE_OVERLAP_PARSE_SHARE = .4;
|
|
33762
|
-
const RECOMMENDED_PNPM_MINIMUM_RELEASE_AGE_MINUTES = 10080;
|
|
33763
|
-
const REACT_SERVER_DOM_PACKAGES = [
|
|
33764
|
-
"react-server-dom-webpack",
|
|
33765
|
-
"react-server-dom-parcel",
|
|
33766
|
-
"react-server-dom-turbopack"
|
|
33767
|
-
];
|
|
33768
|
-
const REACT_BLOG_RSC_ADVISORY_URL = "https://react.dev/blog/2025/12/03/critical-security-vulnerability-in-react-server-components";
|
|
33769
|
-
const VERCEL_NEXTJS_SECURITY_RELEASE_URL = "https://vercel.com/changelog/next-js-may-2026-security-release";
|
|
33770
|
-
const DIAGNOSTIC_CATEGORY_BUCKETS = [
|
|
33771
|
-
"Security",
|
|
33772
|
-
"Bugs",
|
|
33773
|
-
"Performance",
|
|
33774
|
-
"Accessibility",
|
|
33775
|
-
"Maintainability"
|
|
33776
|
-
];
|
|
33777
|
-
const APP_ONLY_RULE_KEYS = new Set([
|
|
33778
|
-
"react-hooks-js/static-components",
|
|
33779
|
-
"react-doctor/no-render-prop-children",
|
|
33780
|
-
"react-doctor/prefer-explicit-variants"
|
|
33781
|
-
]);
|
|
33782
|
-
const COMPILER_CLEANUP_BUCKET = "compiler-cleanup";
|
|
33783
|
-
const COMPILER_CLEANUP_RULE_KEYS = new Set(["react-doctor/react-compiler-no-manual-memoization"]);
|
|
33784
|
-
const ROOT_CAUSE_GROUPABLE_RULE_KEYS = new Set([
|
|
33785
|
-
"react-doctor/no-derived-state",
|
|
33786
|
-
"react-doctor/no-derived-state-effect",
|
|
33787
|
-
"react-doctor/no-derived-useState",
|
|
33788
|
-
"react-doctor/no-adjust-state-on-prop-change",
|
|
33789
|
-
"react-doctor/no-reset-all-state-on-prop-change"
|
|
33790
|
-
]);
|
|
33791
|
-
const MAX_GLOB_PATTERN_LENGTH_CHARS = 1024;
|
|
33792
|
-
const CONFIG_CACHE_TTL_MS = 300 * 1e3;
|
|
33793
|
-
const SOCKET_FREE_PURL_API_BASE = "https://firewall-api.socket.dev/purl";
|
|
33794
|
-
const SOCKET_PACKAGE_PAGE_BASE = "https://socket.dev/npm/package";
|
|
33795
|
-
const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
|
|
33796
|
-
const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
|
|
33797
|
-
const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
|
|
33798
|
-
const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
33799
|
-
const SUPPLY_CHAIN_RULE = "low-supply-chain-score";
|
|
33800
|
-
const SUPPLY_CHAIN_CATEGORY = "Security";
|
|
33801
|
-
const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
|
|
33802
|
-
const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
|
|
33803
|
-
const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
|
|
33804
33855
|
const TSCONFIG_FILENAME = "tsconfig.json";
|
|
33805
33856
|
const isRelativeExtendsValue = (extendsValue) => extendsValue.startsWith("./") || extendsValue.startsWith("../") || Path.isAbsolute(extendsValue);
|
|
33806
33857
|
const ensureJsonExtension = (filePath) => Path.extname(filePath) === "" ? `${filePath}.json` : filePath;
|
|
@@ -36748,14 +36799,17 @@ const checkReactServerComponentsAdvisory = (scanDirectory, project) => {
|
|
|
36748
36799
|
return diagnostics;
|
|
36749
36800
|
};
|
|
36750
36801
|
const REDUCED_MOTION_GREP_PATTERN = "prefers-reduced-motion|useReducedMotion|MotionConfig|reducedMotion";
|
|
36751
|
-
const
|
|
36752
|
-
|
|
36753
|
-
"
|
|
36754
|
-
"
|
|
36755
|
-
"
|
|
36756
|
-
"
|
|
36757
|
-
"
|
|
36758
|
-
|
|
36802
|
+
const REDUCED_MOTION_PATTERN = new RegExp(REDUCED_MOTION_GREP_PATTERN);
|
|
36803
|
+
const REDUCED_MOTION_FILE_EXTENSIONS = new Set([
|
|
36804
|
+
".ts",
|
|
36805
|
+
".tsx",
|
|
36806
|
+
".js",
|
|
36807
|
+
".jsx",
|
|
36808
|
+
".css",
|
|
36809
|
+
".scss"
|
|
36810
|
+
]);
|
|
36811
|
+
const REDUCED_MOTION_FILE_GLOBS = [...REDUCED_MOTION_FILE_EXTENSIONS].map((extension) => `*${extension}`);
|
|
36812
|
+
const GIT_GREP_NO_MATCH_STATUS = 1;
|
|
36759
36813
|
const MISSING_REDUCED_MOTION_DIAGNOSTIC = {
|
|
36760
36814
|
filePath: "package.json",
|
|
36761
36815
|
plugin: "react-doctor",
|
|
@@ -36767,6 +36821,19 @@ const MISSING_REDUCED_MOTION_DIAGNOSTIC = {
|
|
|
36767
36821
|
column: 0,
|
|
36768
36822
|
category: "Accessibility"
|
|
36769
36823
|
};
|
|
36824
|
+
const hasReducedMotionHandlingViaFilesystem = (rootDirectory) => {
|
|
36825
|
+
for (const { absolutePath, name } of walkSourceTreeFiles(rootDirectory)) {
|
|
36826
|
+
if (!REDUCED_MOTION_FILE_EXTENSIONS.has(Path.extname(name))) continue;
|
|
36827
|
+
let content;
|
|
36828
|
+
try {
|
|
36829
|
+
content = NFS.readFileSync(absolutePath, "utf-8");
|
|
36830
|
+
} catch {
|
|
36831
|
+
continue;
|
|
36832
|
+
}
|
|
36833
|
+
if (REDUCED_MOTION_PATTERN.test(content)) return true;
|
|
36834
|
+
}
|
|
36835
|
+
return false;
|
|
36836
|
+
};
|
|
36770
36837
|
const checkReducedMotion = (rootDirectory) => {
|
|
36771
36838
|
const packageJsonPath = Path.join(rootDirectory, "package.json");
|
|
36772
36839
|
if (!isFile(packageJsonPath)) return [];
|
|
@@ -36785,22 +36852,21 @@ const checkReducedMotion = (rootDirectory) => {
|
|
|
36785
36852
|
const result = spawnSync("git", [
|
|
36786
36853
|
"grep",
|
|
36787
36854
|
"--untracked",
|
|
36788
|
-
"-
|
|
36789
|
-
"-E",
|
|
36855
|
+
"-lE",
|
|
36790
36856
|
REDUCED_MOTION_GREP_PATTERN,
|
|
36791
36857
|
"--",
|
|
36792
36858
|
...REDUCED_MOTION_FILE_GLOBS
|
|
36793
36859
|
], {
|
|
36794
36860
|
cwd: rootDirectory,
|
|
36861
|
+
encoding: "utf-8",
|
|
36795
36862
|
stdio: [
|
|
36796
36863
|
"ignore",
|
|
36797
36864
|
"pipe",
|
|
36798
36865
|
"pipe"
|
|
36799
36866
|
]
|
|
36800
36867
|
});
|
|
36801
|
-
if (result.error) return [MISSING_REDUCED_MOTION_DIAGNOSTIC];
|
|
36802
|
-
|
|
36803
|
-
return [MISSING_REDUCED_MOTION_DIAGNOSTIC];
|
|
36868
|
+
if (!(!result.error && (result.status === 0 || result.status === GIT_GREP_NO_MATCH_STATUS))) return hasReducedMotionHandlingViaFilesystem(rootDirectory) ? [] : [MISSING_REDUCED_MOTION_DIAGNOSTIC];
|
|
36869
|
+
return result.status === 0 && result.stdout.split("\n").some((filePath) => filePath.length > 0 && !hasIgnoredPathSegment(filePath)) ? [] : [MISSING_REDUCED_MOTION_DIAGNOSTIC];
|
|
36804
36870
|
};
|
|
36805
36871
|
const buildSecurityScanDiagnostic = (finding, entry, relativePath) => ({
|
|
36806
36872
|
filePath: relativePath,
|
|
@@ -37696,6 +37762,7 @@ const isDiagnosticOnSurface = (diagnostic, surface, config) => {
|
|
|
37696
37762
|
return true;
|
|
37697
37763
|
};
|
|
37698
37764
|
const filterDiagnosticsForSurface = (diagnostics, surface, config) => diagnostics.filter((diagnostic) => isDiagnosticOnSurface(diagnostic, surface, config));
|
|
37765
|
+
const remainingDeadlineBudgetMs = (deadlineEpochMs) => Math.max(deadlineEpochMs - Date.now(), 0);
|
|
37699
37766
|
/**
|
|
37700
37767
|
* Budget for the dead-code phase, scaled to the work. deslop's graph build is
|
|
37701
37768
|
* CPU-bound and roughly linear in file count, so a fixed 120s cap is too tight
|
|
@@ -37714,53 +37781,6 @@ const resolveDeadCodeTimeout = (input) => {
|
|
|
37714
37781
|
phaseTimeoutMs: workerTimeoutMs + DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS
|
|
37715
37782
|
};
|
|
37716
37783
|
};
|
|
37717
|
-
const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
|
|
37718
|
-
const entries = [];
|
|
37719
|
-
for (const relativePath of relativePaths) {
|
|
37720
|
-
const absolutePath = Path.resolve(rootDirectory, relativePath);
|
|
37721
|
-
const sizeBytes = statSourceFileSize(absolutePath);
|
|
37722
|
-
if (isLargeMinifiedFile(absolutePath, sizeBytes)) continue;
|
|
37723
|
-
entries.push({
|
|
37724
|
-
path: relativePath,
|
|
37725
|
-
sizeBytes: sizeBytes ?? 0
|
|
37726
|
-
});
|
|
37727
|
-
}
|
|
37728
|
-
return entries;
|
|
37729
|
-
};
|
|
37730
|
-
const listSourceFilesViaGit = (rootDirectory) => {
|
|
37731
|
-
const result = spawnSync("git", [
|
|
37732
|
-
"ls-files",
|
|
37733
|
-
"-z",
|
|
37734
|
-
"--cached",
|
|
37735
|
-
"--others",
|
|
37736
|
-
"--exclude-standard"
|
|
37737
|
-
], {
|
|
37738
|
-
cwd: rootDirectory,
|
|
37739
|
-
encoding: "utf-8",
|
|
37740
|
-
maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
|
|
37741
|
-
});
|
|
37742
|
-
if (result.error || result.status !== 0) return null;
|
|
37743
|
-
return result.stdout.split("\0").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath));
|
|
37744
|
-
};
|
|
37745
|
-
const listSourceFilesViaFilesystem = (rootDirectory) => {
|
|
37746
|
-
const filePaths = [];
|
|
37747
|
-
const stack = [rootDirectory];
|
|
37748
|
-
while (stack.length > 0) {
|
|
37749
|
-
const currentDirectory = stack.pop();
|
|
37750
|
-
const entries = readDirectoryEntries(currentDirectory);
|
|
37751
|
-
for (const entry of entries) {
|
|
37752
|
-
const absolutePath = Path.join(currentDirectory, entry.name);
|
|
37753
|
-
if (entry.isDirectory()) {
|
|
37754
|
-
if (!entry.name.startsWith(".") && !IGNORED_DIRECTORIES.has(entry.name)) stack.push(absolutePath);
|
|
37755
|
-
continue;
|
|
37756
|
-
}
|
|
37757
|
-
if (entry.isFile() && isLintableSourceFile(entry.name)) filePaths.push(Path.relative(rootDirectory, absolutePath).replace(/\\/g, "/"));
|
|
37758
|
-
}
|
|
37759
|
-
}
|
|
37760
|
-
return filePaths;
|
|
37761
|
-
};
|
|
37762
|
-
const listSourceFilesWithSize = (rootDirectory) => collectSizedSourceFiles(rootDirectory, listSourceFilesViaGit(rootDirectory) ?? listSourceFilesViaFilesystem(rootDirectory));
|
|
37763
|
-
const listSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).map((entry) => entry.path);
|
|
37764
37784
|
const resolveLintIncludePaths = (rootDirectory, userConfig, project) => {
|
|
37765
37785
|
if (!Array.isArray(userConfig?.ignore?.files) || userConfig.ignore.files.length === 0) return;
|
|
37766
37786
|
const ignoredPatterns = compileIgnoredFilePatterns(userConfig);
|
|
@@ -38457,12 +38477,12 @@ const findFilesWithDisableDirectivesViaGit = async (rootDirectory, includePaths)
|
|
|
38457
38477
|
return null;
|
|
38458
38478
|
}
|
|
38459
38479
|
if (grepResult === null) return null;
|
|
38460
|
-
return grepResult.stdout.split("\n").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath));
|
|
38480
|
+
return grepResult.stdout.split("\n").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath));
|
|
38461
38481
|
};
|
|
38462
38482
|
const findFilesWithDisableDirectivesViaFilesystem = (rootDirectory, includePaths) => {
|
|
38463
38483
|
const matches = [];
|
|
38464
38484
|
const checkFile = (relativePath) => {
|
|
38465
|
-
if (!isLintableSourceFile(relativePath)) return;
|
|
38485
|
+
if (!isLintableSourceFile(relativePath) || hasIgnoredPathSegment(relativePath)) return;
|
|
38466
38486
|
const absolutePath = Path.join(rootDirectory, relativePath);
|
|
38467
38487
|
let content;
|
|
38468
38488
|
try {
|
|
@@ -38476,22 +38496,7 @@ const findFilesWithDisableDirectivesViaFilesystem = (rootDirectory, includePaths
|
|
|
38476
38496
|
for (const candidate of includePaths) checkFile(candidate);
|
|
38477
38497
|
return matches;
|
|
38478
38498
|
}
|
|
38479
|
-
const
|
|
38480
|
-
while (stack.length > 0) {
|
|
38481
|
-
const current = stack.pop();
|
|
38482
|
-
if (current === void 0) continue;
|
|
38483
|
-
const entries = readDirectoryEntries(current);
|
|
38484
|
-
for (const entry of entries) {
|
|
38485
|
-
if (entry.isDirectory()) {
|
|
38486
|
-
if (entry.name.startsWith(".") || IGNORED_DIRECTORIES.has(entry.name)) continue;
|
|
38487
|
-
stack.push(Path.join(current, entry.name));
|
|
38488
|
-
continue;
|
|
38489
|
-
}
|
|
38490
|
-
if (!entry.isFile()) continue;
|
|
38491
|
-
const absolute = Path.join(current, entry.name);
|
|
38492
|
-
checkFile(Path.relative(rootDirectory, absolute));
|
|
38493
|
-
}
|
|
38494
|
-
}
|
|
38499
|
+
for (const { absolutePath } of walkSourceTreeFiles(rootDirectory)) checkFile(Path.relative(rootDirectory, absolutePath));
|
|
38495
38500
|
return matches;
|
|
38496
38501
|
};
|
|
38497
38502
|
const findFilesWithDisableDirectives = async (rootDirectory, includePaths) => await findFilesWithDisableDirectivesViaGit(rootDirectory, includePaths) ?? findFilesWithDisableDirectivesViaFilesystem(rootDirectory, includePaths);
|
|
@@ -38708,12 +38713,12 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
38708
38713
|
if (customRulesOnly && registryEntry.originallyExternal) continue;
|
|
38709
38714
|
if (rule.framework !== "global" && !rule.requires) continue;
|
|
38710
38715
|
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledBy)) continue;
|
|
38711
|
-
const
|
|
38716
|
+
const explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey: registryEntry.key }, severityControls);
|
|
38717
|
+
if (rule.defaultEnabled === false && explicitRuleOverride === void 0) continue;
|
|
38718
|
+
const severity = resolveRuleSeverityOverride({
|
|
38712
38719
|
ruleKey: registryEntry.key,
|
|
38713
38720
|
category: rule.category
|
|
38714
|
-
}, severityControls);
|
|
38715
|
-
if (rule.defaultEnabled === false && explicitSeverity === void 0) continue;
|
|
38716
|
-
const severity = explicitSeverity ?? resolveCompilerCleanupBucketSeverity(registryEntry.key, severityControls) ?? rule.severity;
|
|
38721
|
+
}, severityControls) ?? resolveCompilerCleanupBucketSeverity(registryEntry.key, severityControls) ?? rule.severity;
|
|
38717
38722
|
if (severity === "off") continue;
|
|
38718
38723
|
enabledReactDoctorRules[registryEntry.key] = severity;
|
|
38719
38724
|
}
|
|
@@ -39695,21 +39700,33 @@ const isParallelismRelatedSpawnError = (error) => {
|
|
|
39695
39700
|
* loop with a slimmer config in that case.
|
|
39696
39701
|
*/
|
|
39697
39702
|
const spawnLintBatches = async (input) => {
|
|
39698
|
-
const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 8, signal } = input;
|
|
39703
|
+
const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 8, signal, deadlineEpochMs } = input;
|
|
39699
39704
|
const requestedConcurrency = resolveScanConcurrency(input.concurrency ?? 1);
|
|
39700
39705
|
const totalFileCount = fileBatches.reduce((sum, batch) => sum + batch.length, 0);
|
|
39701
39706
|
const runBatchPass = async (concurrency) => {
|
|
39702
39707
|
const allDiagnostics = [];
|
|
39703
39708
|
const droppedFiles = [];
|
|
39709
|
+
const deadlineSkippedFiles = [];
|
|
39710
|
+
const isPastDeadline = () => deadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(deadlineEpochMs) === 0;
|
|
39704
39711
|
let firstDropReason = null;
|
|
39705
|
-
const spawnLintBatch = async (batch, depth,
|
|
39712
|
+
const spawnLintBatch = async (batch, depth, batchState) => {
|
|
39713
|
+
if (isPastDeadline()) {
|
|
39714
|
+
deadlineSkippedFiles.push(...batch);
|
|
39715
|
+
batchState.deadlineSkippedFileCount += batch.length;
|
|
39716
|
+
return [];
|
|
39717
|
+
}
|
|
39706
39718
|
const batchArgs = [...baseArgs, ...batch];
|
|
39707
39719
|
try {
|
|
39708
39720
|
return parseOxlintOutput(await spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, spawnTimeoutMs, outputMaxBytes, signal), project, rootDirectory);
|
|
39709
39721
|
} catch (error) {
|
|
39710
39722
|
if (!isSplittableReactDoctorError(error)) throw error;
|
|
39711
|
-
|
|
39712
|
-
|
|
39723
|
+
if (isPastDeadline()) {
|
|
39724
|
+
deadlineSkippedFiles.push(...batch);
|
|
39725
|
+
batchState.deadlineSkippedFileCount += batch.length;
|
|
39726
|
+
return [];
|
|
39727
|
+
}
|
|
39728
|
+
batchState.deadlineMs ??= Date.now() + splitTotalBudgetMs;
|
|
39729
|
+
const isBudgetElapsed = Date.now() >= batchState.deadlineMs;
|
|
39713
39730
|
const isDepthCapReached = depth >= splitMaxDepth;
|
|
39714
39731
|
if (batch.length <= 1 || isBudgetElapsed || isDepthCapReached) {
|
|
39715
39732
|
droppedFiles.push(...batch);
|
|
@@ -39722,7 +39739,7 @@ const spawnLintBatches = async (input) => {
|
|
|
39722
39739
|
return [];
|
|
39723
39740
|
}
|
|
39724
39741
|
const splitIndex = Math.ceil(batch.length / 2);
|
|
39725
|
-
return [...await spawnLintBatch(batch.slice(0, splitIndex), depth + 1,
|
|
39742
|
+
return [...await spawnLintBatch(batch.slice(0, splitIndex), depth + 1, batchState), ...await spawnLintBatch(batch.slice(splitIndex), depth + 1, batchState)];
|
|
39726
39743
|
}
|
|
39727
39744
|
};
|
|
39728
39745
|
let startedFileCount = 0;
|
|
@@ -39738,9 +39755,17 @@ const spawnLintBatches = async (input) => {
|
|
|
39738
39755
|
progressTimer?.unref?.();
|
|
39739
39756
|
try {
|
|
39740
39757
|
const batchResults = await mapWithConcurrency(fileBatches, concurrency, async (batch) => {
|
|
39758
|
+
if (isPastDeadline()) {
|
|
39759
|
+
deadlineSkippedFiles.push(...batch);
|
|
39760
|
+
return [];
|
|
39761
|
+
}
|
|
39741
39762
|
startedFileCount += batch.length;
|
|
39742
|
-
const
|
|
39743
|
-
|
|
39763
|
+
const batchState = {
|
|
39764
|
+
deadlineMs: null,
|
|
39765
|
+
deadlineSkippedFileCount: 0
|
|
39766
|
+
};
|
|
39767
|
+
const batchDiagnostics = await spawnLintBatch(batch, 0, batchState);
|
|
39768
|
+
scannedFileCount += batch.length - batchState.deadlineSkippedFileCount;
|
|
39744
39769
|
if (onFileProgress) {
|
|
39745
39770
|
displayedFileCount = Math.min(Math.max(displayedFileCount, scannedFileCount), totalFileCount);
|
|
39746
39771
|
onFileProgress(displayedFileCount, totalFileCount);
|
|
@@ -39751,12 +39776,13 @@ const spawnLintBatches = async (input) => {
|
|
|
39751
39776
|
} finally {
|
|
39752
39777
|
if (progressTimer !== null) clearInterval(progressTimer);
|
|
39753
39778
|
}
|
|
39754
|
-
|
|
39755
|
-
|
|
39756
|
-
|
|
39757
|
-
|
|
39758
|
-
|
|
39759
|
-
}
|
|
39779
|
+
const reportSkippedFiles = (skippedFiles, buildMessage) => {
|
|
39780
|
+
if (skippedFiles.length === 0 || !onPartialFailure) return;
|
|
39781
|
+
onPartialFailure(buildMessage(`${skippedFiles.slice(0, 3).join(", ")}${skippedFiles.length > 3 ? `, +${skippedFiles.length - 3} more` : ""}`));
|
|
39782
|
+
};
|
|
39783
|
+
const reasonHint = firstDropReason ? ` — first failure: ${firstDropReason}` : "";
|
|
39784
|
+
reportSkippedFiles(droppedFiles, (fileListPreview) => `${droppedFiles.length} file(s) failed to lint and were skipped (${fileListPreview})${reasonHint}`);
|
|
39785
|
+
reportSkippedFiles(deadlineSkippedFiles, (fileListPreview) => `${deadlineSkippedFiles.length} file(s) skipped — max scan duration reached before they were linted (${fileListPreview})`);
|
|
39760
39786
|
return allDiagnostics;
|
|
39761
39787
|
};
|
|
39762
39788
|
let diagnostics;
|
|
@@ -39960,7 +39986,8 @@ const runOxlint = async (options) => {
|
|
|
39960
39986
|
spawnTimeoutMs,
|
|
39961
39987
|
outputMaxBytes,
|
|
39962
39988
|
concurrency: options.concurrency,
|
|
39963
|
-
signal: options.signal
|
|
39989
|
+
signal: options.signal,
|
|
39990
|
+
deadlineEpochMs: options.deadlineEpochMs
|
|
39964
39991
|
});
|
|
39965
39992
|
writeOxlintConfig(passConfigPath, buildConfigForPass({}));
|
|
39966
39993
|
try {
|
|
@@ -40059,7 +40086,8 @@ const runOxlint = async (options) => {
|
|
|
40059
40086
|
spawnTimeoutMs,
|
|
40060
40087
|
outputMaxBytes,
|
|
40061
40088
|
concurrency: options.concurrency,
|
|
40062
|
-
signal: options.signal
|
|
40089
|
+
signal: options.signal,
|
|
40090
|
+
deadlineEpochMs: options.deadlineEpochMs
|
|
40063
40091
|
});
|
|
40064
40092
|
writeOxlintConfig(configPath, buildConfig({ extendsPaths }));
|
|
40065
40093
|
try {
|
|
@@ -40163,7 +40191,8 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
|
|
|
40163
40191
|
outputMaxBytes,
|
|
40164
40192
|
concurrency,
|
|
40165
40193
|
signal,
|
|
40166
|
-
lintBatchOrdering
|
|
40194
|
+
lintBatchOrdering,
|
|
40195
|
+
deadlineEpochMs: input.deadlineEpochMs
|
|
40167
40196
|
}),
|
|
40168
40197
|
catch: ensureReactDoctorError
|
|
40169
40198
|
});
|
|
@@ -40923,6 +40952,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
40923
40952
|
const deadCodePhaseTimeoutMs = yield* DeadCodePhaseTimeoutMs;
|
|
40924
40953
|
const resolveDeadCodePhaseTimeoutMs = (scaledPhaseTimeoutMs) => deadCodePhaseTimeoutMs === 15e4 ? scaledPhaseTimeoutMs : deadCodePhaseTimeoutMs;
|
|
40925
40954
|
const workerCountSuffix = scanConcurrency > 1 ? ` ${highlighter.dim(`[~${scanConcurrency} workers]`)}` : "";
|
|
40955
|
+
const capToDeadline = (phaseTimeoutMs) => input.deadlineEpochMs === void 0 ? phaseTimeoutMs : Math.min(phaseTimeoutMs, remainingDeadlineBudgetMs(input.deadlineEpochMs));
|
|
40926
40956
|
const shouldRunDeadCode = input.runDeadCode && !isDiffMode && (showWarnings || deadCodeMaySurfaceWhenWarningsHidden(resolvedConfig.config));
|
|
40927
40957
|
const deadCodeOverlapMode = yield* DeadCodeOverlap;
|
|
40928
40958
|
const shouldOverlapDeadCode = shouldRunDeadCode && deadCodeOverlapMode === "on";
|
|
@@ -40952,7 +40982,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
40952
40982
|
});
|
|
40953
40983
|
const deadCodeFiber = shouldOverlapDeadCode ? yield* forkChild(buildCollectDeadCode({
|
|
40954
40984
|
workerTimeoutMs: overlapDeadCodeTimeout.workerTimeoutMs,
|
|
40955
|
-
phaseTimeoutMs: resolveDeadCodePhaseTimeoutMs(overlapDeadCodeTimeout.phaseTimeoutMs)
|
|
40985
|
+
phaseTimeoutMs: capToDeadline(resolveDeadCodePhaseTimeoutMs(overlapDeadCodeTimeout.phaseTimeoutMs))
|
|
40956
40986
|
})) : null;
|
|
40957
40987
|
const scanProgress = yield* progressService.start("Scanning...");
|
|
40958
40988
|
const scanStartTime = Date.now();
|
|
@@ -40977,7 +41007,8 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
40977
41007
|
onCacheStats: (cacheHitFileCount, totalConsideredFileCount) => {
|
|
40978
41008
|
lintCacheHitFileCount = cacheHitFileCount;
|
|
40979
41009
|
lintCacheTotalFileCount = totalConsideredFileCount;
|
|
40980
|
-
}
|
|
41010
|
+
},
|
|
41011
|
+
deadlineEpochMs: input.deadlineEpochMs
|
|
40981
41012
|
}).pipe(catchTag("ReactDoctorError", (error) => unwrap(gen(function* () {
|
|
40982
41013
|
yield* set(lintFailure, {
|
|
40983
41014
|
didFail: true,
|
|
@@ -41004,7 +41035,13 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
41004
41035
|
let deadCodeCollected = [];
|
|
41005
41036
|
if (lintFailureState.didFail) {
|
|
41006
41037
|
if (deadCodeFiber !== null) yield* interrupt(deadCodeFiber);
|
|
41007
|
-
} else if (shouldRunDeadCode) {
|
|
41038
|
+
} else if (shouldRunDeadCode) if (input.deadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(input.deadlineEpochMs) === 0) {
|
|
41039
|
+
if (deadCodeFiber !== null) yield* interrupt(deadCodeFiber);
|
|
41040
|
+
yield* set(deadCodeFailure, {
|
|
41041
|
+
didFail: true,
|
|
41042
|
+
reason: "Dead-code analysis skipped — max scan duration reached."
|
|
41043
|
+
});
|
|
41044
|
+
} else {
|
|
41008
41045
|
yield* scanProgress.update(`Scanned ${scannedFilesLabel}, analyzing dead code...`);
|
|
41009
41046
|
const sequentialDeadCodeTimeout = resolveDeadCodeTimeout({
|
|
41010
41047
|
sourceFileCount: totalFileCount,
|
|
@@ -41013,7 +41050,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
41013
41050
|
});
|
|
41014
41051
|
deadCodeCollected = deadCodeFiber !== null ? yield* join(deadCodeFiber) : yield* buildCollectDeadCode({
|
|
41015
41052
|
workerTimeoutMs: sequentialDeadCodeTimeout.workerTimeoutMs,
|
|
41016
|
-
phaseTimeoutMs: resolveDeadCodePhaseTimeoutMs(sequentialDeadCodeTimeout.phaseTimeoutMs)
|
|
41053
|
+
phaseTimeoutMs: capToDeadline(resolveDeadCodePhaseTimeoutMs(sequentialDeadCodeTimeout.phaseTimeoutMs))
|
|
41017
41054
|
});
|
|
41018
41055
|
}
|
|
41019
41056
|
const deadCodeFailureState = lintFailureState.didFail ? {
|
|
@@ -41051,7 +41088,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
41051
41088
|
};
|
|
41052
41089
|
const scoreSurface = input.scoreSurface ?? "score";
|
|
41053
41090
|
const scoreDiagnostics = filterDiagnosticsForSurface([...finalDiagnostics], scoreSurface, resolvedConfig.config);
|
|
41054
|
-
const score = lintFailureState.didFail ? null : yield* scoreService.compute({
|
|
41091
|
+
const score = lintFailureState.didFail || deadCodeFailureState.didFail ? null : yield* scoreService.compute({
|
|
41055
41092
|
diagnostics: scoreDiagnostics,
|
|
41056
41093
|
isCi: input.isCi,
|
|
41057
41094
|
metadata: scoreMetadata
|
|
@@ -41420,6 +41457,7 @@ const buildJsonReport = (input) => {
|
|
|
41420
41457
|
return {
|
|
41421
41458
|
schemaVersion: 1,
|
|
41422
41459
|
mode: input.mode,
|
|
41460
|
+
...input.baselineDegraded ? { baselineDegraded: true } : {},
|
|
41423
41461
|
...shared
|
|
41424
41462
|
};
|
|
41425
41463
|
};
|
|
@@ -41720,4 +41758,4 @@ const toJsonReport = (result, options) => buildJsonReport({
|
|
|
41720
41758
|
export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
|
|
41721
41759
|
|
|
41722
41760
|
//# sourceMappingURL=index.js.map
|
|
41723
|
-
//# debugId=
|
|
41761
|
+
//# debugId=62cf4740-7938-5db0-8b80-dc81b60af36a
|