react-doctor 0.7.2-dev.aa519e5 → 0.7.2-dev.b97a92f
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 +657 -649
- package/dist/index.d.ts +14 -2
- package/dist/index.js +654 -646
- package/dist/lsp.js +769 -768
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="91ba16f6-8b1a-5cd9-a5d2-fc0b6fce2508")}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__\//;
|
|
@@ -36192,25 +36223,6 @@ const isLargeMinifiedFile = (absolutePath, knownSizeBytes) => {
|
|
|
36192
36223
|
cachedIsLargeMinifiedByPath.set(absolutePath, result);
|
|
36193
36224
|
return result;
|
|
36194
36225
|
};
|
|
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
36226
|
function* walkSourceTreeFiles(rootDirectory) {
|
|
36215
36227
|
const stack = [rootDirectory];
|
|
36216
36228
|
while (stack.length > 0) {
|
|
@@ -36265,23 +36277,6 @@ const listSourceFilesViaFilesystem = (rootDirectory) => {
|
|
|
36265
36277
|
const listSourceFilesWithSize = (rootDirectory) => collectSizedSourceFiles(rootDirectory, (listSourceFilesViaGit(rootDirectory) ?? listSourceFilesViaFilesystem(rootDirectory)).sort());
|
|
36266
36278
|
const listSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).map((entry) => entry.path);
|
|
36267
36279
|
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
36280
|
const cachedPackageJsons = /* @__PURE__ */ new Map();
|
|
36286
36281
|
const readPackageJsonUncached = (packageJsonPath) => {
|
|
36287
36282
|
try {
|
|
@@ -36312,7 +36307,11 @@ const isMonorepoRoot = (directory) => {
|
|
|
36312
36307
|
return Array.isArray(packageJson.workspaces) || Boolean(packageJson.workspaces?.packages);
|
|
36313
36308
|
};
|
|
36314
36309
|
const findMonorepoRoot = (startDirectory) => {
|
|
36315
|
-
|
|
36310
|
+
let currentDirectory = Path.dirname(startDirectory);
|
|
36311
|
+
while (currentDirectory !== Path.dirname(currentDirectory)) {
|
|
36312
|
+
if (isMonorepoRoot(currentDirectory)) return currentDirectory;
|
|
36313
|
+
currentDirectory = Path.dirname(currentDirectory);
|
|
36314
|
+
}
|
|
36316
36315
|
return null;
|
|
36317
36316
|
};
|
|
36318
36317
|
/**
|
|
@@ -36326,6 +36325,146 @@ const findMonorepoRoot = (startDirectory) => {
|
|
|
36326
36325
|
* byte-equivalent copy.
|
|
36327
36326
|
*/
|
|
36328
36327
|
const isProjectBoundary = (directory) => NFS.existsSync(Path.join(directory, ".git")) || isMonorepoRoot(directory);
|
|
36328
|
+
const TSCONFIG_FILENAME = "tsconfig.json";
|
|
36329
|
+
const isRelativeExtendsValue = (extendsValue) => extendsValue.startsWith("./") || extendsValue.startsWith("../") || Path.isAbsolute(extendsValue);
|
|
36330
|
+
const ensureJsonExtension = (filePath) => Path.extname(filePath) === "" ? `${filePath}.json` : filePath;
|
|
36331
|
+
const resolvePackageExtendsPath = (extendsValue, fromConfigDirectory) => {
|
|
36332
|
+
const requireFromConfig = createRequire(Path.join(fromConfigDirectory, "tsconfig.json"));
|
|
36333
|
+
const candidates = [
|
|
36334
|
+
extendsValue,
|
|
36335
|
+
ensureJsonExtension(extendsValue),
|
|
36336
|
+
`${extendsValue.replace(/\/$/, "")}/tsconfig.json`
|
|
36337
|
+
];
|
|
36338
|
+
for (const candidate of candidates) try {
|
|
36339
|
+
return requireFromConfig.resolve(candidate);
|
|
36340
|
+
} catch {
|
|
36341
|
+
continue;
|
|
36342
|
+
}
|
|
36343
|
+
return null;
|
|
36344
|
+
};
|
|
36345
|
+
const resolveExtendsPath = (extendsValue, fromConfigDirectory) => {
|
|
36346
|
+
if (isRelativeExtendsValue(extendsValue)) return ensureJsonExtension(Path.resolve(fromConfigDirectory, extendsValue));
|
|
36347
|
+
return resolvePackageExtendsPath(extendsValue, fromConfigDirectory);
|
|
36348
|
+
};
|
|
36349
|
+
const normalizeCompilerOptions = (compilerOptions) => {
|
|
36350
|
+
if (!isPlainObject(compilerOptions)) return { hasExplicitLib: false };
|
|
36351
|
+
const target = typeof compilerOptions.target === "string" ? compilerOptions.target : void 0;
|
|
36352
|
+
const hasExplicitLib = Object.hasOwn(compilerOptions, "lib");
|
|
36353
|
+
return {
|
|
36354
|
+
target,
|
|
36355
|
+
lib: Array.isArray(compilerOptions.lib) ? compilerOptions.lib.filter((entry) => typeof entry === "string") : void 0,
|
|
36356
|
+
hasExplicitLib
|
|
36357
|
+
};
|
|
36358
|
+
};
|
|
36359
|
+
const readTsConfig = (filePath) => {
|
|
36360
|
+
let content;
|
|
36361
|
+
try {
|
|
36362
|
+
content = NFS.readFileSync(filePath, "utf-8");
|
|
36363
|
+
} catch {
|
|
36364
|
+
return null;
|
|
36365
|
+
}
|
|
36366
|
+
const parsed = ts.parseConfigFileTextToJson(filePath, content);
|
|
36367
|
+
if (!isPlainObject(parsed.config)) return null;
|
|
36368
|
+
return {
|
|
36369
|
+
extends: typeof parsed.config.extends === "string" ? parsed.config.extends : void 0,
|
|
36370
|
+
referencePaths: normalizeReferencePaths(parsed.config.references),
|
|
36371
|
+
compilerOptions: normalizeCompilerOptions(parsed.config.compilerOptions)
|
|
36372
|
+
};
|
|
36373
|
+
};
|
|
36374
|
+
const normalizeReferencePaths = (references) => {
|
|
36375
|
+
if (!Array.isArray(references)) return [];
|
|
36376
|
+
return references.map((reference) => isPlainObject(reference) && typeof reference.path === "string" ? reference.path : null).filter((referencePath) => referencePath !== null);
|
|
36377
|
+
};
|
|
36378
|
+
const mergeCompilerOptions = (inherited, current) => {
|
|
36379
|
+
const target = current.target ?? inherited?.target;
|
|
36380
|
+
const hasExplicitLib = current.hasExplicitLib || Boolean(inherited?.hasExplicitLib);
|
|
36381
|
+
return {
|
|
36382
|
+
target,
|
|
36383
|
+
lib: current.hasExplicitLib ? current.lib : inherited?.lib,
|
|
36384
|
+
hasExplicitLib
|
|
36385
|
+
};
|
|
36386
|
+
};
|
|
36387
|
+
const readResolvedCompilerOptions = (tsConfigPath, extendsDepth, visitedPaths) => {
|
|
36388
|
+
const realPath = NFS.realpathSync.native(tsConfigPath);
|
|
36389
|
+
if (visitedPaths.has(realPath)) return null;
|
|
36390
|
+
const tsConfig = readTsConfig(realPath);
|
|
36391
|
+
if (!tsConfig) return null;
|
|
36392
|
+
const nextVisitedPaths = new Set(visitedPaths);
|
|
36393
|
+
nextVisitedPaths.add(realPath);
|
|
36394
|
+
if (tsConfig.extends && extendsDepth < 8) {
|
|
36395
|
+
const parentPath = resolveExtendsPath(tsConfig.extends, Path.dirname(realPath));
|
|
36396
|
+
if (parentPath && isFile(parentPath)) return mergeCompilerOptions(readResolvedCompilerOptions(parentPath, extendsDepth + 1, nextVisitedPaths), tsConfig.compilerOptions);
|
|
36397
|
+
}
|
|
36398
|
+
return tsConfig.compilerOptions;
|
|
36399
|
+
};
|
|
36400
|
+
const targetYearIsPreES2023 = (target) => {
|
|
36401
|
+
const year = ES_TARGET_YEAR_BY_NAME[target.toLowerCase()];
|
|
36402
|
+
return year !== void 0 && year < 2023;
|
|
36403
|
+
};
|
|
36404
|
+
const libEntryIncludesES2023Array = (entry) => {
|
|
36405
|
+
const normalizedEntry = entry.toLowerCase();
|
|
36406
|
+
if (normalizedEntry === "esnext" || normalizedEntry === "esnext.array") return true;
|
|
36407
|
+
const esYearMatch = /^es(\d{4})(?:\.(.+))?$/.exec(normalizedEntry);
|
|
36408
|
+
if (!esYearMatch) return false;
|
|
36409
|
+
if (Number(esYearMatch[1]) < 2023) return false;
|
|
36410
|
+
const component = esYearMatch[2];
|
|
36411
|
+
return component === void 0 || component === "array";
|
|
36412
|
+
};
|
|
36413
|
+
const libIncludesES2023 = (lib) => lib.some(libEntryIncludesES2023Array);
|
|
36414
|
+
const compilerOptionsArePreES2023 = (compilerOptions) => {
|
|
36415
|
+
if (compilerOptions.target) return targetYearIsPreES2023(compilerOptions.target);
|
|
36416
|
+
if (compilerOptions.hasExplicitLib) return !libIncludesES2023(compilerOptions.lib ?? []);
|
|
36417
|
+
return false;
|
|
36418
|
+
};
|
|
36419
|
+
const compilerOptionsDeclareTargetOrLib = (compilerOptions) => compilerOptions.hasExplicitLib || compilerOptions.target !== void 0;
|
|
36420
|
+
const detectPreES2023FromConfig = (tsConfigPath, visitedConfigPaths = /* @__PURE__ */ new Set()) => {
|
|
36421
|
+
if (visitedConfigPaths.has(tsConfigPath)) return false;
|
|
36422
|
+
const compilerOptions = readResolvedCompilerOptions(tsConfigPath, 0, /* @__PURE__ */ new Set());
|
|
36423
|
+
if (!compilerOptions) return false;
|
|
36424
|
+
if (!compilerOptionsDeclareTargetOrLib(compilerOptions)) {
|
|
36425
|
+
const tsConfig = readTsConfig(tsConfigPath);
|
|
36426
|
+
if (!tsConfig) return false;
|
|
36427
|
+
const nextVisitedConfigPaths = new Set(visitedConfigPaths);
|
|
36428
|
+
nextVisitedConfigPaths.add(tsConfigPath);
|
|
36429
|
+
const configDirectory = Path.dirname(tsConfigPath);
|
|
36430
|
+
return tsConfig.referencePaths.some((referencePath) => {
|
|
36431
|
+
const resolvedReferencePath = Path.resolve(configDirectory, referencePath);
|
|
36432
|
+
const referencedConfigPath = isFile(resolvedReferencePath) ? resolvedReferencePath : Path.join(resolvedReferencePath, TSCONFIG_FILENAME);
|
|
36433
|
+
return isFile(referencedConfigPath) && detectPreES2023FromConfig(referencedConfigPath, nextVisitedConfigPaths);
|
|
36434
|
+
});
|
|
36435
|
+
}
|
|
36436
|
+
return compilerOptionsArePreES2023(compilerOptions);
|
|
36437
|
+
};
|
|
36438
|
+
const detectPreES2023Target = (directory) => {
|
|
36439
|
+
const tsConfigPath = Path.join(directory, TSCONFIG_FILENAME);
|
|
36440
|
+
if (isFile(tsConfigPath)) return detectPreES2023FromConfig(tsConfigPath);
|
|
36441
|
+
for (const fallbackFilename of FALLBACK_TSCONFIG_FILENAMES) {
|
|
36442
|
+
const fallbackPath = Path.join(directory, fallbackFilename);
|
|
36443
|
+
if (isFile(fallbackPath)) return detectPreES2023FromConfig(fallbackPath);
|
|
36444
|
+
}
|
|
36445
|
+
return false;
|
|
36446
|
+
};
|
|
36447
|
+
const FALLBACK_TSCONFIG_FILENAMES = ["tsconfig.app.json", "tsconfig.build.json"];
|
|
36448
|
+
const FRAMEWORK_PACKAGES = {
|
|
36449
|
+
next: "nextjs",
|
|
36450
|
+
"@tanstack/react-start": "tanstack-start",
|
|
36451
|
+
vite: "vite",
|
|
36452
|
+
"react-scripts": "cra",
|
|
36453
|
+
"@remix-run/react": "remix",
|
|
36454
|
+
gatsby: "gatsby",
|
|
36455
|
+
expo: "expo",
|
|
36456
|
+
"react-native": "react-native"
|
|
36457
|
+
};
|
|
36458
|
+
const detectFramework = (dependencies) => {
|
|
36459
|
+
for (const [packageName, frameworkName] of Object.entries(FRAMEWORK_PACKAGES)) if (dependencies[packageName]) return frameworkName;
|
|
36460
|
+
if (dependencies.preact && !dependencies.react) return "preact";
|
|
36461
|
+
return "unknown";
|
|
36462
|
+
};
|
|
36463
|
+
const MOBILE_FRAMEWORKS = new Set(["expo", "react-native"]);
|
|
36464
|
+
const frameworkMergeRank = (framework) => {
|
|
36465
|
+
if (framework === "unknown") return 3;
|
|
36466
|
+
return MOBILE_FRAMEWORKS.has(framework) ? 2 : 1;
|
|
36467
|
+
};
|
|
36329
36468
|
const REACT_COMPILER_PACKAGES = new Set([
|
|
36330
36469
|
"babel-plugin-react-compiler",
|
|
36331
36470
|
"react-compiler-runtime",
|
|
@@ -36362,6 +36501,7 @@ const EXPO_APP_CONFIG_FILENAMES = [
|
|
|
36362
36501
|
];
|
|
36363
36502
|
const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|eslint-plugin-react-compiler|["']react-compiler["']/;
|
|
36364
36503
|
const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
|
|
36504
|
+
const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
|
|
36365
36505
|
const hasCompilerPackage = (packageJson) => {
|
|
36366
36506
|
const allDependencies = {
|
|
36367
36507
|
...packageJson.peerDependencies,
|
|
@@ -36394,34 +36534,10 @@ const detectReactCompiler = (directory, packageJson) => {
|
|
|
36394
36534
|
}
|
|
36395
36535
|
return false;
|
|
36396
36536
|
};
|
|
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
|
-
};
|
|
36537
|
+
const detectNextjsStaticExport = (directory) => NEXT_CONFIG_FILENAMES.some((filename) => {
|
|
36538
|
+
const filePath = Path.join(directory, filename);
|
|
36539
|
+
return isFile(filePath) && STATIC_EXPORT_OUTPUT_PATTERN.test(NFS.readFileSync(filePath, "utf-8"));
|
|
36540
|
+
});
|
|
36425
36541
|
const UNRESOLVABLE_PROTOCOL_VERSION = /^(?:file|git|github|https?|link|patch|portal|workspace|npm):/i;
|
|
36426
36542
|
const DIST_TAG_VERSION = /^[a-z][a-z0-9._-]*$/i;
|
|
36427
36543
|
const WILDCARD_VERSION = /^[*xX](?:\.[*xX])*$/;
|
|
@@ -36559,10 +36675,76 @@ const isConcreteDependencyVersion = (version) => {
|
|
|
36559
36675
|
const normalizedVersion = normalizeDependencyVersion(version);
|
|
36560
36676
|
return normalizedVersion !== null && /\d/.test(normalizedVersion);
|
|
36561
36677
|
};
|
|
36562
|
-
const
|
|
36563
|
-
if (
|
|
36564
|
-
|
|
36565
|
-
return
|
|
36678
|
+
const isMajorMinorAtLeast = (detected, required) => {
|
|
36679
|
+
if (detected === null) return true;
|
|
36680
|
+
if (detected.major !== required.major) return detected.major > required.major;
|
|
36681
|
+
return detected.minor >= required.minor;
|
|
36682
|
+
};
|
|
36683
|
+
const parseReactMajor = (reactVersion) => {
|
|
36684
|
+
if (typeof reactVersion !== "string") return null;
|
|
36685
|
+
return getLowestDependencyMajor(reactVersion);
|
|
36686
|
+
};
|
|
36687
|
+
const MAJOR_MINOR_PATTERN = /(\d{1,4})\.(\d{1,4})/;
|
|
36688
|
+
const MAJOR_ONLY_PATTERN = /(\d{1,4})/;
|
|
36689
|
+
const UPPER_BOUND_COMPARATOR_PATTERN = /<=?\s{0,8}\d{1,4}(?:\.\d{1,4}){0,2}(?:-[^\s,|]+)?/g;
|
|
36690
|
+
const parseReactMajorMinor = (reactVersion) => {
|
|
36691
|
+
if (typeof reactVersion !== "string") return null;
|
|
36692
|
+
const trimmed = reactVersion.trim();
|
|
36693
|
+
if (trimmed.length === 0) return null;
|
|
36694
|
+
const lowerBoundsOnly = trimmed.replace(UPPER_BOUND_COMPARATOR_PATTERN, " ").trim();
|
|
36695
|
+
if (lowerBoundsOnly.length === 0) return null;
|
|
36696
|
+
const majorMinorMatch = lowerBoundsOnly.match(MAJOR_MINOR_PATTERN);
|
|
36697
|
+
if (majorMinorMatch) {
|
|
36698
|
+
const major = Number.parseInt(majorMinorMatch[1], 10);
|
|
36699
|
+
const minor = Number.parseInt(majorMinorMatch[2], 10);
|
|
36700
|
+
if (!Number.isFinite(major) || major <= 0) return null;
|
|
36701
|
+
if (!Number.isFinite(minor) || minor < 0) return null;
|
|
36702
|
+
return {
|
|
36703
|
+
major,
|
|
36704
|
+
minor
|
|
36705
|
+
};
|
|
36706
|
+
}
|
|
36707
|
+
const majorOnlyMatch = lowerBoundsOnly.match(MAJOR_ONLY_PATTERN);
|
|
36708
|
+
if (!majorOnlyMatch) return null;
|
|
36709
|
+
const major = Number.parseInt(majorOnlyMatch[1], 10);
|
|
36710
|
+
if (!Number.isFinite(major) || major <= 0) return null;
|
|
36711
|
+
return {
|
|
36712
|
+
major,
|
|
36713
|
+
minor: 0
|
|
36714
|
+
};
|
|
36715
|
+
};
|
|
36716
|
+
const parseLowerBoundVersion = (versionSpec) => import_semver.validRange(versionSpec) !== null ? import_semver.minVersion(versionSpec) : import_semver.coerce(versionSpec);
|
|
36717
|
+
const parseTailwindMajorMinor = (tailwindVersion) => {
|
|
36718
|
+
if (typeof tailwindVersion !== "string") return null;
|
|
36719
|
+
const trimmed = tailwindVersion.trim();
|
|
36720
|
+
if (trimmed.length === 0) return null;
|
|
36721
|
+
const lowerBound = parseLowerBoundVersion(trimmed);
|
|
36722
|
+
if (lowerBound === null || lowerBound.major <= 0) return null;
|
|
36723
|
+
return {
|
|
36724
|
+
major: lowerBound.major,
|
|
36725
|
+
minor: lowerBound.minor
|
|
36726
|
+
};
|
|
36727
|
+
};
|
|
36728
|
+
const hasUpperBoundOnlyPeerRange = (range) => {
|
|
36729
|
+
if (typeof range !== "string") return false;
|
|
36730
|
+
const normalizedRange = normalizeDependencyVersion(range);
|
|
36731
|
+
if (normalizedRange === null) return false;
|
|
36732
|
+
return splitDependencyVersionBranches(normalizedRange).some((branch) => {
|
|
36733
|
+
const normalizedBranch = normalizeDependencyVersion(branch);
|
|
36734
|
+
return normalizedBranch !== null && getBranchLowestMajor(normalizedBranch) === null && hasUpperBoundComparator(normalizedBranch);
|
|
36735
|
+
});
|
|
36736
|
+
};
|
|
36737
|
+
const peerRangeMinMajor = (range) => {
|
|
36738
|
+
if (typeof range !== "string") return null;
|
|
36739
|
+
return getLowestDependencyMajor(range);
|
|
36740
|
+
};
|
|
36741
|
+
const resolveEffectiveReactMajor = (reactVersion, packageJson) => {
|
|
36742
|
+
const installedReactMajor = parseReactMajor(reactVersion);
|
|
36743
|
+
const peerReactRange = packageJson.peerDependencies?.react;
|
|
36744
|
+
if (typeof peerReactRange !== "string") return installedReactMajor;
|
|
36745
|
+
const peerFloor = peerRangeMinMajor(peerReactRange);
|
|
36746
|
+
if (peerFloor === null) return hasUpperBoundOnlyPeerRange(peerReactRange) ? null : installedReactMajor;
|
|
36747
|
+
return installedReactMajor !== null ? Math.min(installedReactMajor, peerFloor) : peerFloor;
|
|
36566
36748
|
};
|
|
36567
36749
|
const isCatalogReference = (version) => version.startsWith("catalog:");
|
|
36568
36750
|
const extractCatalogName = (version) => {
|
|
@@ -36704,6 +36886,16 @@ const resolveCatalogVersion = (packageJson, packageName, rootDirectory, explicit
|
|
|
36704
36886
|
}
|
|
36705
36887
|
return null;
|
|
36706
36888
|
};
|
|
36889
|
+
const REACT_SECTIONS = [
|
|
36890
|
+
"dependencies",
|
|
36891
|
+
"peerDependencies",
|
|
36892
|
+
"devDependencies"
|
|
36893
|
+
];
|
|
36894
|
+
const TAILWIND_ZOD_SECTIONS = [
|
|
36895
|
+
"dependencies",
|
|
36896
|
+
"devDependencies",
|
|
36897
|
+
"peerDependencies"
|
|
36898
|
+
];
|
|
36707
36899
|
const EMPTY_DEPENDENCY_INFO = {
|
|
36708
36900
|
reactVersion: null,
|
|
36709
36901
|
tailwindVersion: null,
|
|
@@ -36744,6 +36936,10 @@ const extractDependencyInfo = (packageJson) => {
|
|
|
36744
36936
|
framework: detectFramework(allDependencies)
|
|
36745
36937
|
};
|
|
36746
36938
|
};
|
|
36939
|
+
const getDependencySpec = (packageJson, packageName) => {
|
|
36940
|
+
const spec = packageJson.dependencies?.[packageName] ?? packageJson.devDependencies?.[packageName] ?? packageJson.peerDependencies?.[packageName] ?? packageJson.optionalDependencies?.[packageName];
|
|
36941
|
+
return typeof spec === "string" ? spec : null;
|
|
36942
|
+
};
|
|
36747
36943
|
const getDependencyDeclaration = ({ packageJson, packageName, sections }) => {
|
|
36748
36944
|
for (const section of sections) {
|
|
36749
36945
|
const version = packageJson[section]?.[packageName];
|
|
@@ -36760,31 +36956,141 @@ const getDependencyDeclaration = ({ packageJson, packageName, sections }) => {
|
|
|
36760
36956
|
version: null
|
|
36761
36957
|
};
|
|
36762
36958
|
};
|
|
36763
|
-
const
|
|
36764
|
-
|
|
36765
|
-
|
|
36766
|
-
|
|
36767
|
-
|
|
36959
|
+
const REACT_DEPENDENCY_NAMES = new Set([
|
|
36960
|
+
"react",
|
|
36961
|
+
"react-native",
|
|
36962
|
+
"next",
|
|
36963
|
+
"preact"
|
|
36964
|
+
]);
|
|
36965
|
+
const hasReactDependency = (packageJson) => {
|
|
36966
|
+
const allDependencies = {
|
|
36967
|
+
...packageJson.peerDependencies,
|
|
36968
|
+
...packageJson.dependencies,
|
|
36969
|
+
...packageJson.devDependencies
|
|
36970
|
+
};
|
|
36971
|
+
return Object.keys(allDependencies).some((packageName) => REACT_DEPENDENCY_NAMES.has(packageName));
|
|
36972
|
+
};
|
|
36973
|
+
const getPreactVersion = (packageJson) => {
|
|
36974
|
+
return {
|
|
36975
|
+
...packageJson.peerDependencies,
|
|
36976
|
+
...packageJson.dependencies,
|
|
36977
|
+
...packageJson.devDependencies
|
|
36978
|
+
}.preact ?? null;
|
|
36979
|
+
};
|
|
36980
|
+
const TANSTACK_QUERY_PACKAGES = new Set([
|
|
36981
|
+
"@tanstack/react-query",
|
|
36982
|
+
"@tanstack/query-core",
|
|
36983
|
+
"react-query"
|
|
36984
|
+
]);
|
|
36985
|
+
const hasTanStackQuery = (packageJson) => {
|
|
36986
|
+
const allDependencies = {
|
|
36987
|
+
...packageJson.peerDependencies,
|
|
36988
|
+
...packageJson.dependencies,
|
|
36989
|
+
...packageJson.devDependencies
|
|
36990
|
+
};
|
|
36991
|
+
return Object.keys(allDependencies).some((packageName) => TANSTACK_QUERY_PACKAGES.has(packageName));
|
|
36992
|
+
};
|
|
36993
|
+
const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, version }) => {
|
|
36994
|
+
if (version === null || !isCatalogReference(version)) return version;
|
|
36995
|
+
const catalogName = extractCatalogName(version);
|
|
36996
|
+
const resolvedLocalVersion = resolveCatalogVersion(rootPackageJson, packageName, rootDirectory, catalogName);
|
|
36997
|
+
if (resolvedLocalVersion) return resolvedLocalVersion;
|
|
36998
|
+
const monorepoRoot = findMonorepoRoot(rootDirectory);
|
|
36999
|
+
if (!monorepoRoot) return version;
|
|
37000
|
+
const monorepoPackageJsonPath = Path.join(monorepoRoot, "package.json");
|
|
37001
|
+
if (!isFile(monorepoPackageJsonPath)) return version;
|
|
37002
|
+
return resolveCatalogVersion(readPackageJson$1(monorepoPackageJsonPath), packageName, monorepoRoot, catalogName) ?? version;
|
|
37003
|
+
};
|
|
37004
|
+
/**
|
|
37005
|
+
* The chain of ancestor directories of `startDirectory`, nearest first, up to
|
|
37006
|
+
* and including the filesystem root. With `includeStart`, the chain begins at
|
|
37007
|
+
* `startDirectory` itself; otherwise at its parent. The one place the "walk up
|
|
37008
|
+
* the tree" traversal is expressed, so each caller adds only its own match /
|
|
37009
|
+
* stop policy instead of re-deriving the `path.dirname` loop.
|
|
37010
|
+
*/
|
|
37011
|
+
const ancestorDirectories = (startDirectory, { includeStart }) => {
|
|
37012
|
+
const directories = [];
|
|
37013
|
+
let currentDirectory = includeStart ? startDirectory : Path.dirname(startDirectory);
|
|
37014
|
+
while (true) {
|
|
37015
|
+
directories.push(currentDirectory);
|
|
37016
|
+
const parentDirectory = Path.dirname(currentDirectory);
|
|
37017
|
+
if (parentDirectory === currentDirectory) return directories;
|
|
37018
|
+
currentDirectory = parentDirectory;
|
|
36768
37019
|
}
|
|
36769
37020
|
};
|
|
36770
|
-
|
|
36771
|
-
|
|
36772
|
-
|
|
36773
|
-
|
|
36774
|
-
|
|
36775
|
-
|
|
36776
|
-
|
|
36777
|
-
|
|
36778
|
-
|
|
36779
|
-
|
|
36780
|
-
|
|
36781
|
-
|
|
36782
|
-
|
|
36783
|
-
|
|
36784
|
-
|
|
36785
|
-
|
|
37021
|
+
/**
|
|
37022
|
+
* Walk up from `startDirectory` to the nearest ancestor that owns a
|
|
37023
|
+
* `package.json`, stopping at (and including) the enclosing project boundary
|
|
37024
|
+
* — the working tree's git root or a monorepo root. Lets a scan of a package
|
|
37025
|
+
* subfolder that has no `package.json` of its own adopt the nearest enclosing
|
|
37026
|
+
* package as its project root, so it inherits that package's dependency +
|
|
37027
|
+
* framework detection instead of synthesizing an empty (React-blind) project.
|
|
37028
|
+
*
|
|
37029
|
+
* Generalizes the older monorepo-root-only lookup: the nearest ancestor is the
|
|
37030
|
+
* most specific owning package (a leaf workspace, not just the repo root), so
|
|
37031
|
+
* a subfolder of one workspace no longer borrows a sibling's capabilities.
|
|
37032
|
+
*
|
|
37033
|
+
* Returns `null` when no ancestor `package.json` exists inside the project
|
|
37034
|
+
* boundary (a loose tree of files, or a subfolder of a package-less repo).
|
|
37035
|
+
*/
|
|
37036
|
+
const findNearestAncestorPackageJson = (startDirectory) => {
|
|
37037
|
+
if (isProjectBoundary(startDirectory)) return null;
|
|
37038
|
+
for (const directory of ancestorDirectories(startDirectory, { includeStart: false })) {
|
|
37039
|
+
if (isFile(Path.join(directory, "package.json"))) return directory;
|
|
37040
|
+
if (isProjectBoundary(directory)) return null;
|
|
36786
37041
|
}
|
|
36787
|
-
return
|
|
37042
|
+
return null;
|
|
37043
|
+
};
|
|
37044
|
+
const NAMES = new Set([
|
|
37045
|
+
"react-native",
|
|
37046
|
+
"react-native-tvos",
|
|
37047
|
+
...new Set([
|
|
37048
|
+
"expo",
|
|
37049
|
+
"expo-router",
|
|
37050
|
+
"@expo/cli",
|
|
37051
|
+
"@expo/metro-config",
|
|
37052
|
+
"@expo/metro-runtime"
|
|
37053
|
+
]),
|
|
37054
|
+
"react-native-windows",
|
|
37055
|
+
"react-native-macos"
|
|
37056
|
+
]);
|
|
37057
|
+
const PREFIXES = ["@react-native/", "@react-native-"];
|
|
37058
|
+
const isReactNativeDependencyName = (dependencyName) => {
|
|
37059
|
+
if (NAMES.has(dependencyName)) return true;
|
|
37060
|
+
for (const prefix of PREFIXES) if (dependencyName.startsWith(prefix)) return true;
|
|
37061
|
+
return false;
|
|
37062
|
+
};
|
|
37063
|
+
const containsAnyReactNativeDependency = (section) => {
|
|
37064
|
+
if (!section) return false;
|
|
37065
|
+
for (const dependencyName of Object.keys(section)) if (isReactNativeDependencyName(dependencyName)) return true;
|
|
37066
|
+
return false;
|
|
37067
|
+
};
|
|
37068
|
+
const isPackageJsonReactNativeAware = (packageJson) => {
|
|
37069
|
+
if (typeof packageJson["react-native"] === "string") return true;
|
|
37070
|
+
if (containsAnyReactNativeDependency(packageJson.dependencies)) return true;
|
|
37071
|
+
if (containsAnyReactNativeDependency(packageJson.devDependencies)) return true;
|
|
37072
|
+
if (containsAnyReactNativeDependency(packageJson.peerDependencies)) return true;
|
|
37073
|
+
if (containsAnyReactNativeDependency(packageJson.optionalDependencies)) return true;
|
|
37074
|
+
return false;
|
|
37075
|
+
};
|
|
37076
|
+
const REANIMATED_DEPENDENCY_NAME$1 = "react-native-reanimated";
|
|
37077
|
+
const isPackageJsonReanimatedAware = (packageJson) => {
|
|
37078
|
+
const allDependencies = {
|
|
37079
|
+
...packageJson.peerDependencies,
|
|
37080
|
+
...packageJson.dependencies,
|
|
37081
|
+
...packageJson.devDependencies,
|
|
37082
|
+
...packageJson.optionalDependencies
|
|
37083
|
+
};
|
|
37084
|
+
return Object.hasOwn(allDependencies, REANIMATED_DEPENDENCY_NAME$1);
|
|
37085
|
+
};
|
|
37086
|
+
const getWorkspacePatterns = (rootDirectory, packageJson) => {
|
|
37087
|
+
const pnpmPatterns = parsePnpmWorkspacePatterns(rootDirectory);
|
|
37088
|
+
if (pnpmPatterns.length > 0) return pnpmPatterns;
|
|
37089
|
+
if (Array.isArray(packageJson.workspaces)) return packageJson.workspaces;
|
|
37090
|
+
if (packageJson.workspaces?.packages) return packageJson.workspaces.packages;
|
|
37091
|
+
const nxPatterns = getNxWorkspaceDirectories(rootDirectory);
|
|
37092
|
+
if (nxPatterns.length > 0) return nxPatterns;
|
|
37093
|
+
return [];
|
|
36788
37094
|
};
|
|
36789
37095
|
const parsePnpmWorkspacePatterns = (rootDirectory) => {
|
|
36790
37096
|
const workspacePath = Path.join(rootDirectory, "pnpm-workspace.yaml");
|
|
@@ -36803,18 +37109,24 @@ const parsePnpmWorkspacePatterns = (rootDirectory) => {
|
|
|
36803
37109
|
}
|
|
36804
37110
|
return patterns;
|
|
36805
37111
|
};
|
|
36806
|
-
const
|
|
36807
|
-
|
|
36808
|
-
|
|
36809
|
-
|
|
36810
|
-
|
|
36811
|
-
|
|
36812
|
-
if (
|
|
36813
|
-
|
|
36814
|
-
|
|
36815
|
-
const
|
|
36816
|
-
|
|
36817
|
-
|
|
37112
|
+
const NX_PROJECT_DISCOVERY_DIRS = [
|
|
37113
|
+
"apps",
|
|
37114
|
+
"libs",
|
|
37115
|
+
"packages"
|
|
37116
|
+
];
|
|
37117
|
+
const getNxWorkspaceDirectories = (rootDirectory) => {
|
|
37118
|
+
if (!isFile(Path.join(rootDirectory, "nx.json"))) return [];
|
|
37119
|
+
const collected = [];
|
|
37120
|
+
for (const candidate of NX_PROJECT_DISCOVERY_DIRS) {
|
|
37121
|
+
const candidatePath = Path.join(rootDirectory, candidate);
|
|
37122
|
+
if (!isDirectory(candidatePath)) continue;
|
|
37123
|
+
for (const entry of readDirectoryEntries(candidatePath)) {
|
|
37124
|
+
if (!entry.isDirectory()) continue;
|
|
37125
|
+
const projectDirectory = Path.join(candidatePath, entry.name);
|
|
37126
|
+
if (isFile(Path.join(projectDirectory, "project.json")) || isFile(Path.join(projectDirectory, "package.json"))) collected.push(`${candidate}/${entry.name}`);
|
|
37127
|
+
}
|
|
37128
|
+
}
|
|
37129
|
+
return collected;
|
|
36818
37130
|
};
|
|
36819
37131
|
const resolveWorkspaceDirectories = (rootDirectory, pattern) => {
|
|
36820
37132
|
const cleanPattern = pattern.replace(/["']/g, "").replace(/\/\*\*$/, "/*");
|
|
@@ -36834,6 +37146,38 @@ const resolveWorkspaceDirectories = (rootDirectory, pattern) => {
|
|
|
36834
37146
|
}
|
|
36835
37147
|
return resolved;
|
|
36836
37148
|
};
|
|
37149
|
+
const listWorkspacePackages = (rootDirectory) => {
|
|
37150
|
+
const packageJsonPath = Path.join(rootDirectory, "package.json");
|
|
37151
|
+
if (!isFile(packageJsonPath)) return [];
|
|
37152
|
+
const packageJson = readPackageJson$1(packageJsonPath);
|
|
37153
|
+
const patterns = getWorkspacePatterns(rootDirectory, packageJson);
|
|
37154
|
+
if (patterns.length === 0) return [];
|
|
37155
|
+
const packages = [];
|
|
37156
|
+
const seenDirectories = /* @__PURE__ */ new Set();
|
|
37157
|
+
const pushIfNew = (workspacePackage) => {
|
|
37158
|
+
if (seenDirectories.has(workspacePackage.directory)) return;
|
|
37159
|
+
seenDirectories.add(workspacePackage.directory);
|
|
37160
|
+
packages.push(workspacePackage);
|
|
37161
|
+
};
|
|
37162
|
+
if (hasReactDependency(packageJson)) pushIfNew({
|
|
37163
|
+
name: packageJson.name ?? Path.basename(rootDirectory),
|
|
37164
|
+
directory: rootDirectory
|
|
37165
|
+
});
|
|
37166
|
+
for (const pattern of patterns) {
|
|
37167
|
+
const directories = resolveWorkspaceDirectories(rootDirectory, pattern);
|
|
37168
|
+
for (const workspaceDirectory of directories) {
|
|
37169
|
+
const workspacePackageJson = readPackageJson$1(Path.join(workspaceDirectory, "package.json"));
|
|
37170
|
+
if (!hasReactDependency(workspacePackageJson)) continue;
|
|
37171
|
+
pushIfNew({
|
|
37172
|
+
name: workspacePackageJson.name ?? Path.basename(workspaceDirectory),
|
|
37173
|
+
directory: workspaceDirectory
|
|
37174
|
+
});
|
|
37175
|
+
}
|
|
37176
|
+
}
|
|
37177
|
+
return packages;
|
|
37178
|
+
};
|
|
37179
|
+
const REANIMATED_DEPENDENCY_NAME = "react-native-reanimated";
|
|
37180
|
+
const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
|
|
36837
37181
|
const resolveWorkspaceDependencyVersion = ({ concreteVersion, packageName, rootDirectory, rootPackageJson, sections, workspaceDirectory, workspacePackageJson }) => {
|
|
36838
37182
|
const dependencyDeclaration = getDependencyDeclaration({
|
|
36839
37183
|
packageJson: workspacePackageJson,
|
|
@@ -36851,24 +37195,76 @@ const shouldReplaceReactVersion = (currentVersion, nextVersion) => {
|
|
|
36851
37195
|
if (nextMajor === null) return false;
|
|
36852
37196
|
return nextMajor < currentMajor;
|
|
36853
37197
|
};
|
|
36854
|
-
const
|
|
36855
|
-
|
|
36856
|
-
|
|
36857
|
-
|
|
36858
|
-
|
|
37198
|
+
const evaluateManifestFacts = (facts, packageJson, directory) => {
|
|
37199
|
+
if (facts.expo.version === null) {
|
|
37200
|
+
const spec = getDependencySpec(packageJson, "expo");
|
|
37201
|
+
if (spec !== null) facts.expo = {
|
|
37202
|
+
version: spec,
|
|
37203
|
+
sourceDirectory: directory
|
|
37204
|
+
};
|
|
37205
|
+
}
|
|
37206
|
+
if (facts.next.version === null) {
|
|
37207
|
+
const spec = getDependencySpec(packageJson, "next");
|
|
37208
|
+
if (spec !== null) facts.next = {
|
|
37209
|
+
version: spec,
|
|
37210
|
+
sourceDirectory: directory
|
|
37211
|
+
};
|
|
37212
|
+
}
|
|
37213
|
+
if (facts.shopifyFlashList.version === null) {
|
|
37214
|
+
const spec = getDependencySpec(packageJson, SHOPIFY_FLASH_LIST_PACKAGE_NAME);
|
|
37215
|
+
if (spec !== null) facts.shopifyFlashList = {
|
|
37216
|
+
version: spec,
|
|
37217
|
+
sourceDirectory: directory
|
|
37218
|
+
};
|
|
37219
|
+
}
|
|
37220
|
+
if (facts.reanimatedVersion === null) {
|
|
37221
|
+
const spec = getDependencySpec(packageJson, REANIMATED_DEPENDENCY_NAME);
|
|
37222
|
+
if (spec !== null) facts.reanimatedVersion = spec;
|
|
37223
|
+
}
|
|
37224
|
+
facts.hasReactNativeAwarePackage = facts.hasReactNativeAwarePackage || isPackageJsonReactNativeAware(packageJson);
|
|
37225
|
+
facts.hasReanimatedAwarePackage = facts.hasReanimatedAwarePackage || isPackageJsonReanimatedAware(packageJson);
|
|
37226
|
+
};
|
|
37227
|
+
const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGroup }) => {
|
|
37228
|
+
const facts = {
|
|
37229
|
+
reactVersion: null,
|
|
37230
|
+
tailwindVersion: null,
|
|
37231
|
+
zodVersion: null,
|
|
37232
|
+
framework: "unknown",
|
|
37233
|
+
expo: {
|
|
37234
|
+
version: null,
|
|
37235
|
+
sourceDirectory: null
|
|
37236
|
+
},
|
|
37237
|
+
next: {
|
|
37238
|
+
version: null,
|
|
37239
|
+
sourceDirectory: null
|
|
37240
|
+
},
|
|
37241
|
+
shopifyFlashList: {
|
|
37242
|
+
version: null,
|
|
37243
|
+
sourceDirectory: null
|
|
37244
|
+
},
|
|
37245
|
+
hasReactNativeAwarePackage: false,
|
|
37246
|
+
hasReanimatedAwarePackage: false,
|
|
37247
|
+
reanimatedVersion: null
|
|
37248
|
+
};
|
|
37249
|
+
evaluateManifestFacts(facts, rootPackageJson, rootDirectory);
|
|
37250
|
+
let isReactGroupSettled = !collectReactGroup;
|
|
37251
|
+
const visitedDirectories = /* @__PURE__ */ new Set();
|
|
37252
|
+
for (const pattern of getWorkspacePatterns(rootDirectory, rootPackageJson)) {
|
|
37253
|
+
const directories = [...resolveWorkspaceDirectories(rootDirectory, pattern)].sort();
|
|
36859
37254
|
for (const workspaceDirectory of directories) {
|
|
37255
|
+
if (visitedDirectories.has(workspaceDirectory)) continue;
|
|
37256
|
+
visitedDirectories.add(workspaceDirectory);
|
|
36860
37257
|
const workspacePackageJson = readPackageJson$1(Path.join(workspaceDirectory, "package.json"));
|
|
37258
|
+
evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory);
|
|
36861
37259
|
const info = extractDependencyInfo(workspacePackageJson);
|
|
37260
|
+
if (info.framework !== "unknown" && frameworkMergeRank(info.framework) < frameworkMergeRank(facts.framework)) facts.framework = info.framework;
|
|
37261
|
+
if (isReactGroupSettled) continue;
|
|
36862
37262
|
const reactVersion = resolveWorkspaceDependencyVersion({
|
|
36863
37263
|
concreteVersion: info.reactVersion,
|
|
36864
37264
|
packageName: "react",
|
|
36865
37265
|
rootDirectory,
|
|
36866
|
-
rootPackageJson
|
|
36867
|
-
sections:
|
|
36868
|
-
"dependencies",
|
|
36869
|
-
"peerDependencies",
|
|
36870
|
-
"devDependencies"
|
|
36871
|
-
],
|
|
37266
|
+
rootPackageJson,
|
|
37267
|
+
sections: REACT_SECTIONS,
|
|
36872
37268
|
workspaceDirectory,
|
|
36873
37269
|
workspacePackageJson
|
|
36874
37270
|
});
|
|
@@ -36876,12 +37272,8 @@ const findReactInWorkspaces = (rootDirectory, packageJson) => {
|
|
|
36876
37272
|
concreteVersion: info.tailwindVersion,
|
|
36877
37273
|
packageName: "tailwindcss",
|
|
36878
37274
|
rootDirectory,
|
|
36879
|
-
rootPackageJson
|
|
36880
|
-
sections:
|
|
36881
|
-
"dependencies",
|
|
36882
|
-
"devDependencies",
|
|
36883
|
-
"peerDependencies"
|
|
36884
|
-
],
|
|
37275
|
+
rootPackageJson,
|
|
37276
|
+
sections: TAILWIND_ZOD_SECTIONS,
|
|
36885
37277
|
workspaceDirectory,
|
|
36886
37278
|
workspacePackageJson
|
|
36887
37279
|
});
|
|
@@ -36889,24 +37281,19 @@ const findReactInWorkspaces = (rootDirectory, packageJson) => {
|
|
|
36889
37281
|
concreteVersion: info.zodVersion,
|
|
36890
37282
|
packageName: "zod",
|
|
36891
37283
|
rootDirectory,
|
|
36892
|
-
rootPackageJson
|
|
36893
|
-
sections:
|
|
36894
|
-
"dependencies",
|
|
36895
|
-
"devDependencies",
|
|
36896
|
-
"peerDependencies"
|
|
36897
|
-
],
|
|
37284
|
+
rootPackageJson,
|
|
37285
|
+
sections: TAILWIND_ZOD_SECTIONS,
|
|
36898
37286
|
workspaceDirectory,
|
|
36899
37287
|
workspacePackageJson
|
|
36900
37288
|
});
|
|
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;
|
|
37289
|
+
if (reactVersion && shouldReplaceReactVersion(facts.reactVersion, reactVersion)) facts.reactVersion = reactVersion;
|
|
37290
|
+
if (tailwindVersion && !facts.tailwindVersion) facts.tailwindVersion = tailwindVersion;
|
|
37291
|
+
if (zodVersion && !facts.zodVersion) facts.zodVersion = zodVersion;
|
|
37292
|
+
const settledReactMajor = parseReactMajor(facts.reactVersion);
|
|
37293
|
+
isReactGroupSettled = Boolean(facts.reactVersion && facts.tailwindVersion && facts.framework !== "unknown" && settledReactMajor !== null && settledReactMajor <= 17);
|
|
36907
37294
|
}
|
|
36908
37295
|
}
|
|
36909
|
-
return
|
|
37296
|
+
return facts;
|
|
36910
37297
|
};
|
|
36911
37298
|
const findDependencyInfoFromMonorepoRoot = (directory) => {
|
|
36912
37299
|
const monorepoRoot = findMonorepoRoot(directory);
|
|
@@ -36920,29 +37307,17 @@ const findDependencyInfoFromMonorepoRoot = (directory) => {
|
|
|
36920
37307
|
const leafReactDeclaration = leafPackageJson ? getDependencyDeclaration({
|
|
36921
37308
|
packageJson: leafPackageJson,
|
|
36922
37309
|
packageName: "react",
|
|
36923
|
-
sections:
|
|
36924
|
-
"dependencies",
|
|
36925
|
-
"peerDependencies",
|
|
36926
|
-
"devDependencies"
|
|
36927
|
-
]
|
|
37310
|
+
sections: REACT_SECTIONS
|
|
36928
37311
|
}) : null;
|
|
36929
37312
|
const leafTailwindDeclaration = leafPackageJson ? getDependencyDeclaration({
|
|
36930
37313
|
packageJson: leafPackageJson,
|
|
36931
37314
|
packageName: "tailwindcss",
|
|
36932
|
-
sections:
|
|
36933
|
-
"dependencies",
|
|
36934
|
-
"devDependencies",
|
|
36935
|
-
"peerDependencies"
|
|
36936
|
-
]
|
|
37315
|
+
sections: TAILWIND_ZOD_SECTIONS
|
|
36937
37316
|
}) : null;
|
|
36938
37317
|
const leafZodDeclaration = leafPackageJson ? getDependencyDeclaration({
|
|
36939
37318
|
packageJson: leafPackageJson,
|
|
36940
37319
|
packageName: "zod",
|
|
36941
|
-
sections:
|
|
36942
|
-
"dependencies",
|
|
36943
|
-
"devDependencies",
|
|
36944
|
-
"peerDependencies"
|
|
36945
|
-
]
|
|
37320
|
+
sections: TAILWIND_ZOD_SECTIONS
|
|
36946
37321
|
}) : null;
|
|
36947
37322
|
const shouldUseReactFallback = !leafReactDeclaration?.hasDeclaration;
|
|
36948
37323
|
const shouldUseTailwindFallback = leafTailwindDeclaration?.hasDeclaration ?? true;
|
|
@@ -36950,38 +37325,15 @@ const findDependencyInfoFromMonorepoRoot = (directory) => {
|
|
|
36950
37325
|
const reactCatalogVersion = shouldUseReactFallback ? resolveCatalogVersion(rootPackageJson, "react", monorepoRoot, leafReactDeclaration?.catalogReference) : null;
|
|
36951
37326
|
const tailwindCatalogVersion = shouldUseTailwindFallback ? resolveCatalogVersion(rootPackageJson, "tailwindcss", monorepoRoot, leafTailwindDeclaration?.catalogReference) : null;
|
|
36952
37327
|
const zodCatalogVersion = shouldUseZodFallback ? resolveCatalogVersion(rootPackageJson, "zod", monorepoRoot, leafZodDeclaration?.catalogReference) : null;
|
|
36953
|
-
const
|
|
37328
|
+
const workspaceFacts = collectWorkspaceFacts(monorepoRoot, rootPackageJson, { collectReactGroup: true });
|
|
36954
37329
|
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 :
|
|
37330
|
+
reactVersion: shouldUseReactFallback ? reactCatalogVersion ?? rootInfo.reactVersion ?? workspaceFacts.reactVersion : rootInfo.reactVersion ?? workspaceFacts.reactVersion,
|
|
37331
|
+
tailwindVersion: shouldUseTailwindFallback ? tailwindCatalogVersion ?? rootInfo.tailwindVersion ?? workspaceFacts.tailwindVersion : null,
|
|
37332
|
+
zodVersion: shouldUseZodFallback ? zodCatalogVersion ?? rootInfo.zodVersion ?? workspaceFacts.zodVersion : null,
|
|
37333
|
+
framework: rootInfo.framework !== "unknown" ? rootInfo.framework : workspaceFacts.framework
|
|
36959
37334
|
};
|
|
36960
37335
|
};
|
|
36961
37336
|
/**
|
|
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
37337
|
* Last-resort React detection: locate React the way Node's `node_modules`
|
|
36986
37338
|
* resolution would from `directory` — check each `node_modules/react` up the
|
|
36987
37339
|
* tree — but bounded to the enclosing repo so a globally installed React can't
|
|
@@ -37026,295 +37378,6 @@ const resolveInstalledReactVersion = (directory) => {
|
|
|
37026
37378
|
}
|
|
37027
37379
|
return null;
|
|
37028
37380
|
};
|
|
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
37381
|
const toReactWorkspacePackages = (directories) => {
|
|
37319
37382
|
const packages = [];
|
|
37320
37383
|
for (const directory of directories) {
|
|
@@ -37384,14 +37447,13 @@ const discoverReactSubprojects = (rootDirectory) => {
|
|
|
37384
37447
|
const cachedProjectInfos = /* @__PURE__ */ new Map();
|
|
37385
37448
|
/**
|
|
37386
37449
|
* 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).
|
|
37450
|
+
* its own — a monorepo subfolder like `repo/packages`, or any loose tree
|
|
37451
|
+
* of TypeScript/JavaScript files. Dependency + framework detection is
|
|
37452
|
+
* inherited from the enclosing workspace root when there is one, so
|
|
37453
|
+
* scanning a subdirectory of a React monorepo still gets the React
|
|
37454
|
+
* capabilities; a standalone non-React directory simply scans with the
|
|
37455
|
+
* framework-agnostic rules. Throws only when the directory has nothing
|
|
37456
|
+
* to scan (no enclosing project and no source files of its own).
|
|
37395
37457
|
*/
|
|
37396
37458
|
const discoverProjectWithoutPackageJson = (directory) => {
|
|
37397
37459
|
const sourceFileCount = countSourceFiles(directory);
|
|
@@ -37429,6 +37491,7 @@ const discoverProjectWithoutPackageJson = (directory) => {
|
|
|
37429
37491
|
hasReanimated: false,
|
|
37430
37492
|
reanimatedVersion: null,
|
|
37431
37493
|
isPreES2023Target: hasOwnTsConfig && detectPreES2023Target(directory),
|
|
37494
|
+
isStaticExport: false,
|
|
37432
37495
|
sourceFileCount
|
|
37433
37496
|
};
|
|
37434
37497
|
};
|
|
@@ -37442,90 +37505,85 @@ const discoverProject = (directory) => {
|
|
|
37442
37505
|
return synthesized;
|
|
37443
37506
|
}
|
|
37444
37507
|
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({
|
|
37508
|
+
const rootInfo = extractDependencyInfo(packageJson);
|
|
37509
|
+
let framework = rootInfo.framework;
|
|
37510
|
+
const tracked = {
|
|
37511
|
+
react: {
|
|
37512
|
+
version: rootInfo.reactVersion,
|
|
37513
|
+
sections: REACT_SECTIONS
|
|
37514
|
+
},
|
|
37515
|
+
tailwindcss: {
|
|
37516
|
+
version: rootInfo.tailwindVersion,
|
|
37517
|
+
sections: TAILWIND_ZOD_SECTIONS
|
|
37518
|
+
},
|
|
37519
|
+
zod: {
|
|
37520
|
+
version: rootInfo.zodVersion,
|
|
37521
|
+
sections: TAILWIND_ZOD_SECTIONS
|
|
37522
|
+
}
|
|
37523
|
+
};
|
|
37524
|
+
const declarations = Object.fromEntries(Object.entries(tracked).map(([packageName, entry]) => [packageName, getDependencyDeclaration({
|
|
37465
37525
|
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) {
|
|
37526
|
+
packageName,
|
|
37527
|
+
sections: entry.sections
|
|
37528
|
+
})]));
|
|
37529
|
+
const fillFromCatalogs = (source, sourceDirectory) => {
|
|
37530
|
+
for (const [packageName, entry] of Object.entries(tracked)) if (!entry.version && declarations[packageName].hasDeclaration) entry.version = resolveCatalogVersion(source, packageName, sourceDirectory, declarations[packageName].catalogReference);
|
|
37531
|
+
};
|
|
37532
|
+
fillFromCatalogs(packageJson, directory);
|
|
37533
|
+
if (!tracked.react.version || !tracked.tailwindcss.version || !tracked.zod.version) {
|
|
37477
37534
|
const monorepoRoot = findMonorepoRoot(directory);
|
|
37478
37535
|
if (monorepoRoot) {
|
|
37479
37536
|
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
|
-
}
|
|
37537
|
+
if (isFile(monorepoPackageJsonPath)) fillFromCatalogs(readPackageJson$1(monorepoPackageJsonPath), monorepoRoot);
|
|
37486
37538
|
}
|
|
37487
37539
|
}
|
|
37488
|
-
|
|
37489
|
-
|
|
37490
|
-
|
|
37491
|
-
|
|
37492
|
-
|
|
37493
|
-
|
|
37540
|
+
const shouldCollectReactGroup = !tracked.react.version || framework === "unknown";
|
|
37541
|
+
const workspaceFacts = collectWorkspaceFacts(directory, packageJson, { collectReactGroup: shouldCollectReactGroup });
|
|
37542
|
+
if (shouldCollectReactGroup) {
|
|
37543
|
+
tracked.react.version ||= workspaceFacts.reactVersion;
|
|
37544
|
+
tracked.tailwindcss.version ||= workspaceFacts.tailwindVersion;
|
|
37545
|
+
tracked.zod.version ||= workspaceFacts.zodVersion;
|
|
37546
|
+
if (framework === "unknown" && workspaceFacts.framework !== "unknown") framework = workspaceFacts.framework;
|
|
37494
37547
|
}
|
|
37495
|
-
if ((!
|
|
37548
|
+
if ((!tracked.react.version || framework === "unknown") && !isMonorepoRoot(directory)) {
|
|
37496
37549
|
const monorepoInfo = findDependencyInfoFromMonorepoRoot(directory);
|
|
37497
|
-
|
|
37498
|
-
|
|
37499
|
-
|
|
37550
|
+
tracked.react.version ||= monorepoInfo.reactVersion;
|
|
37551
|
+
tracked.tailwindcss.version ||= monorepoInfo.tailwindVersion;
|
|
37552
|
+
tracked.zod.version ||= monorepoInfo.zodVersion;
|
|
37500
37553
|
if (framework === "unknown") framework = monorepoInfo.framework;
|
|
37501
37554
|
}
|
|
37502
|
-
|
|
37503
|
-
|
|
37504
|
-
|
|
37555
|
+
for (const [packageName, entry] of Object.entries(tracked)) {
|
|
37556
|
+
const declaredVersion = declarations[packageName].version;
|
|
37557
|
+
if (!entry.version && declaredVersion && !isCatalogReference(declaredVersion)) entry.version = declaredVersion;
|
|
37558
|
+
}
|
|
37559
|
+
const { react, tailwindcss, zod } = tracked;
|
|
37560
|
+
let reactVersion = react.version;
|
|
37505
37561
|
if (!reactVersion || parseReactMajor(reactVersion) === null) reactVersion = resolveInstalledReactVersion(directory) ?? reactVersion;
|
|
37562
|
+
const tailwindVersion = tailwindcss.version;
|
|
37563
|
+
const zodVersion = zod.version;
|
|
37506
37564
|
const projectName = packageJson.name ?? Path.basename(directory);
|
|
37507
37565
|
const hasTypeScript = NFS.existsSync(Path.join(directory, "tsconfig.json"));
|
|
37508
37566
|
const sourceFileCount = countSourceFiles(directory);
|
|
37509
|
-
const hasReactNativeWorkspace = framework === "expo" || framework === "react-native" ||
|
|
37567
|
+
const hasReactNativeWorkspace = framework === "expo" || framework === "react-native" || workspaceFacts.hasReactNativeAwarePackage;
|
|
37510
37568
|
const expoVersion = hasReactNativeWorkspace ? resolveCatalogBackedDependencyVersion({
|
|
37511
37569
|
rootDirectory: directory,
|
|
37512
37570
|
rootPackageJson: packageJson,
|
|
37513
37571
|
packageName: "expo",
|
|
37514
|
-
version:
|
|
37572
|
+
version: workspaceFacts.expo.version
|
|
37515
37573
|
}) : null;
|
|
37516
37574
|
const shopifyFlashListVersion = hasReactNativeWorkspace ? resolveCatalogBackedDependencyVersion({
|
|
37517
37575
|
rootDirectory: directory,
|
|
37518
37576
|
rootPackageJson: packageJson,
|
|
37519
37577
|
packageName: SHOPIFY_FLASH_LIST_PACKAGE_NAME,
|
|
37520
|
-
version:
|
|
37578
|
+
version: workspaceFacts.shopifyFlashList.version
|
|
37521
37579
|
}) : null;
|
|
37522
|
-
const hasReanimated = hasReactNativeWorkspace &&
|
|
37523
|
-
const reanimatedVersion = hasReanimated ?
|
|
37580
|
+
const hasReanimated = hasReactNativeWorkspace && workspaceFacts.hasReanimatedAwarePackage;
|
|
37581
|
+
const reanimatedVersion = hasReanimated ? workspaceFacts.reanimatedVersion : null;
|
|
37524
37582
|
const nextjsVersion = framework === "nextjs" ? resolveCatalogBackedDependencyVersion({
|
|
37525
37583
|
rootDirectory: directory,
|
|
37526
37584
|
rootPackageJson: packageJson,
|
|
37527
37585
|
packageName: "next",
|
|
37528
|
-
version:
|
|
37586
|
+
version: workspaceFacts.next.version
|
|
37529
37587
|
}) : null;
|
|
37530
37588
|
const preactVersion = getPreactVersion(packageJson);
|
|
37531
37589
|
const isPreES2023Target = hasTypeScript && detectPreES2023Target(directory);
|
|
@@ -37536,7 +37594,7 @@ const discoverProject = (directory) => {
|
|
|
37536
37594
|
reactMajorVersion: resolveEffectiveReactMajor(reactVersion, packageJson),
|
|
37537
37595
|
tailwindVersion,
|
|
37538
37596
|
zodVersion,
|
|
37539
|
-
zodMajorVersion:
|
|
37597
|
+
zodMajorVersion: zodVersion === null ? null : getLowestDependencyMajor(zodVersion),
|
|
37540
37598
|
framework,
|
|
37541
37599
|
hasTypeScript,
|
|
37542
37600
|
hasReactCompiler: detectReactCompiler(directory, packageJson),
|
|
@@ -37552,6 +37610,7 @@ const discoverProject = (directory) => {
|
|
|
37552
37610
|
hasReanimated,
|
|
37553
37611
|
reanimatedVersion,
|
|
37554
37612
|
isPreES2023Target,
|
|
37613
|
+
isStaticExport: framework === "nextjs" && detectNextjsStaticExport(workspaceFacts.next.sourceDirectory ?? directory),
|
|
37555
37614
|
sourceFileCount
|
|
37556
37615
|
};
|
|
37557
37616
|
cachedProjectInfos.set(directory, projectInfo);
|
|
@@ -37567,57 +37626,6 @@ const discoverProject = (directory) => {
|
|
|
37567
37626
|
* single source file has nothing to analyze.
|
|
37568
37627
|
*/
|
|
37569
37628
|
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
37629
|
const messageFromUnknown = (error) => error instanceof Error ? error.message : String(error);
|
|
37622
37630
|
var InvalidGlobPatternError = class extends Error {
|
|
37623
37631
|
pattern;
|
|
@@ -40428,64 +40436,64 @@ function* collectSecurityScanFiles(rootDirectory) {
|
|
|
40428
40436
|
}
|
|
40429
40437
|
}
|
|
40430
40438
|
}
|
|
40431
|
-
|
|
40432
|
-
|
|
40433
|
-
|
|
40434
|
-
|
|
40435
|
-
|
|
40436
|
-
|
|
40437
|
-
|
|
40439
|
+
const CLIENT_ONLY_FRAMEWORKS = new Set([
|
|
40440
|
+
"vite",
|
|
40441
|
+
"cra",
|
|
40442
|
+
"gatsby",
|
|
40443
|
+
"react-native",
|
|
40444
|
+
"expo"
|
|
40445
|
+
]);
|
|
40446
|
+
const addMajorLadder = (capabilities, name, major, earliest, latest) => {
|
|
40447
|
+
if (major === null) return;
|
|
40448
|
+
const cappedMajor = Math.min(major, latest);
|
|
40449
|
+
for (let candidate = earliest; candidate <= cappedMajor; candidate += 1) capabilities.add(`${name}:${candidate}`);
|
|
40450
|
+
};
|
|
40438
40451
|
const buildCapabilities = (project) => {
|
|
40439
40452
|
const capabilities = /* @__PURE__ */ new Set();
|
|
40440
40453
|
capabilities.add(project.framework);
|
|
40441
|
-
if (
|
|
40454
|
+
if (project.reactVersion !== null || project.preactVersion !== null) capabilities.add("react");
|
|
40442
40455
|
if (project.framework === "expo" || project.framework === "react-native" || project.hasReactNativeWorkspace) capabilities.add("react-native");
|
|
40443
40456
|
if (project.expoVersion !== null) capabilities.add("expo");
|
|
40457
|
+
if ((project.framework === "nextjs" || project.framework === "tanstack-start" || project.framework === "remix") && !project.isStaticExport) capabilities.add("server-actions");
|
|
40458
|
+
if (CLIENT_ONLY_FRAMEWORKS.has(project.framework)) capabilities.add("client-only");
|
|
40459
|
+
if (project.isStaticExport) capabilities.add("nextjs:static-export");
|
|
40444
40460
|
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
|
-
}
|
|
40461
|
+
addMajorLadder(capabilities, "react", project.reactMajorVersion, 17, 30);
|
|
40462
|
+
if (project.reactMajorVersion !== null && project.reactMajorVersion >= 19 && isMajorMinorAtLeast(parseReactMajorMinor(project.reactVersion), {
|
|
40463
|
+
major: 19,
|
|
40464
|
+
minor: 2
|
|
40465
|
+
})) capabilities.add("react:19.2");
|
|
40466
|
+
if (project.tailwindVersion !== null) capabilities.add("tailwind");
|
|
40467
|
+
if (project.tailwindVersion !== null && isMajorMinorAtLeast(parseTailwindMajorMinor(project.tailwindVersion), {
|
|
40468
|
+
major: 3,
|
|
40469
|
+
minor: 4
|
|
40470
|
+
})) capabilities.add("tailwind:3.4");
|
|
40471
|
+
if (project.zodVersion !== null) capabilities.add("zod");
|
|
40472
|
+
if (project.zodMajorVersion !== null && project.zodMajorVersion >= 4) capabilities.add("zod:4");
|
|
40467
40473
|
if (project.isPreES2023Target) capabilities.add("pre-es2023");
|
|
40468
40474
|
if (project.hasReactCompiler) capabilities.add("react-compiler");
|
|
40469
40475
|
if (project.hasTanStackQuery) capabilities.add("tanstack-query");
|
|
40470
40476
|
if (project.hasTypeScript) capabilities.add("typescript");
|
|
40471
|
-
if (project.preactVersion !== null)
|
|
40472
|
-
|
|
40473
|
-
|
|
40474
|
-
|
|
40475
|
-
|
|
40476
|
-
|
|
40477
|
-
|
|
40478
|
-
|
|
40479
|
-
|
|
40477
|
+
if (project.preactVersion !== null) capabilities.add("preact");
|
|
40478
|
+
addMajorLadder(capabilities, "preact", project.preactMajorVersion, 10, 20);
|
|
40479
|
+
if (project.preactVersion !== null && project.reactVersion === null) capabilities.add("pure-preact");
|
|
40480
|
+
return capabilities;
|
|
40481
|
+
};
|
|
40482
|
+
const capabilitiesByProject = /* @__PURE__ */ new WeakMap();
|
|
40483
|
+
const getCapabilities = (project) => {
|
|
40484
|
+
const cached = capabilitiesByProject.get(project);
|
|
40485
|
+
if (cached !== void 0) return cached;
|
|
40486
|
+
const capabilities = buildCapabilities(project);
|
|
40487
|
+
capabilitiesByProject.set(project, capabilities);
|
|
40480
40488
|
return capabilities;
|
|
40481
40489
|
};
|
|
40482
|
-
const shouldEnableRule = (requires, tags, capabilities, ignoredTags,
|
|
40490
|
+
const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen) => {
|
|
40483
40491
|
if (requires) {
|
|
40484
40492
|
for (const capability of requires) if (!capabilities.has(capability)) return false;
|
|
40485
40493
|
}
|
|
40486
40494
|
if (tags?.includes("react-jsx-only") && !capabilities.has("react")) return false;
|
|
40487
|
-
if (
|
|
40488
|
-
for (const capability of
|
|
40495
|
+
if (disabledWhen) {
|
|
40496
|
+
for (const capability of disabledWhen) if (capabilities.has(capability)) return false;
|
|
40489
40497
|
}
|
|
40490
40498
|
if (tags) {
|
|
40491
40499
|
for (const tag of tags) if (ignoredTags.has(tag)) return false;
|
|
@@ -40496,14 +40504,14 @@ const yieldToEventLoop = () => new Promise((resolve) => {
|
|
|
40496
40504
|
setImmediate(resolve);
|
|
40497
40505
|
});
|
|
40498
40506
|
const createSecurityScanSession = (rootDirectory, options) => {
|
|
40499
|
-
const capabilities = options.project ?
|
|
40507
|
+
const capabilities = options.project ? getCapabilities(options.project) : /* @__PURE__ */ new Set();
|
|
40500
40508
|
const ignoredTags = options.ignoredTags ?? /* @__PURE__ */ new Set();
|
|
40501
40509
|
const enabledScanRules = REACT_DOCTOR_RULES.flatMap((entry) => {
|
|
40502
40510
|
const rule = entry.rule;
|
|
40503
40511
|
const scan = rule.scan;
|
|
40504
40512
|
if (typeof scan !== "function") return [];
|
|
40505
40513
|
if (rule.defaultEnabled === false) return [];
|
|
40506
|
-
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.
|
|
40514
|
+
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) return [];
|
|
40507
40515
|
return [{
|
|
40508
40516
|
entry,
|
|
40509
40517
|
scan,
|
|
@@ -40523,6 +40531,7 @@ const createSecurityScanSession = (rootDirectory, options) => {
|
|
|
40523
40531
|
return status === true;
|
|
40524
40532
|
};
|
|
40525
40533
|
const scanFileByRule = function* (file) {
|
|
40534
|
+
if (file === null) return;
|
|
40526
40535
|
for (const { entry, scan, committedFilesOnly } of enabledScanRules) {
|
|
40527
40536
|
for (const finding of scan(file)) {
|
|
40528
40537
|
if (committedFilesOnly && isFileGitIgnored(file)) continue;
|
|
@@ -42419,7 +42428,7 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
42419
42428
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
42420
42429
|
const jsPlugins = [];
|
|
42421
42430
|
if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
|
|
42422
|
-
const capabilities =
|
|
42431
|
+
const capabilities = getCapabilities(project);
|
|
42423
42432
|
const enabledReactDoctorRules = {};
|
|
42424
42433
|
for (const registryEntry of REACT_DOCTOR_RULES) {
|
|
42425
42434
|
const rule = reactDoctorPlugin.rules[registryEntry.id];
|
|
@@ -42430,7 +42439,7 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
42430
42439
|
if (rule.scan !== void 0) continue;
|
|
42431
42440
|
if (customRulesOnly && registryEntry.originallyExternal) continue;
|
|
42432
42441
|
if (rule.framework !== "global" && !rule.requires) continue;
|
|
42433
|
-
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.
|
|
42442
|
+
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) continue;
|
|
42434
42443
|
const explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey: registryEntry.key }, severityControls);
|
|
42435
42444
|
if (rule.defaultEnabled === false && explicitRuleOverride === void 0) continue;
|
|
42436
42445
|
const severity = resolveRuleSeverityOverride({
|
|
@@ -42461,6 +42470,7 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
42461
42470
|
settings: { "react-doctor": {
|
|
42462
42471
|
framework: project.framework,
|
|
42463
42472
|
rootDirectory: resolveSettingsRootDirectory(project.rootDirectory),
|
|
42473
|
+
capabilities: [...capabilities].sort(),
|
|
42464
42474
|
...project.shopifyFlashListMajorVersion !== null ? { shopifyFlashListMajorVersion: project.shopifyFlashListMajorVersion } : {},
|
|
42465
42475
|
...serverAuthFunctionNames && serverAuthFunctionNames.length > 0 ? { serverAuthFunctionNames: [...serverAuthFunctionNames] } : {}
|
|
42466
42476
|
} },
|
|
@@ -42751,21 +42761,6 @@ const mapWithConcurrency = async (items, concurrency, task) => {
|
|
|
42751
42761
|
if (errors.length > 0) throw errors[0];
|
|
42752
42762
|
return results;
|
|
42753
42763
|
};
|
|
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
42764
|
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
42765
|
const ACCESSORS_MIN_VERSION = "3.15.0";
|
|
42771
42766
|
const supportsAccessors = (reanimatedVersion) => {
|
|
@@ -43446,8 +43441,14 @@ const PLUGIN_CATEGORY_MAP = {
|
|
|
43446
43441
|
};
|
|
43447
43442
|
const lookupOwnString = (record, key) => Object.hasOwn(record, key) ? record[key] : void 0;
|
|
43448
43443
|
const getRuleRecommendation = (ruleName, project) => {
|
|
43449
|
-
|
|
43450
|
-
return
|
|
43444
|
+
const rule = reactDoctorPlugin.rules[ruleName];
|
|
43445
|
+
if (!rule) return void 0;
|
|
43446
|
+
if (rule.recommendationFor) {
|
|
43447
|
+
const capabilities = getCapabilities(project);
|
|
43448
|
+
const conditionalRecommendation = rule.recommendationFor((capability) => capabilities.has(capability));
|
|
43449
|
+
if (conditionalRecommendation !== void 0) return conditionalRecommendation;
|
|
43450
|
+
}
|
|
43451
|
+
return rule.recommendation;
|
|
43451
43452
|
};
|
|
43452
43453
|
const getRuleCategory = (ruleName) => reactDoctorPlugin.rules[ruleName]?.category;
|
|
43453
43454
|
const getRuleTitle = (ruleName) => reactDoctorPlugin.rules[ruleName]?.title;
|
|
@@ -45796,6 +45797,13 @@ const summarizeDiagnostics = (diagnostics, worstScore = null, worstScoreLabel =
|
|
|
45796
45797
|
scoreLabel: worstScoreLabel
|
|
45797
45798
|
};
|
|
45798
45799
|
};
|
|
45800
|
+
/**
|
|
45801
|
+
* Whether project discovery resolved a React-compatible runtime (React or
|
|
45802
|
+
* Preact, which ships the same hooks + JSX model). This is the same
|
|
45803
|
+
* predicate that grants the `react` capability, so `false` means every
|
|
45804
|
+
* React-runtime rule family was gated off for the project.
|
|
45805
|
+
*/
|
|
45806
|
+
const hasReactRuntime = (project) => project.reactVersion !== null || project.preactVersion !== null;
|
|
45799
45807
|
const toJsonDiff = (diff) => {
|
|
45800
45808
|
if (!diff) return null;
|
|
45801
45809
|
return {
|
|
@@ -46378,7 +46386,7 @@ const makeNoopConsole = () => ({
|
|
|
46378
46386
|
});
|
|
46379
46387
|
//#endregion
|
|
46380
46388
|
//#region src/cli/utils/version.ts
|
|
46381
|
-
const VERSION = "0.7.2-dev.
|
|
46389
|
+
const VERSION = "0.7.2-dev.b97a92f";
|
|
46382
46390
|
//#endregion
|
|
46383
46391
|
//#region src/cli/utils/json-mode.ts
|
|
46384
46392
|
let context = null;
|
|
@@ -46747,13 +46755,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
|
|
|
46747
46755
|
* uploads source-map artifacts under, so stack frames symbolicate. Honors the
|
|
46748
46756
|
* standard `SENTRY_RELEASE` override.
|
|
46749
46757
|
*/
|
|
46750
|
-
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.2-dev.
|
|
46758
|
+
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.2-dev.b97a92f`;
|
|
46751
46759
|
/**
|
|
46752
46760
|
* Deployment environment shown in Sentry's environment filter. Defaults to
|
|
46753
46761
|
* `production` for tagged releases and `development` for dev/unbuilt versions,
|
|
46754
46762
|
* overridable via the standard `SENTRY_ENVIRONMENT` env var.
|
|
46755
46763
|
*/
|
|
46756
|
-
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.2-dev.
|
|
46764
|
+
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.2-dev.b97a92f") ? "development" : "production");
|
|
46757
46765
|
/**
|
|
46758
46766
|
* Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
|
|
46759
46767
|
* (set to `0` to disable tracing) and falls back to
|
|
@@ -64928,4 +64936,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
|
|
|
64928
64936
|
export {};
|
|
64929
64937
|
|
|
64930
64938
|
//# sourceMappingURL=cli.js.map
|
|
64931
|
-
//# debugId=
|
|
64939
|
+
//# debugId=91ba16f6-8b1a-5cd9-a5d2-fc0b6fce2508
|