react-doctor 0.7.2-dev.aa519e5 → 0.7.2-dev.cb8f726
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 +690 -660
- package/dist/lsp.js +769 -768
- package/package.json +3 -3
package/dist/lsp.js
CHANGED
|
@@ -32827,6 +32827,25 @@ var AmbiguousProjectError = class extends Error {
|
|
|
32827
32827
|
}
|
|
32828
32828
|
};
|
|
32829
32829
|
const isProjectDiscoveryError = (value) => value instanceof ProjectNotFoundError || value instanceof NoReactDependencyError || value instanceof PackageJsonNotFoundError || value instanceof NotADirectoryError || value instanceof AmbiguousProjectError;
|
|
32830
|
+
const isErrnoException = (error) => error instanceof Error && "code" in error;
|
|
32831
|
+
const IGNORABLE_READDIR_ERROR_CODES = new Set([
|
|
32832
|
+
"EACCES",
|
|
32833
|
+
"EPERM",
|
|
32834
|
+
"ENOENT",
|
|
32835
|
+
"ENOTDIR",
|
|
32836
|
+
"EINVAL",
|
|
32837
|
+
"ELOOP",
|
|
32838
|
+
"ENAMETOOLONG"
|
|
32839
|
+
]);
|
|
32840
|
+
const isIgnorableReaddirError = (error) => isErrnoException(error) && typeof error.code === "string" && IGNORABLE_READDIR_ERROR_CODES.has(error.code);
|
|
32841
|
+
const readDirectoryEntries = (directoryPath) => {
|
|
32842
|
+
try {
|
|
32843
|
+
return NFS.readdirSync(directoryPath, { withFileTypes: true });
|
|
32844
|
+
} catch (error) {
|
|
32845
|
+
if (isIgnorableReaddirError(error)) return [];
|
|
32846
|
+
throw error;
|
|
32847
|
+
}
|
|
32848
|
+
};
|
|
32830
32849
|
const isFile = (filePath) => {
|
|
32831
32850
|
try {
|
|
32832
32851
|
return NFS.statSync(filePath).isFile();
|
|
@@ -32834,6 +32853,18 @@ const isFile = (filePath) => {
|
|
|
32834
32853
|
return false;
|
|
32835
32854
|
}
|
|
32836
32855
|
};
|
|
32856
|
+
const isDirectory = (directoryPath) => {
|
|
32857
|
+
try {
|
|
32858
|
+
return NFS.statSync(directoryPath).isDirectory();
|
|
32859
|
+
} catch {
|
|
32860
|
+
return false;
|
|
32861
|
+
}
|
|
32862
|
+
};
|
|
32863
|
+
const isPlainObject = (value) => {
|
|
32864
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
32865
|
+
const prototype = Object.getPrototypeOf(value);
|
|
32866
|
+
return prototype === null || prototype === Object.prototype;
|
|
32867
|
+
};
|
|
32837
32868
|
const SOURCE_FILE_PATTERN = /\.(tsx?|jsx?|mts|mjs)$/;
|
|
32838
32869
|
const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
|
|
32839
32870
|
const GENERATED_SOURCE_DIRECTORY_PATTERN = /(?:^|\/)__generated__\//;
|
|
@@ -33053,25 +33084,6 @@ const isLargeMinifiedFile = (absolutePath, knownSizeBytes) => {
|
|
|
33053
33084
|
cachedIsLargeMinifiedByPath.set(absolutePath, result);
|
|
33054
33085
|
return result;
|
|
33055
33086
|
};
|
|
33056
|
-
const isErrnoException = (error) => error instanceof Error && "code" in error;
|
|
33057
|
-
const IGNORABLE_READDIR_ERROR_CODES = new Set([
|
|
33058
|
-
"EACCES",
|
|
33059
|
-
"EPERM",
|
|
33060
|
-
"ENOENT",
|
|
33061
|
-
"ENOTDIR",
|
|
33062
|
-
"EINVAL",
|
|
33063
|
-
"ELOOP",
|
|
33064
|
-
"ENAMETOOLONG"
|
|
33065
|
-
]);
|
|
33066
|
-
const isIgnorableReaddirError = (error) => isErrnoException(error) && typeof error.code === "string" && IGNORABLE_READDIR_ERROR_CODES.has(error.code);
|
|
33067
|
-
const readDirectoryEntries = (directoryPath) => {
|
|
33068
|
-
try {
|
|
33069
|
-
return NFS.readdirSync(directoryPath, { withFileTypes: true });
|
|
33070
|
-
} catch (error) {
|
|
33071
|
-
if (isIgnorableReaddirError(error)) return [];
|
|
33072
|
-
throw error;
|
|
33073
|
-
}
|
|
33074
|
-
};
|
|
33075
33087
|
function* walkSourceTreeFiles(rootDirectory) {
|
|
33076
33088
|
const stack = [rootDirectory];
|
|
33077
33089
|
while (stack.length > 0) {
|
|
@@ -33126,23 +33138,6 @@ const listSourceFilesViaFilesystem = (rootDirectory) => {
|
|
|
33126
33138
|
const listSourceFilesWithSize = (rootDirectory) => collectSizedSourceFiles(rootDirectory, (listSourceFilesViaGit(rootDirectory) ?? listSourceFilesViaFilesystem(rootDirectory)).sort());
|
|
33127
33139
|
const listSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).map((entry) => entry.path);
|
|
33128
33140
|
const countSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).length;
|
|
33129
|
-
/**
|
|
33130
|
-
* The chain of ancestor directories of `startDirectory`, nearest first, up to
|
|
33131
|
-
* and including the filesystem root. With `includeStart`, the chain begins at
|
|
33132
|
-
* `startDirectory` itself; otherwise at its parent. The one place the "walk up
|
|
33133
|
-
* the tree" traversal is expressed, so each caller adds only its own match /
|
|
33134
|
-
* stop policy instead of re-deriving the `path.dirname` loop.
|
|
33135
|
-
*/
|
|
33136
|
-
const ancestorDirectories = (startDirectory, { includeStart }) => {
|
|
33137
|
-
const directories = [];
|
|
33138
|
-
let currentDirectory = includeStart ? startDirectory : Path.dirname(startDirectory);
|
|
33139
|
-
while (true) {
|
|
33140
|
-
directories.push(currentDirectory);
|
|
33141
|
-
const parentDirectory = Path.dirname(currentDirectory);
|
|
33142
|
-
if (parentDirectory === currentDirectory) return directories;
|
|
33143
|
-
currentDirectory = parentDirectory;
|
|
33144
|
-
}
|
|
33145
|
-
};
|
|
33146
33141
|
const cachedPackageJsons = /* @__PURE__ */ new Map();
|
|
33147
33142
|
const clearPackageJsonCache = () => {
|
|
33148
33143
|
cachedPackageJsons.clear();
|
|
@@ -33176,7 +33171,11 @@ const isMonorepoRoot = (directory) => {
|
|
|
33176
33171
|
return Array.isArray(packageJson.workspaces) || Boolean(packageJson.workspaces?.packages);
|
|
33177
33172
|
};
|
|
33178
33173
|
const findMonorepoRoot = (startDirectory) => {
|
|
33179
|
-
|
|
33174
|
+
let currentDirectory = Path.dirname(startDirectory);
|
|
33175
|
+
while (currentDirectory !== Path.dirname(currentDirectory)) {
|
|
33176
|
+
if (isMonorepoRoot(currentDirectory)) return currentDirectory;
|
|
33177
|
+
currentDirectory = Path.dirname(currentDirectory);
|
|
33178
|
+
}
|
|
33180
33179
|
return null;
|
|
33181
33180
|
};
|
|
33182
33181
|
/**
|
|
@@ -33190,6 +33189,146 @@ const findMonorepoRoot = (startDirectory) => {
|
|
|
33190
33189
|
* byte-equivalent copy.
|
|
33191
33190
|
*/
|
|
33192
33191
|
const isProjectBoundary = (directory) => NFS.existsSync(Path.join(directory, ".git")) || isMonorepoRoot(directory);
|
|
33192
|
+
const TSCONFIG_FILENAME = "tsconfig.json";
|
|
33193
|
+
const isRelativeExtendsValue = (extendsValue) => extendsValue.startsWith("./") || extendsValue.startsWith("../") || Path.isAbsolute(extendsValue);
|
|
33194
|
+
const ensureJsonExtension = (filePath) => Path.extname(filePath) === "" ? `${filePath}.json` : filePath;
|
|
33195
|
+
const resolvePackageExtendsPath = (extendsValue, fromConfigDirectory) => {
|
|
33196
|
+
const requireFromConfig = createRequire(Path.join(fromConfigDirectory, "tsconfig.json"));
|
|
33197
|
+
const candidates = [
|
|
33198
|
+
extendsValue,
|
|
33199
|
+
ensureJsonExtension(extendsValue),
|
|
33200
|
+
`${extendsValue.replace(/\/$/, "")}/tsconfig.json`
|
|
33201
|
+
];
|
|
33202
|
+
for (const candidate of candidates) try {
|
|
33203
|
+
return requireFromConfig.resolve(candidate);
|
|
33204
|
+
} catch {
|
|
33205
|
+
continue;
|
|
33206
|
+
}
|
|
33207
|
+
return null;
|
|
33208
|
+
};
|
|
33209
|
+
const resolveExtendsPath = (extendsValue, fromConfigDirectory) => {
|
|
33210
|
+
if (isRelativeExtendsValue(extendsValue)) return ensureJsonExtension(Path.resolve(fromConfigDirectory, extendsValue));
|
|
33211
|
+
return resolvePackageExtendsPath(extendsValue, fromConfigDirectory);
|
|
33212
|
+
};
|
|
33213
|
+
const normalizeCompilerOptions = (compilerOptions) => {
|
|
33214
|
+
if (!isPlainObject(compilerOptions)) return { hasExplicitLib: false };
|
|
33215
|
+
const target = typeof compilerOptions.target === "string" ? compilerOptions.target : void 0;
|
|
33216
|
+
const hasExplicitLib = Object.hasOwn(compilerOptions, "lib");
|
|
33217
|
+
return {
|
|
33218
|
+
target,
|
|
33219
|
+
lib: Array.isArray(compilerOptions.lib) ? compilerOptions.lib.filter((entry) => typeof entry === "string") : void 0,
|
|
33220
|
+
hasExplicitLib
|
|
33221
|
+
};
|
|
33222
|
+
};
|
|
33223
|
+
const readTsConfig = (filePath) => {
|
|
33224
|
+
let content;
|
|
33225
|
+
try {
|
|
33226
|
+
content = NFS.readFileSync(filePath, "utf-8");
|
|
33227
|
+
} catch {
|
|
33228
|
+
return null;
|
|
33229
|
+
}
|
|
33230
|
+
const parsed = ts.parseConfigFileTextToJson(filePath, content);
|
|
33231
|
+
if (!isPlainObject(parsed.config)) return null;
|
|
33232
|
+
return {
|
|
33233
|
+
extends: typeof parsed.config.extends === "string" ? parsed.config.extends : void 0,
|
|
33234
|
+
referencePaths: normalizeReferencePaths(parsed.config.references),
|
|
33235
|
+
compilerOptions: normalizeCompilerOptions(parsed.config.compilerOptions)
|
|
33236
|
+
};
|
|
33237
|
+
};
|
|
33238
|
+
const normalizeReferencePaths = (references) => {
|
|
33239
|
+
if (!Array.isArray(references)) return [];
|
|
33240
|
+
return references.map((reference) => isPlainObject(reference) && typeof reference.path === "string" ? reference.path : null).filter((referencePath) => referencePath !== null);
|
|
33241
|
+
};
|
|
33242
|
+
const mergeCompilerOptions = (inherited, current) => {
|
|
33243
|
+
const target = current.target ?? inherited?.target;
|
|
33244
|
+
const hasExplicitLib = current.hasExplicitLib || Boolean(inherited?.hasExplicitLib);
|
|
33245
|
+
return {
|
|
33246
|
+
target,
|
|
33247
|
+
lib: current.hasExplicitLib ? current.lib : inherited?.lib,
|
|
33248
|
+
hasExplicitLib
|
|
33249
|
+
};
|
|
33250
|
+
};
|
|
33251
|
+
const readResolvedCompilerOptions = (tsConfigPath, extendsDepth, visitedPaths) => {
|
|
33252
|
+
const realPath = NFS.realpathSync.native(tsConfigPath);
|
|
33253
|
+
if (visitedPaths.has(realPath)) return null;
|
|
33254
|
+
const tsConfig = readTsConfig(realPath);
|
|
33255
|
+
if (!tsConfig) return null;
|
|
33256
|
+
const nextVisitedPaths = new Set(visitedPaths);
|
|
33257
|
+
nextVisitedPaths.add(realPath);
|
|
33258
|
+
if (tsConfig.extends && extendsDepth < 8) {
|
|
33259
|
+
const parentPath = resolveExtendsPath(tsConfig.extends, Path.dirname(realPath));
|
|
33260
|
+
if (parentPath && isFile(parentPath)) return mergeCompilerOptions(readResolvedCompilerOptions(parentPath, extendsDepth + 1, nextVisitedPaths), tsConfig.compilerOptions);
|
|
33261
|
+
}
|
|
33262
|
+
return tsConfig.compilerOptions;
|
|
33263
|
+
};
|
|
33264
|
+
const targetYearIsPreES2023 = (target) => {
|
|
33265
|
+
const year = ES_TARGET_YEAR_BY_NAME[target.toLowerCase()];
|
|
33266
|
+
return year !== void 0 && year < 2023;
|
|
33267
|
+
};
|
|
33268
|
+
const libEntryIncludesES2023Array = (entry) => {
|
|
33269
|
+
const normalizedEntry = entry.toLowerCase();
|
|
33270
|
+
if (normalizedEntry === "esnext" || normalizedEntry === "esnext.array") return true;
|
|
33271
|
+
const esYearMatch = /^es(\d{4})(?:\.(.+))?$/.exec(normalizedEntry);
|
|
33272
|
+
if (!esYearMatch) return false;
|
|
33273
|
+
if (Number(esYearMatch[1]) < 2023) return false;
|
|
33274
|
+
const component = esYearMatch[2];
|
|
33275
|
+
return component === void 0 || component === "array";
|
|
33276
|
+
};
|
|
33277
|
+
const libIncludesES2023 = (lib) => lib.some(libEntryIncludesES2023Array);
|
|
33278
|
+
const compilerOptionsArePreES2023 = (compilerOptions) => {
|
|
33279
|
+
if (compilerOptions.target) return targetYearIsPreES2023(compilerOptions.target);
|
|
33280
|
+
if (compilerOptions.hasExplicitLib) return !libIncludesES2023(compilerOptions.lib ?? []);
|
|
33281
|
+
return false;
|
|
33282
|
+
};
|
|
33283
|
+
const compilerOptionsDeclareTargetOrLib = (compilerOptions) => compilerOptions.hasExplicitLib || compilerOptions.target !== void 0;
|
|
33284
|
+
const detectPreES2023FromConfig = (tsConfigPath, visitedConfigPaths = /* @__PURE__ */ new Set()) => {
|
|
33285
|
+
if (visitedConfigPaths.has(tsConfigPath)) return false;
|
|
33286
|
+
const compilerOptions = readResolvedCompilerOptions(tsConfigPath, 0, /* @__PURE__ */ new Set());
|
|
33287
|
+
if (!compilerOptions) return false;
|
|
33288
|
+
if (!compilerOptionsDeclareTargetOrLib(compilerOptions)) {
|
|
33289
|
+
const tsConfig = readTsConfig(tsConfigPath);
|
|
33290
|
+
if (!tsConfig) return false;
|
|
33291
|
+
const nextVisitedConfigPaths = new Set(visitedConfigPaths);
|
|
33292
|
+
nextVisitedConfigPaths.add(tsConfigPath);
|
|
33293
|
+
const configDirectory = Path.dirname(tsConfigPath);
|
|
33294
|
+
return tsConfig.referencePaths.some((referencePath) => {
|
|
33295
|
+
const resolvedReferencePath = Path.resolve(configDirectory, referencePath);
|
|
33296
|
+
const referencedConfigPath = isFile(resolvedReferencePath) ? resolvedReferencePath : Path.join(resolvedReferencePath, TSCONFIG_FILENAME);
|
|
33297
|
+
return isFile(referencedConfigPath) && detectPreES2023FromConfig(referencedConfigPath, nextVisitedConfigPaths);
|
|
33298
|
+
});
|
|
33299
|
+
}
|
|
33300
|
+
return compilerOptionsArePreES2023(compilerOptions);
|
|
33301
|
+
};
|
|
33302
|
+
const detectPreES2023Target = (directory) => {
|
|
33303
|
+
const tsConfigPath = Path.join(directory, TSCONFIG_FILENAME);
|
|
33304
|
+
if (isFile(tsConfigPath)) return detectPreES2023FromConfig(tsConfigPath);
|
|
33305
|
+
for (const fallbackFilename of FALLBACK_TSCONFIG_FILENAMES) {
|
|
33306
|
+
const fallbackPath = Path.join(directory, fallbackFilename);
|
|
33307
|
+
if (isFile(fallbackPath)) return detectPreES2023FromConfig(fallbackPath);
|
|
33308
|
+
}
|
|
33309
|
+
return false;
|
|
33310
|
+
};
|
|
33311
|
+
const FALLBACK_TSCONFIG_FILENAMES = ["tsconfig.app.json", "tsconfig.build.json"];
|
|
33312
|
+
const FRAMEWORK_PACKAGES = {
|
|
33313
|
+
next: "nextjs",
|
|
33314
|
+
"@tanstack/react-start": "tanstack-start",
|
|
33315
|
+
vite: "vite",
|
|
33316
|
+
"react-scripts": "cra",
|
|
33317
|
+
"@remix-run/react": "remix",
|
|
33318
|
+
gatsby: "gatsby",
|
|
33319
|
+
expo: "expo",
|
|
33320
|
+
"react-native": "react-native"
|
|
33321
|
+
};
|
|
33322
|
+
const detectFramework = (dependencies) => {
|
|
33323
|
+
for (const [packageName, frameworkName] of Object.entries(FRAMEWORK_PACKAGES)) if (dependencies[packageName]) return frameworkName;
|
|
33324
|
+
if (dependencies.preact && !dependencies.react) return "preact";
|
|
33325
|
+
return "unknown";
|
|
33326
|
+
};
|
|
33327
|
+
const MOBILE_FRAMEWORKS = new Set(["expo", "react-native"]);
|
|
33328
|
+
const frameworkMergeRank = (framework) => {
|
|
33329
|
+
if (framework === "unknown") return 3;
|
|
33330
|
+
return MOBILE_FRAMEWORKS.has(framework) ? 2 : 1;
|
|
33331
|
+
};
|
|
33193
33332
|
const REACT_COMPILER_PACKAGES = new Set([
|
|
33194
33333
|
"babel-plugin-react-compiler",
|
|
33195
33334
|
"react-compiler-runtime",
|
|
@@ -33226,6 +33365,7 @@ const EXPO_APP_CONFIG_FILENAMES = [
|
|
|
33226
33365
|
];
|
|
33227
33366
|
const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|eslint-plugin-react-compiler|["']react-compiler["']/;
|
|
33228
33367
|
const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
|
|
33368
|
+
const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
|
|
33229
33369
|
const hasCompilerPackage = (packageJson) => {
|
|
33230
33370
|
const allDependencies = {
|
|
33231
33371
|
...packageJson.peerDependencies,
|
|
@@ -33258,34 +33398,10 @@ const detectReactCompiler = (directory, packageJson) => {
|
|
|
33258
33398
|
}
|
|
33259
33399
|
return false;
|
|
33260
33400
|
};
|
|
33261
|
-
const
|
|
33262
|
-
|
|
33263
|
-
|
|
33264
|
-
|
|
33265
|
-
"react-scripts": "cra",
|
|
33266
|
-
"@remix-run/react": "remix",
|
|
33267
|
-
gatsby: "gatsby",
|
|
33268
|
-
expo: "expo",
|
|
33269
|
-
"react-native": "react-native"
|
|
33270
|
-
};
|
|
33271
|
-
const FRAMEWORK_DISPLAY_NAMES = {
|
|
33272
|
-
nextjs: "Next.js",
|
|
33273
|
-
"tanstack-start": "TanStack Start",
|
|
33274
|
-
vite: "Vite",
|
|
33275
|
-
cra: "Create React App",
|
|
33276
|
-
remix: "Remix",
|
|
33277
|
-
gatsby: "Gatsby",
|
|
33278
|
-
expo: "Expo",
|
|
33279
|
-
"react-native": "React Native",
|
|
33280
|
-
preact: "Preact",
|
|
33281
|
-
unknown: "React"
|
|
33282
|
-
};
|
|
33283
|
-
const formatFrameworkName = (framework) => FRAMEWORK_DISPLAY_NAMES[framework];
|
|
33284
|
-
const detectFramework = (dependencies) => {
|
|
33285
|
-
for (const [packageName, frameworkName] of Object.entries(FRAMEWORK_PACKAGES)) if (dependencies[packageName]) return frameworkName;
|
|
33286
|
-
if (dependencies.preact && !dependencies.react) return "preact";
|
|
33287
|
-
return "unknown";
|
|
33288
|
-
};
|
|
33401
|
+
const detectNextjsStaticExport = (directory) => NEXT_CONFIG_FILENAMES.some((filename) => {
|
|
33402
|
+
const filePath = Path.join(directory, filename);
|
|
33403
|
+
return isFile(filePath) && STATIC_EXPORT_OUTPUT_PATTERN.test(NFS.readFileSync(filePath, "utf-8"));
|
|
33404
|
+
});
|
|
33289
33405
|
const UNRESOLVABLE_PROTOCOL_VERSION = /^(?:file|git|github|https?|link|patch|portal|workspace|npm):/i;
|
|
33290
33406
|
const DIST_TAG_VERSION = /^[a-z][a-z0-9._-]*$/i;
|
|
33291
33407
|
const WILDCARD_VERSION = /^[*xX](?:\.[*xX])*$/;
|
|
@@ -33423,39 +33539,105 @@ const isConcreteDependencyVersion = (version) => {
|
|
|
33423
33539
|
const normalizedVersion = normalizeDependencyVersion(version);
|
|
33424
33540
|
return normalizedVersion !== null && /\d/.test(normalizedVersion);
|
|
33425
33541
|
};
|
|
33426
|
-
const
|
|
33427
|
-
if (
|
|
33428
|
-
|
|
33429
|
-
return
|
|
33430
|
-
};
|
|
33431
|
-
const isCatalogReference = (version) => version.startsWith("catalog:");
|
|
33432
|
-
const extractCatalogName = (version) => {
|
|
33433
|
-
if (!isCatalogReference(version)) return null;
|
|
33434
|
-
const name = version.slice(8).trim();
|
|
33435
|
-
return name.length > 0 ? name : null;
|
|
33542
|
+
const isMajorMinorAtLeast = (detected, required) => {
|
|
33543
|
+
if (detected === null) return true;
|
|
33544
|
+
if (detected.major !== required.major) return detected.major > required.major;
|
|
33545
|
+
return detected.minor >= required.minor;
|
|
33436
33546
|
};
|
|
33437
|
-
const
|
|
33438
|
-
|
|
33439
|
-
|
|
33440
|
-
return null;
|
|
33547
|
+
const parseReactMajor = (reactVersion) => {
|
|
33548
|
+
if (typeof reactVersion !== "string") return null;
|
|
33549
|
+
return getLowestDependencyMajor(reactVersion);
|
|
33441
33550
|
};
|
|
33442
|
-
const
|
|
33443
|
-
|
|
33444
|
-
|
|
33445
|
-
|
|
33446
|
-
|
|
33447
|
-
|
|
33448
|
-
|
|
33449
|
-
const
|
|
33450
|
-
|
|
33451
|
-
|
|
33452
|
-
|
|
33453
|
-
|
|
33454
|
-
const
|
|
33455
|
-
if (
|
|
33456
|
-
|
|
33457
|
-
|
|
33458
|
-
|
|
33551
|
+
const MAJOR_MINOR_PATTERN = /(\d{1,4})\.(\d{1,4})/;
|
|
33552
|
+
const MAJOR_ONLY_PATTERN = /(\d{1,4})/;
|
|
33553
|
+
const UPPER_BOUND_COMPARATOR_PATTERN = /<=?\s{0,8}\d{1,4}(?:\.\d{1,4}){0,2}(?:-[^\s,|]+)?/g;
|
|
33554
|
+
const parseReactMajorMinor = (reactVersion) => {
|
|
33555
|
+
if (typeof reactVersion !== "string") return null;
|
|
33556
|
+
const trimmed = reactVersion.trim();
|
|
33557
|
+
if (trimmed.length === 0) return null;
|
|
33558
|
+
const lowerBoundsOnly = trimmed.replace(UPPER_BOUND_COMPARATOR_PATTERN, " ").trim();
|
|
33559
|
+
if (lowerBoundsOnly.length === 0) return null;
|
|
33560
|
+
const majorMinorMatch = lowerBoundsOnly.match(MAJOR_MINOR_PATTERN);
|
|
33561
|
+
if (majorMinorMatch) {
|
|
33562
|
+
const major = Number.parseInt(majorMinorMatch[1], 10);
|
|
33563
|
+
const minor = Number.parseInt(majorMinorMatch[2], 10);
|
|
33564
|
+
if (!Number.isFinite(major) || major <= 0) return null;
|
|
33565
|
+
if (!Number.isFinite(minor) || minor < 0) return null;
|
|
33566
|
+
return {
|
|
33567
|
+
major,
|
|
33568
|
+
minor
|
|
33569
|
+
};
|
|
33570
|
+
}
|
|
33571
|
+
const majorOnlyMatch = lowerBoundsOnly.match(MAJOR_ONLY_PATTERN);
|
|
33572
|
+
if (!majorOnlyMatch) return null;
|
|
33573
|
+
const major = Number.parseInt(majorOnlyMatch[1], 10);
|
|
33574
|
+
if (!Number.isFinite(major) || major <= 0) return null;
|
|
33575
|
+
return {
|
|
33576
|
+
major,
|
|
33577
|
+
minor: 0
|
|
33578
|
+
};
|
|
33579
|
+
};
|
|
33580
|
+
const parseLowerBoundVersion = (versionSpec) => import_semver.validRange(versionSpec) !== null ? import_semver.minVersion(versionSpec) : import_semver.coerce(versionSpec);
|
|
33581
|
+
const parseTailwindMajorMinor = (tailwindVersion) => {
|
|
33582
|
+
if (typeof tailwindVersion !== "string") return null;
|
|
33583
|
+
const trimmed = tailwindVersion.trim();
|
|
33584
|
+
if (trimmed.length === 0) return null;
|
|
33585
|
+
const lowerBound = parseLowerBoundVersion(trimmed);
|
|
33586
|
+
if (lowerBound === null || lowerBound.major <= 0) return null;
|
|
33587
|
+
return {
|
|
33588
|
+
major: lowerBound.major,
|
|
33589
|
+
minor: lowerBound.minor
|
|
33590
|
+
};
|
|
33591
|
+
};
|
|
33592
|
+
const hasUpperBoundOnlyPeerRange = (range) => {
|
|
33593
|
+
if (typeof range !== "string") return false;
|
|
33594
|
+
const normalizedRange = normalizeDependencyVersion(range);
|
|
33595
|
+
if (normalizedRange === null) return false;
|
|
33596
|
+
return splitDependencyVersionBranches(normalizedRange).some((branch) => {
|
|
33597
|
+
const normalizedBranch = normalizeDependencyVersion(branch);
|
|
33598
|
+
return normalizedBranch !== null && getBranchLowestMajor(normalizedBranch) === null && hasUpperBoundComparator(normalizedBranch);
|
|
33599
|
+
});
|
|
33600
|
+
};
|
|
33601
|
+
const peerRangeMinMajor = (range) => {
|
|
33602
|
+
if (typeof range !== "string") return null;
|
|
33603
|
+
return getLowestDependencyMajor(range);
|
|
33604
|
+
};
|
|
33605
|
+
const resolveEffectiveReactMajor = (reactVersion, packageJson) => {
|
|
33606
|
+
const installedReactMajor = parseReactMajor(reactVersion);
|
|
33607
|
+
const peerReactRange = packageJson.peerDependencies?.react;
|
|
33608
|
+
if (typeof peerReactRange !== "string") return installedReactMajor;
|
|
33609
|
+
const peerFloor = peerRangeMinMajor(peerReactRange);
|
|
33610
|
+
if (peerFloor === null) return hasUpperBoundOnlyPeerRange(peerReactRange) ? null : installedReactMajor;
|
|
33611
|
+
return installedReactMajor !== null ? Math.min(installedReactMajor, peerFloor) : peerFloor;
|
|
33612
|
+
};
|
|
33613
|
+
const isCatalogReference = (version) => version.startsWith("catalog:");
|
|
33614
|
+
const extractCatalogName = (version) => {
|
|
33615
|
+
if (!isCatalogReference(version)) return null;
|
|
33616
|
+
const name = version.slice(8).trim();
|
|
33617
|
+
return name.length > 0 ? name : null;
|
|
33618
|
+
};
|
|
33619
|
+
const resolveVersionFromCatalog = (catalog, packageName) => {
|
|
33620
|
+
const version = catalog[packageName];
|
|
33621
|
+
if (typeof version === "string" && !isCatalogReference(version)) return version;
|
|
33622
|
+
return null;
|
|
33623
|
+
};
|
|
33624
|
+
const parsePnpmWorkspaceCatalogs = (rootDirectory) => {
|
|
33625
|
+
const workspacePath = Path.join(rootDirectory, "pnpm-workspace.yaml");
|
|
33626
|
+
if (!isFile(workspacePath)) return {
|
|
33627
|
+
defaultCatalog: {},
|
|
33628
|
+
namedCatalogs: {}
|
|
33629
|
+
};
|
|
33630
|
+
const content = NFS.readFileSync(workspacePath, "utf-8");
|
|
33631
|
+
const defaultCatalog = {};
|
|
33632
|
+
const namedCatalogs = {};
|
|
33633
|
+
let currentSection = "none";
|
|
33634
|
+
let currentCatalogName = "";
|
|
33635
|
+
for (const line of content.split("\n")) {
|
|
33636
|
+
const trimmed = line.trim();
|
|
33637
|
+
if (trimmed.length === 0 || trimmed.startsWith("#")) continue;
|
|
33638
|
+
const indentLevel = line.search(/\S/);
|
|
33639
|
+
if (indentLevel === 0 && trimmed === "catalog:") {
|
|
33640
|
+
currentSection = "catalog";
|
|
33459
33641
|
continue;
|
|
33460
33642
|
}
|
|
33461
33643
|
if (indentLevel === 0 && trimmed === "catalogs:") {
|
|
@@ -33568,6 +33750,16 @@ const resolveCatalogVersion = (packageJson, packageName, rootDirectory, explicit
|
|
|
33568
33750
|
}
|
|
33569
33751
|
return null;
|
|
33570
33752
|
};
|
|
33753
|
+
const REACT_SECTIONS = [
|
|
33754
|
+
"dependencies",
|
|
33755
|
+
"peerDependencies",
|
|
33756
|
+
"devDependencies"
|
|
33757
|
+
];
|
|
33758
|
+
const TAILWIND_ZOD_SECTIONS = [
|
|
33759
|
+
"dependencies",
|
|
33760
|
+
"devDependencies",
|
|
33761
|
+
"peerDependencies"
|
|
33762
|
+
];
|
|
33571
33763
|
const EMPTY_DEPENDENCY_INFO = {
|
|
33572
33764
|
reactVersion: null,
|
|
33573
33765
|
tailwindVersion: null,
|
|
@@ -33608,6 +33800,10 @@ const extractDependencyInfo = (packageJson) => {
|
|
|
33608
33800
|
framework: detectFramework(allDependencies)
|
|
33609
33801
|
};
|
|
33610
33802
|
};
|
|
33803
|
+
const getDependencySpec = (packageJson, packageName) => {
|
|
33804
|
+
const spec = packageJson.dependencies?.[packageName] ?? packageJson.devDependencies?.[packageName] ?? packageJson.peerDependencies?.[packageName] ?? packageJson.optionalDependencies?.[packageName];
|
|
33805
|
+
return typeof spec === "string" ? spec : null;
|
|
33806
|
+
};
|
|
33611
33807
|
const getDependencyDeclaration = ({ packageJson, packageName, sections }) => {
|
|
33612
33808
|
for (const section of sections) {
|
|
33613
33809
|
const version = packageJson[section]?.[packageName];
|
|
@@ -33624,31 +33820,141 @@ const getDependencyDeclaration = ({ packageJson, packageName, sections }) => {
|
|
|
33624
33820
|
version: null
|
|
33625
33821
|
};
|
|
33626
33822
|
};
|
|
33627
|
-
const
|
|
33628
|
-
|
|
33629
|
-
|
|
33630
|
-
|
|
33631
|
-
|
|
33823
|
+
const REACT_DEPENDENCY_NAMES = new Set([
|
|
33824
|
+
"react",
|
|
33825
|
+
"react-native",
|
|
33826
|
+
"next",
|
|
33827
|
+
"preact"
|
|
33828
|
+
]);
|
|
33829
|
+
const hasReactDependency = (packageJson) => {
|
|
33830
|
+
const allDependencies = {
|
|
33831
|
+
...packageJson.peerDependencies,
|
|
33832
|
+
...packageJson.dependencies,
|
|
33833
|
+
...packageJson.devDependencies
|
|
33834
|
+
};
|
|
33835
|
+
return Object.keys(allDependencies).some((packageName) => REACT_DEPENDENCY_NAMES.has(packageName));
|
|
33836
|
+
};
|
|
33837
|
+
const getPreactVersion = (packageJson) => {
|
|
33838
|
+
return {
|
|
33839
|
+
...packageJson.peerDependencies,
|
|
33840
|
+
...packageJson.dependencies,
|
|
33841
|
+
...packageJson.devDependencies
|
|
33842
|
+
}.preact ?? null;
|
|
33843
|
+
};
|
|
33844
|
+
const TANSTACK_QUERY_PACKAGES = new Set([
|
|
33845
|
+
"@tanstack/react-query",
|
|
33846
|
+
"@tanstack/query-core",
|
|
33847
|
+
"react-query"
|
|
33848
|
+
]);
|
|
33849
|
+
const hasTanStackQuery = (packageJson) => {
|
|
33850
|
+
const allDependencies = {
|
|
33851
|
+
...packageJson.peerDependencies,
|
|
33852
|
+
...packageJson.dependencies,
|
|
33853
|
+
...packageJson.devDependencies
|
|
33854
|
+
};
|
|
33855
|
+
return Object.keys(allDependencies).some((packageName) => TANSTACK_QUERY_PACKAGES.has(packageName));
|
|
33856
|
+
};
|
|
33857
|
+
const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, version }) => {
|
|
33858
|
+
if (version === null || !isCatalogReference(version)) return version;
|
|
33859
|
+
const catalogName = extractCatalogName(version);
|
|
33860
|
+
const resolvedLocalVersion = resolveCatalogVersion(rootPackageJson, packageName, rootDirectory, catalogName);
|
|
33861
|
+
if (resolvedLocalVersion) return resolvedLocalVersion;
|
|
33862
|
+
const monorepoRoot = findMonorepoRoot(rootDirectory);
|
|
33863
|
+
if (!monorepoRoot) return version;
|
|
33864
|
+
const monorepoPackageJsonPath = Path.join(monorepoRoot, "package.json");
|
|
33865
|
+
if (!isFile(monorepoPackageJsonPath)) return version;
|
|
33866
|
+
return resolveCatalogVersion(readPackageJson(monorepoPackageJsonPath), packageName, monorepoRoot, catalogName) ?? version;
|
|
33867
|
+
};
|
|
33868
|
+
/**
|
|
33869
|
+
* The chain of ancestor directories of `startDirectory`, nearest first, up to
|
|
33870
|
+
* and including the filesystem root. With `includeStart`, the chain begins at
|
|
33871
|
+
* `startDirectory` itself; otherwise at its parent. The one place the "walk up
|
|
33872
|
+
* the tree" traversal is expressed, so each caller adds only its own match /
|
|
33873
|
+
* stop policy instead of re-deriving the `path.dirname` loop.
|
|
33874
|
+
*/
|
|
33875
|
+
const ancestorDirectories = (startDirectory, { includeStart }) => {
|
|
33876
|
+
const directories = [];
|
|
33877
|
+
let currentDirectory = includeStart ? startDirectory : Path.dirname(startDirectory);
|
|
33878
|
+
while (true) {
|
|
33879
|
+
directories.push(currentDirectory);
|
|
33880
|
+
const parentDirectory = Path.dirname(currentDirectory);
|
|
33881
|
+
if (parentDirectory === currentDirectory) return directories;
|
|
33882
|
+
currentDirectory = parentDirectory;
|
|
33632
33883
|
}
|
|
33633
33884
|
};
|
|
33634
|
-
|
|
33635
|
-
|
|
33636
|
-
|
|
33637
|
-
|
|
33638
|
-
|
|
33639
|
-
|
|
33640
|
-
|
|
33641
|
-
|
|
33642
|
-
|
|
33643
|
-
|
|
33644
|
-
|
|
33645
|
-
|
|
33646
|
-
|
|
33647
|
-
|
|
33648
|
-
|
|
33649
|
-
|
|
33885
|
+
/**
|
|
33886
|
+
* Walk up from `startDirectory` to the nearest ancestor that owns a
|
|
33887
|
+
* `package.json`, stopping at (and including) the enclosing project boundary
|
|
33888
|
+
* — the working tree's git root or a monorepo root. Lets a scan of a package
|
|
33889
|
+
* subfolder that has no `package.json` of its own adopt the nearest enclosing
|
|
33890
|
+
* package as its project root, so it inherits that package's dependency +
|
|
33891
|
+
* framework detection instead of synthesizing an empty (React-blind) project.
|
|
33892
|
+
*
|
|
33893
|
+
* Generalizes the older monorepo-root-only lookup: the nearest ancestor is the
|
|
33894
|
+
* most specific owning package (a leaf workspace, not just the repo root), so
|
|
33895
|
+
* a subfolder of one workspace no longer borrows a sibling's capabilities.
|
|
33896
|
+
*
|
|
33897
|
+
* Returns `null` when no ancestor `package.json` exists inside the project
|
|
33898
|
+
* boundary (a loose tree of files, or a subfolder of a package-less repo).
|
|
33899
|
+
*/
|
|
33900
|
+
const findNearestAncestorPackageJson = (startDirectory) => {
|
|
33901
|
+
if (isProjectBoundary(startDirectory)) return null;
|
|
33902
|
+
for (const directory of ancestorDirectories(startDirectory, { includeStart: false })) {
|
|
33903
|
+
if (isFile(Path.join(directory, "package.json"))) return directory;
|
|
33904
|
+
if (isProjectBoundary(directory)) return null;
|
|
33650
33905
|
}
|
|
33651
|
-
return
|
|
33906
|
+
return null;
|
|
33907
|
+
};
|
|
33908
|
+
const NAMES = new Set([
|
|
33909
|
+
"react-native",
|
|
33910
|
+
"react-native-tvos",
|
|
33911
|
+
...new Set([
|
|
33912
|
+
"expo",
|
|
33913
|
+
"expo-router",
|
|
33914
|
+
"@expo/cli",
|
|
33915
|
+
"@expo/metro-config",
|
|
33916
|
+
"@expo/metro-runtime"
|
|
33917
|
+
]),
|
|
33918
|
+
"react-native-windows",
|
|
33919
|
+
"react-native-macos"
|
|
33920
|
+
]);
|
|
33921
|
+
const PREFIXES = ["@react-native/", "@react-native-"];
|
|
33922
|
+
const isReactNativeDependencyName = (dependencyName) => {
|
|
33923
|
+
if (NAMES.has(dependencyName)) return true;
|
|
33924
|
+
for (const prefix of PREFIXES) if (dependencyName.startsWith(prefix)) return true;
|
|
33925
|
+
return false;
|
|
33926
|
+
};
|
|
33927
|
+
const containsAnyReactNativeDependency = (section) => {
|
|
33928
|
+
if (!section) return false;
|
|
33929
|
+
for (const dependencyName of Object.keys(section)) if (isReactNativeDependencyName(dependencyName)) return true;
|
|
33930
|
+
return false;
|
|
33931
|
+
};
|
|
33932
|
+
const isPackageJsonReactNativeAware = (packageJson) => {
|
|
33933
|
+
if (typeof packageJson["react-native"] === "string") return true;
|
|
33934
|
+
if (containsAnyReactNativeDependency(packageJson.dependencies)) return true;
|
|
33935
|
+
if (containsAnyReactNativeDependency(packageJson.devDependencies)) return true;
|
|
33936
|
+
if (containsAnyReactNativeDependency(packageJson.peerDependencies)) return true;
|
|
33937
|
+
if (containsAnyReactNativeDependency(packageJson.optionalDependencies)) return true;
|
|
33938
|
+
return false;
|
|
33939
|
+
};
|
|
33940
|
+
const REANIMATED_DEPENDENCY_NAME$1 = "react-native-reanimated";
|
|
33941
|
+
const isPackageJsonReanimatedAware = (packageJson) => {
|
|
33942
|
+
const allDependencies = {
|
|
33943
|
+
...packageJson.peerDependencies,
|
|
33944
|
+
...packageJson.dependencies,
|
|
33945
|
+
...packageJson.devDependencies,
|
|
33946
|
+
...packageJson.optionalDependencies
|
|
33947
|
+
};
|
|
33948
|
+
return Object.hasOwn(allDependencies, REANIMATED_DEPENDENCY_NAME$1);
|
|
33949
|
+
};
|
|
33950
|
+
const getWorkspacePatterns = (rootDirectory, packageJson) => {
|
|
33951
|
+
const pnpmPatterns = parsePnpmWorkspacePatterns(rootDirectory);
|
|
33952
|
+
if (pnpmPatterns.length > 0) return pnpmPatterns;
|
|
33953
|
+
if (Array.isArray(packageJson.workspaces)) return packageJson.workspaces;
|
|
33954
|
+
if (packageJson.workspaces?.packages) return packageJson.workspaces.packages;
|
|
33955
|
+
const nxPatterns = getNxWorkspaceDirectories(rootDirectory);
|
|
33956
|
+
if (nxPatterns.length > 0) return nxPatterns;
|
|
33957
|
+
return [];
|
|
33652
33958
|
};
|
|
33653
33959
|
const parsePnpmWorkspacePatterns = (rootDirectory) => {
|
|
33654
33960
|
const workspacePath = Path.join(rootDirectory, "pnpm-workspace.yaml");
|
|
@@ -33667,18 +33973,24 @@ const parsePnpmWorkspacePatterns = (rootDirectory) => {
|
|
|
33667
33973
|
}
|
|
33668
33974
|
return patterns;
|
|
33669
33975
|
};
|
|
33670
|
-
const
|
|
33671
|
-
|
|
33672
|
-
|
|
33673
|
-
|
|
33674
|
-
|
|
33675
|
-
|
|
33676
|
-
if (
|
|
33677
|
-
|
|
33678
|
-
|
|
33679
|
-
const
|
|
33680
|
-
|
|
33681
|
-
|
|
33976
|
+
const NX_PROJECT_DISCOVERY_DIRS = [
|
|
33977
|
+
"apps",
|
|
33978
|
+
"libs",
|
|
33979
|
+
"packages"
|
|
33980
|
+
];
|
|
33981
|
+
const getNxWorkspaceDirectories = (rootDirectory) => {
|
|
33982
|
+
if (!isFile(Path.join(rootDirectory, "nx.json"))) return [];
|
|
33983
|
+
const collected = [];
|
|
33984
|
+
for (const candidate of NX_PROJECT_DISCOVERY_DIRS) {
|
|
33985
|
+
const candidatePath = Path.join(rootDirectory, candidate);
|
|
33986
|
+
if (!isDirectory(candidatePath)) continue;
|
|
33987
|
+
for (const entry of readDirectoryEntries(candidatePath)) {
|
|
33988
|
+
if (!entry.isDirectory()) continue;
|
|
33989
|
+
const projectDirectory = Path.join(candidatePath, entry.name);
|
|
33990
|
+
if (isFile(Path.join(projectDirectory, "project.json")) || isFile(Path.join(projectDirectory, "package.json"))) collected.push(`${candidate}/${entry.name}`);
|
|
33991
|
+
}
|
|
33992
|
+
}
|
|
33993
|
+
return collected;
|
|
33682
33994
|
};
|
|
33683
33995
|
const resolveWorkspaceDirectories = (rootDirectory, pattern) => {
|
|
33684
33996
|
const cleanPattern = pattern.replace(/["']/g, "").replace(/\/\*\*$/, "/*");
|
|
@@ -33690,464 +34002,13 @@ const resolveWorkspaceDirectories = (rootDirectory, pattern) => {
|
|
|
33690
34002
|
const wildcardIndex = cleanPattern.indexOf("*");
|
|
33691
34003
|
const baseDirectory = Path.join(rootDirectory, cleanPattern.slice(0, wildcardIndex));
|
|
33692
34004
|
const suffixAfterWildcard = cleanPattern.slice(wildcardIndex + 1);
|
|
33693
|
-
if (!isDirectory(baseDirectory)) return [];
|
|
33694
|
-
const resolved = [];
|
|
33695
|
-
for (const entry of readDirectoryEntries(baseDirectory)) {
|
|
33696
|
-
const entryPath = Path.join(baseDirectory, entry.name, suffixAfterWildcard);
|
|
33697
|
-
if (isDirectory(entryPath) && isFile(Path.join(entryPath, "package.json"))) resolved.push(entryPath);
|
|
33698
|
-
}
|
|
33699
|
-
return resolved;
|
|
33700
|
-
};
|
|
33701
|
-
const resolveWorkspaceDependencyVersion = ({ concreteVersion, packageName, rootDirectory, rootPackageJson, sections, workspaceDirectory, workspacePackageJson }) => {
|
|
33702
|
-
const dependencyDeclaration = getDependencyDeclaration({
|
|
33703
|
-
packageJson: workspacePackageJson,
|
|
33704
|
-
packageName,
|
|
33705
|
-
sections
|
|
33706
|
-
});
|
|
33707
|
-
if (!dependencyDeclaration.hasDeclaration) return null;
|
|
33708
|
-
return concreteVersion ?? resolveCatalogVersion(workspacePackageJson, packageName, workspaceDirectory, dependencyDeclaration.catalogReference) ?? resolveCatalogVersion(rootPackageJson, packageName, rootDirectory, dependencyDeclaration.catalogReference);
|
|
33709
|
-
};
|
|
33710
|
-
const shouldReplaceReactVersion = (currentVersion, nextVersion) => {
|
|
33711
|
-
if (!currentVersion) return true;
|
|
33712
|
-
const currentMajor = parseReactMajor(currentVersion);
|
|
33713
|
-
const nextMajor = parseReactMajor(nextVersion);
|
|
33714
|
-
if (currentMajor === null) return nextMajor !== null;
|
|
33715
|
-
if (nextMajor === null) return false;
|
|
33716
|
-
return nextMajor < currentMajor;
|
|
33717
|
-
};
|
|
33718
|
-
const findReactInWorkspaces = (rootDirectory, packageJson) => {
|
|
33719
|
-
const patterns = getWorkspacePatterns(rootDirectory, packageJson);
|
|
33720
|
-
const result = { ...EMPTY_DEPENDENCY_INFO };
|
|
33721
|
-
for (const pattern of patterns) {
|
|
33722
|
-
const directories = resolveWorkspaceDirectories(rootDirectory, pattern);
|
|
33723
|
-
for (const workspaceDirectory of directories) {
|
|
33724
|
-
const workspacePackageJson = readPackageJson(Path.join(workspaceDirectory, "package.json"));
|
|
33725
|
-
const info = extractDependencyInfo(workspacePackageJson);
|
|
33726
|
-
const reactVersion = resolveWorkspaceDependencyVersion({
|
|
33727
|
-
concreteVersion: info.reactVersion,
|
|
33728
|
-
packageName: "react",
|
|
33729
|
-
rootDirectory,
|
|
33730
|
-
rootPackageJson: packageJson,
|
|
33731
|
-
sections: [
|
|
33732
|
-
"dependencies",
|
|
33733
|
-
"peerDependencies",
|
|
33734
|
-
"devDependencies"
|
|
33735
|
-
],
|
|
33736
|
-
workspaceDirectory,
|
|
33737
|
-
workspacePackageJson
|
|
33738
|
-
});
|
|
33739
|
-
const tailwindVersion = resolveWorkspaceDependencyVersion({
|
|
33740
|
-
concreteVersion: info.tailwindVersion,
|
|
33741
|
-
packageName: "tailwindcss",
|
|
33742
|
-
rootDirectory,
|
|
33743
|
-
rootPackageJson: packageJson,
|
|
33744
|
-
sections: [
|
|
33745
|
-
"dependencies",
|
|
33746
|
-
"devDependencies",
|
|
33747
|
-
"peerDependencies"
|
|
33748
|
-
],
|
|
33749
|
-
workspaceDirectory,
|
|
33750
|
-
workspacePackageJson
|
|
33751
|
-
});
|
|
33752
|
-
const zodVersion = resolveWorkspaceDependencyVersion({
|
|
33753
|
-
concreteVersion: info.zodVersion,
|
|
33754
|
-
packageName: "zod",
|
|
33755
|
-
rootDirectory,
|
|
33756
|
-
rootPackageJson: packageJson,
|
|
33757
|
-
sections: [
|
|
33758
|
-
"dependencies",
|
|
33759
|
-
"devDependencies",
|
|
33760
|
-
"peerDependencies"
|
|
33761
|
-
],
|
|
33762
|
-
workspaceDirectory,
|
|
33763
|
-
workspacePackageJson
|
|
33764
|
-
});
|
|
33765
|
-
if (reactVersion && shouldReplaceReactVersion(result.reactVersion, reactVersion)) result.reactVersion = reactVersion;
|
|
33766
|
-
if (tailwindVersion && !result.tailwindVersion) result.tailwindVersion = tailwindVersion;
|
|
33767
|
-
if (zodVersion && !result.zodVersion) result.zodVersion = zodVersion;
|
|
33768
|
-
if (info.framework !== "unknown" && result.framework === "unknown") result.framework = info.framework;
|
|
33769
|
-
const resultReactMajor = parseReactMajor(result.reactVersion);
|
|
33770
|
-
if (result.reactVersion && result.tailwindVersion && result.framework !== "unknown" && resultReactMajor !== null && resultReactMajor <= 17) return result;
|
|
33771
|
-
}
|
|
33772
|
-
}
|
|
33773
|
-
return result;
|
|
33774
|
-
};
|
|
33775
|
-
const findDependencyInfoFromMonorepoRoot = (directory) => {
|
|
33776
|
-
const monorepoRoot = findMonorepoRoot(directory);
|
|
33777
|
-
if (!monorepoRoot) return EMPTY_DEPENDENCY_INFO;
|
|
33778
|
-
const monorepoPackageJsonPath = Path.join(monorepoRoot, "package.json");
|
|
33779
|
-
if (!isFile(monorepoPackageJsonPath)) return EMPTY_DEPENDENCY_INFO;
|
|
33780
|
-
const rootPackageJson = readPackageJson(monorepoPackageJsonPath);
|
|
33781
|
-
const rootInfo = extractDependencyInfo(rootPackageJson);
|
|
33782
|
-
const leafPackageJsonPath = Path.join(directory, "package.json");
|
|
33783
|
-
const leafPackageJson = isFile(leafPackageJsonPath) ? readPackageJson(leafPackageJsonPath) : null;
|
|
33784
|
-
const leafReactDeclaration = leafPackageJson ? getDependencyDeclaration({
|
|
33785
|
-
packageJson: leafPackageJson,
|
|
33786
|
-
packageName: "react",
|
|
33787
|
-
sections: [
|
|
33788
|
-
"dependencies",
|
|
33789
|
-
"peerDependencies",
|
|
33790
|
-
"devDependencies"
|
|
33791
|
-
]
|
|
33792
|
-
}) : null;
|
|
33793
|
-
const leafTailwindDeclaration = leafPackageJson ? getDependencyDeclaration({
|
|
33794
|
-
packageJson: leafPackageJson,
|
|
33795
|
-
packageName: "tailwindcss",
|
|
33796
|
-
sections: [
|
|
33797
|
-
"dependencies",
|
|
33798
|
-
"devDependencies",
|
|
33799
|
-
"peerDependencies"
|
|
33800
|
-
]
|
|
33801
|
-
}) : null;
|
|
33802
|
-
const leafZodDeclaration = leafPackageJson ? getDependencyDeclaration({
|
|
33803
|
-
packageJson: leafPackageJson,
|
|
33804
|
-
packageName: "zod",
|
|
33805
|
-
sections: [
|
|
33806
|
-
"dependencies",
|
|
33807
|
-
"devDependencies",
|
|
33808
|
-
"peerDependencies"
|
|
33809
|
-
]
|
|
33810
|
-
}) : null;
|
|
33811
|
-
const shouldUseReactFallback = !leafReactDeclaration?.hasDeclaration;
|
|
33812
|
-
const shouldUseTailwindFallback = leafTailwindDeclaration?.hasDeclaration ?? true;
|
|
33813
|
-
const shouldUseZodFallback = leafZodDeclaration?.hasDeclaration ?? true;
|
|
33814
|
-
const reactCatalogVersion = shouldUseReactFallback ? resolveCatalogVersion(rootPackageJson, "react", monorepoRoot, leafReactDeclaration?.catalogReference) : null;
|
|
33815
|
-
const tailwindCatalogVersion = shouldUseTailwindFallback ? resolveCatalogVersion(rootPackageJson, "tailwindcss", monorepoRoot, leafTailwindDeclaration?.catalogReference) : null;
|
|
33816
|
-
const zodCatalogVersion = shouldUseZodFallback ? resolveCatalogVersion(rootPackageJson, "zod", monorepoRoot, leafZodDeclaration?.catalogReference) : null;
|
|
33817
|
-
const workspaceInfo = findReactInWorkspaces(monorepoRoot, rootPackageJson);
|
|
33818
|
-
return {
|
|
33819
|
-
reactVersion: shouldUseReactFallback ? reactCatalogVersion ?? rootInfo.reactVersion ?? workspaceInfo.reactVersion : rootInfo.reactVersion ?? workspaceInfo.reactVersion,
|
|
33820
|
-
tailwindVersion: shouldUseTailwindFallback ? tailwindCatalogVersion ?? rootInfo.tailwindVersion ?? workspaceInfo.tailwindVersion : null,
|
|
33821
|
-
zodVersion: shouldUseZodFallback ? zodCatalogVersion ?? rootInfo.zodVersion ?? workspaceInfo.zodVersion : null,
|
|
33822
|
-
framework: rootInfo.framework !== "unknown" ? rootInfo.framework : workspaceInfo.framework
|
|
33823
|
-
};
|
|
33824
|
-
};
|
|
33825
|
-
/**
|
|
33826
|
-
* Walk up from `startDirectory` to the nearest ancestor that owns a
|
|
33827
|
-
* `package.json`, stopping at (and including) the enclosing project boundary
|
|
33828
|
-
* — the working tree's git root or a monorepo root. Lets a scan of a package
|
|
33829
|
-
* subfolder that has no `package.json` of its own adopt the nearest enclosing
|
|
33830
|
-
* package as its project root, so it inherits that package's dependency +
|
|
33831
|
-
* framework detection instead of synthesizing an empty (React-blind) project.
|
|
33832
|
-
*
|
|
33833
|
-
* Generalizes the older monorepo-root-only lookup: the nearest ancestor is the
|
|
33834
|
-
* most specific owning package (a leaf workspace, not just the repo root), so
|
|
33835
|
-
* a subfolder of one workspace no longer borrows a sibling's capabilities.
|
|
33836
|
-
*
|
|
33837
|
-
* Returns `null` when no ancestor `package.json` exists inside the project
|
|
33838
|
-
* boundary (a loose tree of files, or a subfolder of a package-less repo).
|
|
33839
|
-
*/
|
|
33840
|
-
const findNearestAncestorPackageJson = (startDirectory) => {
|
|
33841
|
-
if (isProjectBoundary(startDirectory)) return null;
|
|
33842
|
-
for (const directory of ancestorDirectories(startDirectory, { includeStart: false })) {
|
|
33843
|
-
if (isFile(Path.join(directory, "package.json"))) return directory;
|
|
33844
|
-
if (isProjectBoundary(directory)) return null;
|
|
33845
|
-
}
|
|
33846
|
-
return null;
|
|
33847
|
-
};
|
|
33848
|
-
/**
|
|
33849
|
-
* Last-resort React detection: locate React the way Node's `node_modules`
|
|
33850
|
-
* resolution would from `directory` — check each `node_modules/react` up the
|
|
33851
|
-
* tree — but bounded to the enclosing repo so a globally installed React can't
|
|
33852
|
-
* masquerade as the project's version. Stops at (and including) the nearest
|
|
33853
|
-
* project boundary — the git root or a monorepo root — and returns the first
|
|
33854
|
-
* installed `version`.
|
|
33855
|
-
*
|
|
33856
|
-
* Makes "React is installed and importable" ⇒ "React is detected" an invariant
|
|
33857
|
-
* for packages whose only React declaration is a version-less spec
|
|
33858
|
-
* (`workspace:*`, `*`, a dist-tag) or where React lives solely in a hoisted
|
|
33859
|
-
* `node_modules` the declaration walks never reach — the profile of a component
|
|
33860
|
-
* package inside a monorepo. Matching the `node_modules/react` entry rather than
|
|
33861
|
-
* its realpath means a project whose `node_modules` is symlinked elsewhere (a
|
|
33862
|
-
* Docker volume, a shared store) still counts, while a global install outside
|
|
33863
|
-
* the repo does not.
|
|
33864
|
-
*
|
|
33865
|
-
* Returns `null` when React isn't installed within the repo or its package.json
|
|
33866
|
-
* carries no version string. A tree with no boundary marker at all bounds the
|
|
33867
|
-
* search to `directory`, so a dependency hoisted above the scanned package there
|
|
33868
|
-
* is conservatively not adopted.
|
|
33869
|
-
*/
|
|
33870
|
-
/**
|
|
33871
|
-
* The nearest enclosing project boundary (git root or monorepo root), or
|
|
33872
|
-
* `directory` itself when the scan target sits outside any repo. Bounds the
|
|
33873
|
-
* node_modules walk so a React hoisted anywhere inside the repo counts, but a
|
|
33874
|
-
* React in an ancestor above the repo — a home-directory or global
|
|
33875
|
-
* `node_modules` — can't leak in.
|
|
33876
|
-
*/
|
|
33877
|
-
const findContainmentRoot = (directory) => {
|
|
33878
|
-
for (const ancestorDirectory of ancestorDirectories(directory, { includeStart: true })) if (isProjectBoundary(ancestorDirectory)) return ancestorDirectory;
|
|
33879
|
-
return directory;
|
|
33880
|
-
};
|
|
33881
|
-
const resolveInstalledReactVersion = (directory) => {
|
|
33882
|
-
const containmentRoot = findContainmentRoot(directory);
|
|
33883
|
-
for (const ancestorDirectory of ancestorDirectories(directory, { includeStart: true })) {
|
|
33884
|
-
const reactPackageJsonPath = Path.join(ancestorDirectory, "node_modules", "react", "package.json");
|
|
33885
|
-
if (isFile(reactPackageJsonPath)) {
|
|
33886
|
-
const installedVersion = readPackageJson(reactPackageJsonPath).version;
|
|
33887
|
-
return typeof installedVersion === "string" ? installedVersion : null;
|
|
33888
|
-
}
|
|
33889
|
-
if (ancestorDirectory === containmentRoot) return null;
|
|
33890
|
-
}
|
|
33891
|
-
return null;
|
|
33892
|
-
};
|
|
33893
|
-
const findInWorkspacePackageJsons = (rootDirectory, rootPackageJson, select) => {
|
|
33894
|
-
const rootValue = select(rootPackageJson);
|
|
33895
|
-
if (rootValue !== null) return rootValue;
|
|
33896
|
-
const patterns = getWorkspacePatterns(rootDirectory, rootPackageJson);
|
|
33897
|
-
if (patterns.length === 0) return null;
|
|
33898
|
-
const visitedDirectories = /* @__PURE__ */ new Set();
|
|
33899
|
-
for (const pattern of patterns) {
|
|
33900
|
-
const directories = [...resolveWorkspaceDirectories(rootDirectory, pattern)].sort();
|
|
33901
|
-
for (const workspaceDirectory of directories) {
|
|
33902
|
-
if (visitedDirectories.has(workspaceDirectory)) continue;
|
|
33903
|
-
visitedDirectories.add(workspaceDirectory);
|
|
33904
|
-
const value = select(readPackageJson(Path.join(workspaceDirectory, "package.json")));
|
|
33905
|
-
if (value !== null) return value;
|
|
33906
|
-
}
|
|
33907
|
-
}
|
|
33908
|
-
return null;
|
|
33909
|
-
};
|
|
33910
|
-
const someWorkspacePackageJson = (rootDirectory, rootPackageJson, predicate) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => predicate(packageJson) ? true : null) !== null;
|
|
33911
|
-
const NAMES = new Set([
|
|
33912
|
-
"react-native",
|
|
33913
|
-
"react-native-tvos",
|
|
33914
|
-
...new Set([
|
|
33915
|
-
"expo",
|
|
33916
|
-
"expo-router",
|
|
33917
|
-
"@expo/cli",
|
|
33918
|
-
"@expo/metro-config",
|
|
33919
|
-
"@expo/metro-runtime"
|
|
33920
|
-
]),
|
|
33921
|
-
"react-native-windows",
|
|
33922
|
-
"react-native-macos"
|
|
33923
|
-
]);
|
|
33924
|
-
const PREFIXES = ["@react-native/", "@react-native-"];
|
|
33925
|
-
const isReactNativeDependencyName = (dependencyName) => {
|
|
33926
|
-
if (NAMES.has(dependencyName)) return true;
|
|
33927
|
-
for (const prefix of PREFIXES) if (dependencyName.startsWith(prefix)) return true;
|
|
33928
|
-
return false;
|
|
33929
|
-
};
|
|
33930
|
-
const containsAnyReactNativeDependency = (section) => {
|
|
33931
|
-
if (!section) return false;
|
|
33932
|
-
for (const dependencyName of Object.keys(section)) if (isReactNativeDependencyName(dependencyName)) return true;
|
|
33933
|
-
return false;
|
|
33934
|
-
};
|
|
33935
|
-
const isPackageJsonReactNativeAware = (packageJson) => {
|
|
33936
|
-
if (typeof packageJson["react-native"] === "string") return true;
|
|
33937
|
-
if (containsAnyReactNativeDependency(packageJson.dependencies)) return true;
|
|
33938
|
-
if (containsAnyReactNativeDependency(packageJson.devDependencies)) return true;
|
|
33939
|
-
if (containsAnyReactNativeDependency(packageJson.peerDependencies)) return true;
|
|
33940
|
-
if (containsAnyReactNativeDependency(packageJson.optionalDependencies)) return true;
|
|
33941
|
-
return false;
|
|
33942
|
-
};
|
|
33943
|
-
const hasReactNativeWorkspaceAnywhere = (rootDirectory, rootPackageJson) => someWorkspacePackageJson(rootDirectory, rootPackageJson, isPackageJsonReactNativeAware);
|
|
33944
|
-
const getDependencySpec = (packageJson, packageName) => {
|
|
33945
|
-
const spec = packageJson.dependencies?.[packageName] ?? packageJson.devDependencies?.[packageName] ?? packageJson.peerDependencies?.[packageName] ?? packageJson.optionalDependencies?.[packageName];
|
|
33946
|
-
return typeof spec === "string" ? spec : null;
|
|
33947
|
-
};
|
|
33948
|
-
const findExpoVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, "expo"));
|
|
33949
|
-
const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
|
|
33950
|
-
const findShopifyFlashListVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, SHOPIFY_FLASH_LIST_PACKAGE_NAME));
|
|
33951
|
-
const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, version }) => {
|
|
33952
|
-
if (version === null || !isCatalogReference(version)) return version;
|
|
33953
|
-
const catalogName = extractCatalogName(version);
|
|
33954
|
-
const resolvedLocalVersion = resolveCatalogVersion(rootPackageJson, packageName, rootDirectory, catalogName);
|
|
33955
|
-
if (resolvedLocalVersion) return resolvedLocalVersion;
|
|
33956
|
-
const monorepoRoot = findMonorepoRoot(rootDirectory);
|
|
33957
|
-
if (!monorepoRoot) return version;
|
|
33958
|
-
const monorepoPackageJsonPath = path.join(monorepoRoot, "package.json");
|
|
33959
|
-
if (!isFile(monorepoPackageJsonPath)) return version;
|
|
33960
|
-
return resolveCatalogVersion(readPackageJson(monorepoPackageJsonPath), packageName, monorepoRoot, catalogName) ?? version;
|
|
33961
|
-
};
|
|
33962
|
-
const findNextjsVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, "next"));
|
|
33963
|
-
const getPreactVersion = (packageJson) => {
|
|
33964
|
-
return {
|
|
33965
|
-
...packageJson.peerDependencies,
|
|
33966
|
-
...packageJson.dependencies,
|
|
33967
|
-
...packageJson.devDependencies
|
|
33968
|
-
}.preact ?? null;
|
|
33969
|
-
};
|
|
33970
|
-
const TANSTACK_QUERY_PACKAGES = new Set([
|
|
33971
|
-
"@tanstack/react-query",
|
|
33972
|
-
"@tanstack/query-core",
|
|
33973
|
-
"react-query"
|
|
33974
|
-
]);
|
|
33975
|
-
const hasTanStackQuery = (packageJson) => {
|
|
33976
|
-
const allDependencies = {
|
|
33977
|
-
...packageJson.peerDependencies,
|
|
33978
|
-
...packageJson.dependencies,
|
|
33979
|
-
...packageJson.devDependencies
|
|
33980
|
-
};
|
|
33981
|
-
return Object.keys(allDependencies).some((packageName) => TANSTACK_QUERY_PACKAGES.has(packageName));
|
|
33982
|
-
};
|
|
33983
|
-
const REANIMATED_DEPENDENCY_NAME = "react-native-reanimated";
|
|
33984
|
-
const isPackageJsonReanimatedAware = (packageJson) => {
|
|
33985
|
-
const allDependencies = {
|
|
33986
|
-
...packageJson.peerDependencies,
|
|
33987
|
-
...packageJson.dependencies,
|
|
33988
|
-
...packageJson.devDependencies,
|
|
33989
|
-
...packageJson.optionalDependencies
|
|
33990
|
-
};
|
|
33991
|
-
return Object.hasOwn(allDependencies, REANIMATED_DEPENDENCY_NAME);
|
|
33992
|
-
};
|
|
33993
|
-
const parseZodMajor = (zodVersion) => {
|
|
33994
|
-
if (typeof zodVersion !== "string") return null;
|
|
33995
|
-
return getLowestDependencyMajor(zodVersion);
|
|
33996
|
-
};
|
|
33997
|
-
const hasUpperBoundOnlyPeerRange = (range) => {
|
|
33998
|
-
if (typeof range !== "string") return false;
|
|
33999
|
-
const normalizedRange = normalizeDependencyVersion(range);
|
|
34000
|
-
if (normalizedRange === null) return false;
|
|
34001
|
-
return splitDependencyVersionBranches(normalizedRange).some((branch) => {
|
|
34002
|
-
const normalizedBranch = normalizeDependencyVersion(branch);
|
|
34003
|
-
return normalizedBranch !== null && getBranchLowestMajor(normalizedBranch) === null && hasUpperBoundComparator(normalizedBranch);
|
|
34004
|
-
});
|
|
34005
|
-
};
|
|
34006
|
-
const peerRangeMinMajor = (range) => {
|
|
34007
|
-
if (typeof range !== "string") return null;
|
|
34008
|
-
return getLowestDependencyMajor(range);
|
|
34009
|
-
};
|
|
34010
|
-
const resolveEffectiveReactMajor = (reactVersion, packageJson) => {
|
|
34011
|
-
const installedReactMajor = parseReactMajor(reactVersion);
|
|
34012
|
-
const peerReactRange = packageJson.peerDependencies?.react;
|
|
34013
|
-
if (typeof peerReactRange !== "string") return installedReactMajor;
|
|
34014
|
-
const peerFloor = peerRangeMinMajor(peerReactRange);
|
|
34015
|
-
if (peerFloor === null) return hasUpperBoundOnlyPeerRange(peerReactRange) ? null : installedReactMajor;
|
|
34016
|
-
return installedReactMajor !== null ? Math.min(installedReactMajor, peerFloor) : peerFloor;
|
|
34017
|
-
};
|
|
34018
|
-
const TSCONFIG_FILENAME = "tsconfig.json";
|
|
34019
|
-
const isRelativeExtendsValue = (extendsValue) => extendsValue.startsWith("./") || extendsValue.startsWith("../") || Path.isAbsolute(extendsValue);
|
|
34020
|
-
const ensureJsonExtension = (filePath) => Path.extname(filePath) === "" ? `${filePath}.json` : filePath;
|
|
34021
|
-
const resolvePackageExtendsPath = (extendsValue, fromConfigDirectory) => {
|
|
34022
|
-
const requireFromConfig = createRequire(Path.join(fromConfigDirectory, "tsconfig.json"));
|
|
34023
|
-
const candidates = [
|
|
34024
|
-
extendsValue,
|
|
34025
|
-
ensureJsonExtension(extendsValue),
|
|
34026
|
-
`${extendsValue.replace(/\/$/, "")}/tsconfig.json`
|
|
34027
|
-
];
|
|
34028
|
-
for (const candidate of candidates) try {
|
|
34029
|
-
return requireFromConfig.resolve(candidate);
|
|
34030
|
-
} catch {
|
|
34031
|
-
continue;
|
|
34032
|
-
}
|
|
34033
|
-
return null;
|
|
34034
|
-
};
|
|
34035
|
-
const resolveExtendsPath = (extendsValue, fromConfigDirectory) => {
|
|
34036
|
-
if (isRelativeExtendsValue(extendsValue)) return ensureJsonExtension(Path.resolve(fromConfigDirectory, extendsValue));
|
|
34037
|
-
return resolvePackageExtendsPath(extendsValue, fromConfigDirectory);
|
|
34038
|
-
};
|
|
34039
|
-
const normalizeCompilerOptions = (compilerOptions) => {
|
|
34040
|
-
if (!isPlainObject(compilerOptions)) return { hasExplicitLib: false };
|
|
34041
|
-
const target = typeof compilerOptions.target === "string" ? compilerOptions.target : void 0;
|
|
34042
|
-
const hasExplicitLib = Object.hasOwn(compilerOptions, "lib");
|
|
34043
|
-
return {
|
|
34044
|
-
target,
|
|
34045
|
-
lib: Array.isArray(compilerOptions.lib) ? compilerOptions.lib.filter((entry) => typeof entry === "string") : void 0,
|
|
34046
|
-
hasExplicitLib
|
|
34047
|
-
};
|
|
34048
|
-
};
|
|
34049
|
-
const normalizeReferencePaths = (references) => {
|
|
34050
|
-
if (!Array.isArray(references)) return [];
|
|
34051
|
-
return references.map((reference) => isPlainObject(reference) && typeof reference.path === "string" ? reference.path : null).filter((referencePath) => referencePath !== null);
|
|
34052
|
-
};
|
|
34053
|
-
const readTsConfig = (filePath) => {
|
|
34054
|
-
let content;
|
|
34055
|
-
try {
|
|
34056
|
-
content = NFS.readFileSync(filePath, "utf-8");
|
|
34057
|
-
} catch {
|
|
34058
|
-
return null;
|
|
34059
|
-
}
|
|
34060
|
-
const parsed = ts.parseConfigFileTextToJson(filePath, content);
|
|
34061
|
-
if (!isPlainObject(parsed.config)) return null;
|
|
34062
|
-
return {
|
|
34063
|
-
extends: typeof parsed.config.extends === "string" ? parsed.config.extends : void 0,
|
|
34064
|
-
referencePaths: normalizeReferencePaths(parsed.config.references),
|
|
34065
|
-
compilerOptions: normalizeCompilerOptions(parsed.config.compilerOptions)
|
|
34066
|
-
};
|
|
34067
|
-
};
|
|
34068
|
-
const mergeCompilerOptions = (inherited, current) => {
|
|
34069
|
-
const target = current.target ?? inherited?.target;
|
|
34070
|
-
const hasExplicitLib = current.hasExplicitLib || Boolean(inherited?.hasExplicitLib);
|
|
34071
|
-
return {
|
|
34072
|
-
target,
|
|
34073
|
-
lib: current.hasExplicitLib ? current.lib : inherited?.lib,
|
|
34074
|
-
hasExplicitLib
|
|
34075
|
-
};
|
|
34076
|
-
};
|
|
34077
|
-
const readResolvedCompilerOptions = (tsConfigPath, extendsDepth, visitedPaths) => {
|
|
34078
|
-
const realPath = NFS.realpathSync.native(tsConfigPath);
|
|
34079
|
-
if (visitedPaths.has(realPath)) return null;
|
|
34080
|
-
const tsConfig = readTsConfig(realPath);
|
|
34081
|
-
if (!tsConfig) return null;
|
|
34082
|
-
const nextVisitedPaths = new Set(visitedPaths);
|
|
34083
|
-
nextVisitedPaths.add(realPath);
|
|
34084
|
-
if (tsConfig.extends && extendsDepth < 8) {
|
|
34085
|
-
const parentPath = resolveExtendsPath(tsConfig.extends, Path.dirname(realPath));
|
|
34086
|
-
if (parentPath && isFile(parentPath)) return mergeCompilerOptions(readResolvedCompilerOptions(parentPath, extendsDepth + 1, nextVisitedPaths), tsConfig.compilerOptions);
|
|
34087
|
-
}
|
|
34088
|
-
return tsConfig.compilerOptions;
|
|
34089
|
-
};
|
|
34090
|
-
const targetYearIsPreES2023 = (target) => {
|
|
34091
|
-
const year = ES_TARGET_YEAR_BY_NAME[target.toLowerCase()];
|
|
34092
|
-
return year !== void 0 && year < 2023;
|
|
34093
|
-
};
|
|
34094
|
-
const libEntryIncludesES2023Array = (entry) => {
|
|
34095
|
-
const normalizedEntry = entry.toLowerCase();
|
|
34096
|
-
if (normalizedEntry === "esnext" || normalizedEntry === "esnext.array") return true;
|
|
34097
|
-
const esYearMatch = /^es(\d{4})(?:\.(.+))?$/.exec(normalizedEntry);
|
|
34098
|
-
if (!esYearMatch) return false;
|
|
34099
|
-
if (Number(esYearMatch[1]) < 2023) return false;
|
|
34100
|
-
const component = esYearMatch[2];
|
|
34101
|
-
return component === void 0 || component === "array";
|
|
34102
|
-
};
|
|
34103
|
-
const libIncludesES2023 = (lib) => lib.some(libEntryIncludesES2023Array);
|
|
34104
|
-
const compilerOptionsArePreES2023 = (compilerOptions) => {
|
|
34105
|
-
if (compilerOptions.target && targetYearIsPreES2023(compilerOptions.target)) return true;
|
|
34106
|
-
if (compilerOptions.hasExplicitLib) return !libIncludesES2023(compilerOptions.lib ?? []);
|
|
34107
|
-
return false;
|
|
34108
|
-
};
|
|
34109
|
-
const compilerOptionsDeclareTargetOrLib = (compilerOptions) => compilerOptions.hasExplicitLib || compilerOptions.target !== void 0;
|
|
34110
|
-
const detectPreES2023FromConfig = (tsConfigPath, visitedConfigPaths = /* @__PURE__ */ new Set()) => {
|
|
34111
|
-
if (visitedConfigPaths.has(tsConfigPath)) return false;
|
|
34112
|
-
const compilerOptions = readResolvedCompilerOptions(tsConfigPath, 0, /* @__PURE__ */ new Set());
|
|
34113
|
-
if (!compilerOptions) return false;
|
|
34114
|
-
if (!compilerOptionsDeclareTargetOrLib(compilerOptions)) {
|
|
34115
|
-
const tsConfig = readTsConfig(tsConfigPath);
|
|
34116
|
-
if (!tsConfig) return false;
|
|
34117
|
-
const nextVisitedConfigPaths = new Set(visitedConfigPaths);
|
|
34118
|
-
nextVisitedConfigPaths.add(tsConfigPath);
|
|
34119
|
-
const configDirectory = Path.dirname(tsConfigPath);
|
|
34120
|
-
return tsConfig.referencePaths.some((referencePath) => {
|
|
34121
|
-
const resolvedReferencePath = Path.resolve(configDirectory, referencePath);
|
|
34122
|
-
const referencedConfigPath = isFile(resolvedReferencePath) ? resolvedReferencePath : Path.join(resolvedReferencePath, TSCONFIG_FILENAME);
|
|
34123
|
-
return isFile(referencedConfigPath) && detectPreES2023FromConfig(referencedConfigPath, nextVisitedConfigPaths);
|
|
34124
|
-
});
|
|
34125
|
-
}
|
|
34126
|
-
return compilerOptionsArePreES2023(compilerOptions);
|
|
34127
|
-
};
|
|
34128
|
-
const FALLBACK_TSCONFIG_FILENAMES = ["tsconfig.app.json", "tsconfig.build.json"];
|
|
34129
|
-
const detectPreES2023Target = (directory) => {
|
|
34130
|
-
const tsConfigPath = Path.join(directory, TSCONFIG_FILENAME);
|
|
34131
|
-
if (isFile(tsConfigPath)) return detectPreES2023FromConfig(tsConfigPath);
|
|
34132
|
-
for (const fallbackFilename of FALLBACK_TSCONFIG_FILENAMES) {
|
|
34133
|
-
const fallbackPath = Path.join(directory, fallbackFilename);
|
|
34134
|
-
if (isFile(fallbackPath)) return detectPreES2023FromConfig(fallbackPath);
|
|
34005
|
+
if (!isDirectory(baseDirectory)) return [];
|
|
34006
|
+
const resolved = [];
|
|
34007
|
+
for (const entry of readDirectoryEntries(baseDirectory)) {
|
|
34008
|
+
const entryPath = Path.join(baseDirectory, entry.name, suffixAfterWildcard);
|
|
34009
|
+
if (isDirectory(entryPath) && isFile(Path.join(entryPath, "package.json"))) resolved.push(entryPath);
|
|
34135
34010
|
}
|
|
34136
|
-
return
|
|
34137
|
-
};
|
|
34138
|
-
const REACT_DEPENDENCY_NAMES = new Set([
|
|
34139
|
-
"react",
|
|
34140
|
-
"react-native",
|
|
34141
|
-
"next",
|
|
34142
|
-
"preact"
|
|
34143
|
-
]);
|
|
34144
|
-
const hasReactDependency = (packageJson) => {
|
|
34145
|
-
const allDependencies = {
|
|
34146
|
-
...packageJson.peerDependencies,
|
|
34147
|
-
...packageJson.dependencies,
|
|
34148
|
-
...packageJson.devDependencies
|
|
34149
|
-
};
|
|
34150
|
-
return Object.keys(allDependencies).some((packageName) => REACT_DEPENDENCY_NAMES.has(packageName));
|
|
34011
|
+
return resolved;
|
|
34151
34012
|
};
|
|
34152
34013
|
const listWorkspacePackages = (rootDirectory) => {
|
|
34153
34014
|
const packageJsonPath = Path.join(rootDirectory, "package.json");
|
|
@@ -34179,6 +34040,208 @@ const listWorkspacePackages = (rootDirectory) => {
|
|
|
34179
34040
|
}
|
|
34180
34041
|
return packages;
|
|
34181
34042
|
};
|
|
34043
|
+
const REANIMATED_DEPENDENCY_NAME = "react-native-reanimated";
|
|
34044
|
+
const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
|
|
34045
|
+
const resolveWorkspaceDependencyVersion = ({ concreteVersion, packageName, rootDirectory, rootPackageJson, sections, workspaceDirectory, workspacePackageJson }) => {
|
|
34046
|
+
const dependencyDeclaration = getDependencyDeclaration({
|
|
34047
|
+
packageJson: workspacePackageJson,
|
|
34048
|
+
packageName,
|
|
34049
|
+
sections
|
|
34050
|
+
});
|
|
34051
|
+
if (!dependencyDeclaration.hasDeclaration) return null;
|
|
34052
|
+
return concreteVersion ?? resolveCatalogVersion(workspacePackageJson, packageName, workspaceDirectory, dependencyDeclaration.catalogReference) ?? resolveCatalogVersion(rootPackageJson, packageName, rootDirectory, dependencyDeclaration.catalogReference);
|
|
34053
|
+
};
|
|
34054
|
+
const shouldReplaceReactVersion = (currentVersion, nextVersion) => {
|
|
34055
|
+
if (!currentVersion) return true;
|
|
34056
|
+
const currentMajor = parseReactMajor(currentVersion);
|
|
34057
|
+
const nextMajor = parseReactMajor(nextVersion);
|
|
34058
|
+
if (currentMajor === null) return nextMajor !== null;
|
|
34059
|
+
if (nextMajor === null) return false;
|
|
34060
|
+
return nextMajor < currentMajor;
|
|
34061
|
+
};
|
|
34062
|
+
const evaluateManifestFacts = (facts, packageJson, directory) => {
|
|
34063
|
+
if (facts.expo.version === null) {
|
|
34064
|
+
const spec = getDependencySpec(packageJson, "expo");
|
|
34065
|
+
if (spec !== null) facts.expo = {
|
|
34066
|
+
version: spec,
|
|
34067
|
+
sourceDirectory: directory
|
|
34068
|
+
};
|
|
34069
|
+
}
|
|
34070
|
+
if (facts.next.version === null) {
|
|
34071
|
+
const spec = getDependencySpec(packageJson, "next");
|
|
34072
|
+
if (spec !== null) facts.next = {
|
|
34073
|
+
version: spec,
|
|
34074
|
+
sourceDirectory: directory
|
|
34075
|
+
};
|
|
34076
|
+
}
|
|
34077
|
+
if (facts.shopifyFlashList.version === null) {
|
|
34078
|
+
const spec = getDependencySpec(packageJson, SHOPIFY_FLASH_LIST_PACKAGE_NAME);
|
|
34079
|
+
if (spec !== null) facts.shopifyFlashList = {
|
|
34080
|
+
version: spec,
|
|
34081
|
+
sourceDirectory: directory
|
|
34082
|
+
};
|
|
34083
|
+
}
|
|
34084
|
+
if (facts.reanimatedVersion === null) {
|
|
34085
|
+
const spec = getDependencySpec(packageJson, REANIMATED_DEPENDENCY_NAME);
|
|
34086
|
+
if (spec !== null) facts.reanimatedVersion = spec;
|
|
34087
|
+
}
|
|
34088
|
+
facts.hasReactNativeAwarePackage = facts.hasReactNativeAwarePackage || isPackageJsonReactNativeAware(packageJson);
|
|
34089
|
+
facts.hasReanimatedAwarePackage = facts.hasReanimatedAwarePackage || isPackageJsonReanimatedAware(packageJson);
|
|
34090
|
+
};
|
|
34091
|
+
const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGroup }) => {
|
|
34092
|
+
const facts = {
|
|
34093
|
+
reactVersion: null,
|
|
34094
|
+
tailwindVersion: null,
|
|
34095
|
+
zodVersion: null,
|
|
34096
|
+
framework: "unknown",
|
|
34097
|
+
expo: {
|
|
34098
|
+
version: null,
|
|
34099
|
+
sourceDirectory: null
|
|
34100
|
+
},
|
|
34101
|
+
next: {
|
|
34102
|
+
version: null,
|
|
34103
|
+
sourceDirectory: null
|
|
34104
|
+
},
|
|
34105
|
+
shopifyFlashList: {
|
|
34106
|
+
version: null,
|
|
34107
|
+
sourceDirectory: null
|
|
34108
|
+
},
|
|
34109
|
+
hasReactNativeAwarePackage: false,
|
|
34110
|
+
hasReanimatedAwarePackage: false,
|
|
34111
|
+
reanimatedVersion: null
|
|
34112
|
+
};
|
|
34113
|
+
evaluateManifestFacts(facts, rootPackageJson, rootDirectory);
|
|
34114
|
+
let isReactGroupSettled = !collectReactGroup;
|
|
34115
|
+
const visitedDirectories = /* @__PURE__ */ new Set();
|
|
34116
|
+
for (const pattern of getWorkspacePatterns(rootDirectory, rootPackageJson)) {
|
|
34117
|
+
const directories = [...resolveWorkspaceDirectories(rootDirectory, pattern)].sort();
|
|
34118
|
+
for (const workspaceDirectory of directories) {
|
|
34119
|
+
if (visitedDirectories.has(workspaceDirectory)) continue;
|
|
34120
|
+
visitedDirectories.add(workspaceDirectory);
|
|
34121
|
+
const workspacePackageJson = readPackageJson(Path.join(workspaceDirectory, "package.json"));
|
|
34122
|
+
evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory);
|
|
34123
|
+
const info = extractDependencyInfo(workspacePackageJson);
|
|
34124
|
+
if (info.framework !== "unknown" && frameworkMergeRank(info.framework) < frameworkMergeRank(facts.framework)) facts.framework = info.framework;
|
|
34125
|
+
if (isReactGroupSettled) continue;
|
|
34126
|
+
const reactVersion = resolveWorkspaceDependencyVersion({
|
|
34127
|
+
concreteVersion: info.reactVersion,
|
|
34128
|
+
packageName: "react",
|
|
34129
|
+
rootDirectory,
|
|
34130
|
+
rootPackageJson,
|
|
34131
|
+
sections: REACT_SECTIONS,
|
|
34132
|
+
workspaceDirectory,
|
|
34133
|
+
workspacePackageJson
|
|
34134
|
+
});
|
|
34135
|
+
const tailwindVersion = resolveWorkspaceDependencyVersion({
|
|
34136
|
+
concreteVersion: info.tailwindVersion,
|
|
34137
|
+
packageName: "tailwindcss",
|
|
34138
|
+
rootDirectory,
|
|
34139
|
+
rootPackageJson,
|
|
34140
|
+
sections: TAILWIND_ZOD_SECTIONS,
|
|
34141
|
+
workspaceDirectory,
|
|
34142
|
+
workspacePackageJson
|
|
34143
|
+
});
|
|
34144
|
+
const zodVersion = resolveWorkspaceDependencyVersion({
|
|
34145
|
+
concreteVersion: info.zodVersion,
|
|
34146
|
+
packageName: "zod",
|
|
34147
|
+
rootDirectory,
|
|
34148
|
+
rootPackageJson,
|
|
34149
|
+
sections: TAILWIND_ZOD_SECTIONS,
|
|
34150
|
+
workspaceDirectory,
|
|
34151
|
+
workspacePackageJson
|
|
34152
|
+
});
|
|
34153
|
+
if (reactVersion && shouldReplaceReactVersion(facts.reactVersion, reactVersion)) facts.reactVersion = reactVersion;
|
|
34154
|
+
if (tailwindVersion && !facts.tailwindVersion) facts.tailwindVersion = tailwindVersion;
|
|
34155
|
+
if (zodVersion && !facts.zodVersion) facts.zodVersion = zodVersion;
|
|
34156
|
+
const settledReactMajor = parseReactMajor(facts.reactVersion);
|
|
34157
|
+
isReactGroupSettled = Boolean(facts.reactVersion && facts.tailwindVersion && facts.framework !== "unknown" && settledReactMajor !== null && settledReactMajor <= 17);
|
|
34158
|
+
}
|
|
34159
|
+
}
|
|
34160
|
+
return facts;
|
|
34161
|
+
};
|
|
34162
|
+
const findDependencyInfoFromMonorepoRoot = (directory) => {
|
|
34163
|
+
const monorepoRoot = findMonorepoRoot(directory);
|
|
34164
|
+
if (!monorepoRoot) return EMPTY_DEPENDENCY_INFO;
|
|
34165
|
+
const monorepoPackageJsonPath = Path.join(monorepoRoot, "package.json");
|
|
34166
|
+
if (!isFile(monorepoPackageJsonPath)) return EMPTY_DEPENDENCY_INFO;
|
|
34167
|
+
const rootPackageJson = readPackageJson(monorepoPackageJsonPath);
|
|
34168
|
+
const rootInfo = extractDependencyInfo(rootPackageJson);
|
|
34169
|
+
const leafPackageJsonPath = Path.join(directory, "package.json");
|
|
34170
|
+
const leafPackageJson = isFile(leafPackageJsonPath) ? readPackageJson(leafPackageJsonPath) : null;
|
|
34171
|
+
const leafReactDeclaration = leafPackageJson ? getDependencyDeclaration({
|
|
34172
|
+
packageJson: leafPackageJson,
|
|
34173
|
+
packageName: "react",
|
|
34174
|
+
sections: REACT_SECTIONS
|
|
34175
|
+
}) : null;
|
|
34176
|
+
const leafTailwindDeclaration = leafPackageJson ? getDependencyDeclaration({
|
|
34177
|
+
packageJson: leafPackageJson,
|
|
34178
|
+
packageName: "tailwindcss",
|
|
34179
|
+
sections: TAILWIND_ZOD_SECTIONS
|
|
34180
|
+
}) : null;
|
|
34181
|
+
const leafZodDeclaration = leafPackageJson ? getDependencyDeclaration({
|
|
34182
|
+
packageJson: leafPackageJson,
|
|
34183
|
+
packageName: "zod",
|
|
34184
|
+
sections: TAILWIND_ZOD_SECTIONS
|
|
34185
|
+
}) : null;
|
|
34186
|
+
const shouldUseReactFallback = !leafReactDeclaration?.hasDeclaration;
|
|
34187
|
+
const shouldUseTailwindFallback = leafTailwindDeclaration?.hasDeclaration ?? true;
|
|
34188
|
+
const shouldUseZodFallback = leafZodDeclaration?.hasDeclaration ?? true;
|
|
34189
|
+
const reactCatalogVersion = shouldUseReactFallback ? resolveCatalogVersion(rootPackageJson, "react", monorepoRoot, leafReactDeclaration?.catalogReference) : null;
|
|
34190
|
+
const tailwindCatalogVersion = shouldUseTailwindFallback ? resolveCatalogVersion(rootPackageJson, "tailwindcss", monorepoRoot, leafTailwindDeclaration?.catalogReference) : null;
|
|
34191
|
+
const zodCatalogVersion = shouldUseZodFallback ? resolveCatalogVersion(rootPackageJson, "zod", monorepoRoot, leafZodDeclaration?.catalogReference) : null;
|
|
34192
|
+
const workspaceFacts = collectWorkspaceFacts(monorepoRoot, rootPackageJson, { collectReactGroup: true });
|
|
34193
|
+
return {
|
|
34194
|
+
reactVersion: shouldUseReactFallback ? reactCatalogVersion ?? rootInfo.reactVersion ?? workspaceFacts.reactVersion : rootInfo.reactVersion ?? workspaceFacts.reactVersion,
|
|
34195
|
+
tailwindVersion: shouldUseTailwindFallback ? tailwindCatalogVersion ?? rootInfo.tailwindVersion ?? workspaceFacts.tailwindVersion : null,
|
|
34196
|
+
zodVersion: shouldUseZodFallback ? zodCatalogVersion ?? rootInfo.zodVersion ?? workspaceFacts.zodVersion : null,
|
|
34197
|
+
framework: rootInfo.framework !== "unknown" ? rootInfo.framework : workspaceFacts.framework
|
|
34198
|
+
};
|
|
34199
|
+
};
|
|
34200
|
+
/**
|
|
34201
|
+
* Last-resort React detection: locate React the way Node's `node_modules`
|
|
34202
|
+
* resolution would from `directory` — check each `node_modules/react` up the
|
|
34203
|
+
* tree — but bounded to the enclosing repo so a globally installed React can't
|
|
34204
|
+
* masquerade as the project's version. Stops at (and including) the nearest
|
|
34205
|
+
* project boundary — the git root or a monorepo root — and returns the first
|
|
34206
|
+
* installed `version`.
|
|
34207
|
+
*
|
|
34208
|
+
* Makes "React is installed and importable" ⇒ "React is detected" an invariant
|
|
34209
|
+
* for packages whose only React declaration is a version-less spec
|
|
34210
|
+
* (`workspace:*`, `*`, a dist-tag) or where React lives solely in a hoisted
|
|
34211
|
+
* `node_modules` the declaration walks never reach — the profile of a component
|
|
34212
|
+
* package inside a monorepo. Matching the `node_modules/react` entry rather than
|
|
34213
|
+
* its realpath means a project whose `node_modules` is symlinked elsewhere (a
|
|
34214
|
+
* Docker volume, a shared store) still counts, while a global install outside
|
|
34215
|
+
* the repo does not.
|
|
34216
|
+
*
|
|
34217
|
+
* Returns `null` when React isn't installed within the repo or its package.json
|
|
34218
|
+
* carries no version string. A tree with no boundary marker at all bounds the
|
|
34219
|
+
* search to `directory`, so a dependency hoisted above the scanned package there
|
|
34220
|
+
* is conservatively not adopted.
|
|
34221
|
+
*/
|
|
34222
|
+
/**
|
|
34223
|
+
* The nearest enclosing project boundary (git root or monorepo root), or
|
|
34224
|
+
* `directory` itself when the scan target sits outside any repo. Bounds the
|
|
34225
|
+
* node_modules walk so a React hoisted anywhere inside the repo counts, but a
|
|
34226
|
+
* React in an ancestor above the repo — a home-directory or global
|
|
34227
|
+
* `node_modules` — can't leak in.
|
|
34228
|
+
*/
|
|
34229
|
+
const findContainmentRoot = (directory) => {
|
|
34230
|
+
for (const ancestorDirectory of ancestorDirectories(directory, { includeStart: true })) if (isProjectBoundary(ancestorDirectory)) return ancestorDirectory;
|
|
34231
|
+
return directory;
|
|
34232
|
+
};
|
|
34233
|
+
const resolveInstalledReactVersion = (directory) => {
|
|
34234
|
+
const containmentRoot = findContainmentRoot(directory);
|
|
34235
|
+
for (const ancestorDirectory of ancestorDirectories(directory, { includeStart: true })) {
|
|
34236
|
+
const reactPackageJsonPath = Path.join(ancestorDirectory, "node_modules", "react", "package.json");
|
|
34237
|
+
if (isFile(reactPackageJsonPath)) {
|
|
34238
|
+
const installedVersion = readPackageJson(reactPackageJsonPath).version;
|
|
34239
|
+
return typeof installedVersion === "string" ? installedVersion : null;
|
|
34240
|
+
}
|
|
34241
|
+
if (ancestorDirectory === containmentRoot) return null;
|
|
34242
|
+
}
|
|
34243
|
+
return null;
|
|
34244
|
+
};
|
|
34182
34245
|
const toReactWorkspacePackages = (directories) => {
|
|
34183
34246
|
const packages = [];
|
|
34184
34247
|
for (const directory of directories) {
|
|
@@ -34251,14 +34314,13 @@ const clearProjectCache = () => {
|
|
|
34251
34314
|
};
|
|
34252
34315
|
/**
|
|
34253
34316
|
* Build a `ProjectInfo` for a directory that has no `package.json` of
|
|
34254
|
-
* its own — a
|
|
34255
|
-
*
|
|
34256
|
-
*
|
|
34257
|
-
*
|
|
34258
|
-
*
|
|
34259
|
-
*
|
|
34260
|
-
*
|
|
34261
|
-
* nothing to scan (no enclosing project and no source files of its own).
|
|
34317
|
+
* its own — a monorepo subfolder like `repo/packages`, or any loose tree
|
|
34318
|
+
* of TypeScript/JavaScript files. Dependency + framework detection is
|
|
34319
|
+
* inherited from the enclosing workspace root when there is one, so
|
|
34320
|
+
* scanning a subdirectory of a React monorepo still gets the React
|
|
34321
|
+
* capabilities; a standalone non-React directory simply scans with the
|
|
34322
|
+
* framework-agnostic rules. Throws only when the directory has nothing
|
|
34323
|
+
* to scan (no enclosing project and no source files of its own).
|
|
34262
34324
|
*/
|
|
34263
34325
|
const discoverProjectWithoutPackageJson = (directory) => {
|
|
34264
34326
|
const sourceFileCount = countSourceFiles(directory);
|
|
@@ -34296,6 +34358,7 @@ const discoverProjectWithoutPackageJson = (directory) => {
|
|
|
34296
34358
|
hasReanimated: false,
|
|
34297
34359
|
reanimatedVersion: null,
|
|
34298
34360
|
isPreES2023Target: hasOwnTsConfig && detectPreES2023Target(directory),
|
|
34361
|
+
isStaticExport: false,
|
|
34299
34362
|
sourceFileCount
|
|
34300
34363
|
};
|
|
34301
34364
|
};
|
|
@@ -34309,90 +34372,85 @@ const discoverProject = (directory) => {
|
|
|
34309
34372
|
return synthesized;
|
|
34310
34373
|
}
|
|
34311
34374
|
const packageJson = readPackageJson(packageJsonPath);
|
|
34312
|
-
|
|
34313
|
-
|
|
34314
|
-
|
|
34315
|
-
|
|
34316
|
-
|
|
34317
|
-
|
|
34318
|
-
|
|
34319
|
-
|
|
34320
|
-
|
|
34321
|
-
|
|
34322
|
-
|
|
34323
|
-
|
|
34324
|
-
|
|
34325
|
-
|
|
34326
|
-
|
|
34327
|
-
|
|
34328
|
-
|
|
34329
|
-
]
|
|
34330
|
-
});
|
|
34331
|
-
const zodDeclaration = getDependencyDeclaration({
|
|
34375
|
+
const rootInfo = extractDependencyInfo(packageJson);
|
|
34376
|
+
let framework = rootInfo.framework;
|
|
34377
|
+
const tracked = {
|
|
34378
|
+
react: {
|
|
34379
|
+
version: rootInfo.reactVersion,
|
|
34380
|
+
sections: REACT_SECTIONS
|
|
34381
|
+
},
|
|
34382
|
+
tailwindcss: {
|
|
34383
|
+
version: rootInfo.tailwindVersion,
|
|
34384
|
+
sections: TAILWIND_ZOD_SECTIONS
|
|
34385
|
+
},
|
|
34386
|
+
zod: {
|
|
34387
|
+
version: rootInfo.zodVersion,
|
|
34388
|
+
sections: TAILWIND_ZOD_SECTIONS
|
|
34389
|
+
}
|
|
34390
|
+
};
|
|
34391
|
+
const declarations = Object.fromEntries(Object.entries(tracked).map(([packageName, entry]) => [packageName, getDependencyDeclaration({
|
|
34332
34392
|
packageJson,
|
|
34333
|
-
packageName
|
|
34334
|
-
sections:
|
|
34335
|
-
|
|
34336
|
-
|
|
34337
|
-
|
|
34338
|
-
|
|
34339
|
-
|
|
34340
|
-
if (!
|
|
34341
|
-
if (!tailwindVersion && tailwindDeclaration.hasDeclaration) tailwindVersion = resolveCatalogVersion(packageJson, "tailwindcss", directory, tailwindDeclaration.catalogReference);
|
|
34342
|
-
if (!zodVersion && zodDeclaration.hasDeclaration) zodVersion = resolveCatalogVersion(packageJson, "zod", directory, zodDeclaration.catalogReference);
|
|
34343
|
-
if (!reactVersion || !tailwindVersion || !zodVersion) {
|
|
34393
|
+
packageName,
|
|
34394
|
+
sections: entry.sections
|
|
34395
|
+
})]));
|
|
34396
|
+
const fillFromCatalogs = (source, sourceDirectory) => {
|
|
34397
|
+
for (const [packageName, entry] of Object.entries(tracked)) if (!entry.version && declarations[packageName].hasDeclaration) entry.version = resolveCatalogVersion(source, packageName, sourceDirectory, declarations[packageName].catalogReference);
|
|
34398
|
+
};
|
|
34399
|
+
fillFromCatalogs(packageJson, directory);
|
|
34400
|
+
if (!tracked.react.version || !tracked.tailwindcss.version || !tracked.zod.version) {
|
|
34344
34401
|
const monorepoRoot = findMonorepoRoot(directory);
|
|
34345
34402
|
if (monorepoRoot) {
|
|
34346
34403
|
const monorepoPackageJsonPath = Path.join(monorepoRoot, "package.json");
|
|
34347
|
-
if (isFile(monorepoPackageJsonPath))
|
|
34348
|
-
const rootPackageJson = readPackageJson(monorepoPackageJsonPath);
|
|
34349
|
-
if (!reactVersion && reactDeclaration.hasDeclaration) reactVersion = resolveCatalogVersion(rootPackageJson, "react", monorepoRoot, reactDeclaration.catalogReference);
|
|
34350
|
-
if (!tailwindVersion && tailwindDeclaration.hasDeclaration) tailwindVersion = resolveCatalogVersion(rootPackageJson, "tailwindcss", monorepoRoot, tailwindDeclaration.catalogReference);
|
|
34351
|
-
if (!zodVersion && zodDeclaration.hasDeclaration) zodVersion = resolveCatalogVersion(rootPackageJson, "zod", monorepoRoot, zodDeclaration.catalogReference);
|
|
34352
|
-
}
|
|
34404
|
+
if (isFile(monorepoPackageJsonPath)) fillFromCatalogs(readPackageJson(monorepoPackageJsonPath), monorepoRoot);
|
|
34353
34405
|
}
|
|
34354
34406
|
}
|
|
34355
|
-
|
|
34356
|
-
|
|
34357
|
-
|
|
34358
|
-
|
|
34359
|
-
|
|
34360
|
-
|
|
34407
|
+
const shouldCollectReactGroup = !tracked.react.version || framework === "unknown";
|
|
34408
|
+
const workspaceFacts = collectWorkspaceFacts(directory, packageJson, { collectReactGroup: shouldCollectReactGroup });
|
|
34409
|
+
if (shouldCollectReactGroup) {
|
|
34410
|
+
tracked.react.version ||= workspaceFacts.reactVersion;
|
|
34411
|
+
tracked.tailwindcss.version ||= workspaceFacts.tailwindVersion;
|
|
34412
|
+
tracked.zod.version ||= workspaceFacts.zodVersion;
|
|
34413
|
+
if (framework === "unknown" && workspaceFacts.framework !== "unknown") framework = workspaceFacts.framework;
|
|
34361
34414
|
}
|
|
34362
|
-
if ((!
|
|
34415
|
+
if ((!tracked.react.version || framework === "unknown") && !isMonorepoRoot(directory)) {
|
|
34363
34416
|
const monorepoInfo = findDependencyInfoFromMonorepoRoot(directory);
|
|
34364
|
-
|
|
34365
|
-
|
|
34366
|
-
|
|
34417
|
+
tracked.react.version ||= monorepoInfo.reactVersion;
|
|
34418
|
+
tracked.tailwindcss.version ||= monorepoInfo.tailwindVersion;
|
|
34419
|
+
tracked.zod.version ||= monorepoInfo.zodVersion;
|
|
34367
34420
|
if (framework === "unknown") framework = monorepoInfo.framework;
|
|
34368
34421
|
}
|
|
34369
|
-
|
|
34370
|
-
|
|
34371
|
-
|
|
34422
|
+
for (const [packageName, entry] of Object.entries(tracked)) {
|
|
34423
|
+
const declaredVersion = declarations[packageName].version;
|
|
34424
|
+
if (!entry.version && declaredVersion && !isCatalogReference(declaredVersion)) entry.version = declaredVersion;
|
|
34425
|
+
}
|
|
34426
|
+
const { react, tailwindcss, zod } = tracked;
|
|
34427
|
+
let reactVersion = react.version;
|
|
34372
34428
|
if (!reactVersion || parseReactMajor(reactVersion) === null) reactVersion = resolveInstalledReactVersion(directory) ?? reactVersion;
|
|
34429
|
+
const tailwindVersion = tailwindcss.version;
|
|
34430
|
+
const zodVersion = zod.version;
|
|
34373
34431
|
const projectName = packageJson.name ?? Path.basename(directory);
|
|
34374
34432
|
const hasTypeScript = NFS.existsSync(Path.join(directory, "tsconfig.json"));
|
|
34375
34433
|
const sourceFileCount = countSourceFiles(directory);
|
|
34376
|
-
const hasReactNativeWorkspace = framework === "expo" || framework === "react-native" ||
|
|
34434
|
+
const hasReactNativeWorkspace = framework === "expo" || framework === "react-native" || workspaceFacts.hasReactNativeAwarePackage;
|
|
34377
34435
|
const expoVersion = hasReactNativeWorkspace ? resolveCatalogBackedDependencyVersion({
|
|
34378
34436
|
rootDirectory: directory,
|
|
34379
34437
|
rootPackageJson: packageJson,
|
|
34380
34438
|
packageName: "expo",
|
|
34381
|
-
version:
|
|
34439
|
+
version: workspaceFacts.expo.version
|
|
34382
34440
|
}) : null;
|
|
34383
34441
|
const shopifyFlashListVersion = hasReactNativeWorkspace ? resolveCatalogBackedDependencyVersion({
|
|
34384
34442
|
rootDirectory: directory,
|
|
34385
34443
|
rootPackageJson: packageJson,
|
|
34386
34444
|
packageName: SHOPIFY_FLASH_LIST_PACKAGE_NAME,
|
|
34387
|
-
version:
|
|
34445
|
+
version: workspaceFacts.shopifyFlashList.version
|
|
34388
34446
|
}) : null;
|
|
34389
|
-
const hasReanimated = hasReactNativeWorkspace &&
|
|
34390
|
-
const reanimatedVersion = hasReanimated ?
|
|
34447
|
+
const hasReanimated = hasReactNativeWorkspace && workspaceFacts.hasReanimatedAwarePackage;
|
|
34448
|
+
const reanimatedVersion = hasReanimated ? workspaceFacts.reanimatedVersion : null;
|
|
34391
34449
|
const nextjsVersion = framework === "nextjs" ? resolveCatalogBackedDependencyVersion({
|
|
34392
34450
|
rootDirectory: directory,
|
|
34393
34451
|
rootPackageJson: packageJson,
|
|
34394
34452
|
packageName: "next",
|
|
34395
|
-
version:
|
|
34453
|
+
version: workspaceFacts.next.version
|
|
34396
34454
|
}) : null;
|
|
34397
34455
|
const preactVersion = getPreactVersion(packageJson);
|
|
34398
34456
|
const isPreES2023Target = hasTypeScript && detectPreES2023Target(directory);
|
|
@@ -34403,7 +34461,7 @@ const discoverProject = (directory) => {
|
|
|
34403
34461
|
reactMajorVersion: resolveEffectiveReactMajor(reactVersion, packageJson),
|
|
34404
34462
|
tailwindVersion,
|
|
34405
34463
|
zodVersion,
|
|
34406
|
-
zodMajorVersion:
|
|
34464
|
+
zodMajorVersion: zodVersion === null ? null : getLowestDependencyMajor(zodVersion),
|
|
34407
34465
|
framework,
|
|
34408
34466
|
hasTypeScript,
|
|
34409
34467
|
hasReactCompiler: detectReactCompiler(directory, packageJson),
|
|
@@ -34419,6 +34477,7 @@ const discoverProject = (directory) => {
|
|
|
34419
34477
|
hasReanimated,
|
|
34420
34478
|
reanimatedVersion,
|
|
34421
34479
|
isPreES2023Target,
|
|
34480
|
+
isStaticExport: framework === "nextjs" && detectNextjsStaticExport(workspaceFacts.next.sourceDirectory ?? directory),
|
|
34422
34481
|
sourceFileCount
|
|
34423
34482
|
};
|
|
34424
34483
|
cachedProjectInfos.set(directory, projectInfo);
|
|
@@ -34434,57 +34493,6 @@ const discoverProject = (directory) => {
|
|
|
34434
34493
|
* single source file has nothing to analyze.
|
|
34435
34494
|
*/
|
|
34436
34495
|
const isAnalyzableProject = (project) => project.reactVersion !== null || project.preactVersion !== null || project.sourceFileCount > 0;
|
|
34437
|
-
const MAJOR_MINOR_PATTERN = /(\d{1,4})\.(\d{1,4})/;
|
|
34438
|
-
const MAJOR_ONLY_PATTERN = /(\d{1,4})/;
|
|
34439
|
-
const UPPER_BOUND_COMPARATOR_PATTERN = /<=?\s{0,8}\d{1,4}(?:\.\d{1,4}){0,2}(?:-[^\s,|]+)?/g;
|
|
34440
|
-
const parseReactMajorMinor = (reactVersion) => {
|
|
34441
|
-
if (typeof reactVersion !== "string") return null;
|
|
34442
|
-
const trimmed = reactVersion.trim();
|
|
34443
|
-
if (trimmed.length === 0) return null;
|
|
34444
|
-
const lowerBoundsOnly = trimmed.replace(UPPER_BOUND_COMPARATOR_PATTERN, " ").trim();
|
|
34445
|
-
if (lowerBoundsOnly.length === 0) return null;
|
|
34446
|
-
const majorMinorMatch = lowerBoundsOnly.match(MAJOR_MINOR_PATTERN);
|
|
34447
|
-
if (majorMinorMatch) {
|
|
34448
|
-
const major = Number.parseInt(majorMinorMatch[1], 10);
|
|
34449
|
-
const minor = Number.parseInt(majorMinorMatch[2], 10);
|
|
34450
|
-
if (!Number.isFinite(major) || major <= 0) return null;
|
|
34451
|
-
if (!Number.isFinite(minor) || minor < 0) return null;
|
|
34452
|
-
return {
|
|
34453
|
-
major,
|
|
34454
|
-
minor
|
|
34455
|
-
};
|
|
34456
|
-
}
|
|
34457
|
-
const majorOnlyMatch = lowerBoundsOnly.match(MAJOR_ONLY_PATTERN);
|
|
34458
|
-
if (!majorOnlyMatch) return null;
|
|
34459
|
-
const major = Number.parseInt(majorOnlyMatch[1], 10);
|
|
34460
|
-
if (!Number.isFinite(major) || major <= 0) return null;
|
|
34461
|
-
return {
|
|
34462
|
-
major,
|
|
34463
|
-
minor: 0
|
|
34464
|
-
};
|
|
34465
|
-
};
|
|
34466
|
-
const isReactAtLeast = (detected, required) => {
|
|
34467
|
-
if (detected === null) return true;
|
|
34468
|
-
if (detected.major !== required.major) return detected.major > required.major;
|
|
34469
|
-
return detected.minor >= required.minor;
|
|
34470
|
-
};
|
|
34471
|
-
const parseLowerBoundVersion = (versionSpec) => import_semver.validRange(versionSpec) !== null ? import_semver.minVersion(versionSpec) : import_semver.coerce(versionSpec);
|
|
34472
|
-
const parseTailwindMajorMinor = (tailwindVersion) => {
|
|
34473
|
-
if (typeof tailwindVersion !== "string") return null;
|
|
34474
|
-
const trimmed = tailwindVersion.trim();
|
|
34475
|
-
if (trimmed.length === 0) return null;
|
|
34476
|
-
const lowerBound = parseLowerBoundVersion(trimmed);
|
|
34477
|
-
if (lowerBound === null || lowerBound.major <= 0) return null;
|
|
34478
|
-
return {
|
|
34479
|
-
major: lowerBound.major,
|
|
34480
|
-
minor: lowerBound.minor
|
|
34481
|
-
};
|
|
34482
|
-
};
|
|
34483
|
-
const isTailwindAtLeast = (detected, required) => {
|
|
34484
|
-
if (detected === null) return true;
|
|
34485
|
-
if (detected.major !== required.major) return detected.major > required.major;
|
|
34486
|
-
return detected.minor >= required.minor;
|
|
34487
|
-
};
|
|
34488
34496
|
const messageFromUnknown = (error) => error instanceof Error ? error.message : String(error);
|
|
34489
34497
|
var InvalidGlobPatternError = class extends Error {
|
|
34490
34498
|
pattern;
|
|
@@ -37186,64 +37194,64 @@ function* collectSecurityScanFiles(rootDirectory) {
|
|
|
37186
37194
|
}
|
|
37187
37195
|
}
|
|
37188
37196
|
}
|
|
37189
|
-
|
|
37190
|
-
|
|
37191
|
-
|
|
37192
|
-
|
|
37193
|
-
|
|
37194
|
-
|
|
37195
|
-
|
|
37197
|
+
const CLIENT_ONLY_FRAMEWORKS = new Set([
|
|
37198
|
+
"vite",
|
|
37199
|
+
"cra",
|
|
37200
|
+
"gatsby",
|
|
37201
|
+
"react-native",
|
|
37202
|
+
"expo"
|
|
37203
|
+
]);
|
|
37204
|
+
const addMajorLadder = (capabilities, name, major, earliest, latest) => {
|
|
37205
|
+
if (major === null) return;
|
|
37206
|
+
const cappedMajor = Math.min(major, latest);
|
|
37207
|
+
for (let candidate = earliest; candidate <= cappedMajor; candidate += 1) capabilities.add(`${name}:${candidate}`);
|
|
37208
|
+
};
|
|
37196
37209
|
const buildCapabilities = (project) => {
|
|
37197
37210
|
const capabilities = /* @__PURE__ */ new Set();
|
|
37198
37211
|
capabilities.add(project.framework);
|
|
37199
|
-
if (
|
|
37212
|
+
if (project.reactVersion !== null || project.preactVersion !== null) capabilities.add("react");
|
|
37200
37213
|
if (project.framework === "expo" || project.framework === "react-native" || project.hasReactNativeWorkspace) capabilities.add("react-native");
|
|
37201
37214
|
if (project.expoVersion !== null) capabilities.add("expo");
|
|
37215
|
+
if ((project.framework === "nextjs" || project.framework === "tanstack-start" || project.framework === "remix") && !project.isStaticExport) capabilities.add("server-actions");
|
|
37216
|
+
if (CLIENT_ONLY_FRAMEWORKS.has(project.framework)) capabilities.add("client-only");
|
|
37217
|
+
if (project.isStaticExport) capabilities.add("nextjs:static-export");
|
|
37202
37218
|
if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 15) capabilities.add("nextjs:15");
|
|
37203
|
-
|
|
37204
|
-
if (
|
|
37205
|
-
|
|
37206
|
-
|
|
37207
|
-
|
|
37208
|
-
|
|
37209
|
-
|
|
37210
|
-
|
|
37211
|
-
|
|
37212
|
-
|
|
37213
|
-
|
|
37214
|
-
if (project.
|
|
37215
|
-
capabilities.add("tailwind");
|
|
37216
|
-
if (isTailwindAtLeast(parseTailwindMajorMinor(project.tailwindVersion), {
|
|
37217
|
-
major: 3,
|
|
37218
|
-
minor: 4
|
|
37219
|
-
})) capabilities.add("tailwind:3.4");
|
|
37220
|
-
}
|
|
37221
|
-
if (project.zodVersion !== null) {
|
|
37222
|
-
capabilities.add("zod");
|
|
37223
|
-
if (project.zodMajorVersion !== null && project.zodMajorVersion >= 4) capabilities.add("zod:4");
|
|
37224
|
-
}
|
|
37219
|
+
addMajorLadder(capabilities, "react", project.reactMajorVersion, 17, 30);
|
|
37220
|
+
if (project.reactMajorVersion !== null && project.reactMajorVersion >= 19 && isMajorMinorAtLeast(parseReactMajorMinor(project.reactVersion), {
|
|
37221
|
+
major: 19,
|
|
37222
|
+
minor: 2
|
|
37223
|
+
})) capabilities.add("react:19.2");
|
|
37224
|
+
if (project.tailwindVersion !== null) capabilities.add("tailwind");
|
|
37225
|
+
if (project.tailwindVersion !== null && isMajorMinorAtLeast(parseTailwindMajorMinor(project.tailwindVersion), {
|
|
37226
|
+
major: 3,
|
|
37227
|
+
minor: 4
|
|
37228
|
+
})) capabilities.add("tailwind:3.4");
|
|
37229
|
+
if (project.zodVersion !== null) capabilities.add("zod");
|
|
37230
|
+
if (project.zodMajorVersion !== null && project.zodMajorVersion >= 4) capabilities.add("zod:4");
|
|
37225
37231
|
if (project.isPreES2023Target) capabilities.add("pre-es2023");
|
|
37226
37232
|
if (project.hasReactCompiler) capabilities.add("react-compiler");
|
|
37227
37233
|
if (project.hasTanStackQuery) capabilities.add("tanstack-query");
|
|
37228
37234
|
if (project.hasTypeScript) capabilities.add("typescript");
|
|
37229
|
-
if (project.preactVersion !== null)
|
|
37230
|
-
|
|
37231
|
-
|
|
37232
|
-
|
|
37233
|
-
|
|
37234
|
-
|
|
37235
|
-
|
|
37236
|
-
|
|
37237
|
-
|
|
37235
|
+
if (project.preactVersion !== null) capabilities.add("preact");
|
|
37236
|
+
addMajorLadder(capabilities, "preact", project.preactMajorVersion, 10, 20);
|
|
37237
|
+
if (project.preactVersion !== null && project.reactVersion === null) capabilities.add("pure-preact");
|
|
37238
|
+
return capabilities;
|
|
37239
|
+
};
|
|
37240
|
+
const capabilitiesByProject = /* @__PURE__ */ new WeakMap();
|
|
37241
|
+
const getCapabilities = (project) => {
|
|
37242
|
+
const cached = capabilitiesByProject.get(project);
|
|
37243
|
+
if (cached !== void 0) return cached;
|
|
37244
|
+
const capabilities = buildCapabilities(project);
|
|
37245
|
+
capabilitiesByProject.set(project, capabilities);
|
|
37238
37246
|
return capabilities;
|
|
37239
37247
|
};
|
|
37240
|
-
const shouldEnableRule = (requires, tags, capabilities, ignoredTags,
|
|
37248
|
+
const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen) => {
|
|
37241
37249
|
if (requires) {
|
|
37242
37250
|
for (const capability of requires) if (!capabilities.has(capability)) return false;
|
|
37243
37251
|
}
|
|
37244
37252
|
if (tags?.includes("react-jsx-only") && !capabilities.has("react")) return false;
|
|
37245
|
-
if (
|
|
37246
|
-
for (const capability of
|
|
37253
|
+
if (disabledWhen) {
|
|
37254
|
+
for (const capability of disabledWhen) if (capabilities.has(capability)) return false;
|
|
37247
37255
|
}
|
|
37248
37256
|
if (tags) {
|
|
37249
37257
|
for (const tag of tags) if (ignoredTags.has(tag)) return false;
|
|
@@ -37254,14 +37262,14 @@ const yieldToEventLoop = () => new Promise((resolve) => {
|
|
|
37254
37262
|
setImmediate(resolve);
|
|
37255
37263
|
});
|
|
37256
37264
|
const createSecurityScanSession = (rootDirectory, options) => {
|
|
37257
|
-
const capabilities = options.project ?
|
|
37265
|
+
const capabilities = options.project ? getCapabilities(options.project) : /* @__PURE__ */ new Set();
|
|
37258
37266
|
const ignoredTags = options.ignoredTags ?? /* @__PURE__ */ new Set();
|
|
37259
37267
|
const enabledScanRules = REACT_DOCTOR_RULES.flatMap((entry) => {
|
|
37260
37268
|
const rule = entry.rule;
|
|
37261
37269
|
const scan = rule.scan;
|
|
37262
37270
|
if (typeof scan !== "function") return [];
|
|
37263
37271
|
if (rule.defaultEnabled === false) return [];
|
|
37264
|
-
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.
|
|
37272
|
+
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) return [];
|
|
37265
37273
|
return [{
|
|
37266
37274
|
entry,
|
|
37267
37275
|
scan,
|
|
@@ -37281,6 +37289,7 @@ const createSecurityScanSession = (rootDirectory, options) => {
|
|
|
37281
37289
|
return status === true;
|
|
37282
37290
|
};
|
|
37283
37291
|
const scanFileByRule = function* (file) {
|
|
37292
|
+
if (file === null) return;
|
|
37284
37293
|
for (const { entry, scan, committedFilesOnly } of enabledScanRules) {
|
|
37285
37294
|
for (const finding of scan(file)) {
|
|
37286
37295
|
if (committedFilesOnly && isFileGitIgnored(file)) continue;
|
|
@@ -39161,7 +39170,7 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
39161
39170
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
39162
39171
|
const jsPlugins = [];
|
|
39163
39172
|
if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
|
|
39164
|
-
const capabilities =
|
|
39173
|
+
const capabilities = getCapabilities(project);
|
|
39165
39174
|
const enabledReactDoctorRules = {};
|
|
39166
39175
|
for (const registryEntry of REACT_DOCTOR_RULES) {
|
|
39167
39176
|
const rule = reactDoctorPlugin.rules[registryEntry.id];
|
|
@@ -39172,7 +39181,7 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
39172
39181
|
if (rule.scan !== void 0) continue;
|
|
39173
39182
|
if (customRulesOnly && registryEntry.originallyExternal) continue;
|
|
39174
39183
|
if (rule.framework !== "global" && !rule.requires) continue;
|
|
39175
|
-
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.
|
|
39184
|
+
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) continue;
|
|
39176
39185
|
const explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey: registryEntry.key }, severityControls);
|
|
39177
39186
|
if (rule.defaultEnabled === false && explicitRuleOverride === void 0) continue;
|
|
39178
39187
|
const severity = resolveRuleSeverityOverride({
|
|
@@ -39203,6 +39212,7 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
39203
39212
|
settings: { "react-doctor": {
|
|
39204
39213
|
framework: project.framework,
|
|
39205
39214
|
rootDirectory: resolveSettingsRootDirectory(project.rootDirectory),
|
|
39215
|
+
capabilities: [...capabilities].sort(),
|
|
39206
39216
|
...project.shopifyFlashListMajorVersion !== null ? { shopifyFlashListMajorVersion: project.shopifyFlashListMajorVersion } : {},
|
|
39207
39217
|
...serverAuthFunctionNames && serverAuthFunctionNames.length > 0 ? { serverAuthFunctionNames: [...serverAuthFunctionNames] } : {}
|
|
39208
39218
|
} },
|
|
@@ -39493,21 +39503,6 @@ const mapWithConcurrency = async (items, concurrency, task) => {
|
|
|
39493
39503
|
if (errors.length > 0) throw errors[0];
|
|
39494
39504
|
return results;
|
|
39495
39505
|
};
|
|
39496
|
-
const getPublicEnvPrefix = (framework) => {
|
|
39497
|
-
switch (framework) {
|
|
39498
|
-
case "nextjs": return "NEXT_PUBLIC_*";
|
|
39499
|
-
case "vite":
|
|
39500
|
-
case "tanstack-start": return "VITE_*";
|
|
39501
|
-
case "cra": return "REACT_APP_*";
|
|
39502
|
-
case "gatsby": return "GATSBY_*";
|
|
39503
|
-
default: return null;
|
|
39504
|
-
}
|
|
39505
|
-
};
|
|
39506
|
-
const buildNoSecretsRecommendation = (project, fallbackRecommendation) => {
|
|
39507
|
-
const publicEnvPrefix = getPublicEnvPrefix(project.framework);
|
|
39508
|
-
if (!publicEnvPrefix) return fallbackRecommendation;
|
|
39509
|
-
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`;
|
|
39510
|
-
};
|
|
39511
39506
|
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";
|
|
39512
39507
|
const ACCESSORS_MIN_VERSION = "3.15.0";
|
|
39513
39508
|
const supportsAccessors = (reanimatedVersion) => {
|
|
@@ -40188,8 +40183,14 @@ const PLUGIN_CATEGORY_MAP = {
|
|
|
40188
40183
|
};
|
|
40189
40184
|
const lookupOwnString = (record, key) => Object.hasOwn(record, key) ? record[key] : void 0;
|
|
40190
40185
|
const getRuleRecommendation = (ruleName, project) => {
|
|
40191
|
-
|
|
40192
|
-
return
|
|
40186
|
+
const rule = reactDoctorPlugin.rules[ruleName];
|
|
40187
|
+
if (!rule) return void 0;
|
|
40188
|
+
if (rule.recommendationFor) {
|
|
40189
|
+
const capabilities = getCapabilities(project);
|
|
40190
|
+
const conditionalRecommendation = rule.recommendationFor((capability) => capabilities.has(capability));
|
|
40191
|
+
if (conditionalRecommendation !== void 0) return conditionalRecommendation;
|
|
40192
|
+
}
|
|
40193
|
+
return rule.recommendation;
|
|
40193
40194
|
};
|
|
40194
40195
|
const getRuleCategory = (ruleName) => reactDoctorPlugin.rules[ruleName]?.category;
|
|
40195
40196
|
const getRuleTitle = (ruleName) => reactDoctorPlugin.rules[ruleName]?.title;
|
|
@@ -44614,5 +44615,5 @@ const startLanguageServer = () => {
|
|
|
44614
44615
|
};
|
|
44615
44616
|
//#endregion
|
|
44616
44617
|
export { startLanguageServer };
|
|
44617
|
-
!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]="
|
|
44618
|
-
//# debugId=
|
|
44618
|
+
!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]="94aee89d-9f35-5b59-a911-566ac2ef5a0a")}catch(e){}}();
|
|
44619
|
+
//# debugId=94aee89d-9f35-5b59-a911-566ac2ef5a0a
|