react-doctor 0.7.2 → 0.7.3-dev.6b70b32
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 +741 -685
- package/dist/index.d.ts +14 -2
- package/dist/index.js +826 -748
- package/dist/lsp.js +862 -813
- package/package.json +6 -6
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]="d6c8e327-6382-5aed-99c8-f3e537c25f51")}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";
|
|
@@ -35959,6 +35959,25 @@ var AmbiguousProjectError = class extends Error {
|
|
|
35959
35959
|
}
|
|
35960
35960
|
};
|
|
35961
35961
|
const isProjectDiscoveryError = (value) => value instanceof ProjectNotFoundError || value instanceof NoReactDependencyError || value instanceof PackageJsonNotFoundError || value instanceof NotADirectoryError || value instanceof AmbiguousProjectError;
|
|
35962
|
+
const isErrnoException = (error) => error instanceof Error && "code" in error;
|
|
35963
|
+
const IGNORABLE_READDIR_ERROR_CODES = new Set([
|
|
35964
|
+
"EACCES",
|
|
35965
|
+
"EPERM",
|
|
35966
|
+
"ENOENT",
|
|
35967
|
+
"ENOTDIR",
|
|
35968
|
+
"EINVAL",
|
|
35969
|
+
"ELOOP",
|
|
35970
|
+
"ENAMETOOLONG"
|
|
35971
|
+
]);
|
|
35972
|
+
const isIgnorableReaddirError = (error) => isErrnoException(error) && typeof error.code === "string" && IGNORABLE_READDIR_ERROR_CODES.has(error.code);
|
|
35973
|
+
const readDirectoryEntries = (directoryPath) => {
|
|
35974
|
+
try {
|
|
35975
|
+
return NFS.readdirSync(directoryPath, { withFileTypes: true });
|
|
35976
|
+
} catch (error) {
|
|
35977
|
+
if (isIgnorableReaddirError(error)) return [];
|
|
35978
|
+
throw error;
|
|
35979
|
+
}
|
|
35980
|
+
};
|
|
35962
35981
|
const isFile = (filePath) => {
|
|
35963
35982
|
try {
|
|
35964
35983
|
return NFS.statSync(filePath).isFile();
|
|
@@ -35966,6 +35985,18 @@ const isFile = (filePath) => {
|
|
|
35966
35985
|
return false;
|
|
35967
35986
|
}
|
|
35968
35987
|
};
|
|
35988
|
+
const isDirectory = (directoryPath) => {
|
|
35989
|
+
try {
|
|
35990
|
+
return NFS.statSync(directoryPath).isDirectory();
|
|
35991
|
+
} catch {
|
|
35992
|
+
return false;
|
|
35993
|
+
}
|
|
35994
|
+
};
|
|
35995
|
+
const isPlainObject = (value) => {
|
|
35996
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
35997
|
+
const prototype = Object.getPrototypeOf(value);
|
|
35998
|
+
return prototype === null || prototype === Object.prototype;
|
|
35999
|
+
};
|
|
35969
36000
|
const SOURCE_FILE_PATTERN = /\.(tsx?|jsx?|mts|mjs)$/;
|
|
35970
36001
|
const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
|
|
35971
36002
|
const GENERATED_SOURCE_DIRECTORY_PATTERN = /(?:^|\/)__generated__\//;
|
|
@@ -36100,6 +36131,8 @@ const OXLINT_SPAWN_TIMEOUT_MS = 6e4;
|
|
|
36100
36131
|
const NODE_COMPILE_CACHE_DIR_NAME = "node-compile-cache";
|
|
36101
36132
|
const DEAD_CODE_WORKER_TIMEOUT_MS = 12e4;
|
|
36102
36133
|
const OXLINT_SPLIT_TOTAL_BUDGET_MS = 18e4;
|
|
36134
|
+
const ABORT_EXIT_CODES = new Set([134, 3221226505]);
|
|
36135
|
+
const OXLINT_OOM_RESCUE_BUDGET_MS = 6e4;
|
|
36103
36136
|
const DEAD_CODE_PHASE_TIMEOUT_MS = 15e4;
|
|
36104
36137
|
const LINT_PHASE_TIMEOUT_MS = 3e5;
|
|
36105
36138
|
const SCAN_TOTAL_DEADLINE_MS = 9e5;
|
|
@@ -36146,7 +36179,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
|
|
|
36146
36179
|
const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
|
|
36147
36180
|
const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
|
|
36148
36181
|
const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
|
|
36149
|
-
const CORE_PACKAGE_VERSION = "0.7.
|
|
36182
|
+
const CORE_PACKAGE_VERSION = "0.7.3";
|
|
36150
36183
|
const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
|
|
36151
36184
|
const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
|
|
36152
36185
|
const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
@@ -36192,25 +36225,6 @@ const isLargeMinifiedFile = (absolutePath, knownSizeBytes) => {
|
|
|
36192
36225
|
cachedIsLargeMinifiedByPath.set(absolutePath, result);
|
|
36193
36226
|
return result;
|
|
36194
36227
|
};
|
|
36195
|
-
const isErrnoException = (error) => error instanceof Error && "code" in error;
|
|
36196
|
-
const IGNORABLE_READDIR_ERROR_CODES = new Set([
|
|
36197
|
-
"EACCES",
|
|
36198
|
-
"EPERM",
|
|
36199
|
-
"ENOENT",
|
|
36200
|
-
"ENOTDIR",
|
|
36201
|
-
"EINVAL",
|
|
36202
|
-
"ELOOP",
|
|
36203
|
-
"ENAMETOOLONG"
|
|
36204
|
-
]);
|
|
36205
|
-
const isIgnorableReaddirError = (error) => isErrnoException(error) && typeof error.code === "string" && IGNORABLE_READDIR_ERROR_CODES.has(error.code);
|
|
36206
|
-
const readDirectoryEntries = (directoryPath) => {
|
|
36207
|
-
try {
|
|
36208
|
-
return NFS.readdirSync(directoryPath, { withFileTypes: true });
|
|
36209
|
-
} catch (error) {
|
|
36210
|
-
if (isIgnorableReaddirError(error)) return [];
|
|
36211
|
-
throw error;
|
|
36212
|
-
}
|
|
36213
|
-
};
|
|
36214
36228
|
function* walkSourceTreeFiles(rootDirectory) {
|
|
36215
36229
|
const stack = [rootDirectory];
|
|
36216
36230
|
while (stack.length > 0) {
|
|
@@ -36265,23 +36279,6 @@ const listSourceFilesViaFilesystem = (rootDirectory) => {
|
|
|
36265
36279
|
const listSourceFilesWithSize = (rootDirectory) => collectSizedSourceFiles(rootDirectory, (listSourceFilesViaGit(rootDirectory) ?? listSourceFilesViaFilesystem(rootDirectory)).sort());
|
|
36266
36280
|
const listSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).map((entry) => entry.path);
|
|
36267
36281
|
const countSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).length;
|
|
36268
|
-
/**
|
|
36269
|
-
* The chain of ancestor directories of `startDirectory`, nearest first, up to
|
|
36270
|
-
* and including the filesystem root. With `includeStart`, the chain begins at
|
|
36271
|
-
* `startDirectory` itself; otherwise at its parent. The one place the "walk up
|
|
36272
|
-
* the tree" traversal is expressed, so each caller adds only its own match /
|
|
36273
|
-
* stop policy instead of re-deriving the `path.dirname` loop.
|
|
36274
|
-
*/
|
|
36275
|
-
const ancestorDirectories = (startDirectory, { includeStart }) => {
|
|
36276
|
-
const directories = [];
|
|
36277
|
-
let currentDirectory = includeStart ? startDirectory : Path.dirname(startDirectory);
|
|
36278
|
-
while (true) {
|
|
36279
|
-
directories.push(currentDirectory);
|
|
36280
|
-
const parentDirectory = Path.dirname(currentDirectory);
|
|
36281
|
-
if (parentDirectory === currentDirectory) return directories;
|
|
36282
|
-
currentDirectory = parentDirectory;
|
|
36283
|
-
}
|
|
36284
|
-
};
|
|
36285
36282
|
const cachedPackageJsons = /* @__PURE__ */ new Map();
|
|
36286
36283
|
const readPackageJsonUncached = (packageJsonPath) => {
|
|
36287
36284
|
try {
|
|
@@ -36312,7 +36309,11 @@ const isMonorepoRoot = (directory) => {
|
|
|
36312
36309
|
return Array.isArray(packageJson.workspaces) || Boolean(packageJson.workspaces?.packages);
|
|
36313
36310
|
};
|
|
36314
36311
|
const findMonorepoRoot = (startDirectory) => {
|
|
36315
|
-
|
|
36312
|
+
let currentDirectory = Path.dirname(startDirectory);
|
|
36313
|
+
while (currentDirectory !== Path.dirname(currentDirectory)) {
|
|
36314
|
+
if (isMonorepoRoot(currentDirectory)) return currentDirectory;
|
|
36315
|
+
currentDirectory = Path.dirname(currentDirectory);
|
|
36316
|
+
}
|
|
36316
36317
|
return null;
|
|
36317
36318
|
};
|
|
36318
36319
|
/**
|
|
@@ -36326,6 +36327,146 @@ const findMonorepoRoot = (startDirectory) => {
|
|
|
36326
36327
|
* byte-equivalent copy.
|
|
36327
36328
|
*/
|
|
36328
36329
|
const isProjectBoundary = (directory) => NFS.existsSync(Path.join(directory, ".git")) || isMonorepoRoot(directory);
|
|
36330
|
+
const TSCONFIG_FILENAME = "tsconfig.json";
|
|
36331
|
+
const isRelativeExtendsValue = (extendsValue) => extendsValue.startsWith("./") || extendsValue.startsWith("../") || Path.isAbsolute(extendsValue);
|
|
36332
|
+
const ensureJsonExtension = (filePath) => Path.extname(filePath) === "" ? `${filePath}.json` : filePath;
|
|
36333
|
+
const resolvePackageExtendsPath = (extendsValue, fromConfigDirectory) => {
|
|
36334
|
+
const requireFromConfig = createRequire(Path.join(fromConfigDirectory, "tsconfig.json"));
|
|
36335
|
+
const candidates = [
|
|
36336
|
+
extendsValue,
|
|
36337
|
+
ensureJsonExtension(extendsValue),
|
|
36338
|
+
`${extendsValue.replace(/\/$/, "")}/tsconfig.json`
|
|
36339
|
+
];
|
|
36340
|
+
for (const candidate of candidates) try {
|
|
36341
|
+
return requireFromConfig.resolve(candidate);
|
|
36342
|
+
} catch {
|
|
36343
|
+
continue;
|
|
36344
|
+
}
|
|
36345
|
+
return null;
|
|
36346
|
+
};
|
|
36347
|
+
const resolveExtendsPath = (extendsValue, fromConfigDirectory) => {
|
|
36348
|
+
if (isRelativeExtendsValue(extendsValue)) return ensureJsonExtension(Path.resolve(fromConfigDirectory, extendsValue));
|
|
36349
|
+
return resolvePackageExtendsPath(extendsValue, fromConfigDirectory);
|
|
36350
|
+
};
|
|
36351
|
+
const normalizeCompilerOptions = (compilerOptions) => {
|
|
36352
|
+
if (!isPlainObject(compilerOptions)) return { hasExplicitLib: false };
|
|
36353
|
+
const target = typeof compilerOptions.target === "string" ? compilerOptions.target : void 0;
|
|
36354
|
+
const hasExplicitLib = Object.hasOwn(compilerOptions, "lib");
|
|
36355
|
+
return {
|
|
36356
|
+
target,
|
|
36357
|
+
lib: Array.isArray(compilerOptions.lib) ? compilerOptions.lib.filter((entry) => typeof entry === "string") : void 0,
|
|
36358
|
+
hasExplicitLib
|
|
36359
|
+
};
|
|
36360
|
+
};
|
|
36361
|
+
const readTsConfig = (filePath) => {
|
|
36362
|
+
let content;
|
|
36363
|
+
try {
|
|
36364
|
+
content = NFS.readFileSync(filePath, "utf-8");
|
|
36365
|
+
} catch {
|
|
36366
|
+
return null;
|
|
36367
|
+
}
|
|
36368
|
+
const parsed = ts.parseConfigFileTextToJson(filePath, content);
|
|
36369
|
+
if (!isPlainObject(parsed.config)) return null;
|
|
36370
|
+
return {
|
|
36371
|
+
extends: typeof parsed.config.extends === "string" ? parsed.config.extends : void 0,
|
|
36372
|
+
referencePaths: normalizeReferencePaths(parsed.config.references),
|
|
36373
|
+
compilerOptions: normalizeCompilerOptions(parsed.config.compilerOptions)
|
|
36374
|
+
};
|
|
36375
|
+
};
|
|
36376
|
+
const normalizeReferencePaths = (references) => {
|
|
36377
|
+
if (!Array.isArray(references)) return [];
|
|
36378
|
+
return references.map((reference) => isPlainObject(reference) && typeof reference.path === "string" ? reference.path : null).filter((referencePath) => referencePath !== null);
|
|
36379
|
+
};
|
|
36380
|
+
const mergeCompilerOptions = (inherited, current) => {
|
|
36381
|
+
const target = current.target ?? inherited?.target;
|
|
36382
|
+
const hasExplicitLib = current.hasExplicitLib || Boolean(inherited?.hasExplicitLib);
|
|
36383
|
+
return {
|
|
36384
|
+
target,
|
|
36385
|
+
lib: current.hasExplicitLib ? current.lib : inherited?.lib,
|
|
36386
|
+
hasExplicitLib
|
|
36387
|
+
};
|
|
36388
|
+
};
|
|
36389
|
+
const readResolvedCompilerOptions = (tsConfigPath, extendsDepth, visitedPaths) => {
|
|
36390
|
+
const realPath = NFS.realpathSync.native(tsConfigPath);
|
|
36391
|
+
if (visitedPaths.has(realPath)) return null;
|
|
36392
|
+
const tsConfig = readTsConfig(realPath);
|
|
36393
|
+
if (!tsConfig) return null;
|
|
36394
|
+
const nextVisitedPaths = new Set(visitedPaths);
|
|
36395
|
+
nextVisitedPaths.add(realPath);
|
|
36396
|
+
if (tsConfig.extends && extendsDepth < 8) {
|
|
36397
|
+
const parentPath = resolveExtendsPath(tsConfig.extends, Path.dirname(realPath));
|
|
36398
|
+
if (parentPath && isFile(parentPath)) return mergeCompilerOptions(readResolvedCompilerOptions(parentPath, extendsDepth + 1, nextVisitedPaths), tsConfig.compilerOptions);
|
|
36399
|
+
}
|
|
36400
|
+
return tsConfig.compilerOptions;
|
|
36401
|
+
};
|
|
36402
|
+
const targetYearIsPreES2023 = (target) => {
|
|
36403
|
+
const year = ES_TARGET_YEAR_BY_NAME[target.toLowerCase()];
|
|
36404
|
+
return year !== void 0 && year < 2023;
|
|
36405
|
+
};
|
|
36406
|
+
const libEntryIncludesES2023Array = (entry) => {
|
|
36407
|
+
const normalizedEntry = entry.toLowerCase();
|
|
36408
|
+
if (normalizedEntry === "esnext" || normalizedEntry === "esnext.array") return true;
|
|
36409
|
+
const esYearMatch = /^es(\d{4})(?:\.(.+))?$/.exec(normalizedEntry);
|
|
36410
|
+
if (!esYearMatch) return false;
|
|
36411
|
+
if (Number(esYearMatch[1]) < 2023) return false;
|
|
36412
|
+
const component = esYearMatch[2];
|
|
36413
|
+
return component === void 0 || component === "array";
|
|
36414
|
+
};
|
|
36415
|
+
const libIncludesES2023 = (lib) => lib.some(libEntryIncludesES2023Array);
|
|
36416
|
+
const compilerOptionsArePreES2023 = (compilerOptions) => {
|
|
36417
|
+
if (compilerOptions.target) return targetYearIsPreES2023(compilerOptions.target);
|
|
36418
|
+
if (compilerOptions.hasExplicitLib) return !libIncludesES2023(compilerOptions.lib ?? []);
|
|
36419
|
+
return false;
|
|
36420
|
+
};
|
|
36421
|
+
const compilerOptionsDeclareTargetOrLib = (compilerOptions) => compilerOptions.hasExplicitLib || compilerOptions.target !== void 0;
|
|
36422
|
+
const detectPreES2023FromConfig = (tsConfigPath, visitedConfigPaths = /* @__PURE__ */ new Set()) => {
|
|
36423
|
+
if (visitedConfigPaths.has(tsConfigPath)) return false;
|
|
36424
|
+
const compilerOptions = readResolvedCompilerOptions(tsConfigPath, 0, /* @__PURE__ */ new Set());
|
|
36425
|
+
if (!compilerOptions) return false;
|
|
36426
|
+
if (!compilerOptionsDeclareTargetOrLib(compilerOptions)) {
|
|
36427
|
+
const tsConfig = readTsConfig(tsConfigPath);
|
|
36428
|
+
if (!tsConfig) return false;
|
|
36429
|
+
const nextVisitedConfigPaths = new Set(visitedConfigPaths);
|
|
36430
|
+
nextVisitedConfigPaths.add(tsConfigPath);
|
|
36431
|
+
const configDirectory = Path.dirname(tsConfigPath);
|
|
36432
|
+
return tsConfig.referencePaths.some((referencePath) => {
|
|
36433
|
+
const resolvedReferencePath = Path.resolve(configDirectory, referencePath);
|
|
36434
|
+
const referencedConfigPath = isFile(resolvedReferencePath) ? resolvedReferencePath : Path.join(resolvedReferencePath, TSCONFIG_FILENAME);
|
|
36435
|
+
return isFile(referencedConfigPath) && detectPreES2023FromConfig(referencedConfigPath, nextVisitedConfigPaths);
|
|
36436
|
+
});
|
|
36437
|
+
}
|
|
36438
|
+
return compilerOptionsArePreES2023(compilerOptions);
|
|
36439
|
+
};
|
|
36440
|
+
const detectPreES2023Target = (directory) => {
|
|
36441
|
+
const tsConfigPath = Path.join(directory, TSCONFIG_FILENAME);
|
|
36442
|
+
if (isFile(tsConfigPath)) return detectPreES2023FromConfig(tsConfigPath);
|
|
36443
|
+
for (const fallbackFilename of FALLBACK_TSCONFIG_FILENAMES) {
|
|
36444
|
+
const fallbackPath = Path.join(directory, fallbackFilename);
|
|
36445
|
+
if (isFile(fallbackPath)) return detectPreES2023FromConfig(fallbackPath);
|
|
36446
|
+
}
|
|
36447
|
+
return false;
|
|
36448
|
+
};
|
|
36449
|
+
const FALLBACK_TSCONFIG_FILENAMES = ["tsconfig.app.json", "tsconfig.build.json"];
|
|
36450
|
+
const FRAMEWORK_PACKAGES = {
|
|
36451
|
+
next: "nextjs",
|
|
36452
|
+
"@tanstack/react-start": "tanstack-start",
|
|
36453
|
+
vite: "vite",
|
|
36454
|
+
"react-scripts": "cra",
|
|
36455
|
+
"@remix-run/react": "remix",
|
|
36456
|
+
gatsby: "gatsby",
|
|
36457
|
+
expo: "expo",
|
|
36458
|
+
"react-native": "react-native"
|
|
36459
|
+
};
|
|
36460
|
+
const detectFramework = (dependencies) => {
|
|
36461
|
+
for (const [packageName, frameworkName] of Object.entries(FRAMEWORK_PACKAGES)) if (dependencies[packageName]) return frameworkName;
|
|
36462
|
+
if (dependencies.preact && !dependencies.react) return "preact";
|
|
36463
|
+
return "unknown";
|
|
36464
|
+
};
|
|
36465
|
+
const MOBILE_FRAMEWORKS = new Set(["expo", "react-native"]);
|
|
36466
|
+
const frameworkMergeRank = (framework) => {
|
|
36467
|
+
if (framework === "unknown") return 3;
|
|
36468
|
+
return MOBILE_FRAMEWORKS.has(framework) ? 2 : 1;
|
|
36469
|
+
};
|
|
36329
36470
|
const REACT_COMPILER_PACKAGES = new Set([
|
|
36330
36471
|
"babel-plugin-react-compiler",
|
|
36331
36472
|
"react-compiler-runtime",
|
|
@@ -36362,6 +36503,7 @@ const EXPO_APP_CONFIG_FILENAMES = [
|
|
|
36362
36503
|
];
|
|
36363
36504
|
const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|eslint-plugin-react-compiler|["']react-compiler["']/;
|
|
36364
36505
|
const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
|
|
36506
|
+
const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
|
|
36365
36507
|
const hasCompilerPackage = (packageJson) => {
|
|
36366
36508
|
const allDependencies = {
|
|
36367
36509
|
...packageJson.peerDependencies,
|
|
@@ -36394,34 +36536,10 @@ const detectReactCompiler = (directory, packageJson) => {
|
|
|
36394
36536
|
}
|
|
36395
36537
|
return false;
|
|
36396
36538
|
};
|
|
36397
|
-
const
|
|
36398
|
-
|
|
36399
|
-
|
|
36400
|
-
|
|
36401
|
-
"react-scripts": "cra",
|
|
36402
|
-
"@remix-run/react": "remix",
|
|
36403
|
-
gatsby: "gatsby",
|
|
36404
|
-
expo: "expo",
|
|
36405
|
-
"react-native": "react-native"
|
|
36406
|
-
};
|
|
36407
|
-
const FRAMEWORK_DISPLAY_NAMES = {
|
|
36408
|
-
nextjs: "Next.js",
|
|
36409
|
-
"tanstack-start": "TanStack Start",
|
|
36410
|
-
vite: "Vite",
|
|
36411
|
-
cra: "Create React App",
|
|
36412
|
-
remix: "Remix",
|
|
36413
|
-
gatsby: "Gatsby",
|
|
36414
|
-
expo: "Expo",
|
|
36415
|
-
"react-native": "React Native",
|
|
36416
|
-
preact: "Preact",
|
|
36417
|
-
unknown: "React"
|
|
36418
|
-
};
|
|
36419
|
-
const formatFrameworkName = (framework) => FRAMEWORK_DISPLAY_NAMES[framework];
|
|
36420
|
-
const detectFramework = (dependencies) => {
|
|
36421
|
-
for (const [packageName, frameworkName] of Object.entries(FRAMEWORK_PACKAGES)) if (dependencies[packageName]) return frameworkName;
|
|
36422
|
-
if (dependencies.preact && !dependencies.react) return "preact";
|
|
36423
|
-
return "unknown";
|
|
36424
|
-
};
|
|
36539
|
+
const detectNextjsStaticExport = (directory) => NEXT_CONFIG_FILENAMES.some((filename) => {
|
|
36540
|
+
const filePath = Path.join(directory, filename);
|
|
36541
|
+
return isFile(filePath) && STATIC_EXPORT_OUTPUT_PATTERN.test(NFS.readFileSync(filePath, "utf-8"));
|
|
36542
|
+
});
|
|
36425
36543
|
const UNRESOLVABLE_PROTOCOL_VERSION = /^(?:file|git|github|https?|link|patch|portal|workspace|npm):/i;
|
|
36426
36544
|
const DIST_TAG_VERSION = /^[a-z][a-z0-9._-]*$/i;
|
|
36427
36545
|
const WILDCARD_VERSION = /^[*xX](?:\.[*xX])*$/;
|
|
@@ -36559,10 +36677,76 @@ const isConcreteDependencyVersion = (version) => {
|
|
|
36559
36677
|
const normalizedVersion = normalizeDependencyVersion(version);
|
|
36560
36678
|
return normalizedVersion !== null && /\d/.test(normalizedVersion);
|
|
36561
36679
|
};
|
|
36562
|
-
const
|
|
36563
|
-
if (
|
|
36564
|
-
|
|
36565
|
-
return
|
|
36680
|
+
const isMajorMinorAtLeast = (detected, required) => {
|
|
36681
|
+
if (detected === null) return true;
|
|
36682
|
+
if (detected.major !== required.major) return detected.major > required.major;
|
|
36683
|
+
return detected.minor >= required.minor;
|
|
36684
|
+
};
|
|
36685
|
+
const parseReactMajor = (reactVersion) => {
|
|
36686
|
+
if (typeof reactVersion !== "string") return null;
|
|
36687
|
+
return getLowestDependencyMajor(reactVersion);
|
|
36688
|
+
};
|
|
36689
|
+
const MAJOR_MINOR_PATTERN = /(\d{1,4})\.(\d{1,4})/;
|
|
36690
|
+
const MAJOR_ONLY_PATTERN = /(\d{1,4})/;
|
|
36691
|
+
const UPPER_BOUND_COMPARATOR_PATTERN = /<=?\s{0,8}\d{1,4}(?:\.\d{1,4}){0,2}(?:-[^\s,|]+)?/g;
|
|
36692
|
+
const parseReactMajorMinor = (reactVersion) => {
|
|
36693
|
+
if (typeof reactVersion !== "string") return null;
|
|
36694
|
+
const trimmed = reactVersion.trim();
|
|
36695
|
+
if (trimmed.length === 0) return null;
|
|
36696
|
+
const lowerBoundsOnly = trimmed.replace(UPPER_BOUND_COMPARATOR_PATTERN, " ").trim();
|
|
36697
|
+
if (lowerBoundsOnly.length === 0) return null;
|
|
36698
|
+
const majorMinorMatch = lowerBoundsOnly.match(MAJOR_MINOR_PATTERN);
|
|
36699
|
+
if (majorMinorMatch) {
|
|
36700
|
+
const major = Number.parseInt(majorMinorMatch[1], 10);
|
|
36701
|
+
const minor = Number.parseInt(majorMinorMatch[2], 10);
|
|
36702
|
+
if (!Number.isFinite(major) || major <= 0) return null;
|
|
36703
|
+
if (!Number.isFinite(minor) || minor < 0) return null;
|
|
36704
|
+
return {
|
|
36705
|
+
major,
|
|
36706
|
+
minor
|
|
36707
|
+
};
|
|
36708
|
+
}
|
|
36709
|
+
const majorOnlyMatch = lowerBoundsOnly.match(MAJOR_ONLY_PATTERN);
|
|
36710
|
+
if (!majorOnlyMatch) return null;
|
|
36711
|
+
const major = Number.parseInt(majorOnlyMatch[1], 10);
|
|
36712
|
+
if (!Number.isFinite(major) || major <= 0) return null;
|
|
36713
|
+
return {
|
|
36714
|
+
major,
|
|
36715
|
+
minor: 0
|
|
36716
|
+
};
|
|
36717
|
+
};
|
|
36718
|
+
const parseLowerBoundVersion = (versionSpec) => import_semver.validRange(versionSpec) !== null ? import_semver.minVersion(versionSpec) : import_semver.coerce(versionSpec);
|
|
36719
|
+
const parseTailwindMajorMinor = (tailwindVersion) => {
|
|
36720
|
+
if (typeof tailwindVersion !== "string") return null;
|
|
36721
|
+
const trimmed = tailwindVersion.trim();
|
|
36722
|
+
if (trimmed.length === 0) return null;
|
|
36723
|
+
const lowerBound = parseLowerBoundVersion(trimmed);
|
|
36724
|
+
if (lowerBound === null || lowerBound.major <= 0) return null;
|
|
36725
|
+
return {
|
|
36726
|
+
major: lowerBound.major,
|
|
36727
|
+
minor: lowerBound.minor
|
|
36728
|
+
};
|
|
36729
|
+
};
|
|
36730
|
+
const hasUpperBoundOnlyPeerRange = (range) => {
|
|
36731
|
+
if (typeof range !== "string") return false;
|
|
36732
|
+
const normalizedRange = normalizeDependencyVersion(range);
|
|
36733
|
+
if (normalizedRange === null) return false;
|
|
36734
|
+
return splitDependencyVersionBranches(normalizedRange).some((branch) => {
|
|
36735
|
+
const normalizedBranch = normalizeDependencyVersion(branch);
|
|
36736
|
+
return normalizedBranch !== null && getBranchLowestMajor(normalizedBranch) === null && hasUpperBoundComparator(normalizedBranch);
|
|
36737
|
+
});
|
|
36738
|
+
};
|
|
36739
|
+
const peerRangeMinMajor = (range) => {
|
|
36740
|
+
if (typeof range !== "string") return null;
|
|
36741
|
+
return getLowestDependencyMajor(range);
|
|
36742
|
+
};
|
|
36743
|
+
const resolveEffectiveReactMajor = (reactVersion, packageJson) => {
|
|
36744
|
+
const installedReactMajor = parseReactMajor(reactVersion);
|
|
36745
|
+
const peerReactRange = packageJson.peerDependencies?.react;
|
|
36746
|
+
if (typeof peerReactRange !== "string") return installedReactMajor;
|
|
36747
|
+
const peerFloor = peerRangeMinMajor(peerReactRange);
|
|
36748
|
+
if (peerFloor === null) return hasUpperBoundOnlyPeerRange(peerReactRange) ? null : installedReactMajor;
|
|
36749
|
+
return installedReactMajor !== null ? Math.min(installedReactMajor, peerFloor) : peerFloor;
|
|
36566
36750
|
};
|
|
36567
36751
|
const isCatalogReference = (version) => version.startsWith("catalog:");
|
|
36568
36752
|
const extractCatalogName = (version) => {
|
|
@@ -36704,6 +36888,16 @@ const resolveCatalogVersion = (packageJson, packageName, rootDirectory, explicit
|
|
|
36704
36888
|
}
|
|
36705
36889
|
return null;
|
|
36706
36890
|
};
|
|
36891
|
+
const REACT_SECTIONS = [
|
|
36892
|
+
"dependencies",
|
|
36893
|
+
"peerDependencies",
|
|
36894
|
+
"devDependencies"
|
|
36895
|
+
];
|
|
36896
|
+
const TAILWIND_ZOD_SECTIONS = [
|
|
36897
|
+
"dependencies",
|
|
36898
|
+
"devDependencies",
|
|
36899
|
+
"peerDependencies"
|
|
36900
|
+
];
|
|
36707
36901
|
const EMPTY_DEPENDENCY_INFO = {
|
|
36708
36902
|
reactVersion: null,
|
|
36709
36903
|
tailwindVersion: null,
|
|
@@ -36744,6 +36938,10 @@ const extractDependencyInfo = (packageJson) => {
|
|
|
36744
36938
|
framework: detectFramework(allDependencies)
|
|
36745
36939
|
};
|
|
36746
36940
|
};
|
|
36941
|
+
const getDependencySpec = (packageJson, packageName) => {
|
|
36942
|
+
const spec = packageJson.dependencies?.[packageName] ?? packageJson.devDependencies?.[packageName] ?? packageJson.peerDependencies?.[packageName] ?? packageJson.optionalDependencies?.[packageName];
|
|
36943
|
+
return typeof spec === "string" ? spec : null;
|
|
36944
|
+
};
|
|
36747
36945
|
const getDependencyDeclaration = ({ packageJson, packageName, sections }) => {
|
|
36748
36946
|
for (const section of sections) {
|
|
36749
36947
|
const version = packageJson[section]?.[packageName];
|
|
@@ -36760,31 +36958,141 @@ const getDependencyDeclaration = ({ packageJson, packageName, sections }) => {
|
|
|
36760
36958
|
version: null
|
|
36761
36959
|
};
|
|
36762
36960
|
};
|
|
36763
|
-
const
|
|
36764
|
-
|
|
36765
|
-
|
|
36766
|
-
|
|
36767
|
-
|
|
36961
|
+
const REACT_DEPENDENCY_NAMES = new Set([
|
|
36962
|
+
"react",
|
|
36963
|
+
"react-native",
|
|
36964
|
+
"next",
|
|
36965
|
+
"preact"
|
|
36966
|
+
]);
|
|
36967
|
+
const hasReactDependency = (packageJson) => {
|
|
36968
|
+
const allDependencies = {
|
|
36969
|
+
...packageJson.peerDependencies,
|
|
36970
|
+
...packageJson.dependencies,
|
|
36971
|
+
...packageJson.devDependencies
|
|
36972
|
+
};
|
|
36973
|
+
return Object.keys(allDependencies).some((packageName) => REACT_DEPENDENCY_NAMES.has(packageName));
|
|
36974
|
+
};
|
|
36975
|
+
const getPreactVersion = (packageJson) => {
|
|
36976
|
+
return {
|
|
36977
|
+
...packageJson.peerDependencies,
|
|
36978
|
+
...packageJson.dependencies,
|
|
36979
|
+
...packageJson.devDependencies
|
|
36980
|
+
}.preact ?? null;
|
|
36981
|
+
};
|
|
36982
|
+
const TANSTACK_QUERY_PACKAGES = new Set([
|
|
36983
|
+
"@tanstack/react-query",
|
|
36984
|
+
"@tanstack/query-core",
|
|
36985
|
+
"react-query"
|
|
36986
|
+
]);
|
|
36987
|
+
const hasTanStackQuery = (packageJson) => {
|
|
36988
|
+
const allDependencies = {
|
|
36989
|
+
...packageJson.peerDependencies,
|
|
36990
|
+
...packageJson.dependencies,
|
|
36991
|
+
...packageJson.devDependencies
|
|
36992
|
+
};
|
|
36993
|
+
return Object.keys(allDependencies).some((packageName) => TANSTACK_QUERY_PACKAGES.has(packageName));
|
|
36994
|
+
};
|
|
36995
|
+
const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, version }) => {
|
|
36996
|
+
if (version === null || !isCatalogReference(version)) return version;
|
|
36997
|
+
const catalogName = extractCatalogName(version);
|
|
36998
|
+
const resolvedLocalVersion = resolveCatalogVersion(rootPackageJson, packageName, rootDirectory, catalogName);
|
|
36999
|
+
if (resolvedLocalVersion) return resolvedLocalVersion;
|
|
37000
|
+
const monorepoRoot = findMonorepoRoot(rootDirectory);
|
|
37001
|
+
if (!monorepoRoot) return version;
|
|
37002
|
+
const monorepoPackageJsonPath = Path.join(monorepoRoot, "package.json");
|
|
37003
|
+
if (!isFile(monorepoPackageJsonPath)) return version;
|
|
37004
|
+
return resolveCatalogVersion(readPackageJson$1(monorepoPackageJsonPath), packageName, monorepoRoot, catalogName) ?? version;
|
|
37005
|
+
};
|
|
37006
|
+
/**
|
|
37007
|
+
* The chain of ancestor directories of `startDirectory`, nearest first, up to
|
|
37008
|
+
* and including the filesystem root. With `includeStart`, the chain begins at
|
|
37009
|
+
* `startDirectory` itself; otherwise at its parent. The one place the "walk up
|
|
37010
|
+
* the tree" traversal is expressed, so each caller adds only its own match /
|
|
37011
|
+
* stop policy instead of re-deriving the `path.dirname` loop.
|
|
37012
|
+
*/
|
|
37013
|
+
const ancestorDirectories = (startDirectory, { includeStart }) => {
|
|
37014
|
+
const directories = [];
|
|
37015
|
+
let currentDirectory = includeStart ? startDirectory : Path.dirname(startDirectory);
|
|
37016
|
+
while (true) {
|
|
37017
|
+
directories.push(currentDirectory);
|
|
37018
|
+
const parentDirectory = Path.dirname(currentDirectory);
|
|
37019
|
+
if (parentDirectory === currentDirectory) return directories;
|
|
37020
|
+
currentDirectory = parentDirectory;
|
|
36768
37021
|
}
|
|
36769
37022
|
};
|
|
36770
|
-
|
|
36771
|
-
|
|
36772
|
-
|
|
36773
|
-
|
|
36774
|
-
|
|
36775
|
-
|
|
36776
|
-
|
|
36777
|
-
|
|
36778
|
-
|
|
36779
|
-
|
|
36780
|
-
|
|
36781
|
-
|
|
36782
|
-
|
|
36783
|
-
|
|
36784
|
-
|
|
36785
|
-
|
|
37023
|
+
/**
|
|
37024
|
+
* Walk up from `startDirectory` to the nearest ancestor that owns a
|
|
37025
|
+
* `package.json`, stopping at (and including) the enclosing project boundary
|
|
37026
|
+
* — the working tree's git root or a monorepo root. Lets a scan of a package
|
|
37027
|
+
* subfolder that has no `package.json` of its own adopt the nearest enclosing
|
|
37028
|
+
* package as its project root, so it inherits that package's dependency +
|
|
37029
|
+
* framework detection instead of synthesizing an empty (React-blind) project.
|
|
37030
|
+
*
|
|
37031
|
+
* Generalizes the older monorepo-root-only lookup: the nearest ancestor is the
|
|
37032
|
+
* most specific owning package (a leaf workspace, not just the repo root), so
|
|
37033
|
+
* a subfolder of one workspace no longer borrows a sibling's capabilities.
|
|
37034
|
+
*
|
|
37035
|
+
* Returns `null` when no ancestor `package.json` exists inside the project
|
|
37036
|
+
* boundary (a loose tree of files, or a subfolder of a package-less repo).
|
|
37037
|
+
*/
|
|
37038
|
+
const findNearestAncestorPackageJson = (startDirectory) => {
|
|
37039
|
+
if (isProjectBoundary(startDirectory)) return null;
|
|
37040
|
+
for (const directory of ancestorDirectories(startDirectory, { includeStart: false })) {
|
|
37041
|
+
if (isFile(Path.join(directory, "package.json"))) return directory;
|
|
37042
|
+
if (isProjectBoundary(directory)) return null;
|
|
36786
37043
|
}
|
|
36787
|
-
return
|
|
37044
|
+
return null;
|
|
37045
|
+
};
|
|
37046
|
+
const NAMES = new Set([
|
|
37047
|
+
"react-native",
|
|
37048
|
+
"react-native-tvos",
|
|
37049
|
+
...new Set([
|
|
37050
|
+
"expo",
|
|
37051
|
+
"expo-router",
|
|
37052
|
+
"@expo/cli",
|
|
37053
|
+
"@expo/metro-config",
|
|
37054
|
+
"@expo/metro-runtime"
|
|
37055
|
+
]),
|
|
37056
|
+
"react-native-windows",
|
|
37057
|
+
"react-native-macos"
|
|
37058
|
+
]);
|
|
37059
|
+
const PREFIXES = ["@react-native/", "@react-native-"];
|
|
37060
|
+
const isReactNativeDependencyName = (dependencyName) => {
|
|
37061
|
+
if (NAMES.has(dependencyName)) return true;
|
|
37062
|
+
for (const prefix of PREFIXES) if (dependencyName.startsWith(prefix)) return true;
|
|
37063
|
+
return false;
|
|
37064
|
+
};
|
|
37065
|
+
const containsAnyReactNativeDependency = (section) => {
|
|
37066
|
+
if (!section) return false;
|
|
37067
|
+
for (const dependencyName of Object.keys(section)) if (isReactNativeDependencyName(dependencyName)) return true;
|
|
37068
|
+
return false;
|
|
37069
|
+
};
|
|
37070
|
+
const isPackageJsonReactNativeAware = (packageJson) => {
|
|
37071
|
+
if (typeof packageJson["react-native"] === "string") return true;
|
|
37072
|
+
if (containsAnyReactNativeDependency(packageJson.dependencies)) return true;
|
|
37073
|
+
if (containsAnyReactNativeDependency(packageJson.devDependencies)) return true;
|
|
37074
|
+
if (containsAnyReactNativeDependency(packageJson.peerDependencies)) return true;
|
|
37075
|
+
if (containsAnyReactNativeDependency(packageJson.optionalDependencies)) return true;
|
|
37076
|
+
return false;
|
|
37077
|
+
};
|
|
37078
|
+
const REANIMATED_DEPENDENCY_NAME$1 = "react-native-reanimated";
|
|
37079
|
+
const isPackageJsonReanimatedAware = (packageJson) => {
|
|
37080
|
+
const allDependencies = {
|
|
37081
|
+
...packageJson.peerDependencies,
|
|
37082
|
+
...packageJson.dependencies,
|
|
37083
|
+
...packageJson.devDependencies,
|
|
37084
|
+
...packageJson.optionalDependencies
|
|
37085
|
+
};
|
|
37086
|
+
return Object.hasOwn(allDependencies, REANIMATED_DEPENDENCY_NAME$1);
|
|
37087
|
+
};
|
|
37088
|
+
const getWorkspacePatterns = (rootDirectory, packageJson) => {
|
|
37089
|
+
const pnpmPatterns = parsePnpmWorkspacePatterns(rootDirectory);
|
|
37090
|
+
if (pnpmPatterns.length > 0) return pnpmPatterns;
|
|
37091
|
+
if (Array.isArray(packageJson.workspaces)) return packageJson.workspaces;
|
|
37092
|
+
if (packageJson.workspaces?.packages) return packageJson.workspaces.packages;
|
|
37093
|
+
const nxPatterns = getNxWorkspaceDirectories(rootDirectory);
|
|
37094
|
+
if (nxPatterns.length > 0) return nxPatterns;
|
|
37095
|
+
return [];
|
|
36788
37096
|
};
|
|
36789
37097
|
const parsePnpmWorkspacePatterns = (rootDirectory) => {
|
|
36790
37098
|
const workspacePath = Path.join(rootDirectory, "pnpm-workspace.yaml");
|
|
@@ -36803,18 +37111,24 @@ const parsePnpmWorkspacePatterns = (rootDirectory) => {
|
|
|
36803
37111
|
}
|
|
36804
37112
|
return patterns;
|
|
36805
37113
|
};
|
|
36806
|
-
const
|
|
36807
|
-
|
|
36808
|
-
|
|
36809
|
-
|
|
36810
|
-
|
|
36811
|
-
|
|
36812
|
-
if (
|
|
36813
|
-
|
|
36814
|
-
|
|
36815
|
-
const
|
|
36816
|
-
|
|
36817
|
-
|
|
37114
|
+
const NX_PROJECT_DISCOVERY_DIRS = [
|
|
37115
|
+
"apps",
|
|
37116
|
+
"libs",
|
|
37117
|
+
"packages"
|
|
37118
|
+
];
|
|
37119
|
+
const getNxWorkspaceDirectories = (rootDirectory) => {
|
|
37120
|
+
if (!isFile(Path.join(rootDirectory, "nx.json"))) return [];
|
|
37121
|
+
const collected = [];
|
|
37122
|
+
for (const candidate of NX_PROJECT_DISCOVERY_DIRS) {
|
|
37123
|
+
const candidatePath = Path.join(rootDirectory, candidate);
|
|
37124
|
+
if (!isDirectory(candidatePath)) continue;
|
|
37125
|
+
for (const entry of readDirectoryEntries(candidatePath)) {
|
|
37126
|
+
if (!entry.isDirectory()) continue;
|
|
37127
|
+
const projectDirectory = Path.join(candidatePath, entry.name);
|
|
37128
|
+
if (isFile(Path.join(projectDirectory, "project.json")) || isFile(Path.join(projectDirectory, "package.json"))) collected.push(`${candidate}/${entry.name}`);
|
|
37129
|
+
}
|
|
37130
|
+
}
|
|
37131
|
+
return collected;
|
|
36818
37132
|
};
|
|
36819
37133
|
const resolveWorkspaceDirectories = (rootDirectory, pattern) => {
|
|
36820
37134
|
const cleanPattern = pattern.replace(/["']/g, "").replace(/\/\*\*$/, "/*");
|
|
@@ -36834,6 +37148,38 @@ const resolveWorkspaceDirectories = (rootDirectory, pattern) => {
|
|
|
36834
37148
|
}
|
|
36835
37149
|
return resolved;
|
|
36836
37150
|
};
|
|
37151
|
+
const listWorkspacePackages = (rootDirectory) => {
|
|
37152
|
+
const packageJsonPath = Path.join(rootDirectory, "package.json");
|
|
37153
|
+
if (!isFile(packageJsonPath)) return [];
|
|
37154
|
+
const packageJson = readPackageJson$1(packageJsonPath);
|
|
37155
|
+
const patterns = getWorkspacePatterns(rootDirectory, packageJson);
|
|
37156
|
+
if (patterns.length === 0) return [];
|
|
37157
|
+
const packages = [];
|
|
37158
|
+
const seenDirectories = /* @__PURE__ */ new Set();
|
|
37159
|
+
const pushIfNew = (workspacePackage) => {
|
|
37160
|
+
if (seenDirectories.has(workspacePackage.directory)) return;
|
|
37161
|
+
seenDirectories.add(workspacePackage.directory);
|
|
37162
|
+
packages.push(workspacePackage);
|
|
37163
|
+
};
|
|
37164
|
+
if (hasReactDependency(packageJson)) pushIfNew({
|
|
37165
|
+
name: packageJson.name ?? Path.basename(rootDirectory),
|
|
37166
|
+
directory: rootDirectory
|
|
37167
|
+
});
|
|
37168
|
+
for (const pattern of patterns) {
|
|
37169
|
+
const directories = resolveWorkspaceDirectories(rootDirectory, pattern);
|
|
37170
|
+
for (const workspaceDirectory of directories) {
|
|
37171
|
+
const workspacePackageJson = readPackageJson$1(Path.join(workspaceDirectory, "package.json"));
|
|
37172
|
+
if (!hasReactDependency(workspacePackageJson)) continue;
|
|
37173
|
+
pushIfNew({
|
|
37174
|
+
name: workspacePackageJson.name ?? Path.basename(workspaceDirectory),
|
|
37175
|
+
directory: workspaceDirectory
|
|
37176
|
+
});
|
|
37177
|
+
}
|
|
37178
|
+
}
|
|
37179
|
+
return packages;
|
|
37180
|
+
};
|
|
37181
|
+
const REANIMATED_DEPENDENCY_NAME = "react-native-reanimated";
|
|
37182
|
+
const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
|
|
36837
37183
|
const resolveWorkspaceDependencyVersion = ({ concreteVersion, packageName, rootDirectory, rootPackageJson, sections, workspaceDirectory, workspacePackageJson }) => {
|
|
36838
37184
|
const dependencyDeclaration = getDependencyDeclaration({
|
|
36839
37185
|
packageJson: workspacePackageJson,
|
|
@@ -36851,24 +37197,76 @@ const shouldReplaceReactVersion = (currentVersion, nextVersion) => {
|
|
|
36851
37197
|
if (nextMajor === null) return false;
|
|
36852
37198
|
return nextMajor < currentMajor;
|
|
36853
37199
|
};
|
|
36854
|
-
const
|
|
36855
|
-
|
|
36856
|
-
|
|
36857
|
-
|
|
36858
|
-
|
|
37200
|
+
const evaluateManifestFacts = (facts, packageJson, directory) => {
|
|
37201
|
+
if (facts.expo.version === null) {
|
|
37202
|
+
const spec = getDependencySpec(packageJson, "expo");
|
|
37203
|
+
if (spec !== null) facts.expo = {
|
|
37204
|
+
version: spec,
|
|
37205
|
+
sourceDirectory: directory
|
|
37206
|
+
};
|
|
37207
|
+
}
|
|
37208
|
+
if (facts.next.version === null) {
|
|
37209
|
+
const spec = getDependencySpec(packageJson, "next");
|
|
37210
|
+
if (spec !== null) facts.next = {
|
|
37211
|
+
version: spec,
|
|
37212
|
+
sourceDirectory: directory
|
|
37213
|
+
};
|
|
37214
|
+
}
|
|
37215
|
+
if (facts.shopifyFlashList.version === null) {
|
|
37216
|
+
const spec = getDependencySpec(packageJson, SHOPIFY_FLASH_LIST_PACKAGE_NAME);
|
|
37217
|
+
if (spec !== null) facts.shopifyFlashList = {
|
|
37218
|
+
version: spec,
|
|
37219
|
+
sourceDirectory: directory
|
|
37220
|
+
};
|
|
37221
|
+
}
|
|
37222
|
+
if (facts.reanimatedVersion === null) {
|
|
37223
|
+
const spec = getDependencySpec(packageJson, REANIMATED_DEPENDENCY_NAME);
|
|
37224
|
+
if (spec !== null) facts.reanimatedVersion = spec;
|
|
37225
|
+
}
|
|
37226
|
+
facts.hasReactNativeAwarePackage = facts.hasReactNativeAwarePackage || isPackageJsonReactNativeAware(packageJson);
|
|
37227
|
+
facts.hasReanimatedAwarePackage = facts.hasReanimatedAwarePackage || isPackageJsonReanimatedAware(packageJson);
|
|
37228
|
+
};
|
|
37229
|
+
const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGroup }) => {
|
|
37230
|
+
const facts = {
|
|
37231
|
+
reactVersion: null,
|
|
37232
|
+
tailwindVersion: null,
|
|
37233
|
+
zodVersion: null,
|
|
37234
|
+
framework: "unknown",
|
|
37235
|
+
expo: {
|
|
37236
|
+
version: null,
|
|
37237
|
+
sourceDirectory: null
|
|
37238
|
+
},
|
|
37239
|
+
next: {
|
|
37240
|
+
version: null,
|
|
37241
|
+
sourceDirectory: null
|
|
37242
|
+
},
|
|
37243
|
+
shopifyFlashList: {
|
|
37244
|
+
version: null,
|
|
37245
|
+
sourceDirectory: null
|
|
37246
|
+
},
|
|
37247
|
+
hasReactNativeAwarePackage: false,
|
|
37248
|
+
hasReanimatedAwarePackage: false,
|
|
37249
|
+
reanimatedVersion: null
|
|
37250
|
+
};
|
|
37251
|
+
evaluateManifestFacts(facts, rootPackageJson, rootDirectory);
|
|
37252
|
+
let isReactGroupSettled = !collectReactGroup;
|
|
37253
|
+
const visitedDirectories = /* @__PURE__ */ new Set();
|
|
37254
|
+
for (const pattern of getWorkspacePatterns(rootDirectory, rootPackageJson)) {
|
|
37255
|
+
const directories = [...resolveWorkspaceDirectories(rootDirectory, pattern)].sort();
|
|
36859
37256
|
for (const workspaceDirectory of directories) {
|
|
37257
|
+
if (visitedDirectories.has(workspaceDirectory)) continue;
|
|
37258
|
+
visitedDirectories.add(workspaceDirectory);
|
|
36860
37259
|
const workspacePackageJson = readPackageJson$1(Path.join(workspaceDirectory, "package.json"));
|
|
37260
|
+
evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory);
|
|
36861
37261
|
const info = extractDependencyInfo(workspacePackageJson);
|
|
37262
|
+
if (info.framework !== "unknown" && frameworkMergeRank(info.framework) < frameworkMergeRank(facts.framework)) facts.framework = info.framework;
|
|
37263
|
+
if (isReactGroupSettled) continue;
|
|
36862
37264
|
const reactVersion = resolveWorkspaceDependencyVersion({
|
|
36863
37265
|
concreteVersion: info.reactVersion,
|
|
36864
37266
|
packageName: "react",
|
|
36865
37267
|
rootDirectory,
|
|
36866
|
-
rootPackageJson
|
|
36867
|
-
sections:
|
|
36868
|
-
"dependencies",
|
|
36869
|
-
"peerDependencies",
|
|
36870
|
-
"devDependencies"
|
|
36871
|
-
],
|
|
37268
|
+
rootPackageJson,
|
|
37269
|
+
sections: REACT_SECTIONS,
|
|
36872
37270
|
workspaceDirectory,
|
|
36873
37271
|
workspacePackageJson
|
|
36874
37272
|
});
|
|
@@ -36876,12 +37274,8 @@ const findReactInWorkspaces = (rootDirectory, packageJson) => {
|
|
|
36876
37274
|
concreteVersion: info.tailwindVersion,
|
|
36877
37275
|
packageName: "tailwindcss",
|
|
36878
37276
|
rootDirectory,
|
|
36879
|
-
rootPackageJson
|
|
36880
|
-
sections:
|
|
36881
|
-
"dependencies",
|
|
36882
|
-
"devDependencies",
|
|
36883
|
-
"peerDependencies"
|
|
36884
|
-
],
|
|
37277
|
+
rootPackageJson,
|
|
37278
|
+
sections: TAILWIND_ZOD_SECTIONS,
|
|
36885
37279
|
workspaceDirectory,
|
|
36886
37280
|
workspacePackageJson
|
|
36887
37281
|
});
|
|
@@ -36889,24 +37283,19 @@ const findReactInWorkspaces = (rootDirectory, packageJson) => {
|
|
|
36889
37283
|
concreteVersion: info.zodVersion,
|
|
36890
37284
|
packageName: "zod",
|
|
36891
37285
|
rootDirectory,
|
|
36892
|
-
rootPackageJson
|
|
36893
|
-
sections:
|
|
36894
|
-
"dependencies",
|
|
36895
|
-
"devDependencies",
|
|
36896
|
-
"peerDependencies"
|
|
36897
|
-
],
|
|
37286
|
+
rootPackageJson,
|
|
37287
|
+
sections: TAILWIND_ZOD_SECTIONS,
|
|
36898
37288
|
workspaceDirectory,
|
|
36899
37289
|
workspacePackageJson
|
|
36900
37290
|
});
|
|
36901
|
-
if (reactVersion && shouldReplaceReactVersion(
|
|
36902
|
-
if (tailwindVersion && !
|
|
36903
|
-
if (zodVersion && !
|
|
36904
|
-
|
|
36905
|
-
|
|
36906
|
-
if (result.reactVersion && result.tailwindVersion && result.framework !== "unknown" && resultReactMajor !== null && resultReactMajor <= 17) return result;
|
|
37291
|
+
if (reactVersion && shouldReplaceReactVersion(facts.reactVersion, reactVersion)) facts.reactVersion = reactVersion;
|
|
37292
|
+
if (tailwindVersion && !facts.tailwindVersion) facts.tailwindVersion = tailwindVersion;
|
|
37293
|
+
if (zodVersion && !facts.zodVersion) facts.zodVersion = zodVersion;
|
|
37294
|
+
const settledReactMajor = parseReactMajor(facts.reactVersion);
|
|
37295
|
+
isReactGroupSettled = Boolean(facts.reactVersion && facts.tailwindVersion && facts.framework !== "unknown" && settledReactMajor !== null && settledReactMajor <= 17);
|
|
36907
37296
|
}
|
|
36908
37297
|
}
|
|
36909
|
-
return
|
|
37298
|
+
return facts;
|
|
36910
37299
|
};
|
|
36911
37300
|
const findDependencyInfoFromMonorepoRoot = (directory) => {
|
|
36912
37301
|
const monorepoRoot = findMonorepoRoot(directory);
|
|
@@ -36920,29 +37309,17 @@ const findDependencyInfoFromMonorepoRoot = (directory) => {
|
|
|
36920
37309
|
const leafReactDeclaration = leafPackageJson ? getDependencyDeclaration({
|
|
36921
37310
|
packageJson: leafPackageJson,
|
|
36922
37311
|
packageName: "react",
|
|
36923
|
-
sections:
|
|
36924
|
-
"dependencies",
|
|
36925
|
-
"peerDependencies",
|
|
36926
|
-
"devDependencies"
|
|
36927
|
-
]
|
|
37312
|
+
sections: REACT_SECTIONS
|
|
36928
37313
|
}) : null;
|
|
36929
37314
|
const leafTailwindDeclaration = leafPackageJson ? getDependencyDeclaration({
|
|
36930
37315
|
packageJson: leafPackageJson,
|
|
36931
37316
|
packageName: "tailwindcss",
|
|
36932
|
-
sections:
|
|
36933
|
-
"dependencies",
|
|
36934
|
-
"devDependencies",
|
|
36935
|
-
"peerDependencies"
|
|
36936
|
-
]
|
|
37317
|
+
sections: TAILWIND_ZOD_SECTIONS
|
|
36937
37318
|
}) : null;
|
|
36938
37319
|
const leafZodDeclaration = leafPackageJson ? getDependencyDeclaration({
|
|
36939
37320
|
packageJson: leafPackageJson,
|
|
36940
37321
|
packageName: "zod",
|
|
36941
|
-
sections:
|
|
36942
|
-
"dependencies",
|
|
36943
|
-
"devDependencies",
|
|
36944
|
-
"peerDependencies"
|
|
36945
|
-
]
|
|
37322
|
+
sections: TAILWIND_ZOD_SECTIONS
|
|
36946
37323
|
}) : null;
|
|
36947
37324
|
const shouldUseReactFallback = !leafReactDeclaration?.hasDeclaration;
|
|
36948
37325
|
const shouldUseTailwindFallback = leafTailwindDeclaration?.hasDeclaration ?? true;
|
|
@@ -36950,38 +37327,15 @@ const findDependencyInfoFromMonorepoRoot = (directory) => {
|
|
|
36950
37327
|
const reactCatalogVersion = shouldUseReactFallback ? resolveCatalogVersion(rootPackageJson, "react", monorepoRoot, leafReactDeclaration?.catalogReference) : null;
|
|
36951
37328
|
const tailwindCatalogVersion = shouldUseTailwindFallback ? resolveCatalogVersion(rootPackageJson, "tailwindcss", monorepoRoot, leafTailwindDeclaration?.catalogReference) : null;
|
|
36952
37329
|
const zodCatalogVersion = shouldUseZodFallback ? resolveCatalogVersion(rootPackageJson, "zod", monorepoRoot, leafZodDeclaration?.catalogReference) : null;
|
|
36953
|
-
const
|
|
37330
|
+
const workspaceFacts = collectWorkspaceFacts(monorepoRoot, rootPackageJson, { collectReactGroup: true });
|
|
36954
37331
|
return {
|
|
36955
|
-
reactVersion: shouldUseReactFallback ? reactCatalogVersion ?? rootInfo.reactVersion ??
|
|
36956
|
-
tailwindVersion: shouldUseTailwindFallback ? tailwindCatalogVersion ?? rootInfo.tailwindVersion ??
|
|
36957
|
-
zodVersion: shouldUseZodFallback ? zodCatalogVersion ?? rootInfo.zodVersion ??
|
|
36958
|
-
framework: rootInfo.framework !== "unknown" ? rootInfo.framework :
|
|
37332
|
+
reactVersion: shouldUseReactFallback ? reactCatalogVersion ?? rootInfo.reactVersion ?? workspaceFacts.reactVersion : rootInfo.reactVersion ?? workspaceFacts.reactVersion,
|
|
37333
|
+
tailwindVersion: shouldUseTailwindFallback ? tailwindCatalogVersion ?? rootInfo.tailwindVersion ?? workspaceFacts.tailwindVersion : null,
|
|
37334
|
+
zodVersion: shouldUseZodFallback ? zodCatalogVersion ?? rootInfo.zodVersion ?? workspaceFacts.zodVersion : null,
|
|
37335
|
+
framework: rootInfo.framework !== "unknown" ? rootInfo.framework : workspaceFacts.framework
|
|
36959
37336
|
};
|
|
36960
37337
|
};
|
|
36961
37338
|
/**
|
|
36962
|
-
* Walk up from `startDirectory` to the nearest ancestor that owns a
|
|
36963
|
-
* `package.json`, stopping at (and including) the enclosing project boundary
|
|
36964
|
-
* — the working tree's git root or a monorepo root. Lets a scan of a package
|
|
36965
|
-
* subfolder that has no `package.json` of its own adopt the nearest enclosing
|
|
36966
|
-
* package as its project root, so it inherits that package's dependency +
|
|
36967
|
-
* framework detection instead of synthesizing an empty (React-blind) project.
|
|
36968
|
-
*
|
|
36969
|
-
* Generalizes the older monorepo-root-only lookup: the nearest ancestor is the
|
|
36970
|
-
* most specific owning package (a leaf workspace, not just the repo root), so
|
|
36971
|
-
* a subfolder of one workspace no longer borrows a sibling's capabilities.
|
|
36972
|
-
*
|
|
36973
|
-
* Returns `null` when no ancestor `package.json` exists inside the project
|
|
36974
|
-
* boundary (a loose tree of files, or a subfolder of a package-less repo).
|
|
36975
|
-
*/
|
|
36976
|
-
const findNearestAncestorPackageJson = (startDirectory) => {
|
|
36977
|
-
if (isProjectBoundary(startDirectory)) return null;
|
|
36978
|
-
for (const directory of ancestorDirectories(startDirectory, { includeStart: false })) {
|
|
36979
|
-
if (isFile(Path.join(directory, "package.json"))) return directory;
|
|
36980
|
-
if (isProjectBoundary(directory)) return null;
|
|
36981
|
-
}
|
|
36982
|
-
return null;
|
|
36983
|
-
};
|
|
36984
|
-
/**
|
|
36985
37339
|
* Last-resort React detection: locate React the way Node's `node_modules`
|
|
36986
37340
|
* resolution would from `directory` — check each `node_modules/react` up the
|
|
36987
37341
|
* tree — but bounded to the enclosing repo so a globally installed React can't
|
|
@@ -37026,295 +37380,6 @@ const resolveInstalledReactVersion = (directory) => {
|
|
|
37026
37380
|
}
|
|
37027
37381
|
return null;
|
|
37028
37382
|
};
|
|
37029
|
-
const findInWorkspacePackageJsons = (rootDirectory, rootPackageJson, select) => {
|
|
37030
|
-
const rootValue = select(rootPackageJson);
|
|
37031
|
-
if (rootValue !== null) return rootValue;
|
|
37032
|
-
const patterns = getWorkspacePatterns(rootDirectory, rootPackageJson);
|
|
37033
|
-
if (patterns.length === 0) return null;
|
|
37034
|
-
const visitedDirectories = /* @__PURE__ */ new Set();
|
|
37035
|
-
for (const pattern of patterns) {
|
|
37036
|
-
const directories = [...resolveWorkspaceDirectories(rootDirectory, pattern)].sort();
|
|
37037
|
-
for (const workspaceDirectory of directories) {
|
|
37038
|
-
if (visitedDirectories.has(workspaceDirectory)) continue;
|
|
37039
|
-
visitedDirectories.add(workspaceDirectory);
|
|
37040
|
-
const value = select(readPackageJson$1(Path.join(workspaceDirectory, "package.json")));
|
|
37041
|
-
if (value !== null) return value;
|
|
37042
|
-
}
|
|
37043
|
-
}
|
|
37044
|
-
return null;
|
|
37045
|
-
};
|
|
37046
|
-
const someWorkspacePackageJson = (rootDirectory, rootPackageJson, predicate) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => predicate(packageJson) ? true : null) !== null;
|
|
37047
|
-
const NAMES = new Set([
|
|
37048
|
-
"react-native",
|
|
37049
|
-
"react-native-tvos",
|
|
37050
|
-
...new Set([
|
|
37051
|
-
"expo",
|
|
37052
|
-
"expo-router",
|
|
37053
|
-
"@expo/cli",
|
|
37054
|
-
"@expo/metro-config",
|
|
37055
|
-
"@expo/metro-runtime"
|
|
37056
|
-
]),
|
|
37057
|
-
"react-native-windows",
|
|
37058
|
-
"react-native-macos"
|
|
37059
|
-
]);
|
|
37060
|
-
const PREFIXES = ["@react-native/", "@react-native-"];
|
|
37061
|
-
const isReactNativeDependencyName = (dependencyName) => {
|
|
37062
|
-
if (NAMES.has(dependencyName)) return true;
|
|
37063
|
-
for (const prefix of PREFIXES) if (dependencyName.startsWith(prefix)) return true;
|
|
37064
|
-
return false;
|
|
37065
|
-
};
|
|
37066
|
-
const containsAnyReactNativeDependency = (section) => {
|
|
37067
|
-
if (!section) return false;
|
|
37068
|
-
for (const dependencyName of Object.keys(section)) if (isReactNativeDependencyName(dependencyName)) return true;
|
|
37069
|
-
return false;
|
|
37070
|
-
};
|
|
37071
|
-
const isPackageJsonReactNativeAware = (packageJson) => {
|
|
37072
|
-
if (typeof packageJson["react-native"] === "string") return true;
|
|
37073
|
-
if (containsAnyReactNativeDependency(packageJson.dependencies)) return true;
|
|
37074
|
-
if (containsAnyReactNativeDependency(packageJson.devDependencies)) return true;
|
|
37075
|
-
if (containsAnyReactNativeDependency(packageJson.peerDependencies)) return true;
|
|
37076
|
-
if (containsAnyReactNativeDependency(packageJson.optionalDependencies)) return true;
|
|
37077
|
-
return false;
|
|
37078
|
-
};
|
|
37079
|
-
const hasReactNativeWorkspaceAnywhere = (rootDirectory, rootPackageJson) => someWorkspacePackageJson(rootDirectory, rootPackageJson, isPackageJsonReactNativeAware);
|
|
37080
|
-
const getDependencySpec = (packageJson, packageName) => {
|
|
37081
|
-
const spec = packageJson.dependencies?.[packageName] ?? packageJson.devDependencies?.[packageName] ?? packageJson.peerDependencies?.[packageName] ?? packageJson.optionalDependencies?.[packageName];
|
|
37082
|
-
return typeof spec === "string" ? spec : null;
|
|
37083
|
-
};
|
|
37084
|
-
const findExpoVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, "expo"));
|
|
37085
|
-
const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
|
|
37086
|
-
const findShopifyFlashListVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, SHOPIFY_FLASH_LIST_PACKAGE_NAME));
|
|
37087
|
-
const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, version }) => {
|
|
37088
|
-
if (version === null || !isCatalogReference(version)) return version;
|
|
37089
|
-
const catalogName = extractCatalogName(version);
|
|
37090
|
-
const resolvedLocalVersion = resolveCatalogVersion(rootPackageJson, packageName, rootDirectory, catalogName);
|
|
37091
|
-
if (resolvedLocalVersion) return resolvedLocalVersion;
|
|
37092
|
-
const monorepoRoot = findMonorepoRoot(rootDirectory);
|
|
37093
|
-
if (!monorepoRoot) return version;
|
|
37094
|
-
const monorepoPackageJsonPath = path.join(monorepoRoot, "package.json");
|
|
37095
|
-
if (!isFile(monorepoPackageJsonPath)) return version;
|
|
37096
|
-
return resolveCatalogVersion(readPackageJson$1(monorepoPackageJsonPath), packageName, monorepoRoot, catalogName) ?? version;
|
|
37097
|
-
};
|
|
37098
|
-
const findNextjsVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, "next"));
|
|
37099
|
-
const getPreactVersion = (packageJson) => {
|
|
37100
|
-
return {
|
|
37101
|
-
...packageJson.peerDependencies,
|
|
37102
|
-
...packageJson.dependencies,
|
|
37103
|
-
...packageJson.devDependencies
|
|
37104
|
-
}.preact ?? null;
|
|
37105
|
-
};
|
|
37106
|
-
const TANSTACK_QUERY_PACKAGES = new Set([
|
|
37107
|
-
"@tanstack/react-query",
|
|
37108
|
-
"@tanstack/query-core",
|
|
37109
|
-
"react-query"
|
|
37110
|
-
]);
|
|
37111
|
-
const hasTanStackQuery = (packageJson) => {
|
|
37112
|
-
const allDependencies = {
|
|
37113
|
-
...packageJson.peerDependencies,
|
|
37114
|
-
...packageJson.dependencies,
|
|
37115
|
-
...packageJson.devDependencies
|
|
37116
|
-
};
|
|
37117
|
-
return Object.keys(allDependencies).some((packageName) => TANSTACK_QUERY_PACKAGES.has(packageName));
|
|
37118
|
-
};
|
|
37119
|
-
const REANIMATED_DEPENDENCY_NAME = "react-native-reanimated";
|
|
37120
|
-
const isPackageJsonReanimatedAware = (packageJson) => {
|
|
37121
|
-
const allDependencies = {
|
|
37122
|
-
...packageJson.peerDependencies,
|
|
37123
|
-
...packageJson.dependencies,
|
|
37124
|
-
...packageJson.devDependencies,
|
|
37125
|
-
...packageJson.optionalDependencies
|
|
37126
|
-
};
|
|
37127
|
-
return Object.hasOwn(allDependencies, REANIMATED_DEPENDENCY_NAME);
|
|
37128
|
-
};
|
|
37129
|
-
const parseZodMajor = (zodVersion) => {
|
|
37130
|
-
if (typeof zodVersion !== "string") return null;
|
|
37131
|
-
return getLowestDependencyMajor(zodVersion);
|
|
37132
|
-
};
|
|
37133
|
-
const hasUpperBoundOnlyPeerRange = (range) => {
|
|
37134
|
-
if (typeof range !== "string") return false;
|
|
37135
|
-
const normalizedRange = normalizeDependencyVersion(range);
|
|
37136
|
-
if (normalizedRange === null) return false;
|
|
37137
|
-
return splitDependencyVersionBranches(normalizedRange).some((branch) => {
|
|
37138
|
-
const normalizedBranch = normalizeDependencyVersion(branch);
|
|
37139
|
-
return normalizedBranch !== null && getBranchLowestMajor(normalizedBranch) === null && hasUpperBoundComparator(normalizedBranch);
|
|
37140
|
-
});
|
|
37141
|
-
};
|
|
37142
|
-
const peerRangeMinMajor = (range) => {
|
|
37143
|
-
if (typeof range !== "string") return null;
|
|
37144
|
-
return getLowestDependencyMajor(range);
|
|
37145
|
-
};
|
|
37146
|
-
const resolveEffectiveReactMajor = (reactVersion, packageJson) => {
|
|
37147
|
-
const installedReactMajor = parseReactMajor(reactVersion);
|
|
37148
|
-
const peerReactRange = packageJson.peerDependencies?.react;
|
|
37149
|
-
if (typeof peerReactRange !== "string") return installedReactMajor;
|
|
37150
|
-
const peerFloor = peerRangeMinMajor(peerReactRange);
|
|
37151
|
-
if (peerFloor === null) return hasUpperBoundOnlyPeerRange(peerReactRange) ? null : installedReactMajor;
|
|
37152
|
-
return installedReactMajor !== null ? Math.min(installedReactMajor, peerFloor) : peerFloor;
|
|
37153
|
-
};
|
|
37154
|
-
const TSCONFIG_FILENAME = "tsconfig.json";
|
|
37155
|
-
const isRelativeExtendsValue = (extendsValue) => extendsValue.startsWith("./") || extendsValue.startsWith("../") || Path.isAbsolute(extendsValue);
|
|
37156
|
-
const ensureJsonExtension = (filePath) => Path.extname(filePath) === "" ? `${filePath}.json` : filePath;
|
|
37157
|
-
const resolvePackageExtendsPath = (extendsValue, fromConfigDirectory) => {
|
|
37158
|
-
const requireFromConfig = createRequire(Path.join(fromConfigDirectory, "tsconfig.json"));
|
|
37159
|
-
const candidates = [
|
|
37160
|
-
extendsValue,
|
|
37161
|
-
ensureJsonExtension(extendsValue),
|
|
37162
|
-
`${extendsValue.replace(/\/$/, "")}/tsconfig.json`
|
|
37163
|
-
];
|
|
37164
|
-
for (const candidate of candidates) try {
|
|
37165
|
-
return requireFromConfig.resolve(candidate);
|
|
37166
|
-
} catch {
|
|
37167
|
-
continue;
|
|
37168
|
-
}
|
|
37169
|
-
return null;
|
|
37170
|
-
};
|
|
37171
|
-
const resolveExtendsPath = (extendsValue, fromConfigDirectory) => {
|
|
37172
|
-
if (isRelativeExtendsValue(extendsValue)) return ensureJsonExtension(Path.resolve(fromConfigDirectory, extendsValue));
|
|
37173
|
-
return resolvePackageExtendsPath(extendsValue, fromConfigDirectory);
|
|
37174
|
-
};
|
|
37175
|
-
const normalizeCompilerOptions = (compilerOptions) => {
|
|
37176
|
-
if (!isPlainObject(compilerOptions)) return { hasExplicitLib: false };
|
|
37177
|
-
const target = typeof compilerOptions.target === "string" ? compilerOptions.target : void 0;
|
|
37178
|
-
const hasExplicitLib = Object.hasOwn(compilerOptions, "lib");
|
|
37179
|
-
return {
|
|
37180
|
-
target,
|
|
37181
|
-
lib: Array.isArray(compilerOptions.lib) ? compilerOptions.lib.filter((entry) => typeof entry === "string") : void 0,
|
|
37182
|
-
hasExplicitLib
|
|
37183
|
-
};
|
|
37184
|
-
};
|
|
37185
|
-
const normalizeReferencePaths = (references) => {
|
|
37186
|
-
if (!Array.isArray(references)) return [];
|
|
37187
|
-
return references.map((reference) => isPlainObject(reference) && typeof reference.path === "string" ? reference.path : null).filter((referencePath) => referencePath !== null);
|
|
37188
|
-
};
|
|
37189
|
-
const readTsConfig = (filePath) => {
|
|
37190
|
-
let content;
|
|
37191
|
-
try {
|
|
37192
|
-
content = NFS.readFileSync(filePath, "utf-8");
|
|
37193
|
-
} catch {
|
|
37194
|
-
return null;
|
|
37195
|
-
}
|
|
37196
|
-
const parsed = ts.parseConfigFileTextToJson(filePath, content);
|
|
37197
|
-
if (!isPlainObject(parsed.config)) return null;
|
|
37198
|
-
return {
|
|
37199
|
-
extends: typeof parsed.config.extends === "string" ? parsed.config.extends : void 0,
|
|
37200
|
-
referencePaths: normalizeReferencePaths(parsed.config.references),
|
|
37201
|
-
compilerOptions: normalizeCompilerOptions(parsed.config.compilerOptions)
|
|
37202
|
-
};
|
|
37203
|
-
};
|
|
37204
|
-
const mergeCompilerOptions = (inherited, current) => {
|
|
37205
|
-
const target = current.target ?? inherited?.target;
|
|
37206
|
-
const hasExplicitLib = current.hasExplicitLib || Boolean(inherited?.hasExplicitLib);
|
|
37207
|
-
return {
|
|
37208
|
-
target,
|
|
37209
|
-
lib: current.hasExplicitLib ? current.lib : inherited?.lib,
|
|
37210
|
-
hasExplicitLib
|
|
37211
|
-
};
|
|
37212
|
-
};
|
|
37213
|
-
const readResolvedCompilerOptions = (tsConfigPath, extendsDepth, visitedPaths) => {
|
|
37214
|
-
const realPath = NFS.realpathSync.native(tsConfigPath);
|
|
37215
|
-
if (visitedPaths.has(realPath)) return null;
|
|
37216
|
-
const tsConfig = readTsConfig(realPath);
|
|
37217
|
-
if (!tsConfig) return null;
|
|
37218
|
-
const nextVisitedPaths = new Set(visitedPaths);
|
|
37219
|
-
nextVisitedPaths.add(realPath);
|
|
37220
|
-
if (tsConfig.extends && extendsDepth < 8) {
|
|
37221
|
-
const parentPath = resolveExtendsPath(tsConfig.extends, Path.dirname(realPath));
|
|
37222
|
-
if (parentPath && isFile(parentPath)) return mergeCompilerOptions(readResolvedCompilerOptions(parentPath, extendsDepth + 1, nextVisitedPaths), tsConfig.compilerOptions);
|
|
37223
|
-
}
|
|
37224
|
-
return tsConfig.compilerOptions;
|
|
37225
|
-
};
|
|
37226
|
-
const targetYearIsPreES2023 = (target) => {
|
|
37227
|
-
const year = ES_TARGET_YEAR_BY_NAME[target.toLowerCase()];
|
|
37228
|
-
return year !== void 0 && year < 2023;
|
|
37229
|
-
};
|
|
37230
|
-
const libEntryIncludesES2023Array = (entry) => {
|
|
37231
|
-
const normalizedEntry = entry.toLowerCase();
|
|
37232
|
-
if (normalizedEntry === "esnext" || normalizedEntry === "esnext.array") return true;
|
|
37233
|
-
const esYearMatch = /^es(\d{4})(?:\.(.+))?$/.exec(normalizedEntry);
|
|
37234
|
-
if (!esYearMatch) return false;
|
|
37235
|
-
if (Number(esYearMatch[1]) < 2023) return false;
|
|
37236
|
-
const component = esYearMatch[2];
|
|
37237
|
-
return component === void 0 || component === "array";
|
|
37238
|
-
};
|
|
37239
|
-
const libIncludesES2023 = (lib) => lib.some(libEntryIncludesES2023Array);
|
|
37240
|
-
const compilerOptionsArePreES2023 = (compilerOptions) => {
|
|
37241
|
-
if (compilerOptions.target && targetYearIsPreES2023(compilerOptions.target)) return true;
|
|
37242
|
-
if (compilerOptions.hasExplicitLib) return !libIncludesES2023(compilerOptions.lib ?? []);
|
|
37243
|
-
return false;
|
|
37244
|
-
};
|
|
37245
|
-
const compilerOptionsDeclareTargetOrLib = (compilerOptions) => compilerOptions.hasExplicitLib || compilerOptions.target !== void 0;
|
|
37246
|
-
const detectPreES2023FromConfig = (tsConfigPath, visitedConfigPaths = /* @__PURE__ */ new Set()) => {
|
|
37247
|
-
if (visitedConfigPaths.has(tsConfigPath)) return false;
|
|
37248
|
-
const compilerOptions = readResolvedCompilerOptions(tsConfigPath, 0, /* @__PURE__ */ new Set());
|
|
37249
|
-
if (!compilerOptions) return false;
|
|
37250
|
-
if (!compilerOptionsDeclareTargetOrLib(compilerOptions)) {
|
|
37251
|
-
const tsConfig = readTsConfig(tsConfigPath);
|
|
37252
|
-
if (!tsConfig) return false;
|
|
37253
|
-
const nextVisitedConfigPaths = new Set(visitedConfigPaths);
|
|
37254
|
-
nextVisitedConfigPaths.add(tsConfigPath);
|
|
37255
|
-
const configDirectory = Path.dirname(tsConfigPath);
|
|
37256
|
-
return tsConfig.referencePaths.some((referencePath) => {
|
|
37257
|
-
const resolvedReferencePath = Path.resolve(configDirectory, referencePath);
|
|
37258
|
-
const referencedConfigPath = isFile(resolvedReferencePath) ? resolvedReferencePath : Path.join(resolvedReferencePath, TSCONFIG_FILENAME);
|
|
37259
|
-
return isFile(referencedConfigPath) && detectPreES2023FromConfig(referencedConfigPath, nextVisitedConfigPaths);
|
|
37260
|
-
});
|
|
37261
|
-
}
|
|
37262
|
-
return compilerOptionsArePreES2023(compilerOptions);
|
|
37263
|
-
};
|
|
37264
|
-
const FALLBACK_TSCONFIG_FILENAMES = ["tsconfig.app.json", "tsconfig.build.json"];
|
|
37265
|
-
const detectPreES2023Target = (directory) => {
|
|
37266
|
-
const tsConfigPath = Path.join(directory, TSCONFIG_FILENAME);
|
|
37267
|
-
if (isFile(tsConfigPath)) return detectPreES2023FromConfig(tsConfigPath);
|
|
37268
|
-
for (const fallbackFilename of FALLBACK_TSCONFIG_FILENAMES) {
|
|
37269
|
-
const fallbackPath = Path.join(directory, fallbackFilename);
|
|
37270
|
-
if (isFile(fallbackPath)) return detectPreES2023FromConfig(fallbackPath);
|
|
37271
|
-
}
|
|
37272
|
-
return false;
|
|
37273
|
-
};
|
|
37274
|
-
const REACT_DEPENDENCY_NAMES = new Set([
|
|
37275
|
-
"react",
|
|
37276
|
-
"react-native",
|
|
37277
|
-
"next",
|
|
37278
|
-
"preact"
|
|
37279
|
-
]);
|
|
37280
|
-
const hasReactDependency = (packageJson) => {
|
|
37281
|
-
const allDependencies = {
|
|
37282
|
-
...packageJson.peerDependencies,
|
|
37283
|
-
...packageJson.dependencies,
|
|
37284
|
-
...packageJson.devDependencies
|
|
37285
|
-
};
|
|
37286
|
-
return Object.keys(allDependencies).some((packageName) => REACT_DEPENDENCY_NAMES.has(packageName));
|
|
37287
|
-
};
|
|
37288
|
-
const listWorkspacePackages = (rootDirectory) => {
|
|
37289
|
-
const packageJsonPath = Path.join(rootDirectory, "package.json");
|
|
37290
|
-
if (!isFile(packageJsonPath)) return [];
|
|
37291
|
-
const packageJson = readPackageJson$1(packageJsonPath);
|
|
37292
|
-
const patterns = getWorkspacePatterns(rootDirectory, packageJson);
|
|
37293
|
-
if (patterns.length === 0) return [];
|
|
37294
|
-
const packages = [];
|
|
37295
|
-
const seenDirectories = /* @__PURE__ */ new Set();
|
|
37296
|
-
const pushIfNew = (workspacePackage) => {
|
|
37297
|
-
if (seenDirectories.has(workspacePackage.directory)) return;
|
|
37298
|
-
seenDirectories.add(workspacePackage.directory);
|
|
37299
|
-
packages.push(workspacePackage);
|
|
37300
|
-
};
|
|
37301
|
-
if (hasReactDependency(packageJson)) pushIfNew({
|
|
37302
|
-
name: packageJson.name ?? Path.basename(rootDirectory),
|
|
37303
|
-
directory: rootDirectory
|
|
37304
|
-
});
|
|
37305
|
-
for (const pattern of patterns) {
|
|
37306
|
-
const directories = resolveWorkspaceDirectories(rootDirectory, pattern);
|
|
37307
|
-
for (const workspaceDirectory of directories) {
|
|
37308
|
-
const workspacePackageJson = readPackageJson$1(Path.join(workspaceDirectory, "package.json"));
|
|
37309
|
-
if (!hasReactDependency(workspacePackageJson)) continue;
|
|
37310
|
-
pushIfNew({
|
|
37311
|
-
name: workspacePackageJson.name ?? Path.basename(workspaceDirectory),
|
|
37312
|
-
directory: workspaceDirectory
|
|
37313
|
-
});
|
|
37314
|
-
}
|
|
37315
|
-
}
|
|
37316
|
-
return packages;
|
|
37317
|
-
};
|
|
37318
37383
|
const toReactWorkspacePackages = (directories) => {
|
|
37319
37384
|
const packages = [];
|
|
37320
37385
|
for (const directory of directories) {
|
|
@@ -37384,14 +37449,13 @@ const discoverReactSubprojects = (rootDirectory) => {
|
|
|
37384
37449
|
const cachedProjectInfos = /* @__PURE__ */ new Map();
|
|
37385
37450
|
/**
|
|
37386
37451
|
* Build a `ProjectInfo` for a directory that has no `package.json` of
|
|
37387
|
-
* its own — a
|
|
37388
|
-
*
|
|
37389
|
-
*
|
|
37390
|
-
*
|
|
37391
|
-
*
|
|
37392
|
-
*
|
|
37393
|
-
*
|
|
37394
|
-
* nothing to scan (no enclosing project and no source files of its own).
|
|
37452
|
+
* its own — a monorepo subfolder like `repo/packages`, or any loose tree
|
|
37453
|
+
* of TypeScript/JavaScript files. Dependency + framework detection is
|
|
37454
|
+
* inherited from the enclosing workspace root when there is one, so
|
|
37455
|
+
* scanning a subdirectory of a React monorepo still gets the React
|
|
37456
|
+
* capabilities; a standalone non-React directory simply scans with the
|
|
37457
|
+
* framework-agnostic rules. Throws only when the directory has nothing
|
|
37458
|
+
* to scan (no enclosing project and no source files of its own).
|
|
37395
37459
|
*/
|
|
37396
37460
|
const discoverProjectWithoutPackageJson = (directory) => {
|
|
37397
37461
|
const sourceFileCount = countSourceFiles(directory);
|
|
@@ -37429,6 +37493,7 @@ const discoverProjectWithoutPackageJson = (directory) => {
|
|
|
37429
37493
|
hasReanimated: false,
|
|
37430
37494
|
reanimatedVersion: null,
|
|
37431
37495
|
isPreES2023Target: hasOwnTsConfig && detectPreES2023Target(directory),
|
|
37496
|
+
isStaticExport: false,
|
|
37432
37497
|
sourceFileCount
|
|
37433
37498
|
};
|
|
37434
37499
|
};
|
|
@@ -37442,90 +37507,85 @@ const discoverProject = (directory) => {
|
|
|
37442
37507
|
return synthesized;
|
|
37443
37508
|
}
|
|
37444
37509
|
const packageJson = readPackageJson$1(packageJsonPath);
|
|
37445
|
-
|
|
37446
|
-
|
|
37447
|
-
|
|
37448
|
-
|
|
37449
|
-
|
|
37450
|
-
|
|
37451
|
-
|
|
37452
|
-
|
|
37453
|
-
|
|
37454
|
-
|
|
37455
|
-
|
|
37456
|
-
|
|
37457
|
-
|
|
37458
|
-
|
|
37459
|
-
|
|
37460
|
-
|
|
37461
|
-
|
|
37462
|
-
]
|
|
37463
|
-
});
|
|
37464
|
-
const zodDeclaration = getDependencyDeclaration({
|
|
37510
|
+
const rootInfo = extractDependencyInfo(packageJson);
|
|
37511
|
+
let framework = rootInfo.framework;
|
|
37512
|
+
const tracked = {
|
|
37513
|
+
react: {
|
|
37514
|
+
version: rootInfo.reactVersion,
|
|
37515
|
+
sections: REACT_SECTIONS
|
|
37516
|
+
},
|
|
37517
|
+
tailwindcss: {
|
|
37518
|
+
version: rootInfo.tailwindVersion,
|
|
37519
|
+
sections: TAILWIND_ZOD_SECTIONS
|
|
37520
|
+
},
|
|
37521
|
+
zod: {
|
|
37522
|
+
version: rootInfo.zodVersion,
|
|
37523
|
+
sections: TAILWIND_ZOD_SECTIONS
|
|
37524
|
+
}
|
|
37525
|
+
};
|
|
37526
|
+
const declarations = Object.fromEntries(Object.entries(tracked).map(([packageName, entry]) => [packageName, getDependencyDeclaration({
|
|
37465
37527
|
packageJson,
|
|
37466
|
-
packageName
|
|
37467
|
-
sections:
|
|
37468
|
-
|
|
37469
|
-
|
|
37470
|
-
|
|
37471
|
-
|
|
37472
|
-
|
|
37473
|
-
if (!
|
|
37474
|
-
if (!tailwindVersion && tailwindDeclaration.hasDeclaration) tailwindVersion = resolveCatalogVersion(packageJson, "tailwindcss", directory, tailwindDeclaration.catalogReference);
|
|
37475
|
-
if (!zodVersion && zodDeclaration.hasDeclaration) zodVersion = resolveCatalogVersion(packageJson, "zod", directory, zodDeclaration.catalogReference);
|
|
37476
|
-
if (!reactVersion || !tailwindVersion || !zodVersion) {
|
|
37528
|
+
packageName,
|
|
37529
|
+
sections: entry.sections
|
|
37530
|
+
})]));
|
|
37531
|
+
const fillFromCatalogs = (source, sourceDirectory) => {
|
|
37532
|
+
for (const [packageName, entry] of Object.entries(tracked)) if (!entry.version && declarations[packageName].hasDeclaration) entry.version = resolveCatalogVersion(source, packageName, sourceDirectory, declarations[packageName].catalogReference);
|
|
37533
|
+
};
|
|
37534
|
+
fillFromCatalogs(packageJson, directory);
|
|
37535
|
+
if (!tracked.react.version || !tracked.tailwindcss.version || !tracked.zod.version) {
|
|
37477
37536
|
const monorepoRoot = findMonorepoRoot(directory);
|
|
37478
37537
|
if (monorepoRoot) {
|
|
37479
37538
|
const monorepoPackageJsonPath = Path.join(monorepoRoot, "package.json");
|
|
37480
|
-
if (isFile(monorepoPackageJsonPath))
|
|
37481
|
-
const rootPackageJson = readPackageJson$1(monorepoPackageJsonPath);
|
|
37482
|
-
if (!reactVersion && reactDeclaration.hasDeclaration) reactVersion = resolveCatalogVersion(rootPackageJson, "react", monorepoRoot, reactDeclaration.catalogReference);
|
|
37483
|
-
if (!tailwindVersion && tailwindDeclaration.hasDeclaration) tailwindVersion = resolveCatalogVersion(rootPackageJson, "tailwindcss", monorepoRoot, tailwindDeclaration.catalogReference);
|
|
37484
|
-
if (!zodVersion && zodDeclaration.hasDeclaration) zodVersion = resolveCatalogVersion(rootPackageJson, "zod", monorepoRoot, zodDeclaration.catalogReference);
|
|
37485
|
-
}
|
|
37539
|
+
if (isFile(monorepoPackageJsonPath)) fillFromCatalogs(readPackageJson$1(monorepoPackageJsonPath), monorepoRoot);
|
|
37486
37540
|
}
|
|
37487
37541
|
}
|
|
37488
|
-
|
|
37489
|
-
|
|
37490
|
-
|
|
37491
|
-
|
|
37492
|
-
|
|
37493
|
-
|
|
37542
|
+
const shouldCollectReactGroup = !tracked.react.version || framework === "unknown";
|
|
37543
|
+
const workspaceFacts = collectWorkspaceFacts(directory, packageJson, { collectReactGroup: shouldCollectReactGroup });
|
|
37544
|
+
if (shouldCollectReactGroup) {
|
|
37545
|
+
tracked.react.version ||= workspaceFacts.reactVersion;
|
|
37546
|
+
tracked.tailwindcss.version ||= workspaceFacts.tailwindVersion;
|
|
37547
|
+
tracked.zod.version ||= workspaceFacts.zodVersion;
|
|
37548
|
+
if (framework === "unknown" && workspaceFacts.framework !== "unknown") framework = workspaceFacts.framework;
|
|
37494
37549
|
}
|
|
37495
|
-
if ((!
|
|
37550
|
+
if ((!tracked.react.version || framework === "unknown") && !isMonorepoRoot(directory)) {
|
|
37496
37551
|
const monorepoInfo = findDependencyInfoFromMonorepoRoot(directory);
|
|
37497
|
-
|
|
37498
|
-
|
|
37499
|
-
|
|
37552
|
+
tracked.react.version ||= monorepoInfo.reactVersion;
|
|
37553
|
+
tracked.tailwindcss.version ||= monorepoInfo.tailwindVersion;
|
|
37554
|
+
tracked.zod.version ||= monorepoInfo.zodVersion;
|
|
37500
37555
|
if (framework === "unknown") framework = monorepoInfo.framework;
|
|
37501
37556
|
}
|
|
37502
|
-
|
|
37503
|
-
|
|
37504
|
-
|
|
37557
|
+
for (const [packageName, entry] of Object.entries(tracked)) {
|
|
37558
|
+
const declaredVersion = declarations[packageName].version;
|
|
37559
|
+
if (!entry.version && declaredVersion && !isCatalogReference(declaredVersion)) entry.version = declaredVersion;
|
|
37560
|
+
}
|
|
37561
|
+
const { react, tailwindcss, zod } = tracked;
|
|
37562
|
+
let reactVersion = react.version;
|
|
37505
37563
|
if (!reactVersion || parseReactMajor(reactVersion) === null) reactVersion = resolveInstalledReactVersion(directory) ?? reactVersion;
|
|
37564
|
+
const tailwindVersion = tailwindcss.version;
|
|
37565
|
+
const zodVersion = zod.version;
|
|
37506
37566
|
const projectName = packageJson.name ?? Path.basename(directory);
|
|
37507
37567
|
const hasTypeScript = NFS.existsSync(Path.join(directory, "tsconfig.json"));
|
|
37508
37568
|
const sourceFileCount = countSourceFiles(directory);
|
|
37509
|
-
const hasReactNativeWorkspace = framework === "expo" || framework === "react-native" ||
|
|
37569
|
+
const hasReactNativeWorkspace = framework === "expo" || framework === "react-native" || workspaceFacts.hasReactNativeAwarePackage;
|
|
37510
37570
|
const expoVersion = hasReactNativeWorkspace ? resolveCatalogBackedDependencyVersion({
|
|
37511
37571
|
rootDirectory: directory,
|
|
37512
37572
|
rootPackageJson: packageJson,
|
|
37513
37573
|
packageName: "expo",
|
|
37514
|
-
version:
|
|
37574
|
+
version: workspaceFacts.expo.version
|
|
37515
37575
|
}) : null;
|
|
37516
37576
|
const shopifyFlashListVersion = hasReactNativeWorkspace ? resolveCatalogBackedDependencyVersion({
|
|
37517
37577
|
rootDirectory: directory,
|
|
37518
37578
|
rootPackageJson: packageJson,
|
|
37519
37579
|
packageName: SHOPIFY_FLASH_LIST_PACKAGE_NAME,
|
|
37520
|
-
version:
|
|
37580
|
+
version: workspaceFacts.shopifyFlashList.version
|
|
37521
37581
|
}) : null;
|
|
37522
|
-
const hasReanimated = hasReactNativeWorkspace &&
|
|
37523
|
-
const reanimatedVersion = hasReanimated ?
|
|
37582
|
+
const hasReanimated = hasReactNativeWorkspace && workspaceFacts.hasReanimatedAwarePackage;
|
|
37583
|
+
const reanimatedVersion = hasReanimated ? workspaceFacts.reanimatedVersion : null;
|
|
37524
37584
|
const nextjsVersion = framework === "nextjs" ? resolveCatalogBackedDependencyVersion({
|
|
37525
37585
|
rootDirectory: directory,
|
|
37526
37586
|
rootPackageJson: packageJson,
|
|
37527
37587
|
packageName: "next",
|
|
37528
|
-
version:
|
|
37588
|
+
version: workspaceFacts.next.version
|
|
37529
37589
|
}) : null;
|
|
37530
37590
|
const preactVersion = getPreactVersion(packageJson);
|
|
37531
37591
|
const isPreES2023Target = hasTypeScript && detectPreES2023Target(directory);
|
|
@@ -37536,7 +37596,7 @@ const discoverProject = (directory) => {
|
|
|
37536
37596
|
reactMajorVersion: resolveEffectiveReactMajor(reactVersion, packageJson),
|
|
37537
37597
|
tailwindVersion,
|
|
37538
37598
|
zodVersion,
|
|
37539
|
-
zodMajorVersion:
|
|
37599
|
+
zodMajorVersion: zodVersion === null ? null : getLowestDependencyMajor(zodVersion),
|
|
37540
37600
|
framework,
|
|
37541
37601
|
hasTypeScript,
|
|
37542
37602
|
hasReactCompiler: detectReactCompiler(directory, packageJson),
|
|
@@ -37552,6 +37612,7 @@ const discoverProject = (directory) => {
|
|
|
37552
37612
|
hasReanimated,
|
|
37553
37613
|
reanimatedVersion,
|
|
37554
37614
|
isPreES2023Target,
|
|
37615
|
+
isStaticExport: framework === "nextjs" && detectNextjsStaticExport(workspaceFacts.next.sourceDirectory ?? directory),
|
|
37555
37616
|
sourceFileCount
|
|
37556
37617
|
};
|
|
37557
37618
|
cachedProjectInfos.set(directory, projectInfo);
|
|
@@ -37567,57 +37628,6 @@ const discoverProject = (directory) => {
|
|
|
37567
37628
|
* single source file has nothing to analyze.
|
|
37568
37629
|
*/
|
|
37569
37630
|
const isAnalyzableProject = (project) => project.reactVersion !== null || project.preactVersion !== null || project.sourceFileCount > 0;
|
|
37570
|
-
const MAJOR_MINOR_PATTERN = /(\d{1,4})\.(\d{1,4})/;
|
|
37571
|
-
const MAJOR_ONLY_PATTERN = /(\d{1,4})/;
|
|
37572
|
-
const UPPER_BOUND_COMPARATOR_PATTERN = /<=?\s{0,8}\d{1,4}(?:\.\d{1,4}){0,2}(?:-[^\s,|]+)?/g;
|
|
37573
|
-
const parseReactMajorMinor = (reactVersion) => {
|
|
37574
|
-
if (typeof reactVersion !== "string") return null;
|
|
37575
|
-
const trimmed = reactVersion.trim();
|
|
37576
|
-
if (trimmed.length === 0) return null;
|
|
37577
|
-
const lowerBoundsOnly = trimmed.replace(UPPER_BOUND_COMPARATOR_PATTERN, " ").trim();
|
|
37578
|
-
if (lowerBoundsOnly.length === 0) return null;
|
|
37579
|
-
const majorMinorMatch = lowerBoundsOnly.match(MAJOR_MINOR_PATTERN);
|
|
37580
|
-
if (majorMinorMatch) {
|
|
37581
|
-
const major = Number.parseInt(majorMinorMatch[1], 10);
|
|
37582
|
-
const minor = Number.parseInt(majorMinorMatch[2], 10);
|
|
37583
|
-
if (!Number.isFinite(major) || major <= 0) return null;
|
|
37584
|
-
if (!Number.isFinite(minor) || minor < 0) return null;
|
|
37585
|
-
return {
|
|
37586
|
-
major,
|
|
37587
|
-
minor
|
|
37588
|
-
};
|
|
37589
|
-
}
|
|
37590
|
-
const majorOnlyMatch = lowerBoundsOnly.match(MAJOR_ONLY_PATTERN);
|
|
37591
|
-
if (!majorOnlyMatch) return null;
|
|
37592
|
-
const major = Number.parseInt(majorOnlyMatch[1], 10);
|
|
37593
|
-
if (!Number.isFinite(major) || major <= 0) return null;
|
|
37594
|
-
return {
|
|
37595
|
-
major,
|
|
37596
|
-
minor: 0
|
|
37597
|
-
};
|
|
37598
|
-
};
|
|
37599
|
-
const isReactAtLeast = (detected, required) => {
|
|
37600
|
-
if (detected === null) return true;
|
|
37601
|
-
if (detected.major !== required.major) return detected.major > required.major;
|
|
37602
|
-
return detected.minor >= required.minor;
|
|
37603
|
-
};
|
|
37604
|
-
const parseLowerBoundVersion = (versionSpec) => import_semver.validRange(versionSpec) !== null ? import_semver.minVersion(versionSpec) : import_semver.coerce(versionSpec);
|
|
37605
|
-
const parseTailwindMajorMinor = (tailwindVersion) => {
|
|
37606
|
-
if (typeof tailwindVersion !== "string") return null;
|
|
37607
|
-
const trimmed = tailwindVersion.trim();
|
|
37608
|
-
if (trimmed.length === 0) return null;
|
|
37609
|
-
const lowerBound = parseLowerBoundVersion(trimmed);
|
|
37610
|
-
if (lowerBound === null || lowerBound.major <= 0) return null;
|
|
37611
|
-
return {
|
|
37612
|
-
major: lowerBound.major,
|
|
37613
|
-
minor: lowerBound.minor
|
|
37614
|
-
};
|
|
37615
|
-
};
|
|
37616
|
-
const isTailwindAtLeast = (detected, required) => {
|
|
37617
|
-
if (detected === null) return true;
|
|
37618
|
-
if (detected.major !== required.major) return detected.major > required.major;
|
|
37619
|
-
return detected.minor >= required.minor;
|
|
37620
|
-
};
|
|
37621
37631
|
const messageFromUnknown = (error) => error instanceof Error ? error.message : String(error);
|
|
37622
37632
|
var InvalidGlobPatternError = class extends Error {
|
|
37623
37633
|
pattern;
|
|
@@ -40428,64 +40438,64 @@ function* collectSecurityScanFiles(rootDirectory) {
|
|
|
40428
40438
|
}
|
|
40429
40439
|
}
|
|
40430
40440
|
}
|
|
40431
|
-
|
|
40432
|
-
|
|
40433
|
-
|
|
40434
|
-
|
|
40435
|
-
|
|
40436
|
-
|
|
40437
|
-
|
|
40441
|
+
const CLIENT_ONLY_FRAMEWORKS = new Set([
|
|
40442
|
+
"vite",
|
|
40443
|
+
"cra",
|
|
40444
|
+
"gatsby",
|
|
40445
|
+
"react-native",
|
|
40446
|
+
"expo"
|
|
40447
|
+
]);
|
|
40448
|
+
const addMajorLadder = (capabilities, name, major, earliest, latest) => {
|
|
40449
|
+
if (major === null) return;
|
|
40450
|
+
const cappedMajor = Math.min(major, latest);
|
|
40451
|
+
for (let candidate = earliest; candidate <= cappedMajor; candidate += 1) capabilities.add(`${name}:${candidate}`);
|
|
40452
|
+
};
|
|
40438
40453
|
const buildCapabilities = (project) => {
|
|
40439
40454
|
const capabilities = /* @__PURE__ */ new Set();
|
|
40440
40455
|
capabilities.add(project.framework);
|
|
40441
|
-
if (
|
|
40456
|
+
if (project.reactVersion !== null || project.preactVersion !== null) capabilities.add("react");
|
|
40442
40457
|
if (project.framework === "expo" || project.framework === "react-native" || project.hasReactNativeWorkspace) capabilities.add("react-native");
|
|
40443
40458
|
if (project.expoVersion !== null) capabilities.add("expo");
|
|
40459
|
+
if ((project.framework === "nextjs" || project.framework === "tanstack-start" || project.framework === "remix") && !project.isStaticExport) capabilities.add("server-actions");
|
|
40460
|
+
if (CLIENT_ONLY_FRAMEWORKS.has(project.framework)) capabilities.add("client-only");
|
|
40461
|
+
if (project.isStaticExport) capabilities.add("nextjs:static-export");
|
|
40444
40462
|
if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 15) capabilities.add("nextjs:15");
|
|
40445
|
-
|
|
40446
|
-
if (
|
|
40447
|
-
|
|
40448
|
-
|
|
40449
|
-
|
|
40450
|
-
|
|
40451
|
-
|
|
40452
|
-
|
|
40453
|
-
|
|
40454
|
-
|
|
40455
|
-
|
|
40456
|
-
if (project.
|
|
40457
|
-
capabilities.add("tailwind");
|
|
40458
|
-
if (isTailwindAtLeast(parseTailwindMajorMinor(project.tailwindVersion), {
|
|
40459
|
-
major: 3,
|
|
40460
|
-
minor: 4
|
|
40461
|
-
})) capabilities.add("tailwind:3.4");
|
|
40462
|
-
}
|
|
40463
|
-
if (project.zodVersion !== null) {
|
|
40464
|
-
capabilities.add("zod");
|
|
40465
|
-
if (project.zodMajorVersion !== null && project.zodMajorVersion >= 4) capabilities.add("zod:4");
|
|
40466
|
-
}
|
|
40463
|
+
addMajorLadder(capabilities, "react", project.reactMajorVersion, 17, 30);
|
|
40464
|
+
if (project.reactMajorVersion !== null && project.reactMajorVersion >= 19 && isMajorMinorAtLeast(parseReactMajorMinor(project.reactVersion), {
|
|
40465
|
+
major: 19,
|
|
40466
|
+
minor: 2
|
|
40467
|
+
})) capabilities.add("react:19.2");
|
|
40468
|
+
if (project.tailwindVersion !== null) capabilities.add("tailwind");
|
|
40469
|
+
if (project.tailwindVersion !== null && isMajorMinorAtLeast(parseTailwindMajorMinor(project.tailwindVersion), {
|
|
40470
|
+
major: 3,
|
|
40471
|
+
minor: 4
|
|
40472
|
+
})) capabilities.add("tailwind:3.4");
|
|
40473
|
+
if (project.zodVersion !== null) capabilities.add("zod");
|
|
40474
|
+
if (project.zodMajorVersion !== null && project.zodMajorVersion >= 4) capabilities.add("zod:4");
|
|
40467
40475
|
if (project.isPreES2023Target) capabilities.add("pre-es2023");
|
|
40468
40476
|
if (project.hasReactCompiler) capabilities.add("react-compiler");
|
|
40469
40477
|
if (project.hasTanStackQuery) capabilities.add("tanstack-query");
|
|
40470
40478
|
if (project.hasTypeScript) capabilities.add("typescript");
|
|
40471
|
-
if (project.preactVersion !== null)
|
|
40472
|
-
|
|
40473
|
-
|
|
40474
|
-
if (preactMajor !== null) {
|
|
40475
|
-
const cappedPreactMajor = Math.min(preactMajor, 20);
|
|
40476
|
-
for (let major = 10; major <= cappedPreactMajor; major++) capabilities.add(`preact:${major}`);
|
|
40477
|
-
}
|
|
40478
|
-
if (project.reactVersion === null) capabilities.add("pure-preact");
|
|
40479
|
-
}
|
|
40479
|
+
if (project.preactVersion !== null) capabilities.add("preact");
|
|
40480
|
+
addMajorLadder(capabilities, "preact", project.preactMajorVersion, 10, 20);
|
|
40481
|
+
if (project.preactVersion !== null && project.reactVersion === null) capabilities.add("pure-preact");
|
|
40480
40482
|
return capabilities;
|
|
40481
40483
|
};
|
|
40482
|
-
const
|
|
40484
|
+
const capabilitiesByProject = /* @__PURE__ */ new WeakMap();
|
|
40485
|
+
const getCapabilities = (project) => {
|
|
40486
|
+
const cached = capabilitiesByProject.get(project);
|
|
40487
|
+
if (cached !== void 0) return cached;
|
|
40488
|
+
const capabilities = buildCapabilities(project);
|
|
40489
|
+
capabilitiesByProject.set(project, capabilities);
|
|
40490
|
+
return capabilities;
|
|
40491
|
+
};
|
|
40492
|
+
const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen) => {
|
|
40483
40493
|
if (requires) {
|
|
40484
40494
|
for (const capability of requires) if (!capabilities.has(capability)) return false;
|
|
40485
40495
|
}
|
|
40486
40496
|
if (tags?.includes("react-jsx-only") && !capabilities.has("react")) return false;
|
|
40487
|
-
if (
|
|
40488
|
-
for (const capability of
|
|
40497
|
+
if (disabledWhen) {
|
|
40498
|
+
for (const capability of disabledWhen) if (capabilities.has(capability)) return false;
|
|
40489
40499
|
}
|
|
40490
40500
|
if (tags) {
|
|
40491
40501
|
for (const tag of tags) if (ignoredTags.has(tag)) return false;
|
|
@@ -40496,14 +40506,14 @@ const yieldToEventLoop = () => new Promise((resolve) => {
|
|
|
40496
40506
|
setImmediate(resolve);
|
|
40497
40507
|
});
|
|
40498
40508
|
const createSecurityScanSession = (rootDirectory, options) => {
|
|
40499
|
-
const capabilities = options.project ?
|
|
40509
|
+
const capabilities = options.project ? getCapabilities(options.project) : /* @__PURE__ */ new Set();
|
|
40500
40510
|
const ignoredTags = options.ignoredTags ?? /* @__PURE__ */ new Set();
|
|
40501
40511
|
const enabledScanRules = REACT_DOCTOR_RULES.flatMap((entry) => {
|
|
40502
40512
|
const rule = entry.rule;
|
|
40503
40513
|
const scan = rule.scan;
|
|
40504
40514
|
if (typeof scan !== "function") return [];
|
|
40505
40515
|
if (rule.defaultEnabled === false) return [];
|
|
40506
|
-
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.
|
|
40516
|
+
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) return [];
|
|
40507
40517
|
return [{
|
|
40508
40518
|
entry,
|
|
40509
40519
|
scan,
|
|
@@ -40523,6 +40533,7 @@ const createSecurityScanSession = (rootDirectory, options) => {
|
|
|
40523
40533
|
return status === true;
|
|
40524
40534
|
};
|
|
40525
40535
|
const scanFileByRule = function* (file) {
|
|
40536
|
+
if (file === null) return;
|
|
40526
40537
|
for (const { entry, scan, committedFilesOnly } of enabledScanRules) {
|
|
40527
40538
|
for (const finding of scan(file)) {
|
|
40528
40539
|
if (committedFilesOnly && isFileGitIgnored(file)) continue;
|
|
@@ -42419,7 +42430,7 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
42419
42430
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
42420
42431
|
const jsPlugins = [];
|
|
42421
42432
|
if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
|
|
42422
|
-
const capabilities =
|
|
42433
|
+
const capabilities = getCapabilities(project);
|
|
42423
42434
|
const enabledReactDoctorRules = {};
|
|
42424
42435
|
for (const registryEntry of REACT_DOCTOR_RULES) {
|
|
42425
42436
|
const rule = reactDoctorPlugin.rules[registryEntry.id];
|
|
@@ -42430,7 +42441,7 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
42430
42441
|
if (rule.scan !== void 0) continue;
|
|
42431
42442
|
if (customRulesOnly && registryEntry.originallyExternal) continue;
|
|
42432
42443
|
if (rule.framework !== "global" && !rule.requires) continue;
|
|
42433
|
-
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.
|
|
42444
|
+
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) continue;
|
|
42434
42445
|
const explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey: registryEntry.key }, severityControls);
|
|
42435
42446
|
if (rule.defaultEnabled === false && explicitRuleOverride === void 0) continue;
|
|
42436
42447
|
const severity = resolveRuleSeverityOverride({
|
|
@@ -42461,6 +42472,7 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
42461
42472
|
settings: { "react-doctor": {
|
|
42462
42473
|
framework: project.framework,
|
|
42463
42474
|
rootDirectory: resolveSettingsRootDirectory(project.rootDirectory),
|
|
42475
|
+
capabilities: [...capabilities].sort(),
|
|
42464
42476
|
...project.shopifyFlashListMajorVersion !== null ? { shopifyFlashListMajorVersion: project.shopifyFlashListMajorVersion } : {},
|
|
42465
42477
|
...serverAuthFunctionNames && serverAuthFunctionNames.length > 0 ? { serverAuthFunctionNames: [...serverAuthFunctionNames] } : {}
|
|
42466
42478
|
} },
|
|
@@ -42751,21 +42763,6 @@ const mapWithConcurrency = async (items, concurrency, task) => {
|
|
|
42751
42763
|
if (errors.length > 0) throw errors[0];
|
|
42752
42764
|
return results;
|
|
42753
42765
|
};
|
|
42754
|
-
const getPublicEnvPrefix = (framework) => {
|
|
42755
|
-
switch (framework) {
|
|
42756
|
-
case "nextjs": return "NEXT_PUBLIC_*";
|
|
42757
|
-
case "vite":
|
|
42758
|
-
case "tanstack-start": return "VITE_*";
|
|
42759
|
-
case "cra": return "REACT_APP_*";
|
|
42760
|
-
case "gatsby": return "GATSBY_*";
|
|
42761
|
-
default: return null;
|
|
42762
|
-
}
|
|
42763
|
-
};
|
|
42764
|
-
const buildNoSecretsRecommendation = (project, fallbackRecommendation) => {
|
|
42765
|
-
const publicEnvPrefix = getPublicEnvPrefix(project.framework);
|
|
42766
|
-
if (!publicEnvPrefix) return fallbackRecommendation;
|
|
42767
|
-
return `Move secrets to server-only code. In ${formatFrameworkName(project.framework)}, only \`${publicEnvPrefix}\` env vars are exposed to the browser, and they must not contain secrets`;
|
|
42768
|
-
};
|
|
42769
42766
|
const REANIMATED_SHARED_VALUE_HINT = "If this is a Reanimated shared value, prefer its React Compiler-compatible `.get()` / `.set()` accessors over `.value` — https://docs.swmansion.com/react-native-reanimated/docs/core/useSharedValue/#react-compiler-support";
|
|
42770
42767
|
const ACCESSORS_MIN_VERSION = "3.15.0";
|
|
42771
42768
|
const supportsAccessors = (reanimatedVersion) => {
|
|
@@ -43446,8 +43443,14 @@ const PLUGIN_CATEGORY_MAP = {
|
|
|
43446
43443
|
};
|
|
43447
43444
|
const lookupOwnString = (record, key) => Object.hasOwn(record, key) ? record[key] : void 0;
|
|
43448
43445
|
const getRuleRecommendation = (ruleName, project) => {
|
|
43449
|
-
|
|
43450
|
-
return
|
|
43446
|
+
const rule = reactDoctorPlugin.rules[ruleName];
|
|
43447
|
+
if (!rule) return void 0;
|
|
43448
|
+
if (rule.recommendationFor) {
|
|
43449
|
+
const capabilities = getCapabilities(project);
|
|
43450
|
+
const conditionalRecommendation = rule.recommendationFor((capability) => capabilities.has(capability));
|
|
43451
|
+
if (conditionalRecommendation !== void 0) return conditionalRecommendation;
|
|
43452
|
+
}
|
|
43453
|
+
return rule.recommendation;
|
|
43451
43454
|
};
|
|
43452
43455
|
const getRuleCategory = (ruleName) => reactDoctorPlugin.rules[ruleName]?.category;
|
|
43453
43456
|
const getRuleTitle = (ruleName) => reactDoctorPlugin.rules[ruleName]?.title;
|
|
@@ -43601,7 +43604,9 @@ const SANITIZED_ENV = buildOxlintChildEnv(process.env);
|
|
|
43601
43604
|
* - `OxlintBatchExceeded { kind: "output-too-large" }` — stdout+stderr
|
|
43602
43605
|
* crossed `OXLINT_OUTPUT_MAX_BYTES`.
|
|
43603
43606
|
* - `OxlintBatchExceeded { kind: "oom" | "killed" }` — child exited
|
|
43604
|
-
* on a signal (SIGABRT → OOM, others → generic kill)
|
|
43607
|
+
* on a signal (SIGABRT → OOM, others → generic kill), or with one
|
|
43608
|
+
* of the abort exit codes Windows reports instead of a signal
|
|
43609
|
+
* (`ABORT_EXIT_CODES` → OOM).
|
|
43605
43610
|
* - `OxlintSpawnFailed { cause }` — `spawn` itself errored, or the
|
|
43606
43611
|
* child exited successfully but printed only stderr.
|
|
43607
43612
|
*
|
|
@@ -43667,7 +43672,7 @@ const spawnOxlint = (args, rootDirectory, nodeBinaryPath, spawnTimeoutMs = OXLIN
|
|
|
43667
43672
|
clearAbortListener();
|
|
43668
43673
|
reject(new ReactDoctorError({ reason: new OxlintSpawnFailed({ cause: error }) }));
|
|
43669
43674
|
});
|
|
43670
|
-
child.on("close", (
|
|
43675
|
+
child.on("close", (code, signal) => {
|
|
43671
43676
|
clearTimeout(timeoutHandle);
|
|
43672
43677
|
clearAbortListener();
|
|
43673
43678
|
if (didKillForSize) {
|
|
@@ -43677,10 +43682,11 @@ const spawnOxlint = (args, rootDirectory, nodeBinaryPath, spawnTimeoutMs = OXLIN
|
|
|
43677
43682
|
}) }));
|
|
43678
43683
|
return;
|
|
43679
43684
|
}
|
|
43680
|
-
|
|
43685
|
+
const isAbortExitCode = code !== null && ABORT_EXIT_CODES.has(code);
|
|
43686
|
+
if (signal || isAbortExitCode) {
|
|
43681
43687
|
const stderrOutput = Buffer.concat(stderrBuffers).toString("utf-8").trim();
|
|
43682
|
-
const isOom = signal === "SIGABRT";
|
|
43683
|
-
const detailParts = [`killed by ${signal}`];
|
|
43688
|
+
const isOom = signal === "SIGABRT" || isAbortExitCode;
|
|
43689
|
+
const detailParts = [signal ? `killed by ${signal}` : `aborted with exit code ${code}`];
|
|
43684
43690
|
if (isOom) detailParts.push("try scanning fewer files with --diff");
|
|
43685
43691
|
if (stderrOutput) detailParts.push(stderrOutput);
|
|
43686
43692
|
reject(new ReactDoctorError({ reason: new OxlintBatchExceeded({
|
|
@@ -43723,12 +43729,19 @@ const isParallelismRelatedSpawnError = (error) => {
|
|
|
43723
43729
|
* (surfaced via `onPartialFailure`) so JSON-mode consumers see WHICH
|
|
43724
43730
|
* files were skipped instead of silently losing them.
|
|
43725
43731
|
*
|
|
43726
|
-
* Parallel runs (concurrency > 1) get
|
|
43727
|
-
* fails with a resource-exhaustion error that's exclusive
|
|
43728
|
-
* many oxlint subprocesses at once (EAGAIN / EMFILE /
|
|
43729
|
-
* see `isParallelismRelatedSpawnError`), the whole
|
|
43730
|
-
* with a single worker. That's the only failure a
|
|
43731
|
-
* clear, so every other error class is left to
|
|
43732
|
+
* Parallel runs (concurrency > 1) get two extra safety nets:
|
|
43733
|
+
* - If the pass fails with a resource-exhaustion error that's exclusive
|
|
43734
|
+
* to running many oxlint subprocesses at once (EAGAIN / EMFILE /
|
|
43735
|
+
* ENFILE / ENOMEM — see `isParallelismRelatedSpawnError`), the whole
|
|
43736
|
+
* pass replays once with a single worker. That's the only failure a
|
|
43737
|
+
* serial replay can clear, so every other error class is left to
|
|
43738
|
+
* propagate.
|
|
43739
|
+
* - Files dropped because oxlint's native binding SIGABRT'd under
|
|
43740
|
+
* memory pressure (`OxlintBatchExceeded { kind: "oom" }`) get one
|
|
43741
|
+
* serial single-file-batch rescue pass: the OOM is usually a function
|
|
43742
|
+
* of N concurrent oxlint allocator arenas, not the file itself, so a
|
|
43743
|
+
* lone process with the machine to itself typically clears it —
|
|
43744
|
+
* turning a partial scan into a complete (if slower) one.
|
|
43732
43745
|
*
|
|
43733
43746
|
* Errors that aren't splittable and aren't parallelism-related (oxlint
|
|
43734
43747
|
* config crash, JS plugin resolution failure, etc.) propagate to the
|
|
@@ -43738,13 +43751,16 @@ const isParallelismRelatedSpawnError = (error) => {
|
|
|
43738
43751
|
const spawnLintBatches = async (input) => {
|
|
43739
43752
|
const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 8, signal, deadlineEpochMs } = input;
|
|
43740
43753
|
const requestedConcurrency = resolveScanConcurrency(input.concurrency ?? 1);
|
|
43741
|
-
|
|
43742
|
-
const
|
|
43754
|
+
let rescueDeadlineEpochMs;
|
|
43755
|
+
const isPastDeadline = () => deadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(deadlineEpochMs) === 0 || rescueDeadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(rescueDeadlineEpochMs) === 0;
|
|
43756
|
+
const runBatchPass = async (concurrency, passBatches, passOnFileProgress) => {
|
|
43757
|
+
const totalFileCount = passBatches.reduce((sum, batch) => sum + batch.length, 0);
|
|
43743
43758
|
const allDiagnostics = [];
|
|
43744
43759
|
const droppedFiles = [];
|
|
43760
|
+
const oomDroppedFiles = [];
|
|
43745
43761
|
const deadlineSkippedFiles = [];
|
|
43746
|
-
const isPastDeadline = () => deadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(deadlineEpochMs) === 0;
|
|
43747
43762
|
let firstDropReason = null;
|
|
43763
|
+
let firstNonOomDropReason = null;
|
|
43748
43764
|
const spawnLintBatch = async (batch, depth, batchState) => {
|
|
43749
43765
|
if (isPastDeadline()) {
|
|
43750
43766
|
deadlineSkippedFiles.push(...batch);
|
|
@@ -43766,12 +43782,14 @@ const spawnLintBatches = async (input) => {
|
|
|
43766
43782
|
const isDepthCapReached = depth >= splitMaxDepth;
|
|
43767
43783
|
if (batch.length <= 1 || isBudgetElapsed || isDepthCapReached) {
|
|
43768
43784
|
droppedFiles.push(...batch);
|
|
43769
|
-
|
|
43770
|
-
|
|
43771
|
-
|
|
43772
|
-
|
|
43773
|
-
|
|
43774
|
-
}
|
|
43785
|
+
const isOomDrop = error.reason._tag === "OxlintBatchExceeded" && error.reason.kind === "oom";
|
|
43786
|
+
if (isOomDrop) oomDroppedFiles.push(...batch);
|
|
43787
|
+
let limitHint = "";
|
|
43788
|
+
if (isDepthCapReached) limitHint = ` (split depth cap of ${splitMaxDepth} levels reached)`;
|
|
43789
|
+
else if (isBudgetElapsed) limitHint = ` (split budget of ${splitTotalBudgetMs / MILLISECONDS_PER_SECOND}s exhausted at depth ${depth})`;
|
|
43790
|
+
const dropReason = batch.length > 1 ? `${error.message}${limitHint}` : error.message;
|
|
43791
|
+
firstDropReason ??= dropReason;
|
|
43792
|
+
if (!isOomDrop) firstNonOomDropReason ??= dropReason;
|
|
43775
43793
|
return [];
|
|
43776
43794
|
}
|
|
43777
43795
|
const splitIndex = Math.ceil(batch.length / 2);
|
|
@@ -43781,16 +43799,16 @@ const spawnLintBatches = async (input) => {
|
|
|
43781
43799
|
let startedFileCount = 0;
|
|
43782
43800
|
let scannedFileCount = 0;
|
|
43783
43801
|
let displayedFileCount = 0;
|
|
43784
|
-
const progressTimer =
|
|
43802
|
+
const progressTimer = passOnFileProgress && totalFileCount > 1 ? setInterval(() => {
|
|
43785
43803
|
const ceiling = Math.min(startedFileCount, totalFileCount - 1);
|
|
43786
43804
|
if (displayedFileCount < ceiling) {
|
|
43787
43805
|
displayedFileCount += 1;
|
|
43788
|
-
|
|
43806
|
+
passOnFileProgress(displayedFileCount, totalFileCount);
|
|
43789
43807
|
}
|
|
43790
43808
|
}, 50) : null;
|
|
43791
43809
|
progressTimer?.unref?.();
|
|
43792
43810
|
try {
|
|
43793
|
-
const batchResults = await mapWithConcurrency(
|
|
43811
|
+
const batchResults = await mapWithConcurrency(passBatches, concurrency, async (batch) => {
|
|
43794
43812
|
if (isPastDeadline()) {
|
|
43795
43813
|
deadlineSkippedFiles.push(...batch);
|
|
43796
43814
|
return [];
|
|
@@ -43802,9 +43820,9 @@ const spawnLintBatches = async (input) => {
|
|
|
43802
43820
|
};
|
|
43803
43821
|
const batchDiagnostics = await spawnLintBatch(batch, 0, batchState);
|
|
43804
43822
|
scannedFileCount += batch.length - batchState.deadlineSkippedFileCount;
|
|
43805
|
-
if (
|
|
43823
|
+
if (passOnFileProgress) {
|
|
43806
43824
|
displayedFileCount = Math.min(Math.max(displayedFileCount, scannedFileCount), totalFileCount);
|
|
43807
|
-
|
|
43825
|
+
passOnFileProgress(displayedFileCount, totalFileCount);
|
|
43808
43826
|
}
|
|
43809
43827
|
return batchDiagnostics;
|
|
43810
43828
|
});
|
|
@@ -43812,22 +43830,53 @@ const spawnLintBatches = async (input) => {
|
|
|
43812
43830
|
} finally {
|
|
43813
43831
|
if (progressTimer !== null) clearInterval(progressTimer);
|
|
43814
43832
|
}
|
|
43815
|
-
|
|
43816
|
-
|
|
43817
|
-
|
|
43833
|
+
return {
|
|
43834
|
+
diagnostics: allDiagnostics,
|
|
43835
|
+
droppedFiles,
|
|
43836
|
+
oomDroppedFiles,
|
|
43837
|
+
deadlineSkippedFiles,
|
|
43838
|
+
firstDropReason,
|
|
43839
|
+
firstNonOomDropReason
|
|
43818
43840
|
};
|
|
43819
|
-
const reasonHint = firstDropReason ? ` — first failure: ${firstDropReason}` : "";
|
|
43820
|
-
reportSkippedFiles(droppedFiles, (fileListPreview) => `${droppedFiles.length} file(s) failed to lint and were skipped (${fileListPreview})${reasonHint}`);
|
|
43821
|
-
reportSkippedFiles(deadlineSkippedFiles, (fileListPreview) => `${deadlineSkippedFiles.length} file(s) skipped — max scan duration reached before they were linted (${fileListPreview})`);
|
|
43822
|
-
return allDiagnostics;
|
|
43823
43841
|
};
|
|
43824
|
-
let
|
|
43842
|
+
let outcome;
|
|
43843
|
+
let effectiveConcurrency = requestedConcurrency;
|
|
43825
43844
|
try {
|
|
43826
|
-
|
|
43845
|
+
outcome = await runBatchPass(requestedConcurrency, fileBatches, onFileProgress);
|
|
43827
43846
|
} catch (error) {
|
|
43828
43847
|
if (requestedConcurrency <= 1 || !isParallelismRelatedSpawnError(error)) throw error;
|
|
43829
|
-
|
|
43848
|
+
effectiveConcurrency = 1;
|
|
43849
|
+
outcome = await runBatchPass(1, fileBatches, onFileProgress);
|
|
43850
|
+
}
|
|
43851
|
+
let { droppedFiles, firstDropReason } = outcome;
|
|
43852
|
+
const diagnostics = outcome.diagnostics;
|
|
43853
|
+
if (outcome.oomDroppedFiles.length > 0 && effectiveConcurrency > 1 && !isPastDeadline()) {
|
|
43854
|
+
rescueDeadlineEpochMs = Date.now() + OXLINT_OOM_RESCUE_BUDGET_MS;
|
|
43855
|
+
const rescuedFiles = /* @__PURE__ */ new Set();
|
|
43856
|
+
let firstRescueFailureReason = null;
|
|
43857
|
+
for (const oomDroppedFile of outcome.oomDroppedFiles) {
|
|
43858
|
+
if (isPastDeadline()) break;
|
|
43859
|
+
try {
|
|
43860
|
+
const rescueOutcome = await runBatchPass(1, [[oomDroppedFile]], void 0);
|
|
43861
|
+
diagnostics.push(...rescueOutcome.diagnostics);
|
|
43862
|
+
if (rescueOutcome.droppedFiles.length > 0 || rescueOutcome.deadlineSkippedFiles.length > 0) firstRescueFailureReason ??= rescueOutcome.firstDropReason;
|
|
43863
|
+
else rescuedFiles.add(oomDroppedFile);
|
|
43864
|
+
} catch (error) {
|
|
43865
|
+
firstRescueFailureReason ??= error instanceof Error ? error.message : String(error);
|
|
43866
|
+
}
|
|
43867
|
+
}
|
|
43868
|
+
rescueDeadlineEpochMs = void 0;
|
|
43869
|
+
droppedFiles = droppedFiles.filter((filePath) => !rescuedFiles.has(filePath));
|
|
43870
|
+
if (droppedFiles.length === 0) firstDropReason = null;
|
|
43871
|
+
else firstDropReason = firstRescueFailureReason ?? outcome.firstNonOomDropReason ?? firstDropReason;
|
|
43830
43872
|
}
|
|
43873
|
+
const reportSkippedFiles = (skippedFiles, buildMessage) => {
|
|
43874
|
+
if (skippedFiles.length === 0 || !onPartialFailure) return;
|
|
43875
|
+
onPartialFailure(buildMessage(`${skippedFiles.slice(0, 3).join(", ")}${skippedFiles.length > 3 ? `, +${skippedFiles.length - 3} more` : ""}`));
|
|
43876
|
+
};
|
|
43877
|
+
const reasonHint = firstDropReason ? ` — first failure: ${firstDropReason}` : "";
|
|
43878
|
+
reportSkippedFiles(droppedFiles, (fileListPreview) => `${droppedFiles.length} file(s) failed to lint and were skipped (${fileListPreview})${reasonHint}`);
|
|
43879
|
+
reportSkippedFiles(outcome.deadlineSkippedFiles, (fileListPreview) => `${outcome.deadlineSkippedFiles.length} file(s) skipped — max scan duration reached before they were linted (${fileListPreview})`);
|
|
43831
43880
|
return dedupeDiagnostics(diagnostics);
|
|
43832
43881
|
};
|
|
43833
43882
|
let didValidate = false;
|
|
@@ -45796,6 +45845,13 @@ const summarizeDiagnostics = (diagnostics, worstScore = null, worstScoreLabel =
|
|
|
45796
45845
|
scoreLabel: worstScoreLabel
|
|
45797
45846
|
};
|
|
45798
45847
|
};
|
|
45848
|
+
/**
|
|
45849
|
+
* Whether project discovery resolved a React-compatible runtime (React or
|
|
45850
|
+
* Preact, which ships the same hooks + JSX model). This is the same
|
|
45851
|
+
* predicate that grants the `react` capability, so `false` means every
|
|
45852
|
+
* React-runtime rule family was gated off for the project.
|
|
45853
|
+
*/
|
|
45854
|
+
const hasReactRuntime = (project) => project.reactVersion !== null || project.preactVersion !== null;
|
|
45799
45855
|
const toJsonDiff = (diff) => {
|
|
45800
45856
|
if (!diff) return null;
|
|
45801
45857
|
return {
|
|
@@ -46378,7 +46434,7 @@ const makeNoopConsole = () => ({
|
|
|
46378
46434
|
});
|
|
46379
46435
|
//#endregion
|
|
46380
46436
|
//#region src/cli/utils/version.ts
|
|
46381
|
-
const VERSION = "0.7.
|
|
46437
|
+
const VERSION = "0.7.3-dev.6b70b32";
|
|
46382
46438
|
//#endregion
|
|
46383
46439
|
//#region src/cli/utils/json-mode.ts
|
|
46384
46440
|
let context = null;
|
|
@@ -46747,13 +46803,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
|
|
|
46747
46803
|
* uploads source-map artifacts under, so stack frames symbolicate. Honors the
|
|
46748
46804
|
* standard `SENTRY_RELEASE` override.
|
|
46749
46805
|
*/
|
|
46750
|
-
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.
|
|
46806
|
+
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.3-dev.6b70b32`;
|
|
46751
46807
|
/**
|
|
46752
46808
|
* Deployment environment shown in Sentry's environment filter. Defaults to
|
|
46753
46809
|
* `production` for tagged releases and `development` for dev/unbuilt versions,
|
|
46754
46810
|
* overridable via the standard `SENTRY_ENVIRONMENT` env var.
|
|
46755
46811
|
*/
|
|
46756
|
-
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.
|
|
46812
|
+
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.3-dev.6b70b32") ? "development" : "production");
|
|
46757
46813
|
/**
|
|
46758
46814
|
* Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
|
|
46759
46815
|
* (set to `0` to disable tracing) and falls back to
|
|
@@ -64928,4 +64984,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
|
|
|
64928
64984
|
export {};
|
|
64929
64985
|
|
|
64930
64986
|
//# sourceMappingURL=cli.js.map
|
|
64931
|
-
//# debugId=
|
|
64987
|
+
//# debugId=d6c8e327-6382-5aed-99c8-f3e537c25f51
|