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/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="7b7e0da8-d676-570d-b0e2-7fc3a4fe85ab")}catch(e){}}();
|
|
3
3
|
import { r as __toESM$1, t as __commonJSMin$1 } from "./chunk-N93fKeF6.js";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import * as NFS from "node:fs";
|
|
@@ -32791,6 +32791,25 @@ var AmbiguousProjectError = class extends Error {
|
|
|
32791
32791
|
}
|
|
32792
32792
|
};
|
|
32793
32793
|
const isProjectDiscoveryError = (value) => value instanceof ProjectNotFoundError || value instanceof NoReactDependencyError || value instanceof PackageJsonNotFoundError || value instanceof NotADirectoryError || value instanceof AmbiguousProjectError;
|
|
32794
|
+
const isErrnoException = (error) => error instanceof Error && "code" in error;
|
|
32795
|
+
const IGNORABLE_READDIR_ERROR_CODES = new Set([
|
|
32796
|
+
"EACCES",
|
|
32797
|
+
"EPERM",
|
|
32798
|
+
"ENOENT",
|
|
32799
|
+
"ENOTDIR",
|
|
32800
|
+
"EINVAL",
|
|
32801
|
+
"ELOOP",
|
|
32802
|
+
"ENAMETOOLONG"
|
|
32803
|
+
]);
|
|
32804
|
+
const isIgnorableReaddirError = (error) => isErrnoException(error) && typeof error.code === "string" && IGNORABLE_READDIR_ERROR_CODES.has(error.code);
|
|
32805
|
+
const readDirectoryEntries = (directoryPath) => {
|
|
32806
|
+
try {
|
|
32807
|
+
return NFS.readdirSync(directoryPath, { withFileTypes: true });
|
|
32808
|
+
} catch (error) {
|
|
32809
|
+
if (isIgnorableReaddirError(error)) return [];
|
|
32810
|
+
throw error;
|
|
32811
|
+
}
|
|
32812
|
+
};
|
|
32794
32813
|
const isFile = (filePath) => {
|
|
32795
32814
|
try {
|
|
32796
32815
|
return NFS.statSync(filePath).isFile();
|
|
@@ -32798,6 +32817,18 @@ const isFile = (filePath) => {
|
|
|
32798
32817
|
return false;
|
|
32799
32818
|
}
|
|
32800
32819
|
};
|
|
32820
|
+
const isDirectory = (directoryPath) => {
|
|
32821
|
+
try {
|
|
32822
|
+
return NFS.statSync(directoryPath).isDirectory();
|
|
32823
|
+
} catch {
|
|
32824
|
+
return false;
|
|
32825
|
+
}
|
|
32826
|
+
};
|
|
32827
|
+
const isPlainObject = (value) => {
|
|
32828
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
32829
|
+
const prototype = Object.getPrototypeOf(value);
|
|
32830
|
+
return prototype === null || prototype === Object.prototype;
|
|
32831
|
+
};
|
|
32801
32832
|
const SOURCE_FILE_PATTERN = /\.(tsx?|jsx?|mts|mjs)$/;
|
|
32802
32833
|
const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
|
|
32803
32834
|
const GENERATED_SOURCE_DIRECTORY_PATTERN = /(?:^|\/)__generated__\//;
|
|
@@ -32994,25 +33025,6 @@ const isLargeMinifiedFile = (absolutePath, knownSizeBytes) => {
|
|
|
32994
33025
|
cachedIsLargeMinifiedByPath.set(absolutePath, result);
|
|
32995
33026
|
return result;
|
|
32996
33027
|
};
|
|
32997
|
-
const isErrnoException = (error) => error instanceof Error && "code" in error;
|
|
32998
|
-
const IGNORABLE_READDIR_ERROR_CODES = new Set([
|
|
32999
|
-
"EACCES",
|
|
33000
|
-
"EPERM",
|
|
33001
|
-
"ENOENT",
|
|
33002
|
-
"ENOTDIR",
|
|
33003
|
-
"EINVAL",
|
|
33004
|
-
"ELOOP",
|
|
33005
|
-
"ENAMETOOLONG"
|
|
33006
|
-
]);
|
|
33007
|
-
const isIgnorableReaddirError = (error) => isErrnoException(error) && typeof error.code === "string" && IGNORABLE_READDIR_ERROR_CODES.has(error.code);
|
|
33008
|
-
const readDirectoryEntries = (directoryPath) => {
|
|
33009
|
-
try {
|
|
33010
|
-
return NFS.readdirSync(directoryPath, { withFileTypes: true });
|
|
33011
|
-
} catch (error) {
|
|
33012
|
-
if (isIgnorableReaddirError(error)) return [];
|
|
33013
|
-
throw error;
|
|
33014
|
-
}
|
|
33015
|
-
};
|
|
33016
33028
|
function* walkSourceTreeFiles(rootDirectory) {
|
|
33017
33029
|
const stack = [rootDirectory];
|
|
33018
33030
|
while (stack.length > 0) {
|
|
@@ -33067,23 +33079,6 @@ const listSourceFilesViaFilesystem = (rootDirectory) => {
|
|
|
33067
33079
|
const listSourceFilesWithSize = (rootDirectory) => collectSizedSourceFiles(rootDirectory, (listSourceFilesViaGit(rootDirectory) ?? listSourceFilesViaFilesystem(rootDirectory)).sort());
|
|
33068
33080
|
const listSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).map((entry) => entry.path);
|
|
33069
33081
|
const countSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).length;
|
|
33070
|
-
/**
|
|
33071
|
-
* The chain of ancestor directories of `startDirectory`, nearest first, up to
|
|
33072
|
-
* and including the filesystem root. With `includeStart`, the chain begins at
|
|
33073
|
-
* `startDirectory` itself; otherwise at its parent. The one place the "walk up
|
|
33074
|
-
* the tree" traversal is expressed, so each caller adds only its own match /
|
|
33075
|
-
* stop policy instead of re-deriving the `path.dirname` loop.
|
|
33076
|
-
*/
|
|
33077
|
-
const ancestorDirectories = (startDirectory, { includeStart }) => {
|
|
33078
|
-
const directories = [];
|
|
33079
|
-
let currentDirectory = includeStart ? startDirectory : Path.dirname(startDirectory);
|
|
33080
|
-
while (true) {
|
|
33081
|
-
directories.push(currentDirectory);
|
|
33082
|
-
const parentDirectory = Path.dirname(currentDirectory);
|
|
33083
|
-
if (parentDirectory === currentDirectory) return directories;
|
|
33084
|
-
currentDirectory = parentDirectory;
|
|
33085
|
-
}
|
|
33086
|
-
};
|
|
33087
33082
|
const cachedPackageJsons = /* @__PURE__ */ new Map();
|
|
33088
33083
|
const clearPackageJsonCache = () => {
|
|
33089
33084
|
cachedPackageJsons.clear();
|
|
@@ -33117,7 +33112,11 @@ const isMonorepoRoot = (directory) => {
|
|
|
33117
33112
|
return Array.isArray(packageJson.workspaces) || Boolean(packageJson.workspaces?.packages);
|
|
33118
33113
|
};
|
|
33119
33114
|
const findMonorepoRoot = (startDirectory) => {
|
|
33120
|
-
|
|
33115
|
+
let currentDirectory = Path.dirname(startDirectory);
|
|
33116
|
+
while (currentDirectory !== Path.dirname(currentDirectory)) {
|
|
33117
|
+
if (isMonorepoRoot(currentDirectory)) return currentDirectory;
|
|
33118
|
+
currentDirectory = Path.dirname(currentDirectory);
|
|
33119
|
+
}
|
|
33121
33120
|
return null;
|
|
33122
33121
|
};
|
|
33123
33122
|
/**
|
|
@@ -33131,6 +33130,146 @@ const findMonorepoRoot = (startDirectory) => {
|
|
|
33131
33130
|
* byte-equivalent copy.
|
|
33132
33131
|
*/
|
|
33133
33132
|
const isProjectBoundary = (directory) => NFS.existsSync(Path.join(directory, ".git")) || isMonorepoRoot(directory);
|
|
33133
|
+
const TSCONFIG_FILENAME = "tsconfig.json";
|
|
33134
|
+
const isRelativeExtendsValue = (extendsValue) => extendsValue.startsWith("./") || extendsValue.startsWith("../") || Path.isAbsolute(extendsValue);
|
|
33135
|
+
const ensureJsonExtension = (filePath) => Path.extname(filePath) === "" ? `${filePath}.json` : filePath;
|
|
33136
|
+
const resolvePackageExtendsPath = (extendsValue, fromConfigDirectory) => {
|
|
33137
|
+
const requireFromConfig = createRequire(Path.join(fromConfigDirectory, "tsconfig.json"));
|
|
33138
|
+
const candidates = [
|
|
33139
|
+
extendsValue,
|
|
33140
|
+
ensureJsonExtension(extendsValue),
|
|
33141
|
+
`${extendsValue.replace(/\/$/, "")}/tsconfig.json`
|
|
33142
|
+
];
|
|
33143
|
+
for (const candidate of candidates) try {
|
|
33144
|
+
return requireFromConfig.resolve(candidate);
|
|
33145
|
+
} catch {
|
|
33146
|
+
continue;
|
|
33147
|
+
}
|
|
33148
|
+
return null;
|
|
33149
|
+
};
|
|
33150
|
+
const resolveExtendsPath = (extendsValue, fromConfigDirectory) => {
|
|
33151
|
+
if (isRelativeExtendsValue(extendsValue)) return ensureJsonExtension(Path.resolve(fromConfigDirectory, extendsValue));
|
|
33152
|
+
return resolvePackageExtendsPath(extendsValue, fromConfigDirectory);
|
|
33153
|
+
};
|
|
33154
|
+
const normalizeCompilerOptions = (compilerOptions) => {
|
|
33155
|
+
if (!isPlainObject(compilerOptions)) return { hasExplicitLib: false };
|
|
33156
|
+
const target = typeof compilerOptions.target === "string" ? compilerOptions.target : void 0;
|
|
33157
|
+
const hasExplicitLib = Object.hasOwn(compilerOptions, "lib");
|
|
33158
|
+
return {
|
|
33159
|
+
target,
|
|
33160
|
+
lib: Array.isArray(compilerOptions.lib) ? compilerOptions.lib.filter((entry) => typeof entry === "string") : void 0,
|
|
33161
|
+
hasExplicitLib
|
|
33162
|
+
};
|
|
33163
|
+
};
|
|
33164
|
+
const readTsConfig = (filePath) => {
|
|
33165
|
+
let content;
|
|
33166
|
+
try {
|
|
33167
|
+
content = NFS.readFileSync(filePath, "utf-8");
|
|
33168
|
+
} catch {
|
|
33169
|
+
return null;
|
|
33170
|
+
}
|
|
33171
|
+
const parsed = ts.parseConfigFileTextToJson(filePath, content);
|
|
33172
|
+
if (!isPlainObject(parsed.config)) return null;
|
|
33173
|
+
return {
|
|
33174
|
+
extends: typeof parsed.config.extends === "string" ? parsed.config.extends : void 0,
|
|
33175
|
+
referencePaths: normalizeReferencePaths(parsed.config.references),
|
|
33176
|
+
compilerOptions: normalizeCompilerOptions(parsed.config.compilerOptions)
|
|
33177
|
+
};
|
|
33178
|
+
};
|
|
33179
|
+
const normalizeReferencePaths = (references) => {
|
|
33180
|
+
if (!Array.isArray(references)) return [];
|
|
33181
|
+
return references.map((reference) => isPlainObject(reference) && typeof reference.path === "string" ? reference.path : null).filter((referencePath) => referencePath !== null);
|
|
33182
|
+
};
|
|
33183
|
+
const mergeCompilerOptions = (inherited, current) => {
|
|
33184
|
+
const target = current.target ?? inherited?.target;
|
|
33185
|
+
const hasExplicitLib = current.hasExplicitLib || Boolean(inherited?.hasExplicitLib);
|
|
33186
|
+
return {
|
|
33187
|
+
target,
|
|
33188
|
+
lib: current.hasExplicitLib ? current.lib : inherited?.lib,
|
|
33189
|
+
hasExplicitLib
|
|
33190
|
+
};
|
|
33191
|
+
};
|
|
33192
|
+
const readResolvedCompilerOptions = (tsConfigPath, extendsDepth, visitedPaths) => {
|
|
33193
|
+
const realPath = NFS.realpathSync.native(tsConfigPath);
|
|
33194
|
+
if (visitedPaths.has(realPath)) return null;
|
|
33195
|
+
const tsConfig = readTsConfig(realPath);
|
|
33196
|
+
if (!tsConfig) return null;
|
|
33197
|
+
const nextVisitedPaths = new Set(visitedPaths);
|
|
33198
|
+
nextVisitedPaths.add(realPath);
|
|
33199
|
+
if (tsConfig.extends && extendsDepth < 8) {
|
|
33200
|
+
const parentPath = resolveExtendsPath(tsConfig.extends, Path.dirname(realPath));
|
|
33201
|
+
if (parentPath && isFile(parentPath)) return mergeCompilerOptions(readResolvedCompilerOptions(parentPath, extendsDepth + 1, nextVisitedPaths), tsConfig.compilerOptions);
|
|
33202
|
+
}
|
|
33203
|
+
return tsConfig.compilerOptions;
|
|
33204
|
+
};
|
|
33205
|
+
const targetYearIsPreES2023 = (target) => {
|
|
33206
|
+
const year = ES_TARGET_YEAR_BY_NAME[target.toLowerCase()];
|
|
33207
|
+
return year !== void 0 && year < 2023;
|
|
33208
|
+
};
|
|
33209
|
+
const libEntryIncludesES2023Array = (entry) => {
|
|
33210
|
+
const normalizedEntry = entry.toLowerCase();
|
|
33211
|
+
if (normalizedEntry === "esnext" || normalizedEntry === "esnext.array") return true;
|
|
33212
|
+
const esYearMatch = /^es(\d{4})(?:\.(.+))?$/.exec(normalizedEntry);
|
|
33213
|
+
if (!esYearMatch) return false;
|
|
33214
|
+
if (Number(esYearMatch[1]) < 2023) return false;
|
|
33215
|
+
const component = esYearMatch[2];
|
|
33216
|
+
return component === void 0 || component === "array";
|
|
33217
|
+
};
|
|
33218
|
+
const libIncludesES2023 = (lib) => lib.some(libEntryIncludesES2023Array);
|
|
33219
|
+
const compilerOptionsArePreES2023 = (compilerOptions) => {
|
|
33220
|
+
if (compilerOptions.target) return targetYearIsPreES2023(compilerOptions.target);
|
|
33221
|
+
if (compilerOptions.hasExplicitLib) return !libIncludesES2023(compilerOptions.lib ?? []);
|
|
33222
|
+
return false;
|
|
33223
|
+
};
|
|
33224
|
+
const compilerOptionsDeclareTargetOrLib = (compilerOptions) => compilerOptions.hasExplicitLib || compilerOptions.target !== void 0;
|
|
33225
|
+
const detectPreES2023FromConfig = (tsConfigPath, visitedConfigPaths = /* @__PURE__ */ new Set()) => {
|
|
33226
|
+
if (visitedConfigPaths.has(tsConfigPath)) return false;
|
|
33227
|
+
const compilerOptions = readResolvedCompilerOptions(tsConfigPath, 0, /* @__PURE__ */ new Set());
|
|
33228
|
+
if (!compilerOptions) return false;
|
|
33229
|
+
if (!compilerOptionsDeclareTargetOrLib(compilerOptions)) {
|
|
33230
|
+
const tsConfig = readTsConfig(tsConfigPath);
|
|
33231
|
+
if (!tsConfig) return false;
|
|
33232
|
+
const nextVisitedConfigPaths = new Set(visitedConfigPaths);
|
|
33233
|
+
nextVisitedConfigPaths.add(tsConfigPath);
|
|
33234
|
+
const configDirectory = Path.dirname(tsConfigPath);
|
|
33235
|
+
return tsConfig.referencePaths.some((referencePath) => {
|
|
33236
|
+
const resolvedReferencePath = Path.resolve(configDirectory, referencePath);
|
|
33237
|
+
const referencedConfigPath = isFile(resolvedReferencePath) ? resolvedReferencePath : Path.join(resolvedReferencePath, TSCONFIG_FILENAME);
|
|
33238
|
+
return isFile(referencedConfigPath) && detectPreES2023FromConfig(referencedConfigPath, nextVisitedConfigPaths);
|
|
33239
|
+
});
|
|
33240
|
+
}
|
|
33241
|
+
return compilerOptionsArePreES2023(compilerOptions);
|
|
33242
|
+
};
|
|
33243
|
+
const detectPreES2023Target = (directory) => {
|
|
33244
|
+
const tsConfigPath = Path.join(directory, TSCONFIG_FILENAME);
|
|
33245
|
+
if (isFile(tsConfigPath)) return detectPreES2023FromConfig(tsConfigPath);
|
|
33246
|
+
for (const fallbackFilename of FALLBACK_TSCONFIG_FILENAMES) {
|
|
33247
|
+
const fallbackPath = Path.join(directory, fallbackFilename);
|
|
33248
|
+
if (isFile(fallbackPath)) return detectPreES2023FromConfig(fallbackPath);
|
|
33249
|
+
}
|
|
33250
|
+
return false;
|
|
33251
|
+
};
|
|
33252
|
+
const FALLBACK_TSCONFIG_FILENAMES = ["tsconfig.app.json", "tsconfig.build.json"];
|
|
33253
|
+
const FRAMEWORK_PACKAGES = {
|
|
33254
|
+
next: "nextjs",
|
|
33255
|
+
"@tanstack/react-start": "tanstack-start",
|
|
33256
|
+
vite: "vite",
|
|
33257
|
+
"react-scripts": "cra",
|
|
33258
|
+
"@remix-run/react": "remix",
|
|
33259
|
+
gatsby: "gatsby",
|
|
33260
|
+
expo: "expo",
|
|
33261
|
+
"react-native": "react-native"
|
|
33262
|
+
};
|
|
33263
|
+
const detectFramework = (dependencies) => {
|
|
33264
|
+
for (const [packageName, frameworkName] of Object.entries(FRAMEWORK_PACKAGES)) if (dependencies[packageName]) return frameworkName;
|
|
33265
|
+
if (dependencies.preact && !dependencies.react) return "preact";
|
|
33266
|
+
return "unknown";
|
|
33267
|
+
};
|
|
33268
|
+
const MOBILE_FRAMEWORKS = new Set(["expo", "react-native"]);
|
|
33269
|
+
const frameworkMergeRank = (framework) => {
|
|
33270
|
+
if (framework === "unknown") return 3;
|
|
33271
|
+
return MOBILE_FRAMEWORKS.has(framework) ? 2 : 1;
|
|
33272
|
+
};
|
|
33134
33273
|
const REACT_COMPILER_PACKAGES = new Set([
|
|
33135
33274
|
"babel-plugin-react-compiler",
|
|
33136
33275
|
"react-compiler-runtime",
|
|
@@ -33167,6 +33306,7 @@ const EXPO_APP_CONFIG_FILENAMES = [
|
|
|
33167
33306
|
];
|
|
33168
33307
|
const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|eslint-plugin-react-compiler|["']react-compiler["']/;
|
|
33169
33308
|
const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
|
|
33309
|
+
const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
|
|
33170
33310
|
const hasCompilerPackage = (packageJson) => {
|
|
33171
33311
|
const allDependencies = {
|
|
33172
33312
|
...packageJson.peerDependencies,
|
|
@@ -33199,34 +33339,10 @@ const detectReactCompiler = (directory, packageJson) => {
|
|
|
33199
33339
|
}
|
|
33200
33340
|
return false;
|
|
33201
33341
|
};
|
|
33202
|
-
const
|
|
33203
|
-
|
|
33204
|
-
|
|
33205
|
-
|
|
33206
|
-
"react-scripts": "cra",
|
|
33207
|
-
"@remix-run/react": "remix",
|
|
33208
|
-
gatsby: "gatsby",
|
|
33209
|
-
expo: "expo",
|
|
33210
|
-
"react-native": "react-native"
|
|
33211
|
-
};
|
|
33212
|
-
const FRAMEWORK_DISPLAY_NAMES = {
|
|
33213
|
-
nextjs: "Next.js",
|
|
33214
|
-
"tanstack-start": "TanStack Start",
|
|
33215
|
-
vite: "Vite",
|
|
33216
|
-
cra: "Create React App",
|
|
33217
|
-
remix: "Remix",
|
|
33218
|
-
gatsby: "Gatsby",
|
|
33219
|
-
expo: "Expo",
|
|
33220
|
-
"react-native": "React Native",
|
|
33221
|
-
preact: "Preact",
|
|
33222
|
-
unknown: "React"
|
|
33223
|
-
};
|
|
33224
|
-
const formatFrameworkName = (framework) => FRAMEWORK_DISPLAY_NAMES[framework];
|
|
33225
|
-
const detectFramework = (dependencies) => {
|
|
33226
|
-
for (const [packageName, frameworkName] of Object.entries(FRAMEWORK_PACKAGES)) if (dependencies[packageName]) return frameworkName;
|
|
33227
|
-
if (dependencies.preact && !dependencies.react) return "preact";
|
|
33228
|
-
return "unknown";
|
|
33229
|
-
};
|
|
33342
|
+
const detectNextjsStaticExport = (directory) => NEXT_CONFIG_FILENAMES.some((filename) => {
|
|
33343
|
+
const filePath = Path.join(directory, filename);
|
|
33344
|
+
return isFile(filePath) && STATIC_EXPORT_OUTPUT_PATTERN.test(NFS.readFileSync(filePath, "utf-8"));
|
|
33345
|
+
});
|
|
33230
33346
|
const UNRESOLVABLE_PROTOCOL_VERSION = /^(?:file|git|github|https?|link|patch|portal|workspace|npm):/i;
|
|
33231
33347
|
const DIST_TAG_VERSION = /^[a-z][a-z0-9._-]*$/i;
|
|
33232
33348
|
const WILDCARD_VERSION = /^[*xX](?:\.[*xX])*$/;
|
|
@@ -33364,10 +33480,76 @@ const isConcreteDependencyVersion = (version) => {
|
|
|
33364
33480
|
const normalizedVersion = normalizeDependencyVersion(version);
|
|
33365
33481
|
return normalizedVersion !== null && /\d/.test(normalizedVersion);
|
|
33366
33482
|
};
|
|
33367
|
-
const
|
|
33368
|
-
if (
|
|
33369
|
-
|
|
33370
|
-
return
|
|
33483
|
+
const isMajorMinorAtLeast = (detected, required) => {
|
|
33484
|
+
if (detected === null) return true;
|
|
33485
|
+
if (detected.major !== required.major) return detected.major > required.major;
|
|
33486
|
+
return detected.minor >= required.minor;
|
|
33487
|
+
};
|
|
33488
|
+
const parseReactMajor = (reactVersion) => {
|
|
33489
|
+
if (typeof reactVersion !== "string") return null;
|
|
33490
|
+
return getLowestDependencyMajor(reactVersion);
|
|
33491
|
+
};
|
|
33492
|
+
const MAJOR_MINOR_PATTERN = /(\d{1,4})\.(\d{1,4})/;
|
|
33493
|
+
const MAJOR_ONLY_PATTERN = /(\d{1,4})/;
|
|
33494
|
+
const UPPER_BOUND_COMPARATOR_PATTERN = /<=?\s{0,8}\d{1,4}(?:\.\d{1,4}){0,2}(?:-[^\s,|]+)?/g;
|
|
33495
|
+
const parseReactMajorMinor = (reactVersion) => {
|
|
33496
|
+
if (typeof reactVersion !== "string") return null;
|
|
33497
|
+
const trimmed = reactVersion.trim();
|
|
33498
|
+
if (trimmed.length === 0) return null;
|
|
33499
|
+
const lowerBoundsOnly = trimmed.replace(UPPER_BOUND_COMPARATOR_PATTERN, " ").trim();
|
|
33500
|
+
if (lowerBoundsOnly.length === 0) return null;
|
|
33501
|
+
const majorMinorMatch = lowerBoundsOnly.match(MAJOR_MINOR_PATTERN);
|
|
33502
|
+
if (majorMinorMatch) {
|
|
33503
|
+
const major = Number.parseInt(majorMinorMatch[1], 10);
|
|
33504
|
+
const minor = Number.parseInt(majorMinorMatch[2], 10);
|
|
33505
|
+
if (!Number.isFinite(major) || major <= 0) return null;
|
|
33506
|
+
if (!Number.isFinite(minor) || minor < 0) return null;
|
|
33507
|
+
return {
|
|
33508
|
+
major,
|
|
33509
|
+
minor
|
|
33510
|
+
};
|
|
33511
|
+
}
|
|
33512
|
+
const majorOnlyMatch = lowerBoundsOnly.match(MAJOR_ONLY_PATTERN);
|
|
33513
|
+
if (!majorOnlyMatch) return null;
|
|
33514
|
+
const major = Number.parseInt(majorOnlyMatch[1], 10);
|
|
33515
|
+
if (!Number.isFinite(major) || major <= 0) return null;
|
|
33516
|
+
return {
|
|
33517
|
+
major,
|
|
33518
|
+
minor: 0
|
|
33519
|
+
};
|
|
33520
|
+
};
|
|
33521
|
+
const parseLowerBoundVersion = (versionSpec) => import_semver.validRange(versionSpec) !== null ? import_semver.minVersion(versionSpec) : import_semver.coerce(versionSpec);
|
|
33522
|
+
const parseTailwindMajorMinor = (tailwindVersion) => {
|
|
33523
|
+
if (typeof tailwindVersion !== "string") return null;
|
|
33524
|
+
const trimmed = tailwindVersion.trim();
|
|
33525
|
+
if (trimmed.length === 0) return null;
|
|
33526
|
+
const lowerBound = parseLowerBoundVersion(trimmed);
|
|
33527
|
+
if (lowerBound === null || lowerBound.major <= 0) return null;
|
|
33528
|
+
return {
|
|
33529
|
+
major: lowerBound.major,
|
|
33530
|
+
minor: lowerBound.minor
|
|
33531
|
+
};
|
|
33532
|
+
};
|
|
33533
|
+
const hasUpperBoundOnlyPeerRange = (range) => {
|
|
33534
|
+
if (typeof range !== "string") return false;
|
|
33535
|
+
const normalizedRange = normalizeDependencyVersion(range);
|
|
33536
|
+
if (normalizedRange === null) return false;
|
|
33537
|
+
return splitDependencyVersionBranches(normalizedRange).some((branch) => {
|
|
33538
|
+
const normalizedBranch = normalizeDependencyVersion(branch);
|
|
33539
|
+
return normalizedBranch !== null && getBranchLowestMajor(normalizedBranch) === null && hasUpperBoundComparator(normalizedBranch);
|
|
33540
|
+
});
|
|
33541
|
+
};
|
|
33542
|
+
const peerRangeMinMajor = (range) => {
|
|
33543
|
+
if (typeof range !== "string") return null;
|
|
33544
|
+
return getLowestDependencyMajor(range);
|
|
33545
|
+
};
|
|
33546
|
+
const resolveEffectiveReactMajor = (reactVersion, packageJson) => {
|
|
33547
|
+
const installedReactMajor = parseReactMajor(reactVersion);
|
|
33548
|
+
const peerReactRange = packageJson.peerDependencies?.react;
|
|
33549
|
+
if (typeof peerReactRange !== "string") return installedReactMajor;
|
|
33550
|
+
const peerFloor = peerRangeMinMajor(peerReactRange);
|
|
33551
|
+
if (peerFloor === null) return hasUpperBoundOnlyPeerRange(peerReactRange) ? null : installedReactMajor;
|
|
33552
|
+
return installedReactMajor !== null ? Math.min(installedReactMajor, peerFloor) : peerFloor;
|
|
33371
33553
|
};
|
|
33372
33554
|
const isCatalogReference = (version) => version.startsWith("catalog:");
|
|
33373
33555
|
const extractCatalogName = (version) => {
|
|
@@ -33509,6 +33691,16 @@ const resolveCatalogVersion = (packageJson, packageName, rootDirectory, explicit
|
|
|
33509
33691
|
}
|
|
33510
33692
|
return null;
|
|
33511
33693
|
};
|
|
33694
|
+
const REACT_SECTIONS = [
|
|
33695
|
+
"dependencies",
|
|
33696
|
+
"peerDependencies",
|
|
33697
|
+
"devDependencies"
|
|
33698
|
+
];
|
|
33699
|
+
const TAILWIND_ZOD_SECTIONS = [
|
|
33700
|
+
"dependencies",
|
|
33701
|
+
"devDependencies",
|
|
33702
|
+
"peerDependencies"
|
|
33703
|
+
];
|
|
33512
33704
|
const EMPTY_DEPENDENCY_INFO = {
|
|
33513
33705
|
reactVersion: null,
|
|
33514
33706
|
tailwindVersion: null,
|
|
@@ -33549,6 +33741,10 @@ const extractDependencyInfo = (packageJson) => {
|
|
|
33549
33741
|
framework: detectFramework(allDependencies)
|
|
33550
33742
|
};
|
|
33551
33743
|
};
|
|
33744
|
+
const getDependencySpec = (packageJson, packageName) => {
|
|
33745
|
+
const spec = packageJson.dependencies?.[packageName] ?? packageJson.devDependencies?.[packageName] ?? packageJson.peerDependencies?.[packageName] ?? packageJson.optionalDependencies?.[packageName];
|
|
33746
|
+
return typeof spec === "string" ? spec : null;
|
|
33747
|
+
};
|
|
33552
33748
|
const getDependencyDeclaration = ({ packageJson, packageName, sections }) => {
|
|
33553
33749
|
for (const section of sections) {
|
|
33554
33750
|
const version = packageJson[section]?.[packageName];
|
|
@@ -33565,31 +33761,141 @@ const getDependencyDeclaration = ({ packageJson, packageName, sections }) => {
|
|
|
33565
33761
|
version: null
|
|
33566
33762
|
};
|
|
33567
33763
|
};
|
|
33568
|
-
const
|
|
33569
|
-
|
|
33570
|
-
|
|
33571
|
-
|
|
33572
|
-
|
|
33764
|
+
const REACT_DEPENDENCY_NAMES = new Set([
|
|
33765
|
+
"react",
|
|
33766
|
+
"react-native",
|
|
33767
|
+
"next",
|
|
33768
|
+
"preact"
|
|
33769
|
+
]);
|
|
33770
|
+
const hasReactDependency = (packageJson) => {
|
|
33771
|
+
const allDependencies = {
|
|
33772
|
+
...packageJson.peerDependencies,
|
|
33773
|
+
...packageJson.dependencies,
|
|
33774
|
+
...packageJson.devDependencies
|
|
33775
|
+
};
|
|
33776
|
+
return Object.keys(allDependencies).some((packageName) => REACT_DEPENDENCY_NAMES.has(packageName));
|
|
33777
|
+
};
|
|
33778
|
+
const getPreactVersion = (packageJson) => {
|
|
33779
|
+
return {
|
|
33780
|
+
...packageJson.peerDependencies,
|
|
33781
|
+
...packageJson.dependencies,
|
|
33782
|
+
...packageJson.devDependencies
|
|
33783
|
+
}.preact ?? null;
|
|
33784
|
+
};
|
|
33785
|
+
const TANSTACK_QUERY_PACKAGES = new Set([
|
|
33786
|
+
"@tanstack/react-query",
|
|
33787
|
+
"@tanstack/query-core",
|
|
33788
|
+
"react-query"
|
|
33789
|
+
]);
|
|
33790
|
+
const hasTanStackQuery = (packageJson) => {
|
|
33791
|
+
const allDependencies = {
|
|
33792
|
+
...packageJson.peerDependencies,
|
|
33793
|
+
...packageJson.dependencies,
|
|
33794
|
+
...packageJson.devDependencies
|
|
33795
|
+
};
|
|
33796
|
+
return Object.keys(allDependencies).some((packageName) => TANSTACK_QUERY_PACKAGES.has(packageName));
|
|
33797
|
+
};
|
|
33798
|
+
const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, version }) => {
|
|
33799
|
+
if (version === null || !isCatalogReference(version)) return version;
|
|
33800
|
+
const catalogName = extractCatalogName(version);
|
|
33801
|
+
const resolvedLocalVersion = resolveCatalogVersion(rootPackageJson, packageName, rootDirectory, catalogName);
|
|
33802
|
+
if (resolvedLocalVersion) return resolvedLocalVersion;
|
|
33803
|
+
const monorepoRoot = findMonorepoRoot(rootDirectory);
|
|
33804
|
+
if (!monorepoRoot) return version;
|
|
33805
|
+
const monorepoPackageJsonPath = Path.join(monorepoRoot, "package.json");
|
|
33806
|
+
if (!isFile(monorepoPackageJsonPath)) return version;
|
|
33807
|
+
return resolveCatalogVersion(readPackageJson(monorepoPackageJsonPath), packageName, monorepoRoot, catalogName) ?? version;
|
|
33808
|
+
};
|
|
33809
|
+
/**
|
|
33810
|
+
* The chain of ancestor directories of `startDirectory`, nearest first, up to
|
|
33811
|
+
* and including the filesystem root. With `includeStart`, the chain begins at
|
|
33812
|
+
* `startDirectory` itself; otherwise at its parent. The one place the "walk up
|
|
33813
|
+
* the tree" traversal is expressed, so each caller adds only its own match /
|
|
33814
|
+
* stop policy instead of re-deriving the `path.dirname` loop.
|
|
33815
|
+
*/
|
|
33816
|
+
const ancestorDirectories = (startDirectory, { includeStart }) => {
|
|
33817
|
+
const directories = [];
|
|
33818
|
+
let currentDirectory = includeStart ? startDirectory : Path.dirname(startDirectory);
|
|
33819
|
+
while (true) {
|
|
33820
|
+
directories.push(currentDirectory);
|
|
33821
|
+
const parentDirectory = Path.dirname(currentDirectory);
|
|
33822
|
+
if (parentDirectory === currentDirectory) return directories;
|
|
33823
|
+
currentDirectory = parentDirectory;
|
|
33573
33824
|
}
|
|
33574
33825
|
};
|
|
33575
|
-
|
|
33576
|
-
|
|
33577
|
-
|
|
33578
|
-
|
|
33579
|
-
|
|
33580
|
-
|
|
33581
|
-
|
|
33582
|
-
|
|
33583
|
-
|
|
33584
|
-
|
|
33585
|
-
|
|
33586
|
-
|
|
33587
|
-
|
|
33588
|
-
|
|
33589
|
-
|
|
33590
|
-
|
|
33826
|
+
/**
|
|
33827
|
+
* Walk up from `startDirectory` to the nearest ancestor that owns a
|
|
33828
|
+
* `package.json`, stopping at (and including) the enclosing project boundary
|
|
33829
|
+
* — the working tree's git root or a monorepo root. Lets a scan of a package
|
|
33830
|
+
* subfolder that has no `package.json` of its own adopt the nearest enclosing
|
|
33831
|
+
* package as its project root, so it inherits that package's dependency +
|
|
33832
|
+
* framework detection instead of synthesizing an empty (React-blind) project.
|
|
33833
|
+
*
|
|
33834
|
+
* Generalizes the older monorepo-root-only lookup: the nearest ancestor is the
|
|
33835
|
+
* most specific owning package (a leaf workspace, not just the repo root), so
|
|
33836
|
+
* a subfolder of one workspace no longer borrows a sibling's capabilities.
|
|
33837
|
+
*
|
|
33838
|
+
* Returns `null` when no ancestor `package.json` exists inside the project
|
|
33839
|
+
* boundary (a loose tree of files, or a subfolder of a package-less repo).
|
|
33840
|
+
*/
|
|
33841
|
+
const findNearestAncestorPackageJson = (startDirectory) => {
|
|
33842
|
+
if (isProjectBoundary(startDirectory)) return null;
|
|
33843
|
+
for (const directory of ancestorDirectories(startDirectory, { includeStart: false })) {
|
|
33844
|
+
if (isFile(Path.join(directory, "package.json"))) return directory;
|
|
33845
|
+
if (isProjectBoundary(directory)) return null;
|
|
33591
33846
|
}
|
|
33592
|
-
return
|
|
33847
|
+
return null;
|
|
33848
|
+
};
|
|
33849
|
+
const NAMES = new Set([
|
|
33850
|
+
"react-native",
|
|
33851
|
+
"react-native-tvos",
|
|
33852
|
+
...new Set([
|
|
33853
|
+
"expo",
|
|
33854
|
+
"expo-router",
|
|
33855
|
+
"@expo/cli",
|
|
33856
|
+
"@expo/metro-config",
|
|
33857
|
+
"@expo/metro-runtime"
|
|
33858
|
+
]),
|
|
33859
|
+
"react-native-windows",
|
|
33860
|
+
"react-native-macos"
|
|
33861
|
+
]);
|
|
33862
|
+
const PREFIXES = ["@react-native/", "@react-native-"];
|
|
33863
|
+
const isReactNativeDependencyName = (dependencyName) => {
|
|
33864
|
+
if (NAMES.has(dependencyName)) return true;
|
|
33865
|
+
for (const prefix of PREFIXES) if (dependencyName.startsWith(prefix)) return true;
|
|
33866
|
+
return false;
|
|
33867
|
+
};
|
|
33868
|
+
const containsAnyReactNativeDependency = (section) => {
|
|
33869
|
+
if (!section) return false;
|
|
33870
|
+
for (const dependencyName of Object.keys(section)) if (isReactNativeDependencyName(dependencyName)) return true;
|
|
33871
|
+
return false;
|
|
33872
|
+
};
|
|
33873
|
+
const isPackageJsonReactNativeAware = (packageJson) => {
|
|
33874
|
+
if (typeof packageJson["react-native"] === "string") return true;
|
|
33875
|
+
if (containsAnyReactNativeDependency(packageJson.dependencies)) return true;
|
|
33876
|
+
if (containsAnyReactNativeDependency(packageJson.devDependencies)) return true;
|
|
33877
|
+
if (containsAnyReactNativeDependency(packageJson.peerDependencies)) return true;
|
|
33878
|
+
if (containsAnyReactNativeDependency(packageJson.optionalDependencies)) return true;
|
|
33879
|
+
return false;
|
|
33880
|
+
};
|
|
33881
|
+
const REANIMATED_DEPENDENCY_NAME$1 = "react-native-reanimated";
|
|
33882
|
+
const isPackageJsonReanimatedAware = (packageJson) => {
|
|
33883
|
+
const allDependencies = {
|
|
33884
|
+
...packageJson.peerDependencies,
|
|
33885
|
+
...packageJson.dependencies,
|
|
33886
|
+
...packageJson.devDependencies,
|
|
33887
|
+
...packageJson.optionalDependencies
|
|
33888
|
+
};
|
|
33889
|
+
return Object.hasOwn(allDependencies, REANIMATED_DEPENDENCY_NAME$1);
|
|
33890
|
+
};
|
|
33891
|
+
const getWorkspacePatterns = (rootDirectory, packageJson) => {
|
|
33892
|
+
const pnpmPatterns = parsePnpmWorkspacePatterns(rootDirectory);
|
|
33893
|
+
if (pnpmPatterns.length > 0) return pnpmPatterns;
|
|
33894
|
+
if (Array.isArray(packageJson.workspaces)) return packageJson.workspaces;
|
|
33895
|
+
if (packageJson.workspaces?.packages) return packageJson.workspaces.packages;
|
|
33896
|
+
const nxPatterns = getNxWorkspaceDirectories(rootDirectory);
|
|
33897
|
+
if (nxPatterns.length > 0) return nxPatterns;
|
|
33898
|
+
return [];
|
|
33593
33899
|
};
|
|
33594
33900
|
const parsePnpmWorkspacePatterns = (rootDirectory) => {
|
|
33595
33901
|
const workspacePath = Path.join(rootDirectory, "pnpm-workspace.yaml");
|
|
@@ -33608,18 +33914,24 @@ const parsePnpmWorkspacePatterns = (rootDirectory) => {
|
|
|
33608
33914
|
}
|
|
33609
33915
|
return patterns;
|
|
33610
33916
|
};
|
|
33611
|
-
const
|
|
33612
|
-
|
|
33613
|
-
|
|
33614
|
-
|
|
33615
|
-
|
|
33616
|
-
|
|
33617
|
-
if (
|
|
33618
|
-
|
|
33619
|
-
|
|
33620
|
-
const
|
|
33621
|
-
|
|
33622
|
-
|
|
33917
|
+
const NX_PROJECT_DISCOVERY_DIRS = [
|
|
33918
|
+
"apps",
|
|
33919
|
+
"libs",
|
|
33920
|
+
"packages"
|
|
33921
|
+
];
|
|
33922
|
+
const getNxWorkspaceDirectories = (rootDirectory) => {
|
|
33923
|
+
if (!isFile(Path.join(rootDirectory, "nx.json"))) return [];
|
|
33924
|
+
const collected = [];
|
|
33925
|
+
for (const candidate of NX_PROJECT_DISCOVERY_DIRS) {
|
|
33926
|
+
const candidatePath = Path.join(rootDirectory, candidate);
|
|
33927
|
+
if (!isDirectory(candidatePath)) continue;
|
|
33928
|
+
for (const entry of readDirectoryEntries(candidatePath)) {
|
|
33929
|
+
if (!entry.isDirectory()) continue;
|
|
33930
|
+
const projectDirectory = Path.join(candidatePath, entry.name);
|
|
33931
|
+
if (isFile(Path.join(projectDirectory, "project.json")) || isFile(Path.join(projectDirectory, "package.json"))) collected.push(`${candidate}/${entry.name}`);
|
|
33932
|
+
}
|
|
33933
|
+
}
|
|
33934
|
+
return collected;
|
|
33623
33935
|
};
|
|
33624
33936
|
const resolveWorkspaceDirectories = (rootDirectory, pattern) => {
|
|
33625
33937
|
const cleanPattern = pattern.replace(/["']/g, "").replace(/\/\*\*$/, "/*");
|
|
@@ -33639,6 +33951,38 @@ const resolveWorkspaceDirectories = (rootDirectory, pattern) => {
|
|
|
33639
33951
|
}
|
|
33640
33952
|
return resolved;
|
|
33641
33953
|
};
|
|
33954
|
+
const listWorkspacePackages = (rootDirectory) => {
|
|
33955
|
+
const packageJsonPath = Path.join(rootDirectory, "package.json");
|
|
33956
|
+
if (!isFile(packageJsonPath)) return [];
|
|
33957
|
+
const packageJson = readPackageJson(packageJsonPath);
|
|
33958
|
+
const patterns = getWorkspacePatterns(rootDirectory, packageJson);
|
|
33959
|
+
if (patterns.length === 0) return [];
|
|
33960
|
+
const packages = [];
|
|
33961
|
+
const seenDirectories = /* @__PURE__ */ new Set();
|
|
33962
|
+
const pushIfNew = (workspacePackage) => {
|
|
33963
|
+
if (seenDirectories.has(workspacePackage.directory)) return;
|
|
33964
|
+
seenDirectories.add(workspacePackage.directory);
|
|
33965
|
+
packages.push(workspacePackage);
|
|
33966
|
+
};
|
|
33967
|
+
if (hasReactDependency(packageJson)) pushIfNew({
|
|
33968
|
+
name: packageJson.name ?? Path.basename(rootDirectory),
|
|
33969
|
+
directory: rootDirectory
|
|
33970
|
+
});
|
|
33971
|
+
for (const pattern of patterns) {
|
|
33972
|
+
const directories = resolveWorkspaceDirectories(rootDirectory, pattern);
|
|
33973
|
+
for (const workspaceDirectory of directories) {
|
|
33974
|
+
const workspacePackageJson = readPackageJson(Path.join(workspaceDirectory, "package.json"));
|
|
33975
|
+
if (!hasReactDependency(workspacePackageJson)) continue;
|
|
33976
|
+
pushIfNew({
|
|
33977
|
+
name: workspacePackageJson.name ?? Path.basename(workspaceDirectory),
|
|
33978
|
+
directory: workspaceDirectory
|
|
33979
|
+
});
|
|
33980
|
+
}
|
|
33981
|
+
}
|
|
33982
|
+
return packages;
|
|
33983
|
+
};
|
|
33984
|
+
const REANIMATED_DEPENDENCY_NAME = "react-native-reanimated";
|
|
33985
|
+
const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
|
|
33642
33986
|
const resolveWorkspaceDependencyVersion = ({ concreteVersion, packageName, rootDirectory, rootPackageJson, sections, workspaceDirectory, workspacePackageJson }) => {
|
|
33643
33987
|
const dependencyDeclaration = getDependencyDeclaration({
|
|
33644
33988
|
packageJson: workspacePackageJson,
|
|
@@ -33656,24 +34000,76 @@ const shouldReplaceReactVersion = (currentVersion, nextVersion) => {
|
|
|
33656
34000
|
if (nextMajor === null) return false;
|
|
33657
34001
|
return nextMajor < currentMajor;
|
|
33658
34002
|
};
|
|
33659
|
-
const
|
|
33660
|
-
|
|
33661
|
-
|
|
33662
|
-
|
|
33663
|
-
|
|
34003
|
+
const evaluateManifestFacts = (facts, packageJson, directory) => {
|
|
34004
|
+
if (facts.expo.version === null) {
|
|
34005
|
+
const spec = getDependencySpec(packageJson, "expo");
|
|
34006
|
+
if (spec !== null) facts.expo = {
|
|
34007
|
+
version: spec,
|
|
34008
|
+
sourceDirectory: directory
|
|
34009
|
+
};
|
|
34010
|
+
}
|
|
34011
|
+
if (facts.next.version === null) {
|
|
34012
|
+
const spec = getDependencySpec(packageJson, "next");
|
|
34013
|
+
if (spec !== null) facts.next = {
|
|
34014
|
+
version: spec,
|
|
34015
|
+
sourceDirectory: directory
|
|
34016
|
+
};
|
|
34017
|
+
}
|
|
34018
|
+
if (facts.shopifyFlashList.version === null) {
|
|
34019
|
+
const spec = getDependencySpec(packageJson, SHOPIFY_FLASH_LIST_PACKAGE_NAME);
|
|
34020
|
+
if (spec !== null) facts.shopifyFlashList = {
|
|
34021
|
+
version: spec,
|
|
34022
|
+
sourceDirectory: directory
|
|
34023
|
+
};
|
|
34024
|
+
}
|
|
34025
|
+
if (facts.reanimatedVersion === null) {
|
|
34026
|
+
const spec = getDependencySpec(packageJson, REANIMATED_DEPENDENCY_NAME);
|
|
34027
|
+
if (spec !== null) facts.reanimatedVersion = spec;
|
|
34028
|
+
}
|
|
34029
|
+
facts.hasReactNativeAwarePackage = facts.hasReactNativeAwarePackage || isPackageJsonReactNativeAware(packageJson);
|
|
34030
|
+
facts.hasReanimatedAwarePackage = facts.hasReanimatedAwarePackage || isPackageJsonReanimatedAware(packageJson);
|
|
34031
|
+
};
|
|
34032
|
+
const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGroup }) => {
|
|
34033
|
+
const facts = {
|
|
34034
|
+
reactVersion: null,
|
|
34035
|
+
tailwindVersion: null,
|
|
34036
|
+
zodVersion: null,
|
|
34037
|
+
framework: "unknown",
|
|
34038
|
+
expo: {
|
|
34039
|
+
version: null,
|
|
34040
|
+
sourceDirectory: null
|
|
34041
|
+
},
|
|
34042
|
+
next: {
|
|
34043
|
+
version: null,
|
|
34044
|
+
sourceDirectory: null
|
|
34045
|
+
},
|
|
34046
|
+
shopifyFlashList: {
|
|
34047
|
+
version: null,
|
|
34048
|
+
sourceDirectory: null
|
|
34049
|
+
},
|
|
34050
|
+
hasReactNativeAwarePackage: false,
|
|
34051
|
+
hasReanimatedAwarePackage: false,
|
|
34052
|
+
reanimatedVersion: null
|
|
34053
|
+
};
|
|
34054
|
+
evaluateManifestFacts(facts, rootPackageJson, rootDirectory);
|
|
34055
|
+
let isReactGroupSettled = !collectReactGroup;
|
|
34056
|
+
const visitedDirectories = /* @__PURE__ */ new Set();
|
|
34057
|
+
for (const pattern of getWorkspacePatterns(rootDirectory, rootPackageJson)) {
|
|
34058
|
+
const directories = [...resolveWorkspaceDirectories(rootDirectory, pattern)].sort();
|
|
33664
34059
|
for (const workspaceDirectory of directories) {
|
|
34060
|
+
if (visitedDirectories.has(workspaceDirectory)) continue;
|
|
34061
|
+
visitedDirectories.add(workspaceDirectory);
|
|
33665
34062
|
const workspacePackageJson = readPackageJson(Path.join(workspaceDirectory, "package.json"));
|
|
34063
|
+
evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory);
|
|
33666
34064
|
const info = extractDependencyInfo(workspacePackageJson);
|
|
34065
|
+
if (info.framework !== "unknown" && frameworkMergeRank(info.framework) < frameworkMergeRank(facts.framework)) facts.framework = info.framework;
|
|
34066
|
+
if (isReactGroupSettled) continue;
|
|
33667
34067
|
const reactVersion = resolveWorkspaceDependencyVersion({
|
|
33668
34068
|
concreteVersion: info.reactVersion,
|
|
33669
34069
|
packageName: "react",
|
|
33670
34070
|
rootDirectory,
|
|
33671
|
-
rootPackageJson
|
|
33672
|
-
sections:
|
|
33673
|
-
"dependencies",
|
|
33674
|
-
"peerDependencies",
|
|
33675
|
-
"devDependencies"
|
|
33676
|
-
],
|
|
34071
|
+
rootPackageJson,
|
|
34072
|
+
sections: REACT_SECTIONS,
|
|
33677
34073
|
workspaceDirectory,
|
|
33678
34074
|
workspacePackageJson
|
|
33679
34075
|
});
|
|
@@ -33681,12 +34077,8 @@ const findReactInWorkspaces = (rootDirectory, packageJson) => {
|
|
|
33681
34077
|
concreteVersion: info.tailwindVersion,
|
|
33682
34078
|
packageName: "tailwindcss",
|
|
33683
34079
|
rootDirectory,
|
|
33684
|
-
rootPackageJson
|
|
33685
|
-
sections:
|
|
33686
|
-
"dependencies",
|
|
33687
|
-
"devDependencies",
|
|
33688
|
-
"peerDependencies"
|
|
33689
|
-
],
|
|
34080
|
+
rootPackageJson,
|
|
34081
|
+
sections: TAILWIND_ZOD_SECTIONS,
|
|
33690
34082
|
workspaceDirectory,
|
|
33691
34083
|
workspacePackageJson
|
|
33692
34084
|
});
|
|
@@ -33694,24 +34086,19 @@ const findReactInWorkspaces = (rootDirectory, packageJson) => {
|
|
|
33694
34086
|
concreteVersion: info.zodVersion,
|
|
33695
34087
|
packageName: "zod",
|
|
33696
34088
|
rootDirectory,
|
|
33697
|
-
rootPackageJson
|
|
33698
|
-
sections:
|
|
33699
|
-
"dependencies",
|
|
33700
|
-
"devDependencies",
|
|
33701
|
-
"peerDependencies"
|
|
33702
|
-
],
|
|
34089
|
+
rootPackageJson,
|
|
34090
|
+
sections: TAILWIND_ZOD_SECTIONS,
|
|
33703
34091
|
workspaceDirectory,
|
|
33704
34092
|
workspacePackageJson
|
|
33705
34093
|
});
|
|
33706
|
-
if (reactVersion && shouldReplaceReactVersion(
|
|
33707
|
-
if (tailwindVersion && !
|
|
33708
|
-
if (zodVersion && !
|
|
33709
|
-
|
|
33710
|
-
|
|
33711
|
-
if (result.reactVersion && result.tailwindVersion && result.framework !== "unknown" && resultReactMajor !== null && resultReactMajor <= 17) return result;
|
|
34094
|
+
if (reactVersion && shouldReplaceReactVersion(facts.reactVersion, reactVersion)) facts.reactVersion = reactVersion;
|
|
34095
|
+
if (tailwindVersion && !facts.tailwindVersion) facts.tailwindVersion = tailwindVersion;
|
|
34096
|
+
if (zodVersion && !facts.zodVersion) facts.zodVersion = zodVersion;
|
|
34097
|
+
const settledReactMajor = parseReactMajor(facts.reactVersion);
|
|
34098
|
+
isReactGroupSettled = Boolean(facts.reactVersion && facts.tailwindVersion && facts.framework !== "unknown" && settledReactMajor !== null && settledReactMajor <= 17);
|
|
33712
34099
|
}
|
|
33713
34100
|
}
|
|
33714
|
-
return
|
|
34101
|
+
return facts;
|
|
33715
34102
|
};
|
|
33716
34103
|
const findDependencyInfoFromMonorepoRoot = (directory) => {
|
|
33717
34104
|
const monorepoRoot = findMonorepoRoot(directory);
|
|
@@ -33725,29 +34112,17 @@ const findDependencyInfoFromMonorepoRoot = (directory) => {
|
|
|
33725
34112
|
const leafReactDeclaration = leafPackageJson ? getDependencyDeclaration({
|
|
33726
34113
|
packageJson: leafPackageJson,
|
|
33727
34114
|
packageName: "react",
|
|
33728
|
-
sections:
|
|
33729
|
-
"dependencies",
|
|
33730
|
-
"peerDependencies",
|
|
33731
|
-
"devDependencies"
|
|
33732
|
-
]
|
|
34115
|
+
sections: REACT_SECTIONS
|
|
33733
34116
|
}) : null;
|
|
33734
34117
|
const leafTailwindDeclaration = leafPackageJson ? getDependencyDeclaration({
|
|
33735
34118
|
packageJson: leafPackageJson,
|
|
33736
34119
|
packageName: "tailwindcss",
|
|
33737
|
-
sections:
|
|
33738
|
-
"dependencies",
|
|
33739
|
-
"devDependencies",
|
|
33740
|
-
"peerDependencies"
|
|
33741
|
-
]
|
|
34120
|
+
sections: TAILWIND_ZOD_SECTIONS
|
|
33742
34121
|
}) : null;
|
|
33743
34122
|
const leafZodDeclaration = leafPackageJson ? getDependencyDeclaration({
|
|
33744
34123
|
packageJson: leafPackageJson,
|
|
33745
34124
|
packageName: "zod",
|
|
33746
|
-
sections:
|
|
33747
|
-
"dependencies",
|
|
33748
|
-
"devDependencies",
|
|
33749
|
-
"peerDependencies"
|
|
33750
|
-
]
|
|
34125
|
+
sections: TAILWIND_ZOD_SECTIONS
|
|
33751
34126
|
}) : null;
|
|
33752
34127
|
const shouldUseReactFallback = !leafReactDeclaration?.hasDeclaration;
|
|
33753
34128
|
const shouldUseTailwindFallback = leafTailwindDeclaration?.hasDeclaration ?? true;
|
|
@@ -33755,38 +34130,15 @@ const findDependencyInfoFromMonorepoRoot = (directory) => {
|
|
|
33755
34130
|
const reactCatalogVersion = shouldUseReactFallback ? resolveCatalogVersion(rootPackageJson, "react", monorepoRoot, leafReactDeclaration?.catalogReference) : null;
|
|
33756
34131
|
const tailwindCatalogVersion = shouldUseTailwindFallback ? resolveCatalogVersion(rootPackageJson, "tailwindcss", monorepoRoot, leafTailwindDeclaration?.catalogReference) : null;
|
|
33757
34132
|
const zodCatalogVersion = shouldUseZodFallback ? resolveCatalogVersion(rootPackageJson, "zod", monorepoRoot, leafZodDeclaration?.catalogReference) : null;
|
|
33758
|
-
const
|
|
34133
|
+
const workspaceFacts = collectWorkspaceFacts(monorepoRoot, rootPackageJson, { collectReactGroup: true });
|
|
33759
34134
|
return {
|
|
33760
|
-
reactVersion: shouldUseReactFallback ? reactCatalogVersion ?? rootInfo.reactVersion ??
|
|
33761
|
-
tailwindVersion: shouldUseTailwindFallback ? tailwindCatalogVersion ?? rootInfo.tailwindVersion ??
|
|
33762
|
-
zodVersion: shouldUseZodFallback ? zodCatalogVersion ?? rootInfo.zodVersion ??
|
|
33763
|
-
framework: rootInfo.framework !== "unknown" ? rootInfo.framework :
|
|
34135
|
+
reactVersion: shouldUseReactFallback ? reactCatalogVersion ?? rootInfo.reactVersion ?? workspaceFacts.reactVersion : rootInfo.reactVersion ?? workspaceFacts.reactVersion,
|
|
34136
|
+
tailwindVersion: shouldUseTailwindFallback ? tailwindCatalogVersion ?? rootInfo.tailwindVersion ?? workspaceFacts.tailwindVersion : null,
|
|
34137
|
+
zodVersion: shouldUseZodFallback ? zodCatalogVersion ?? rootInfo.zodVersion ?? workspaceFacts.zodVersion : null,
|
|
34138
|
+
framework: rootInfo.framework !== "unknown" ? rootInfo.framework : workspaceFacts.framework
|
|
33764
34139
|
};
|
|
33765
34140
|
};
|
|
33766
34141
|
/**
|
|
33767
|
-
* Walk up from `startDirectory` to the nearest ancestor that owns a
|
|
33768
|
-
* `package.json`, stopping at (and including) the enclosing project boundary
|
|
33769
|
-
* — the working tree's git root or a monorepo root. Lets a scan of a package
|
|
33770
|
-
* subfolder that has no `package.json` of its own adopt the nearest enclosing
|
|
33771
|
-
* package as its project root, so it inherits that package's dependency +
|
|
33772
|
-
* framework detection instead of synthesizing an empty (React-blind) project.
|
|
33773
|
-
*
|
|
33774
|
-
* Generalizes the older monorepo-root-only lookup: the nearest ancestor is the
|
|
33775
|
-
* most specific owning package (a leaf workspace, not just the repo root), so
|
|
33776
|
-
* a subfolder of one workspace no longer borrows a sibling's capabilities.
|
|
33777
|
-
*
|
|
33778
|
-
* Returns `null` when no ancestor `package.json` exists inside the project
|
|
33779
|
-
* boundary (a loose tree of files, or a subfolder of a package-less repo).
|
|
33780
|
-
*/
|
|
33781
|
-
const findNearestAncestorPackageJson = (startDirectory) => {
|
|
33782
|
-
if (isProjectBoundary(startDirectory)) return null;
|
|
33783
|
-
for (const directory of ancestorDirectories(startDirectory, { includeStart: false })) {
|
|
33784
|
-
if (isFile(Path.join(directory, "package.json"))) return directory;
|
|
33785
|
-
if (isProjectBoundary(directory)) return null;
|
|
33786
|
-
}
|
|
33787
|
-
return null;
|
|
33788
|
-
};
|
|
33789
|
-
/**
|
|
33790
34142
|
* Last-resort React detection: locate React the way Node's `node_modules`
|
|
33791
34143
|
* resolution would from `directory` — check each `node_modules/react` up the
|
|
33792
34144
|
* tree — but bounded to the enclosing repo so a globally installed React can't
|
|
@@ -33831,295 +34183,6 @@ const resolveInstalledReactVersion = (directory) => {
|
|
|
33831
34183
|
}
|
|
33832
34184
|
return null;
|
|
33833
34185
|
};
|
|
33834
|
-
const findInWorkspacePackageJsons = (rootDirectory, rootPackageJson, select) => {
|
|
33835
|
-
const rootValue = select(rootPackageJson);
|
|
33836
|
-
if (rootValue !== null) return rootValue;
|
|
33837
|
-
const patterns = getWorkspacePatterns(rootDirectory, rootPackageJson);
|
|
33838
|
-
if (patterns.length === 0) return null;
|
|
33839
|
-
const visitedDirectories = /* @__PURE__ */ new Set();
|
|
33840
|
-
for (const pattern of patterns) {
|
|
33841
|
-
const directories = [...resolveWorkspaceDirectories(rootDirectory, pattern)].sort();
|
|
33842
|
-
for (const workspaceDirectory of directories) {
|
|
33843
|
-
if (visitedDirectories.has(workspaceDirectory)) continue;
|
|
33844
|
-
visitedDirectories.add(workspaceDirectory);
|
|
33845
|
-
const value = select(readPackageJson(Path.join(workspaceDirectory, "package.json")));
|
|
33846
|
-
if (value !== null) return value;
|
|
33847
|
-
}
|
|
33848
|
-
}
|
|
33849
|
-
return null;
|
|
33850
|
-
};
|
|
33851
|
-
const someWorkspacePackageJson = (rootDirectory, rootPackageJson, predicate) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => predicate(packageJson) ? true : null) !== null;
|
|
33852
|
-
const NAMES = new Set([
|
|
33853
|
-
"react-native",
|
|
33854
|
-
"react-native-tvos",
|
|
33855
|
-
...new Set([
|
|
33856
|
-
"expo",
|
|
33857
|
-
"expo-router",
|
|
33858
|
-
"@expo/cli",
|
|
33859
|
-
"@expo/metro-config",
|
|
33860
|
-
"@expo/metro-runtime"
|
|
33861
|
-
]),
|
|
33862
|
-
"react-native-windows",
|
|
33863
|
-
"react-native-macos"
|
|
33864
|
-
]);
|
|
33865
|
-
const PREFIXES = ["@react-native/", "@react-native-"];
|
|
33866
|
-
const isReactNativeDependencyName = (dependencyName) => {
|
|
33867
|
-
if (NAMES.has(dependencyName)) return true;
|
|
33868
|
-
for (const prefix of PREFIXES) if (dependencyName.startsWith(prefix)) return true;
|
|
33869
|
-
return false;
|
|
33870
|
-
};
|
|
33871
|
-
const containsAnyReactNativeDependency = (section) => {
|
|
33872
|
-
if (!section) return false;
|
|
33873
|
-
for (const dependencyName of Object.keys(section)) if (isReactNativeDependencyName(dependencyName)) return true;
|
|
33874
|
-
return false;
|
|
33875
|
-
};
|
|
33876
|
-
const isPackageJsonReactNativeAware = (packageJson) => {
|
|
33877
|
-
if (typeof packageJson["react-native"] === "string") return true;
|
|
33878
|
-
if (containsAnyReactNativeDependency(packageJson.dependencies)) return true;
|
|
33879
|
-
if (containsAnyReactNativeDependency(packageJson.devDependencies)) return true;
|
|
33880
|
-
if (containsAnyReactNativeDependency(packageJson.peerDependencies)) return true;
|
|
33881
|
-
if (containsAnyReactNativeDependency(packageJson.optionalDependencies)) return true;
|
|
33882
|
-
return false;
|
|
33883
|
-
};
|
|
33884
|
-
const hasReactNativeWorkspaceAnywhere = (rootDirectory, rootPackageJson) => someWorkspacePackageJson(rootDirectory, rootPackageJson, isPackageJsonReactNativeAware);
|
|
33885
|
-
const getDependencySpec = (packageJson, packageName) => {
|
|
33886
|
-
const spec = packageJson.dependencies?.[packageName] ?? packageJson.devDependencies?.[packageName] ?? packageJson.peerDependencies?.[packageName] ?? packageJson.optionalDependencies?.[packageName];
|
|
33887
|
-
return typeof spec === "string" ? spec : null;
|
|
33888
|
-
};
|
|
33889
|
-
const findExpoVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, "expo"));
|
|
33890
|
-
const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
|
|
33891
|
-
const findShopifyFlashListVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, SHOPIFY_FLASH_LIST_PACKAGE_NAME));
|
|
33892
|
-
const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, version }) => {
|
|
33893
|
-
if (version === null || !isCatalogReference(version)) return version;
|
|
33894
|
-
const catalogName = extractCatalogName(version);
|
|
33895
|
-
const resolvedLocalVersion = resolveCatalogVersion(rootPackageJson, packageName, rootDirectory, catalogName);
|
|
33896
|
-
if (resolvedLocalVersion) return resolvedLocalVersion;
|
|
33897
|
-
const monorepoRoot = findMonorepoRoot(rootDirectory);
|
|
33898
|
-
if (!monorepoRoot) return version;
|
|
33899
|
-
const monorepoPackageJsonPath = path.join(monorepoRoot, "package.json");
|
|
33900
|
-
if (!isFile(monorepoPackageJsonPath)) return version;
|
|
33901
|
-
return resolveCatalogVersion(readPackageJson(monorepoPackageJsonPath), packageName, monorepoRoot, catalogName) ?? version;
|
|
33902
|
-
};
|
|
33903
|
-
const findNextjsVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, "next"));
|
|
33904
|
-
const getPreactVersion = (packageJson) => {
|
|
33905
|
-
return {
|
|
33906
|
-
...packageJson.peerDependencies,
|
|
33907
|
-
...packageJson.dependencies,
|
|
33908
|
-
...packageJson.devDependencies
|
|
33909
|
-
}.preact ?? null;
|
|
33910
|
-
};
|
|
33911
|
-
const TANSTACK_QUERY_PACKAGES = new Set([
|
|
33912
|
-
"@tanstack/react-query",
|
|
33913
|
-
"@tanstack/query-core",
|
|
33914
|
-
"react-query"
|
|
33915
|
-
]);
|
|
33916
|
-
const hasTanStackQuery = (packageJson) => {
|
|
33917
|
-
const allDependencies = {
|
|
33918
|
-
...packageJson.peerDependencies,
|
|
33919
|
-
...packageJson.dependencies,
|
|
33920
|
-
...packageJson.devDependencies
|
|
33921
|
-
};
|
|
33922
|
-
return Object.keys(allDependencies).some((packageName) => TANSTACK_QUERY_PACKAGES.has(packageName));
|
|
33923
|
-
};
|
|
33924
|
-
const REANIMATED_DEPENDENCY_NAME = "react-native-reanimated";
|
|
33925
|
-
const isPackageJsonReanimatedAware = (packageJson) => {
|
|
33926
|
-
const allDependencies = {
|
|
33927
|
-
...packageJson.peerDependencies,
|
|
33928
|
-
...packageJson.dependencies,
|
|
33929
|
-
...packageJson.devDependencies,
|
|
33930
|
-
...packageJson.optionalDependencies
|
|
33931
|
-
};
|
|
33932
|
-
return Object.hasOwn(allDependencies, REANIMATED_DEPENDENCY_NAME);
|
|
33933
|
-
};
|
|
33934
|
-
const parseZodMajor = (zodVersion) => {
|
|
33935
|
-
if (typeof zodVersion !== "string") return null;
|
|
33936
|
-
return getLowestDependencyMajor(zodVersion);
|
|
33937
|
-
};
|
|
33938
|
-
const hasUpperBoundOnlyPeerRange = (range) => {
|
|
33939
|
-
if (typeof range !== "string") return false;
|
|
33940
|
-
const normalizedRange = normalizeDependencyVersion(range);
|
|
33941
|
-
if (normalizedRange === null) return false;
|
|
33942
|
-
return splitDependencyVersionBranches(normalizedRange).some((branch) => {
|
|
33943
|
-
const normalizedBranch = normalizeDependencyVersion(branch);
|
|
33944
|
-
return normalizedBranch !== null && getBranchLowestMajor(normalizedBranch) === null && hasUpperBoundComparator(normalizedBranch);
|
|
33945
|
-
});
|
|
33946
|
-
};
|
|
33947
|
-
const peerRangeMinMajor = (range) => {
|
|
33948
|
-
if (typeof range !== "string") return null;
|
|
33949
|
-
return getLowestDependencyMajor(range);
|
|
33950
|
-
};
|
|
33951
|
-
const resolveEffectiveReactMajor = (reactVersion, packageJson) => {
|
|
33952
|
-
const installedReactMajor = parseReactMajor(reactVersion);
|
|
33953
|
-
const peerReactRange = packageJson.peerDependencies?.react;
|
|
33954
|
-
if (typeof peerReactRange !== "string") return installedReactMajor;
|
|
33955
|
-
const peerFloor = peerRangeMinMajor(peerReactRange);
|
|
33956
|
-
if (peerFloor === null) return hasUpperBoundOnlyPeerRange(peerReactRange) ? null : installedReactMajor;
|
|
33957
|
-
return installedReactMajor !== null ? Math.min(installedReactMajor, peerFloor) : peerFloor;
|
|
33958
|
-
};
|
|
33959
|
-
const TSCONFIG_FILENAME = "tsconfig.json";
|
|
33960
|
-
const isRelativeExtendsValue = (extendsValue) => extendsValue.startsWith("./") || extendsValue.startsWith("../") || Path.isAbsolute(extendsValue);
|
|
33961
|
-
const ensureJsonExtension = (filePath) => Path.extname(filePath) === "" ? `${filePath}.json` : filePath;
|
|
33962
|
-
const resolvePackageExtendsPath = (extendsValue, fromConfigDirectory) => {
|
|
33963
|
-
const requireFromConfig = createRequire(Path.join(fromConfigDirectory, "tsconfig.json"));
|
|
33964
|
-
const candidates = [
|
|
33965
|
-
extendsValue,
|
|
33966
|
-
ensureJsonExtension(extendsValue),
|
|
33967
|
-
`${extendsValue.replace(/\/$/, "")}/tsconfig.json`
|
|
33968
|
-
];
|
|
33969
|
-
for (const candidate of candidates) try {
|
|
33970
|
-
return requireFromConfig.resolve(candidate);
|
|
33971
|
-
} catch {
|
|
33972
|
-
continue;
|
|
33973
|
-
}
|
|
33974
|
-
return null;
|
|
33975
|
-
};
|
|
33976
|
-
const resolveExtendsPath = (extendsValue, fromConfigDirectory) => {
|
|
33977
|
-
if (isRelativeExtendsValue(extendsValue)) return ensureJsonExtension(Path.resolve(fromConfigDirectory, extendsValue));
|
|
33978
|
-
return resolvePackageExtendsPath(extendsValue, fromConfigDirectory);
|
|
33979
|
-
};
|
|
33980
|
-
const normalizeCompilerOptions = (compilerOptions) => {
|
|
33981
|
-
if (!isPlainObject(compilerOptions)) return { hasExplicitLib: false };
|
|
33982
|
-
const target = typeof compilerOptions.target === "string" ? compilerOptions.target : void 0;
|
|
33983
|
-
const hasExplicitLib = Object.hasOwn(compilerOptions, "lib");
|
|
33984
|
-
return {
|
|
33985
|
-
target,
|
|
33986
|
-
lib: Array.isArray(compilerOptions.lib) ? compilerOptions.lib.filter((entry) => typeof entry === "string") : void 0,
|
|
33987
|
-
hasExplicitLib
|
|
33988
|
-
};
|
|
33989
|
-
};
|
|
33990
|
-
const normalizeReferencePaths = (references) => {
|
|
33991
|
-
if (!Array.isArray(references)) return [];
|
|
33992
|
-
return references.map((reference) => isPlainObject(reference) && typeof reference.path === "string" ? reference.path : null).filter((referencePath) => referencePath !== null);
|
|
33993
|
-
};
|
|
33994
|
-
const readTsConfig = (filePath) => {
|
|
33995
|
-
let content;
|
|
33996
|
-
try {
|
|
33997
|
-
content = NFS.readFileSync(filePath, "utf-8");
|
|
33998
|
-
} catch {
|
|
33999
|
-
return null;
|
|
34000
|
-
}
|
|
34001
|
-
const parsed = ts.parseConfigFileTextToJson(filePath, content);
|
|
34002
|
-
if (!isPlainObject(parsed.config)) return null;
|
|
34003
|
-
return {
|
|
34004
|
-
extends: typeof parsed.config.extends === "string" ? parsed.config.extends : void 0,
|
|
34005
|
-
referencePaths: normalizeReferencePaths(parsed.config.references),
|
|
34006
|
-
compilerOptions: normalizeCompilerOptions(parsed.config.compilerOptions)
|
|
34007
|
-
};
|
|
34008
|
-
};
|
|
34009
|
-
const mergeCompilerOptions = (inherited, current) => {
|
|
34010
|
-
const target = current.target ?? inherited?.target;
|
|
34011
|
-
const hasExplicitLib = current.hasExplicitLib || Boolean(inherited?.hasExplicitLib);
|
|
34012
|
-
return {
|
|
34013
|
-
target,
|
|
34014
|
-
lib: current.hasExplicitLib ? current.lib : inherited?.lib,
|
|
34015
|
-
hasExplicitLib
|
|
34016
|
-
};
|
|
34017
|
-
};
|
|
34018
|
-
const readResolvedCompilerOptions = (tsConfigPath, extendsDepth, visitedPaths) => {
|
|
34019
|
-
const realPath = NFS.realpathSync.native(tsConfigPath);
|
|
34020
|
-
if (visitedPaths.has(realPath)) return null;
|
|
34021
|
-
const tsConfig = readTsConfig(realPath);
|
|
34022
|
-
if (!tsConfig) return null;
|
|
34023
|
-
const nextVisitedPaths = new Set(visitedPaths);
|
|
34024
|
-
nextVisitedPaths.add(realPath);
|
|
34025
|
-
if (tsConfig.extends && extendsDepth < 8) {
|
|
34026
|
-
const parentPath = resolveExtendsPath(tsConfig.extends, Path.dirname(realPath));
|
|
34027
|
-
if (parentPath && isFile(parentPath)) return mergeCompilerOptions(readResolvedCompilerOptions(parentPath, extendsDepth + 1, nextVisitedPaths), tsConfig.compilerOptions);
|
|
34028
|
-
}
|
|
34029
|
-
return tsConfig.compilerOptions;
|
|
34030
|
-
};
|
|
34031
|
-
const targetYearIsPreES2023 = (target) => {
|
|
34032
|
-
const year = ES_TARGET_YEAR_BY_NAME[target.toLowerCase()];
|
|
34033
|
-
return year !== void 0 && year < 2023;
|
|
34034
|
-
};
|
|
34035
|
-
const libEntryIncludesES2023Array = (entry) => {
|
|
34036
|
-
const normalizedEntry = entry.toLowerCase();
|
|
34037
|
-
if (normalizedEntry === "esnext" || normalizedEntry === "esnext.array") return true;
|
|
34038
|
-
const esYearMatch = /^es(\d{4})(?:\.(.+))?$/.exec(normalizedEntry);
|
|
34039
|
-
if (!esYearMatch) return false;
|
|
34040
|
-
if (Number(esYearMatch[1]) < 2023) return false;
|
|
34041
|
-
const component = esYearMatch[2];
|
|
34042
|
-
return component === void 0 || component === "array";
|
|
34043
|
-
};
|
|
34044
|
-
const libIncludesES2023 = (lib) => lib.some(libEntryIncludesES2023Array);
|
|
34045
|
-
const compilerOptionsArePreES2023 = (compilerOptions) => {
|
|
34046
|
-
if (compilerOptions.target && targetYearIsPreES2023(compilerOptions.target)) return true;
|
|
34047
|
-
if (compilerOptions.hasExplicitLib) return !libIncludesES2023(compilerOptions.lib ?? []);
|
|
34048
|
-
return false;
|
|
34049
|
-
};
|
|
34050
|
-
const compilerOptionsDeclareTargetOrLib = (compilerOptions) => compilerOptions.hasExplicitLib || compilerOptions.target !== void 0;
|
|
34051
|
-
const detectPreES2023FromConfig = (tsConfigPath, visitedConfigPaths = /* @__PURE__ */ new Set()) => {
|
|
34052
|
-
if (visitedConfigPaths.has(tsConfigPath)) return false;
|
|
34053
|
-
const compilerOptions = readResolvedCompilerOptions(tsConfigPath, 0, /* @__PURE__ */ new Set());
|
|
34054
|
-
if (!compilerOptions) return false;
|
|
34055
|
-
if (!compilerOptionsDeclareTargetOrLib(compilerOptions)) {
|
|
34056
|
-
const tsConfig = readTsConfig(tsConfigPath);
|
|
34057
|
-
if (!tsConfig) return false;
|
|
34058
|
-
const nextVisitedConfigPaths = new Set(visitedConfigPaths);
|
|
34059
|
-
nextVisitedConfigPaths.add(tsConfigPath);
|
|
34060
|
-
const configDirectory = Path.dirname(tsConfigPath);
|
|
34061
|
-
return tsConfig.referencePaths.some((referencePath) => {
|
|
34062
|
-
const resolvedReferencePath = Path.resolve(configDirectory, referencePath);
|
|
34063
|
-
const referencedConfigPath = isFile(resolvedReferencePath) ? resolvedReferencePath : Path.join(resolvedReferencePath, TSCONFIG_FILENAME);
|
|
34064
|
-
return isFile(referencedConfigPath) && detectPreES2023FromConfig(referencedConfigPath, nextVisitedConfigPaths);
|
|
34065
|
-
});
|
|
34066
|
-
}
|
|
34067
|
-
return compilerOptionsArePreES2023(compilerOptions);
|
|
34068
|
-
};
|
|
34069
|
-
const FALLBACK_TSCONFIG_FILENAMES = ["tsconfig.app.json", "tsconfig.build.json"];
|
|
34070
|
-
const detectPreES2023Target = (directory) => {
|
|
34071
|
-
const tsConfigPath = Path.join(directory, TSCONFIG_FILENAME);
|
|
34072
|
-
if (isFile(tsConfigPath)) return detectPreES2023FromConfig(tsConfigPath);
|
|
34073
|
-
for (const fallbackFilename of FALLBACK_TSCONFIG_FILENAMES) {
|
|
34074
|
-
const fallbackPath = Path.join(directory, fallbackFilename);
|
|
34075
|
-
if (isFile(fallbackPath)) return detectPreES2023FromConfig(fallbackPath);
|
|
34076
|
-
}
|
|
34077
|
-
return false;
|
|
34078
|
-
};
|
|
34079
|
-
const REACT_DEPENDENCY_NAMES = new Set([
|
|
34080
|
-
"react",
|
|
34081
|
-
"react-native",
|
|
34082
|
-
"next",
|
|
34083
|
-
"preact"
|
|
34084
|
-
]);
|
|
34085
|
-
const hasReactDependency = (packageJson) => {
|
|
34086
|
-
const allDependencies = {
|
|
34087
|
-
...packageJson.peerDependencies,
|
|
34088
|
-
...packageJson.dependencies,
|
|
34089
|
-
...packageJson.devDependencies
|
|
34090
|
-
};
|
|
34091
|
-
return Object.keys(allDependencies).some((packageName) => REACT_DEPENDENCY_NAMES.has(packageName));
|
|
34092
|
-
};
|
|
34093
|
-
const listWorkspacePackages = (rootDirectory) => {
|
|
34094
|
-
const packageJsonPath = Path.join(rootDirectory, "package.json");
|
|
34095
|
-
if (!isFile(packageJsonPath)) return [];
|
|
34096
|
-
const packageJson = readPackageJson(packageJsonPath);
|
|
34097
|
-
const patterns = getWorkspacePatterns(rootDirectory, packageJson);
|
|
34098
|
-
if (patterns.length === 0) return [];
|
|
34099
|
-
const packages = [];
|
|
34100
|
-
const seenDirectories = /* @__PURE__ */ new Set();
|
|
34101
|
-
const pushIfNew = (workspacePackage) => {
|
|
34102
|
-
if (seenDirectories.has(workspacePackage.directory)) return;
|
|
34103
|
-
seenDirectories.add(workspacePackage.directory);
|
|
34104
|
-
packages.push(workspacePackage);
|
|
34105
|
-
};
|
|
34106
|
-
if (hasReactDependency(packageJson)) pushIfNew({
|
|
34107
|
-
name: packageJson.name ?? Path.basename(rootDirectory),
|
|
34108
|
-
directory: rootDirectory
|
|
34109
|
-
});
|
|
34110
|
-
for (const pattern of patterns) {
|
|
34111
|
-
const directories = resolveWorkspaceDirectories(rootDirectory, pattern);
|
|
34112
|
-
for (const workspaceDirectory of directories) {
|
|
34113
|
-
const workspacePackageJson = readPackageJson(Path.join(workspaceDirectory, "package.json"));
|
|
34114
|
-
if (!hasReactDependency(workspacePackageJson)) continue;
|
|
34115
|
-
pushIfNew({
|
|
34116
|
-
name: workspacePackageJson.name ?? Path.basename(workspaceDirectory),
|
|
34117
|
-
directory: workspaceDirectory
|
|
34118
|
-
});
|
|
34119
|
-
}
|
|
34120
|
-
}
|
|
34121
|
-
return packages;
|
|
34122
|
-
};
|
|
34123
34186
|
const toReactWorkspacePackages = (directories) => {
|
|
34124
34187
|
const packages = [];
|
|
34125
34188
|
for (const directory of directories) {
|
|
@@ -34192,14 +34255,13 @@ const clearProjectCache = () => {
|
|
|
34192
34255
|
};
|
|
34193
34256
|
/**
|
|
34194
34257
|
* Build a `ProjectInfo` for a directory that has no `package.json` of
|
|
34195
|
-
* its own — a
|
|
34196
|
-
*
|
|
34197
|
-
*
|
|
34198
|
-
*
|
|
34199
|
-
*
|
|
34200
|
-
*
|
|
34201
|
-
*
|
|
34202
|
-
* nothing to scan (no enclosing project and no source files of its own).
|
|
34258
|
+
* its own — a monorepo subfolder like `repo/packages`, or any loose tree
|
|
34259
|
+
* of TypeScript/JavaScript files. Dependency + framework detection is
|
|
34260
|
+
* inherited from the enclosing workspace root when there is one, so
|
|
34261
|
+
* scanning a subdirectory of a React monorepo still gets the React
|
|
34262
|
+
* capabilities; a standalone non-React directory simply scans with the
|
|
34263
|
+
* framework-agnostic rules. Throws only when the directory has nothing
|
|
34264
|
+
* to scan (no enclosing project and no source files of its own).
|
|
34203
34265
|
*/
|
|
34204
34266
|
const discoverProjectWithoutPackageJson = (directory) => {
|
|
34205
34267
|
const sourceFileCount = countSourceFiles(directory);
|
|
@@ -34237,6 +34299,7 @@ const discoverProjectWithoutPackageJson = (directory) => {
|
|
|
34237
34299
|
hasReanimated: false,
|
|
34238
34300
|
reanimatedVersion: null,
|
|
34239
34301
|
isPreES2023Target: hasOwnTsConfig && detectPreES2023Target(directory),
|
|
34302
|
+
isStaticExport: false,
|
|
34240
34303
|
sourceFileCount
|
|
34241
34304
|
};
|
|
34242
34305
|
};
|
|
@@ -34250,90 +34313,85 @@ const discoverProject = (directory) => {
|
|
|
34250
34313
|
return synthesized;
|
|
34251
34314
|
}
|
|
34252
34315
|
const packageJson = readPackageJson(packageJsonPath);
|
|
34253
|
-
|
|
34254
|
-
|
|
34255
|
-
|
|
34256
|
-
|
|
34257
|
-
|
|
34258
|
-
|
|
34259
|
-
|
|
34260
|
-
|
|
34261
|
-
|
|
34262
|
-
|
|
34263
|
-
|
|
34264
|
-
|
|
34265
|
-
|
|
34266
|
-
|
|
34267
|
-
|
|
34268
|
-
|
|
34269
|
-
|
|
34270
|
-
]
|
|
34271
|
-
});
|
|
34272
|
-
const zodDeclaration = getDependencyDeclaration({
|
|
34316
|
+
const rootInfo = extractDependencyInfo(packageJson);
|
|
34317
|
+
let framework = rootInfo.framework;
|
|
34318
|
+
const tracked = {
|
|
34319
|
+
react: {
|
|
34320
|
+
version: rootInfo.reactVersion,
|
|
34321
|
+
sections: REACT_SECTIONS
|
|
34322
|
+
},
|
|
34323
|
+
tailwindcss: {
|
|
34324
|
+
version: rootInfo.tailwindVersion,
|
|
34325
|
+
sections: TAILWIND_ZOD_SECTIONS
|
|
34326
|
+
},
|
|
34327
|
+
zod: {
|
|
34328
|
+
version: rootInfo.zodVersion,
|
|
34329
|
+
sections: TAILWIND_ZOD_SECTIONS
|
|
34330
|
+
}
|
|
34331
|
+
};
|
|
34332
|
+
const declarations = Object.fromEntries(Object.entries(tracked).map(([packageName, entry]) => [packageName, getDependencyDeclaration({
|
|
34273
34333
|
packageJson,
|
|
34274
|
-
packageName
|
|
34275
|
-
sections:
|
|
34276
|
-
|
|
34277
|
-
|
|
34278
|
-
|
|
34279
|
-
|
|
34280
|
-
|
|
34281
|
-
if (!
|
|
34282
|
-
if (!tailwindVersion && tailwindDeclaration.hasDeclaration) tailwindVersion = resolveCatalogVersion(packageJson, "tailwindcss", directory, tailwindDeclaration.catalogReference);
|
|
34283
|
-
if (!zodVersion && zodDeclaration.hasDeclaration) zodVersion = resolveCatalogVersion(packageJson, "zod", directory, zodDeclaration.catalogReference);
|
|
34284
|
-
if (!reactVersion || !tailwindVersion || !zodVersion) {
|
|
34334
|
+
packageName,
|
|
34335
|
+
sections: entry.sections
|
|
34336
|
+
})]));
|
|
34337
|
+
const fillFromCatalogs = (source, sourceDirectory) => {
|
|
34338
|
+
for (const [packageName, entry] of Object.entries(tracked)) if (!entry.version && declarations[packageName].hasDeclaration) entry.version = resolveCatalogVersion(source, packageName, sourceDirectory, declarations[packageName].catalogReference);
|
|
34339
|
+
};
|
|
34340
|
+
fillFromCatalogs(packageJson, directory);
|
|
34341
|
+
if (!tracked.react.version || !tracked.tailwindcss.version || !tracked.zod.version) {
|
|
34285
34342
|
const monorepoRoot = findMonorepoRoot(directory);
|
|
34286
34343
|
if (monorepoRoot) {
|
|
34287
34344
|
const monorepoPackageJsonPath = Path.join(monorepoRoot, "package.json");
|
|
34288
|
-
if (isFile(monorepoPackageJsonPath))
|
|
34289
|
-
const rootPackageJson = readPackageJson(monorepoPackageJsonPath);
|
|
34290
|
-
if (!reactVersion && reactDeclaration.hasDeclaration) reactVersion = resolveCatalogVersion(rootPackageJson, "react", monorepoRoot, reactDeclaration.catalogReference);
|
|
34291
|
-
if (!tailwindVersion && tailwindDeclaration.hasDeclaration) tailwindVersion = resolveCatalogVersion(rootPackageJson, "tailwindcss", monorepoRoot, tailwindDeclaration.catalogReference);
|
|
34292
|
-
if (!zodVersion && zodDeclaration.hasDeclaration) zodVersion = resolveCatalogVersion(rootPackageJson, "zod", monorepoRoot, zodDeclaration.catalogReference);
|
|
34293
|
-
}
|
|
34345
|
+
if (isFile(monorepoPackageJsonPath)) fillFromCatalogs(readPackageJson(monorepoPackageJsonPath), monorepoRoot);
|
|
34294
34346
|
}
|
|
34295
34347
|
}
|
|
34296
|
-
|
|
34297
|
-
|
|
34298
|
-
|
|
34299
|
-
|
|
34300
|
-
|
|
34301
|
-
|
|
34348
|
+
const shouldCollectReactGroup = !tracked.react.version || framework === "unknown";
|
|
34349
|
+
const workspaceFacts = collectWorkspaceFacts(directory, packageJson, { collectReactGroup: shouldCollectReactGroup });
|
|
34350
|
+
if (shouldCollectReactGroup) {
|
|
34351
|
+
tracked.react.version ||= workspaceFacts.reactVersion;
|
|
34352
|
+
tracked.tailwindcss.version ||= workspaceFacts.tailwindVersion;
|
|
34353
|
+
tracked.zod.version ||= workspaceFacts.zodVersion;
|
|
34354
|
+
if (framework === "unknown" && workspaceFacts.framework !== "unknown") framework = workspaceFacts.framework;
|
|
34302
34355
|
}
|
|
34303
|
-
if ((!
|
|
34356
|
+
if ((!tracked.react.version || framework === "unknown") && !isMonorepoRoot(directory)) {
|
|
34304
34357
|
const monorepoInfo = findDependencyInfoFromMonorepoRoot(directory);
|
|
34305
|
-
|
|
34306
|
-
|
|
34307
|
-
|
|
34358
|
+
tracked.react.version ||= monorepoInfo.reactVersion;
|
|
34359
|
+
tracked.tailwindcss.version ||= monorepoInfo.tailwindVersion;
|
|
34360
|
+
tracked.zod.version ||= monorepoInfo.zodVersion;
|
|
34308
34361
|
if (framework === "unknown") framework = monorepoInfo.framework;
|
|
34309
34362
|
}
|
|
34310
|
-
|
|
34311
|
-
|
|
34312
|
-
|
|
34363
|
+
for (const [packageName, entry] of Object.entries(tracked)) {
|
|
34364
|
+
const declaredVersion = declarations[packageName].version;
|
|
34365
|
+
if (!entry.version && declaredVersion && !isCatalogReference(declaredVersion)) entry.version = declaredVersion;
|
|
34366
|
+
}
|
|
34367
|
+
const { react, tailwindcss, zod } = tracked;
|
|
34368
|
+
let reactVersion = react.version;
|
|
34313
34369
|
if (!reactVersion || parseReactMajor(reactVersion) === null) reactVersion = resolveInstalledReactVersion(directory) ?? reactVersion;
|
|
34370
|
+
const tailwindVersion = tailwindcss.version;
|
|
34371
|
+
const zodVersion = zod.version;
|
|
34314
34372
|
const projectName = packageJson.name ?? Path.basename(directory);
|
|
34315
34373
|
const hasTypeScript = NFS.existsSync(Path.join(directory, "tsconfig.json"));
|
|
34316
34374
|
const sourceFileCount = countSourceFiles(directory);
|
|
34317
|
-
const hasReactNativeWorkspace = framework === "expo" || framework === "react-native" ||
|
|
34375
|
+
const hasReactNativeWorkspace = framework === "expo" || framework === "react-native" || workspaceFacts.hasReactNativeAwarePackage;
|
|
34318
34376
|
const expoVersion = hasReactNativeWorkspace ? resolveCatalogBackedDependencyVersion({
|
|
34319
34377
|
rootDirectory: directory,
|
|
34320
34378
|
rootPackageJson: packageJson,
|
|
34321
34379
|
packageName: "expo",
|
|
34322
|
-
version:
|
|
34380
|
+
version: workspaceFacts.expo.version
|
|
34323
34381
|
}) : null;
|
|
34324
34382
|
const shopifyFlashListVersion = hasReactNativeWorkspace ? resolveCatalogBackedDependencyVersion({
|
|
34325
34383
|
rootDirectory: directory,
|
|
34326
34384
|
rootPackageJson: packageJson,
|
|
34327
34385
|
packageName: SHOPIFY_FLASH_LIST_PACKAGE_NAME,
|
|
34328
|
-
version:
|
|
34386
|
+
version: workspaceFacts.shopifyFlashList.version
|
|
34329
34387
|
}) : null;
|
|
34330
|
-
const hasReanimated = hasReactNativeWorkspace &&
|
|
34331
|
-
const reanimatedVersion = hasReanimated ?
|
|
34388
|
+
const hasReanimated = hasReactNativeWorkspace && workspaceFacts.hasReanimatedAwarePackage;
|
|
34389
|
+
const reanimatedVersion = hasReanimated ? workspaceFacts.reanimatedVersion : null;
|
|
34332
34390
|
const nextjsVersion = framework === "nextjs" ? resolveCatalogBackedDependencyVersion({
|
|
34333
34391
|
rootDirectory: directory,
|
|
34334
34392
|
rootPackageJson: packageJson,
|
|
34335
34393
|
packageName: "next",
|
|
34336
|
-
version:
|
|
34394
|
+
version: workspaceFacts.next.version
|
|
34337
34395
|
}) : null;
|
|
34338
34396
|
const preactVersion = getPreactVersion(packageJson);
|
|
34339
34397
|
const isPreES2023Target = hasTypeScript && detectPreES2023Target(directory);
|
|
@@ -34344,7 +34402,7 @@ const discoverProject = (directory) => {
|
|
|
34344
34402
|
reactMajorVersion: resolveEffectiveReactMajor(reactVersion, packageJson),
|
|
34345
34403
|
tailwindVersion,
|
|
34346
34404
|
zodVersion,
|
|
34347
|
-
zodMajorVersion:
|
|
34405
|
+
zodMajorVersion: zodVersion === null ? null : getLowestDependencyMajor(zodVersion),
|
|
34348
34406
|
framework,
|
|
34349
34407
|
hasTypeScript,
|
|
34350
34408
|
hasReactCompiler: detectReactCompiler(directory, packageJson),
|
|
@@ -34360,6 +34418,7 @@ const discoverProject = (directory) => {
|
|
|
34360
34418
|
hasReanimated,
|
|
34361
34419
|
reanimatedVersion,
|
|
34362
34420
|
isPreES2023Target,
|
|
34421
|
+
isStaticExport: framework === "nextjs" && detectNextjsStaticExport(workspaceFacts.next.sourceDirectory ?? directory),
|
|
34363
34422
|
sourceFileCount
|
|
34364
34423
|
};
|
|
34365
34424
|
cachedProjectInfos.set(directory, projectInfo);
|
|
@@ -34375,57 +34434,6 @@ const discoverProject = (directory) => {
|
|
|
34375
34434
|
* single source file has nothing to analyze.
|
|
34376
34435
|
*/
|
|
34377
34436
|
const isAnalyzableProject = (project) => project.reactVersion !== null || project.preactVersion !== null || project.sourceFileCount > 0;
|
|
34378
|
-
const MAJOR_MINOR_PATTERN = /(\d{1,4})\.(\d{1,4})/;
|
|
34379
|
-
const MAJOR_ONLY_PATTERN = /(\d{1,4})/;
|
|
34380
|
-
const UPPER_BOUND_COMPARATOR_PATTERN = /<=?\s{0,8}\d{1,4}(?:\.\d{1,4}){0,2}(?:-[^\s,|]+)?/g;
|
|
34381
|
-
const parseReactMajorMinor = (reactVersion) => {
|
|
34382
|
-
if (typeof reactVersion !== "string") return null;
|
|
34383
|
-
const trimmed = reactVersion.trim();
|
|
34384
|
-
if (trimmed.length === 0) return null;
|
|
34385
|
-
const lowerBoundsOnly = trimmed.replace(UPPER_BOUND_COMPARATOR_PATTERN, " ").trim();
|
|
34386
|
-
if (lowerBoundsOnly.length === 0) return null;
|
|
34387
|
-
const majorMinorMatch = lowerBoundsOnly.match(MAJOR_MINOR_PATTERN);
|
|
34388
|
-
if (majorMinorMatch) {
|
|
34389
|
-
const major = Number.parseInt(majorMinorMatch[1], 10);
|
|
34390
|
-
const minor = Number.parseInt(majorMinorMatch[2], 10);
|
|
34391
|
-
if (!Number.isFinite(major) || major <= 0) return null;
|
|
34392
|
-
if (!Number.isFinite(minor) || minor < 0) return null;
|
|
34393
|
-
return {
|
|
34394
|
-
major,
|
|
34395
|
-
minor
|
|
34396
|
-
};
|
|
34397
|
-
}
|
|
34398
|
-
const majorOnlyMatch = lowerBoundsOnly.match(MAJOR_ONLY_PATTERN);
|
|
34399
|
-
if (!majorOnlyMatch) return null;
|
|
34400
|
-
const major = Number.parseInt(majorOnlyMatch[1], 10);
|
|
34401
|
-
if (!Number.isFinite(major) || major <= 0) return null;
|
|
34402
|
-
return {
|
|
34403
|
-
major,
|
|
34404
|
-
minor: 0
|
|
34405
|
-
};
|
|
34406
|
-
};
|
|
34407
|
-
const isReactAtLeast = (detected, required) => {
|
|
34408
|
-
if (detected === null) return true;
|
|
34409
|
-
if (detected.major !== required.major) return detected.major > required.major;
|
|
34410
|
-
return detected.minor >= required.minor;
|
|
34411
|
-
};
|
|
34412
|
-
const parseLowerBoundVersion = (versionSpec) => import_semver.validRange(versionSpec) !== null ? import_semver.minVersion(versionSpec) : import_semver.coerce(versionSpec);
|
|
34413
|
-
const parseTailwindMajorMinor = (tailwindVersion) => {
|
|
34414
|
-
if (typeof tailwindVersion !== "string") return null;
|
|
34415
|
-
const trimmed = tailwindVersion.trim();
|
|
34416
|
-
if (trimmed.length === 0) return null;
|
|
34417
|
-
const lowerBound = parseLowerBoundVersion(trimmed);
|
|
34418
|
-
if (lowerBound === null || lowerBound.major <= 0) return null;
|
|
34419
|
-
return {
|
|
34420
|
-
major: lowerBound.major,
|
|
34421
|
-
minor: lowerBound.minor
|
|
34422
|
-
};
|
|
34423
|
-
};
|
|
34424
|
-
const isTailwindAtLeast = (detected, required) => {
|
|
34425
|
-
if (detected === null) return true;
|
|
34426
|
-
if (detected.major !== required.major) return detected.major > required.major;
|
|
34427
|
-
return detected.minor >= required.minor;
|
|
34428
|
-
};
|
|
34429
34437
|
const messageFromUnknown = (error) => error instanceof Error ? error.message : String(error);
|
|
34430
34438
|
var InvalidGlobPatternError = class extends Error {
|
|
34431
34439
|
pattern;
|
|
@@ -37201,64 +37209,64 @@ function* collectSecurityScanFiles(rootDirectory) {
|
|
|
37201
37209
|
}
|
|
37202
37210
|
}
|
|
37203
37211
|
}
|
|
37204
|
-
|
|
37205
|
-
|
|
37206
|
-
|
|
37207
|
-
|
|
37208
|
-
|
|
37209
|
-
|
|
37210
|
-
|
|
37212
|
+
const CLIENT_ONLY_FRAMEWORKS = new Set([
|
|
37213
|
+
"vite",
|
|
37214
|
+
"cra",
|
|
37215
|
+
"gatsby",
|
|
37216
|
+
"react-native",
|
|
37217
|
+
"expo"
|
|
37218
|
+
]);
|
|
37219
|
+
const addMajorLadder = (capabilities, name, major, earliest, latest) => {
|
|
37220
|
+
if (major === null) return;
|
|
37221
|
+
const cappedMajor = Math.min(major, latest);
|
|
37222
|
+
for (let candidate = earliest; candidate <= cappedMajor; candidate += 1) capabilities.add(`${name}:${candidate}`);
|
|
37223
|
+
};
|
|
37211
37224
|
const buildCapabilities = (project) => {
|
|
37212
37225
|
const capabilities = /* @__PURE__ */ new Set();
|
|
37213
37226
|
capabilities.add(project.framework);
|
|
37214
|
-
if (
|
|
37227
|
+
if (project.reactVersion !== null || project.preactVersion !== null) capabilities.add("react");
|
|
37215
37228
|
if (project.framework === "expo" || project.framework === "react-native" || project.hasReactNativeWorkspace) capabilities.add("react-native");
|
|
37216
37229
|
if (project.expoVersion !== null) capabilities.add("expo");
|
|
37230
|
+
if ((project.framework === "nextjs" || project.framework === "tanstack-start" || project.framework === "remix") && !project.isStaticExport) capabilities.add("server-actions");
|
|
37231
|
+
if (CLIENT_ONLY_FRAMEWORKS.has(project.framework)) capabilities.add("client-only");
|
|
37232
|
+
if (project.isStaticExport) capabilities.add("nextjs:static-export");
|
|
37217
37233
|
if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 15) capabilities.add("nextjs:15");
|
|
37218
|
-
|
|
37219
|
-
if (
|
|
37220
|
-
|
|
37221
|
-
|
|
37222
|
-
|
|
37223
|
-
|
|
37224
|
-
|
|
37225
|
-
|
|
37226
|
-
|
|
37227
|
-
|
|
37228
|
-
|
|
37229
|
-
if (project.
|
|
37230
|
-
capabilities.add("tailwind");
|
|
37231
|
-
if (isTailwindAtLeast(parseTailwindMajorMinor(project.tailwindVersion), {
|
|
37232
|
-
major: 3,
|
|
37233
|
-
minor: 4
|
|
37234
|
-
})) capabilities.add("tailwind:3.4");
|
|
37235
|
-
}
|
|
37236
|
-
if (project.zodVersion !== null) {
|
|
37237
|
-
capabilities.add("zod");
|
|
37238
|
-
if (project.zodMajorVersion !== null && project.zodMajorVersion >= 4) capabilities.add("zod:4");
|
|
37239
|
-
}
|
|
37234
|
+
addMajorLadder(capabilities, "react", project.reactMajorVersion, 17, 30);
|
|
37235
|
+
if (project.reactMajorVersion !== null && project.reactMajorVersion >= 19 && isMajorMinorAtLeast(parseReactMajorMinor(project.reactVersion), {
|
|
37236
|
+
major: 19,
|
|
37237
|
+
minor: 2
|
|
37238
|
+
})) capabilities.add("react:19.2");
|
|
37239
|
+
if (project.tailwindVersion !== null) capabilities.add("tailwind");
|
|
37240
|
+
if (project.tailwindVersion !== null && isMajorMinorAtLeast(parseTailwindMajorMinor(project.tailwindVersion), {
|
|
37241
|
+
major: 3,
|
|
37242
|
+
minor: 4
|
|
37243
|
+
})) capabilities.add("tailwind:3.4");
|
|
37244
|
+
if (project.zodVersion !== null) capabilities.add("zod");
|
|
37245
|
+
if (project.zodMajorVersion !== null && project.zodMajorVersion >= 4) capabilities.add("zod:4");
|
|
37240
37246
|
if (project.isPreES2023Target) capabilities.add("pre-es2023");
|
|
37241
37247
|
if (project.hasReactCompiler) capabilities.add("react-compiler");
|
|
37242
37248
|
if (project.hasTanStackQuery) capabilities.add("tanstack-query");
|
|
37243
37249
|
if (project.hasTypeScript) capabilities.add("typescript");
|
|
37244
|
-
if (project.preactVersion !== null)
|
|
37245
|
-
|
|
37246
|
-
|
|
37247
|
-
|
|
37248
|
-
|
|
37249
|
-
|
|
37250
|
-
|
|
37251
|
-
|
|
37252
|
-
|
|
37250
|
+
if (project.preactVersion !== null) capabilities.add("preact");
|
|
37251
|
+
addMajorLadder(capabilities, "preact", project.preactMajorVersion, 10, 20);
|
|
37252
|
+
if (project.preactVersion !== null && project.reactVersion === null) capabilities.add("pure-preact");
|
|
37253
|
+
return capabilities;
|
|
37254
|
+
};
|
|
37255
|
+
const capabilitiesByProject = /* @__PURE__ */ new WeakMap();
|
|
37256
|
+
const getCapabilities = (project) => {
|
|
37257
|
+
const cached = capabilitiesByProject.get(project);
|
|
37258
|
+
if (cached !== void 0) return cached;
|
|
37259
|
+
const capabilities = buildCapabilities(project);
|
|
37260
|
+
capabilitiesByProject.set(project, capabilities);
|
|
37253
37261
|
return capabilities;
|
|
37254
37262
|
};
|
|
37255
|
-
const shouldEnableRule = (requires, tags, capabilities, ignoredTags,
|
|
37263
|
+
const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen) => {
|
|
37256
37264
|
if (requires) {
|
|
37257
37265
|
for (const capability of requires) if (!capabilities.has(capability)) return false;
|
|
37258
37266
|
}
|
|
37259
37267
|
if (tags?.includes("react-jsx-only") && !capabilities.has("react")) return false;
|
|
37260
|
-
if (
|
|
37261
|
-
for (const capability of
|
|
37268
|
+
if (disabledWhen) {
|
|
37269
|
+
for (const capability of disabledWhen) if (capabilities.has(capability)) return false;
|
|
37262
37270
|
}
|
|
37263
37271
|
if (tags) {
|
|
37264
37272
|
for (const tag of tags) if (ignoredTags.has(tag)) return false;
|
|
@@ -37269,14 +37277,14 @@ const yieldToEventLoop = () => new Promise((resolve) => {
|
|
|
37269
37277
|
setImmediate(resolve);
|
|
37270
37278
|
});
|
|
37271
37279
|
const createSecurityScanSession = (rootDirectory, options) => {
|
|
37272
|
-
const capabilities = options.project ?
|
|
37280
|
+
const capabilities = options.project ? getCapabilities(options.project) : /* @__PURE__ */ new Set();
|
|
37273
37281
|
const ignoredTags = options.ignoredTags ?? /* @__PURE__ */ new Set();
|
|
37274
37282
|
const enabledScanRules = REACT_DOCTOR_RULES.flatMap((entry) => {
|
|
37275
37283
|
const rule = entry.rule;
|
|
37276
37284
|
const scan = rule.scan;
|
|
37277
37285
|
if (typeof scan !== "function") return [];
|
|
37278
37286
|
if (rule.defaultEnabled === false) return [];
|
|
37279
|
-
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.
|
|
37287
|
+
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) return [];
|
|
37280
37288
|
return [{
|
|
37281
37289
|
entry,
|
|
37282
37290
|
scan,
|
|
@@ -37296,6 +37304,7 @@ const createSecurityScanSession = (rootDirectory, options) => {
|
|
|
37296
37304
|
return status === true;
|
|
37297
37305
|
};
|
|
37298
37306
|
const scanFileByRule = function* (file) {
|
|
37307
|
+
if (file === null) return;
|
|
37299
37308
|
for (const { entry, scan, committedFilesOnly } of enabledScanRules) {
|
|
37300
37309
|
for (const finding of scan(file)) {
|
|
37301
37310
|
if (committedFilesOnly && isFileGitIgnored(file)) continue;
|
|
@@ -39176,7 +39185,7 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
39176
39185
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
39177
39186
|
const jsPlugins = [];
|
|
39178
39187
|
if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
|
|
39179
|
-
const capabilities =
|
|
39188
|
+
const capabilities = getCapabilities(project);
|
|
39180
39189
|
const enabledReactDoctorRules = {};
|
|
39181
39190
|
for (const registryEntry of REACT_DOCTOR_RULES) {
|
|
39182
39191
|
const rule = reactDoctorPlugin.rules[registryEntry.id];
|
|
@@ -39187,7 +39196,7 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
39187
39196
|
if (rule.scan !== void 0) continue;
|
|
39188
39197
|
if (customRulesOnly && registryEntry.originallyExternal) continue;
|
|
39189
39198
|
if (rule.framework !== "global" && !rule.requires) continue;
|
|
39190
|
-
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.
|
|
39199
|
+
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) continue;
|
|
39191
39200
|
const explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey: registryEntry.key }, severityControls);
|
|
39192
39201
|
if (rule.defaultEnabled === false && explicitRuleOverride === void 0) continue;
|
|
39193
39202
|
const severity = resolveRuleSeverityOverride({
|
|
@@ -39218,6 +39227,7 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
39218
39227
|
settings: { "react-doctor": {
|
|
39219
39228
|
framework: project.framework,
|
|
39220
39229
|
rootDirectory: resolveSettingsRootDirectory(project.rootDirectory),
|
|
39230
|
+
capabilities: [...capabilities].sort(),
|
|
39221
39231
|
...project.shopifyFlashListMajorVersion !== null ? { shopifyFlashListMajorVersion: project.shopifyFlashListMajorVersion } : {},
|
|
39222
39232
|
...serverAuthFunctionNames && serverAuthFunctionNames.length > 0 ? { serverAuthFunctionNames: [...serverAuthFunctionNames] } : {}
|
|
39223
39233
|
} },
|
|
@@ -39508,21 +39518,6 @@ const mapWithConcurrency = async (items, concurrency, task) => {
|
|
|
39508
39518
|
if (errors.length > 0) throw errors[0];
|
|
39509
39519
|
return results;
|
|
39510
39520
|
};
|
|
39511
|
-
const getPublicEnvPrefix = (framework) => {
|
|
39512
|
-
switch (framework) {
|
|
39513
|
-
case "nextjs": return "NEXT_PUBLIC_*";
|
|
39514
|
-
case "vite":
|
|
39515
|
-
case "tanstack-start": return "VITE_*";
|
|
39516
|
-
case "cra": return "REACT_APP_*";
|
|
39517
|
-
case "gatsby": return "GATSBY_*";
|
|
39518
|
-
default: return null;
|
|
39519
|
-
}
|
|
39520
|
-
};
|
|
39521
|
-
const buildNoSecretsRecommendation = (project, fallbackRecommendation) => {
|
|
39522
|
-
const publicEnvPrefix = getPublicEnvPrefix(project.framework);
|
|
39523
|
-
if (!publicEnvPrefix) return fallbackRecommendation;
|
|
39524
|
-
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`;
|
|
39525
|
-
};
|
|
39526
39521
|
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";
|
|
39527
39522
|
const ACCESSORS_MIN_VERSION = "3.15.0";
|
|
39528
39523
|
const supportsAccessors = (reanimatedVersion) => {
|
|
@@ -40203,8 +40198,14 @@ const PLUGIN_CATEGORY_MAP = {
|
|
|
40203
40198
|
};
|
|
40204
40199
|
const lookupOwnString = (record, key) => Object.hasOwn(record, key) ? record[key] : void 0;
|
|
40205
40200
|
const getRuleRecommendation = (ruleName, project) => {
|
|
40206
|
-
|
|
40207
|
-
return
|
|
40201
|
+
const rule = reactDoctorPlugin.rules[ruleName];
|
|
40202
|
+
if (!rule) return void 0;
|
|
40203
|
+
if (rule.recommendationFor) {
|
|
40204
|
+
const capabilities = getCapabilities(project);
|
|
40205
|
+
const conditionalRecommendation = rule.recommendationFor((capability) => capabilities.has(capability));
|
|
40206
|
+
if (conditionalRecommendation !== void 0) return conditionalRecommendation;
|
|
40207
|
+
}
|
|
40208
|
+
return rule.recommendation;
|
|
40208
40209
|
};
|
|
40209
40210
|
const getRuleCategory = (ruleName) => reactDoctorPlugin.rules[ruleName]?.category;
|
|
40210
40211
|
const getRuleTitle = (ruleName) => reactDoctorPlugin.rules[ruleName]?.title;
|
|
@@ -42529,6 +42530,13 @@ const summarizeDiagnostics = (diagnostics, worstScore = null, worstScoreLabel =
|
|
|
42529
42530
|
scoreLabel: worstScoreLabel
|
|
42530
42531
|
};
|
|
42531
42532
|
};
|
|
42533
|
+
/**
|
|
42534
|
+
* Whether project discovery resolved a React-compatible runtime (React or
|
|
42535
|
+
* Preact, which ships the same hooks + JSX model). This is the same
|
|
42536
|
+
* predicate that grants the `react` capability, so `false` means every
|
|
42537
|
+
* React-runtime rule family was gated off for the project.
|
|
42538
|
+
*/
|
|
42539
|
+
const hasReactRuntime = (project) => project.reactVersion !== null || project.preactVersion !== null;
|
|
42532
42540
|
const toJsonDiff = (diff) => {
|
|
42533
42541
|
if (!diff) return null;
|
|
42534
42542
|
return {
|
|
@@ -42895,4 +42903,4 @@ const toJsonReport = (result, options) => buildJsonReport({
|
|
|
42895
42903
|
export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
|
|
42896
42904
|
|
|
42897
42905
|
//# sourceMappingURL=index.js.map
|
|
42898
|
-
//# debugId=
|
|
42906
|
+
//# debugId=7b7e0da8-d676-570d-b0e2-7fc3a4fe85ab
|