deslop-js 0.0.7 → 0.0.9

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.
Files changed (3) hide show
  1. package/dist/index.cjs +860 -130
  2. package/dist/index.mjs +861 -131
  3. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import path, { basename, dirname, extname, join, relative, resolve, sep } from "node:path";
1
+ import path, { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
2
2
  import { existsSync, readFileSync, statSync } from "node:fs";
3
3
  import fg from "fast-glob";
4
4
  import { readFile } from "node:fs/promises";
@@ -224,7 +224,9 @@ const PLATFORM_SUFFIXES = [
224
224
  ".desktop",
225
225
  ".windows",
226
226
  ".macos",
227
- ".any"
227
+ ".any",
228
+ ".server",
229
+ ".client"
228
230
  ];
229
231
  const REACT_NATIVE_PLATFORM_EXTENSIONS = [
230
232
  ".web.ts",
@@ -575,6 +577,10 @@ const extractNamedExportDeclaration = (node, sourceText, exports) => {
575
577
  }
576
578
  };
577
579
  const extractDefaultExportDeclaration = (node, sourceText, exports) => {
580
+ const defaultExpression = node.declaration;
581
+ let defaultExportLocalName;
582
+ if (defaultExpression?.type === "Identifier" && typeof defaultExpression.name === "string") defaultExportLocalName = defaultExpression.name;
583
+ else if ((defaultExpression?.type === "FunctionDeclaration" || defaultExpression?.type === "ClassDeclaration") && defaultExpression.id?.name) defaultExportLocalName = defaultExpression.id.name;
578
584
  exports.push({
579
585
  name: "default",
580
586
  isDefault: true,
@@ -585,7 +591,8 @@ const extractDefaultExportDeclaration = (node, sourceText, exports) => {
585
591
  reExportOriginalName: void 0,
586
592
  isNamespaceReExport: false,
587
593
  line: getLineFromOffset(sourceText, node.start),
588
- column: getColumnFromOffset(sourceText, node.start)
594
+ column: getColumnFromOffset(sourceText, node.start),
595
+ defaultExportLocalName
589
596
  });
590
597
  };
591
598
  const extractExportAllDeclaration = (node, sourceText, exports) => {
@@ -1066,6 +1073,12 @@ const collectWorkspacePatterns = (rootDir) => {
1066
1073
  const packageLines = extractPnpmWorkspacePackages(readFileSync(pnpmWorkspacePath, "utf-8"));
1067
1074
  patterns.push(...packageLines);
1068
1075
  } catch {}
1076
+ const lernaJsonPath = join(rootDir, "lerna.json");
1077
+ if (existsSync(lernaJsonPath)) try {
1078
+ const content = readFileSync(lernaJsonPath, "utf-8");
1079
+ const lernaJson = JSON.parse(content);
1080
+ if (Array.isArray(lernaJson.packages)) patterns.push(...lernaJson.packages.filter((pattern) => typeof pattern === "string" && !pattern.startsWith("!")));
1081
+ } catch {}
1069
1082
  return patterns;
1070
1083
  };
1071
1084
  const extractPnpmWorkspacePackages = (yamlContent) => {
@@ -1627,6 +1640,54 @@ const resolveSourcePath = (distPath, directory) => {
1627
1640
  }
1628
1641
  };
1629
1642
 
1643
+ //#endregion
1644
+ //#region src/utils/find-monorepo-root.ts
1645
+ const MONOREPO_ROOT_MARKERS = [
1646
+ "pnpm-workspace.yaml",
1647
+ "pnpm-workspace.yml",
1648
+ "lerna.json",
1649
+ "nx.json",
1650
+ "turbo.json",
1651
+ "rush.json"
1652
+ ];
1653
+ const LOCKFILE_MARKERS = [
1654
+ "pnpm-lock.yaml",
1655
+ "yarn.lock",
1656
+ "package-lock.json",
1657
+ "bun.lockb",
1658
+ "bun.lock"
1659
+ ];
1660
+ const MAX_MONOREPO_WALK_DEPTH = 5;
1661
+ const findMonorepoRoot = (rootDir) => {
1662
+ let currentDirectory = resolve(rootDir);
1663
+ let walkedDepth = 0;
1664
+ while (walkedDepth < MAX_MONOREPO_WALK_DEPTH) {
1665
+ const parentDirectory = dirname(currentDirectory);
1666
+ if (parentDirectory === currentDirectory) break;
1667
+ currentDirectory = parentDirectory;
1668
+ walkedDepth++;
1669
+ if (existsSync(join(currentDirectory, ".git"))) {
1670
+ for (const marker of MONOREPO_ROOT_MARKERS) if (existsSync(join(currentDirectory, marker))) return currentDirectory;
1671
+ const packageJsonPath = join(currentDirectory, "package.json");
1672
+ if (existsSync(packageJsonPath)) try {
1673
+ const content = readFileSync(packageJsonPath, "utf-8");
1674
+ if (JSON.parse(content).workspaces) return currentDirectory;
1675
+ } catch {}
1676
+ for (const lockfile of LOCKFILE_MARKERS) if (existsSync(join(currentDirectory, lockfile))) return currentDirectory;
1677
+ return;
1678
+ }
1679
+ for (const marker of MONOREPO_ROOT_MARKERS) if (existsSync(join(currentDirectory, marker))) return currentDirectory;
1680
+ const packageJsonPath = join(currentDirectory, "package.json");
1681
+ if (existsSync(packageJsonPath)) try {
1682
+ const content = readFileSync(packageJsonPath, "utf-8");
1683
+ if (JSON.parse(content).workspaces) return currentDirectory;
1684
+ } catch {
1685
+ continue;
1686
+ }
1687
+ for (const lockfile of LOCKFILE_MARKERS) if (existsSync(join(currentDirectory, lockfile))) return currentDirectory;
1688
+ }
1689
+ };
1690
+
1630
1691
  //#endregion
1631
1692
  //#region src/collect/entries.ts
1632
1693
  const collectSourceFiles = async (config) => {
@@ -1732,6 +1793,14 @@ const resolveEntries = async (config) => {
1732
1793
  for (const entryPath of allDiscoveredEntries) if (entryPath.endsWith(".html") && existsSync(entryPath)) htmlScriptEntries.push(...extractScriptTagsFromHtmlFile(entryPath));
1733
1794
  const angularEntries = extractAngularEntryPoints(absoluteRoot);
1734
1795
  for (const workspacePackage of entryEligiblePackages) angularEntries.push(...extractAngularEntryPoints(workspacePackage.directory));
1796
+ const browserExtensionEntries = extractBrowserExtensionEntries(absoluteRoot);
1797
+ for (const workspacePackage of entryEligiblePackages) browserExtensionEntries.push(...extractBrowserExtensionEntries(workspacePackage.directory));
1798
+ const webWorkerEntries = extractWebWorkerEntries(absoluteRoot);
1799
+ for (const workspacePackage of entryEligiblePackages) webWorkerEntries.push(...extractWebWorkerEntries(workspacePackage.directory));
1800
+ const tsConfigIncludeEntries = extractTsConfigIncludeFilesEntries(absoluteRoot);
1801
+ for (const workspacePackage of entryEligiblePackages) tsConfigIncludeEntries.push(...extractTsConfigIncludeFilesEntries(workspacePackage.directory));
1802
+ const wranglerEntries = extractWranglerEntries(absoluteRoot);
1803
+ for (const workspacePackage of entryEligiblePackages) wranglerEntries.push(...extractWranglerEntries(workspacePackage.directory));
1735
1804
  const testSetupEntries = extractTestSetupFiles(absoluteRoot);
1736
1805
  for (const workspacePackage of entryEligiblePackages) testSetupEntries.push(...extractTestSetupFiles(workspacePackage.directory));
1737
1806
  const pluginFileEntries = extractNextConfigPluginFiles(absoluteRoot);
@@ -1753,6 +1822,10 @@ const resolveEntries = async (config) => {
1753
1822
  ...bundlerConfigEntries,
1754
1823
  ...htmlScriptEntries,
1755
1824
  ...angularEntries,
1825
+ ...browserExtensionEntries,
1826
+ ...webWorkerEntries,
1827
+ ...tsConfigIncludeEntries,
1828
+ ...wranglerEntries,
1756
1829
  ...pluginFileEntries,
1757
1830
  ...toolingDiscovery.entryFiles,
1758
1831
  ...ciEntries
@@ -2396,6 +2469,231 @@ const extractScriptTagsFromHtmlFile = (htmlFilePath) => {
2396
2469
  } catch {}
2397
2470
  return entries;
2398
2471
  };
2472
+ const TSCONFIG_FILENAME_GLOBS = ["tsconfig.json", "tsconfig.*.json"];
2473
+ const stripJsoncCommentsLocal = (sourceText) => {
2474
+ let result = "";
2475
+ let insideString = false;
2476
+ let index = 0;
2477
+ while (index < sourceText.length) {
2478
+ const ch = sourceText[index];
2479
+ if (insideString) {
2480
+ if (ch === "\\" && index + 1 < sourceText.length) {
2481
+ result += sourceText[index] + sourceText[index + 1];
2482
+ index += 2;
2483
+ continue;
2484
+ }
2485
+ if (ch === "\"") insideString = false;
2486
+ result += ch;
2487
+ index++;
2488
+ continue;
2489
+ }
2490
+ if (ch === "\"") {
2491
+ insideString = true;
2492
+ result += ch;
2493
+ index++;
2494
+ continue;
2495
+ }
2496
+ if (ch === "/" && index + 1 < sourceText.length) {
2497
+ if (sourceText[index + 1] === "/") {
2498
+ while (index < sourceText.length && sourceText[index] !== "\n") index++;
2499
+ continue;
2500
+ }
2501
+ if (sourceText[index + 1] === "*") {
2502
+ index += 2;
2503
+ while (index + 1 < sourceText.length && !(sourceText[index] === "*" && sourceText[index + 1] === "/")) index++;
2504
+ index += 2;
2505
+ continue;
2506
+ }
2507
+ }
2508
+ result += ch;
2509
+ index++;
2510
+ }
2511
+ return result.replace(/,(\s*[}\]])/g, "$1");
2512
+ };
2513
+ const extractTsConfigIncludeFilesEntries = (directory) => {
2514
+ const entries = [];
2515
+ const tsconfigPaths = fg.sync(TSCONFIG_FILENAME_GLOBS, {
2516
+ cwd: directory,
2517
+ absolute: true,
2518
+ onlyFiles: true,
2519
+ ignore: [
2520
+ "**/node_modules/**",
2521
+ "**/dist/**",
2522
+ "**/build/**"
2523
+ ],
2524
+ deep: 1
2525
+ });
2526
+ for (const tsconfigPath of tsconfigPaths) try {
2527
+ const cleaned = stripJsoncCommentsLocal(readFileSync(tsconfigPath, "utf-8"));
2528
+ const tsconfigJson = JSON.parse(cleaned);
2529
+ const tsconfigDir = dirname(tsconfigPath);
2530
+ const collectPaths = (rawList) => {
2531
+ if (!Array.isArray(rawList)) return;
2532
+ for (const item of rawList) {
2533
+ if (typeof item !== "string") continue;
2534
+ if (item.includes("*") || item.includes("?")) continue;
2535
+ const candidatePath = resolve(tsconfigDir, item);
2536
+ if (existsSync(candidatePath)) entries.push(candidatePath);
2537
+ }
2538
+ };
2539
+ collectPaths(tsconfigJson.include);
2540
+ collectPaths(tsconfigJson.files);
2541
+ } catch {}
2542
+ return entries;
2543
+ };
2544
+ const WRANGLER_TOML_MAIN_PATTERN = /^\s*main\s*=\s*['"]([^'"\n]+)['"]/m;
2545
+ const WRANGLER_JSON_MAIN_PATTERN = /"main"\s*:\s*"([^"]+)"/;
2546
+ const WRANGLER_SERVICE_BINDINGS_PATTERN = /entry_point\s*=\s*['"]([^'"\n]+)['"]/g;
2547
+ const extractWranglerEntries = (directory) => {
2548
+ const entries = [];
2549
+ const wranglerPaths = fg.sync([
2550
+ "wrangler.toml",
2551
+ "wrangler.json",
2552
+ "wrangler.jsonc"
2553
+ ], {
2554
+ cwd: directory,
2555
+ absolute: true,
2556
+ onlyFiles: true,
2557
+ ignore: ["**/node_modules/**"],
2558
+ deep: 1
2559
+ });
2560
+ for (const wranglerPath of wranglerPaths) try {
2561
+ const content = readFileSync(wranglerPath, "utf-8");
2562
+ const wranglerDir = dirname(wranglerPath);
2563
+ const mainMatch = wranglerPath.endsWith(".toml") ? content.match(WRANGLER_TOML_MAIN_PATTERN) : content.match(WRANGLER_JSON_MAIN_PATTERN);
2564
+ if (mainMatch?.[1]) {
2565
+ const candidatePath = resolve(wranglerDir, mainMatch[1]);
2566
+ if (existsSync(candidatePath)) entries.push(candidatePath);
2567
+ else {
2568
+ const sourceCandidate = resolveSourcePath(candidatePath, wranglerDir);
2569
+ if (sourceCandidate) entries.push(sourceCandidate);
2570
+ }
2571
+ }
2572
+ let entryPointMatch;
2573
+ WRANGLER_SERVICE_BINDINGS_PATTERN.lastIndex = 0;
2574
+ while ((entryPointMatch = WRANGLER_SERVICE_BINDINGS_PATTERN.exec(content)) !== null) {
2575
+ const candidatePath = resolve(wranglerDir, entryPointMatch[1]);
2576
+ if (existsSync(candidatePath)) entries.push(candidatePath);
2577
+ }
2578
+ } catch {}
2579
+ return entries;
2580
+ };
2581
+ const WORKER_FILE_GLOBS = [
2582
+ "**/*.worker.{ts,tsx,js,jsx,mts,mjs,cts,cjs}",
2583
+ "**/*.sw.{ts,tsx,js,jsx,mts,mjs,cts,cjs}",
2584
+ "**/sw.{ts,tsx,js,jsx,mts,mjs,cts,cjs}",
2585
+ "**/service-worker.{ts,tsx,js,jsx,mts,mjs,cts,cjs}"
2586
+ ];
2587
+ const extractWebWorkerEntries = (directory) => {
2588
+ return fg.sync(WORKER_FILE_GLOBS, {
2589
+ cwd: directory,
2590
+ absolute: true,
2591
+ onlyFiles: true,
2592
+ ignore: [
2593
+ "**/node_modules/**",
2594
+ "**/dist/**",
2595
+ "**/build/**",
2596
+ "**/.next/**",
2597
+ "**/out/**"
2598
+ ],
2599
+ deep: 8
2600
+ });
2601
+ };
2602
+ const collectBrowserExtensionManifestPaths = (manifest) => {
2603
+ const candidatePaths = [];
2604
+ if (typeof manifest !== "object" || manifest === null) return candidatePaths;
2605
+ const manifestRecord = manifest;
2606
+ const background = manifestRecord.background;
2607
+ if (typeof background === "object" && background !== null) {
2608
+ const backgroundRecord = background;
2609
+ if (typeof backgroundRecord.service_worker === "string") candidatePaths.push(backgroundRecord.service_worker);
2610
+ if (typeof backgroundRecord.page === "string") candidatePaths.push(backgroundRecord.page);
2611
+ if (typeof backgroundRecord.scripts === "string") candidatePaths.push(backgroundRecord.scripts);
2612
+ if (Array.isArray(backgroundRecord.scripts)) {
2613
+ for (const scriptPath of backgroundRecord.scripts) if (typeof scriptPath === "string") candidatePaths.push(scriptPath);
2614
+ }
2615
+ }
2616
+ const contentScripts = manifestRecord.content_scripts;
2617
+ if (Array.isArray(contentScripts)) for (const contentScript of contentScripts) {
2618
+ if (typeof contentScript !== "object" || contentScript === null) continue;
2619
+ const contentScriptRecord = contentScript;
2620
+ if (Array.isArray(contentScriptRecord.js)) {
2621
+ for (const scriptPath of contentScriptRecord.js) if (typeof scriptPath === "string") candidatePaths.push(scriptPath);
2622
+ }
2623
+ if (Array.isArray(contentScriptRecord.css)) {
2624
+ for (const stylePath of contentScriptRecord.css) if (typeof stylePath === "string") candidatePaths.push(stylePath);
2625
+ }
2626
+ }
2627
+ const action = manifestRecord.action ?? manifestRecord.browser_action ?? manifestRecord.page_action;
2628
+ if (typeof action === "object" && action !== null) {
2629
+ const actionRecord = action;
2630
+ if (typeof actionRecord.default_popup === "string") candidatePaths.push(actionRecord.default_popup);
2631
+ }
2632
+ if (typeof manifestRecord.devtools_page === "string") candidatePaths.push(manifestRecord.devtools_page);
2633
+ if (typeof manifestRecord.options_page === "string") candidatePaths.push(manifestRecord.options_page);
2634
+ if (typeof manifestRecord.options_ui === "object" && manifestRecord.options_ui !== null) {
2635
+ const optionsRecord = manifestRecord.options_ui;
2636
+ if (typeof optionsRecord.page === "string") candidatePaths.push(optionsRecord.page);
2637
+ }
2638
+ if (typeof manifestRecord.sandbox === "object" && manifestRecord.sandbox !== null) {
2639
+ const sandboxRecord = manifestRecord.sandbox;
2640
+ if (Array.isArray(sandboxRecord.pages)) {
2641
+ for (const pagePath of sandboxRecord.pages) if (typeof pagePath === "string") candidatePaths.push(pagePath);
2642
+ }
2643
+ }
2644
+ return candidatePaths;
2645
+ };
2646
+ const isLikelyBrowserExtensionManifest = (manifest) => {
2647
+ if (typeof manifest !== "object" || manifest === null) return false;
2648
+ return typeof manifest.manifest_version === "number";
2649
+ };
2650
+ const extractBrowserExtensionEntries = (directory) => {
2651
+ const entries = [];
2652
+ const manifestPaths = fg.sync([
2653
+ "manifest.json",
2654
+ "manifest.*.json",
2655
+ "src/manifest.json",
2656
+ "src/manifest.*.json",
2657
+ "public/manifest.json",
2658
+ "public/manifest.*.json",
2659
+ "static/manifest.json"
2660
+ ], {
2661
+ cwd: directory,
2662
+ absolute: true,
2663
+ onlyFiles: true,
2664
+ ignore: [
2665
+ "**/node_modules/**",
2666
+ "**/dist/**",
2667
+ "**/build/**"
2668
+ ],
2669
+ deep: 3
2670
+ });
2671
+ for (const manifestPath of manifestPaths) try {
2672
+ const content = readFileSync(manifestPath, "utf-8");
2673
+ const manifest = JSON.parse(content);
2674
+ if (!isLikelyBrowserExtensionManifest(manifest)) continue;
2675
+ const manifestDir = dirname(manifestPath);
2676
+ const candidatePaths = collectBrowserExtensionManifestPaths(manifest);
2677
+ const resolutionRoots = [
2678
+ manifestDir,
2679
+ resolve(manifestDir, ".."),
2680
+ directory
2681
+ ];
2682
+ for (const candidatePath of candidatePaths) for (const resolutionRoot of resolutionRoots) {
2683
+ const candidateAbsolutePath = resolve(resolutionRoot, candidatePath);
2684
+ if (existsSync(candidateAbsolutePath)) {
2685
+ entries.push(candidateAbsolutePath);
2686
+ break;
2687
+ }
2688
+ const sourceFile = resolveSourcePath(candidateAbsolutePath, resolutionRoot);
2689
+ if (sourceFile) {
2690
+ entries.push(sourceFile);
2691
+ break;
2692
+ }
2693
+ }
2694
+ } catch {}
2695
+ return entries;
2696
+ };
2399
2697
  const ANGULAR_ENTRY_KEYS = [
2400
2698
  "main",
2401
2699
  "polyfills",
@@ -3126,8 +3424,14 @@ const FRAMEWORK_PATTERNS = [
3126
3424
  alwaysUsed: ["tsr.config.json", "app.config.{ts,js}"]
3127
3425
  },
3128
3426
  {
3129
- enablers: ["vite", "rolldown-vite"],
3130
- enablerPrefixes: ["@vitejs/"],
3427
+ enablers: [
3428
+ "vite",
3429
+ "rolldown-vite",
3430
+ "vite-plus",
3431
+ "@voidzero-dev/vite-plus-core",
3432
+ "@voidzero-dev/vite-plus-test"
3433
+ ],
3434
+ enablerPrefixes: ["@vitejs/", "@voidzero-dev/vite-plus"],
3131
3435
  entryPatterns: [
3132
3436
  "src/main.{ts,tsx,js,jsx}",
3133
3437
  "src/index.{ts,tsx,js,jsx}",
@@ -3415,10 +3719,25 @@ const detectBunTestRunner = (directory) => {
3415
3719
  return false;
3416
3720
  }
3417
3721
  };
3722
+ const readPackageJsonDependencies = (packageJsonPath) => {
3723
+ try {
3724
+ const content = readFileSync(packageJsonPath, "utf-8");
3725
+ const packageJson = JSON.parse(content);
3726
+ return {
3727
+ ...packageJson.dependencies,
3728
+ ...packageJson.devDependencies,
3729
+ ...packageJson.optionalDependencies
3730
+ };
3731
+ } catch {
3732
+ return {};
3733
+ }
3734
+ };
3418
3735
  const discoverTestRunnerEntryPoints = (rootDir, workspacePackages) => {
3419
3736
  const allEntries = [];
3420
3737
  const allAlwaysUsed = [];
3421
3738
  const directoriesToCheck = [rootDir, ...workspacePackages.map((workspacePackage) => workspacePackage.directory)];
3739
+ const monorepoRoot = findMonorepoRoot(rootDir);
3740
+ const monorepoRootDeps = monorepoRoot && monorepoRoot !== rootDir ? readPackageJsonDependencies(join(monorepoRoot, "package.json")) : {};
3422
3741
  for (const directory of directoriesToCheck) {
3423
3742
  const packageJsonPath = join(directory, "package.json");
3424
3743
  if (!existsSync(packageJsonPath)) continue;
@@ -3443,16 +3762,25 @@ const discoverTestRunnerEntryPoints = (rootDir, workspacePackages) => {
3443
3762
  })) return true;
3444
3763
  return runner.configFileActivators.some((configFile) => existsSync(join(checkDirectory, configFile)));
3445
3764
  };
3446
- for (const runner of TEST_FRAMEWORK_PATTERNS) if (isRunnerEnabled(runner, allDependencies, directory)) {
3447
- const isVitestRunner = runner.enablers.includes("vitest");
3448
- const isJestRunner = runner.enablers.includes("jest");
3449
- let customPatterns = [];
3450
- if (isVitestRunner) customPatterns = extractVitestIncludePatterns(directory);
3451
- else if (isJestRunner) customPatterns = extractJestTestMatchPatterns(directory);
3452
- if (customPatterns.length > 0) activatedPatterns.push(...customPatterns);
3453
- else activatedPatterns.push(...runner.entryPatterns);
3454
- activatedFixturePatterns.push(...runner.fixturePatterns);
3455
- activatedAlwaysUsed.push(...runner.alwaysUsed);
3765
+ for (const runner of TEST_FRAMEWORK_PATTERNS) {
3766
+ const enabledLocally = isRunnerEnabled(runner, allDependencies, directory);
3767
+ const enabledViaMonorepo = !enabledLocally && monorepoRoot && (isRunnerEnabled(runner, monorepoRootDeps, monorepoRoot) || runner.configFileActivators.some((configFile) => existsSync(join(monorepoRoot, configFile))));
3768
+ if (enabledLocally || enabledViaMonorepo) {
3769
+ const isVitestRunner = runner.enablers.includes("vitest");
3770
+ const isJestRunner = runner.enablers.includes("jest");
3771
+ let customPatterns = [];
3772
+ if (isVitestRunner) {
3773
+ customPatterns = extractVitestIncludePatterns(directory);
3774
+ if (customPatterns.length === 0 && monorepoRoot) customPatterns = extractVitestIncludePatterns(monorepoRoot);
3775
+ } else if (isJestRunner) {
3776
+ customPatterns = extractJestTestMatchPatterns(directory);
3777
+ if (customPatterns.length === 0 && monorepoRoot) customPatterns = extractJestTestMatchPatterns(monorepoRoot);
3778
+ }
3779
+ if (customPatterns.length > 0) activatedPatterns.push(...customPatterns);
3780
+ else activatedPatterns.push(...runner.entryPatterns);
3781
+ activatedFixturePatterns.push(...runner.fixturePatterns);
3782
+ activatedAlwaysUsed.push(...runner.alwaysUsed);
3783
+ }
3456
3784
  }
3457
3785
  if (activatedPatterns.length === 0 && directory !== rootDir) {
3458
3786
  const rootPackageJsonPath = join(rootDir, "package.json");
@@ -3517,6 +3845,45 @@ const isToolingPluginEnabled = (plugin, dependencies) => {
3517
3845
  }
3518
3846
  return false;
3519
3847
  };
3848
+ const FRAMEWORK_SCRIPT_BINARIES = {
3849
+ next: ["next"],
3850
+ nuxt: ["nuxt"],
3851
+ astro: ["astro"],
3852
+ gatsby: ["gatsby"],
3853
+ remix: ["remix"],
3854
+ "@sveltejs/kit": ["svelte-kit", "vite-svelte-kit"],
3855
+ "@docusaurus/core": ["docusaurus"],
3856
+ "@angular/core": ["ng"],
3857
+ "@nestjs/core": ["nest"],
3858
+ storybook: [
3859
+ "storybook",
3860
+ "start-storybook",
3861
+ "build-storybook"
3862
+ ]
3863
+ };
3864
+ const detectFrameworkFromScripts = (scripts) => {
3865
+ const enabledEnablers = /* @__PURE__ */ new Set();
3866
+ if (!scripts || typeof scripts !== "object") return enabledEnablers;
3867
+ for (const scriptValue of Object.values(scripts)) {
3868
+ if (typeof scriptValue !== "string") continue;
3869
+ const tokenized = scriptValue.split(/[\s|&;]+/);
3870
+ for (const token of tokenized) {
3871
+ const cleaned = token.replace(/^.*\//, "");
3872
+ for (const [enabler, binaries] of Object.entries(FRAMEWORK_SCRIPT_BINARIES)) if (binaries.includes(cleaned)) enabledEnablers.add(enabler);
3873
+ }
3874
+ }
3875
+ return enabledEnablers;
3876
+ };
3877
+ const readPackageScripts = (directory) => {
3878
+ const packageJsonPath = join(directory, "package.json");
3879
+ if (!existsSync(packageJsonPath)) return void 0;
3880
+ try {
3881
+ const content = readFileSync(packageJsonPath, "utf-8");
3882
+ return JSON.parse(content).scripts;
3883
+ } catch {
3884
+ return;
3885
+ }
3886
+ };
3520
3887
  const discoverToolingEntryPoints = (rootDir, workspacePackages) => {
3521
3888
  const allEntries = [];
3522
3889
  const allAlwaysUsed = [];
@@ -3532,6 +3899,8 @@ const discoverToolingEntryPoints = (rootDir, workspacePackages) => {
3532
3899
  ...rootPackageJson.optionalDependencies
3533
3900
  };
3534
3901
  } catch {}
3902
+ const monorepoRoot = findMonorepoRoot(rootDir);
3903
+ const monorepoRootDeps = monorepoRoot && monorepoRoot !== rootDir ? readPackageJsonDependencies(join(monorepoRoot, "package.json")) : {};
3535
3904
  for (const directory of directoriesToCheck) {
3536
3905
  const packageJsonPath = join(directory, "package.json");
3537
3906
  if (!existsSync(packageJsonPath)) continue;
@@ -3547,7 +3916,10 @@ const discoverToolingEntryPoints = (rootDir, workspacePackages) => {
3547
3916
  } catch {
3548
3917
  continue;
3549
3918
  }
3550
- const mergedDependencies = directory === rootDir ? rootDependencies : workspaceDependencies;
3919
+ const scriptDetectedEnablers = detectFrameworkFromScripts(readPackageScripts(directory));
3920
+ const mergedDependencies = { ...workspaceDependencies };
3921
+ if (directory === rootDir) Object.assign(mergedDependencies, rootDependencies);
3922
+ else for (const enabler of scriptDetectedEnablers) if (enabler in monorepoRootDeps || enabler in rootDependencies) mergedDependencies[enabler] = "*";
3551
3923
  const activatedPatterns = [];
3552
3924
  const activatedAlwaysUsed = [];
3553
3925
  for (const plugin of FRAMEWORK_PATTERNS) if (isToolingPluginEnabled(plugin, mergedDependencies)) {
@@ -3685,16 +4057,28 @@ const COMMON_RESOLVER_OPTIONS = {
3685
4057
  ".cjs": [".cts", ".cjs"]
3686
4058
  }
3687
4059
  };
4060
+ const WEBPACK_CONFIG_GLOBS = [
4061
+ "webpack.config.{js,ts,mjs,cjs}",
4062
+ "**/webpack*.config.{js,ts,mjs,cjs}",
4063
+ "**/webpack.config*.{js,ts,mjs,cjs}",
4064
+ "**/webpack*.config*.babel.{js,ts}"
4065
+ ];
4066
+ const WEBPACK_ALIAS_BLOCK_PATTERN = /alias\s*:\s*\{([\s\S]*?)\}/g;
4067
+ const WEBPACK_ALIAS_ENTRY_PATTERN = /["']?([@\w$./-]+)["']?\s*:\s*(?:path\.(?:resolve|join)\(\s*__dirname\s*,\s*((?:["'][^"']+["']\s*,?\s*)+)\)|["']([^"']+)["'])/g;
4068
+ const WEBPACK_MODULES_BLOCK_PATTERN = /modules\s*:\s*\[([\s\S]*?)\]/g;
4069
+ const WEBPACK_PATH_CALL_PATTERN = /path\.(?:resolve|join)\(\s*__dirname\s*,\s*((?:["'][^"']+["']\s*,?\s*)+)\)/g;
4070
+ const WEBPACK_STRING_LITERAL_PATTERN = /["']([^"']+)["']/g;
3688
4071
  const TSCONFIG_FILENAMES = [
3689
4072
  "tsconfig.json",
3690
4073
  "tsconfig.web.json",
3691
4074
  "tsconfig.app.json",
3692
- "tsconfig.base.json"
4075
+ "tsconfig.base.json",
4076
+ "jsconfig.json"
3693
4077
  ];
3694
- const findNearestTsconfig = (fromDir, rootDir) => {
4078
+ const findNearestTsconfig = (fromDir, rootDir, monorepoRootDir) => {
3695
4079
  let currentDirectory = fromDir;
3696
- const normalizedRoot = resolve(rootDir);
3697
- while (currentDirectory.length >= normalizedRoot.length) {
4080
+ const stopAt = monorepoRootDir ? resolve(monorepoRootDir) : resolve(rootDir);
4081
+ while (currentDirectory.length >= stopAt.length) {
3698
4082
  for (const tsconfigFilename of TSCONFIG_FILENAMES) {
3699
4083
  const tsconfigCandidate = join(currentDirectory, tsconfigFilename);
3700
4084
  if (cachedExistsSync(tsconfigCandidate)) return tsconfigCandidate;
@@ -3733,6 +4117,108 @@ const resolveScssPartial = (specifier, fromDirectory) => {
3733
4117
  candidates.push(join(basePath, `_index.sass`));
3734
4118
  for (const candidate of candidates) if (cachedExistsSync(candidate)) return candidate;
3735
4119
  };
4120
+ const isInsideDirectory = (filePath, directory) => {
4121
+ const relativePath = relative(directory, filePath);
4122
+ return relativePath === "" || !relativePath.startsWith("..") && !isAbsolute(relativePath);
4123
+ };
4124
+ const extractQuotedSegments = (value) => {
4125
+ const segments = [];
4126
+ let segmentMatch;
4127
+ WEBPACK_STRING_LITERAL_PATTERN.lastIndex = 0;
4128
+ while ((segmentMatch = WEBPACK_STRING_LITERAL_PATTERN.exec(value)) !== null) segments.push(segmentMatch[1]);
4129
+ return segments;
4130
+ };
4131
+ const resolveWebpackPathValue = (value, configDirectory) => {
4132
+ if (isAbsolute(value)) return value;
4133
+ return resolve(configDirectory, value);
4134
+ };
4135
+ const findWebpackConfigScope = (configPath, rootDir) => {
4136
+ let currentDirectory = dirname(configPath);
4137
+ const absoluteRoot = resolve(rootDir);
4138
+ while (currentDirectory.length >= absoluteRoot.length) {
4139
+ if (cachedExistsSync(join(currentDirectory, "package.json"))) return currentDirectory;
4140
+ const parentDirectory = dirname(currentDirectory);
4141
+ if (parentDirectory === currentDirectory) break;
4142
+ currentDirectory = parentDirectory;
4143
+ }
4144
+ return absoluteRoot;
4145
+ };
4146
+ const extractWebpackAliases = (content, configDirectory) => {
4147
+ const aliases = [];
4148
+ let aliasBlockMatch;
4149
+ WEBPACK_ALIAS_BLOCK_PATTERN.lastIndex = 0;
4150
+ while ((aliasBlockMatch = WEBPACK_ALIAS_BLOCK_PATTERN.exec(content)) !== null) {
4151
+ const aliasBlock = aliasBlockMatch[1];
4152
+ let aliasEntryMatch;
4153
+ WEBPACK_ALIAS_ENTRY_PATTERN.lastIndex = 0;
4154
+ while ((aliasEntryMatch = WEBPACK_ALIAS_ENTRY_PATTERN.exec(aliasBlock)) !== null) {
4155
+ const rawName = aliasEntryMatch[1];
4156
+ const pathCallSegments = aliasEntryMatch[2];
4157
+ const stringTarget = aliasEntryMatch[3];
4158
+ if (!pathCallSegments && !stringTarget) continue;
4159
+ const isExact = rawName.endsWith("$");
4160
+ const name = isExact ? rawName.slice(0, -1) : rawName.replace(/\/$/, "");
4161
+ let targetDirectory;
4162
+ if (pathCallSegments) targetDirectory = resolve(configDirectory, ...extractQuotedSegments(pathCallSegments));
4163
+ else if (stringTarget) targetDirectory = resolveWebpackPathValue(stringTarget, configDirectory);
4164
+ else continue;
4165
+ aliases.push({
4166
+ name,
4167
+ targetDirectory,
4168
+ isExact
4169
+ });
4170
+ }
4171
+ }
4172
+ return aliases;
4173
+ };
4174
+ const extractWebpackModuleDirectories = (content, configDirectory) => {
4175
+ const moduleDirectories = [];
4176
+ let modulesBlockMatch;
4177
+ WEBPACK_MODULES_BLOCK_PATTERN.lastIndex = 0;
4178
+ while ((modulesBlockMatch = WEBPACK_MODULES_BLOCK_PATTERN.exec(content)) !== null) {
4179
+ const modulesBlock = modulesBlockMatch[1];
4180
+ let pathCallMatch;
4181
+ WEBPACK_PATH_CALL_PATTERN.lastIndex = 0;
4182
+ while ((pathCallMatch = WEBPACK_PATH_CALL_PATTERN.exec(modulesBlock)) !== null) moduleDirectories.push(resolve(configDirectory, ...extractQuotedSegments(pathCallMatch[1])));
4183
+ let stringMatch;
4184
+ WEBPACK_STRING_LITERAL_PATTERN.lastIndex = 0;
4185
+ while ((stringMatch = WEBPACK_STRING_LITERAL_PATTERN.exec(modulesBlock)) !== null) {
4186
+ const moduleDirectory = stringMatch[1];
4187
+ if (moduleDirectory === "node_modules") continue;
4188
+ moduleDirectories.push(resolveWebpackPathValue(moduleDirectory, configDirectory));
4189
+ }
4190
+ }
4191
+ return [...new Set(moduleDirectories)];
4192
+ };
4193
+ const loadWebpackResolverConfigs = (rootDir) => {
4194
+ const configPaths = fg.sync(WEBPACK_CONFIG_GLOBS, {
4195
+ cwd: rootDir,
4196
+ absolute: true,
4197
+ onlyFiles: true,
4198
+ ignore: [
4199
+ "**/node_modules/**",
4200
+ "**/dist/**",
4201
+ "**/build/**"
4202
+ ],
4203
+ deep: 4
4204
+ });
4205
+ const configs = [];
4206
+ for (const configPath of configPaths) try {
4207
+ const content = cachedReadFileSync(configPath);
4208
+ const configDirectory = dirname(configPath);
4209
+ const aliases = extractWebpackAliases(content, configDirectory);
4210
+ const moduleDirectories = extractWebpackModuleDirectories(content, configDirectory);
4211
+ if (aliases.length === 0 && moduleDirectories.length === 0) continue;
4212
+ configs.push({
4213
+ scopeDirectory: findWebpackConfigScope(configPath, rootDir),
4214
+ aliases,
4215
+ moduleDirectories
4216
+ });
4217
+ } catch {
4218
+ continue;
4219
+ }
4220
+ return configs;
4221
+ };
3736
4222
  const createResolver = (config, workspacePackages = [], options = {}) => {
3737
4223
  const resolverCache = /* @__PURE__ */ new Map();
3738
4224
  const resolveResultCache = /* @__PURE__ */ new Map();
@@ -3769,18 +4255,20 @@ const createResolver = (config, workspacePackages = [], options = {}) => {
3769
4255
  };
3770
4256
  const workspaceNameToDirectory = /* @__PURE__ */ new Map();
3771
4257
  for (const workspacePackage of workspacePackages) workspaceNameToDirectory.set(workspacePackage.name, workspacePackage.directory);
4258
+ const webpackResolverConfigs = (options.monorepoRoot && options.monorepoRoot !== config.rootDir ? [config.rootDir, options.monorepoRoot] : [config.rootDir]).flatMap(loadWebpackResolverConfigs).sort((leftConfig, rightConfig) => rightConfig.scopeDirectory.length - leftConfig.scopeDirectory.length);
3772
4259
  let rootTsconfigPath;
3773
4260
  if (config.tsConfigPath) rootTsconfigPath = resolve(config.rootDir, config.tsConfigPath);
3774
- else for (const candidate of [
3775
- "tsconfig.json",
3776
- "tsconfig.web.json",
3777
- "tsconfig.app.json",
3778
- "tsconfig.base.json"
3779
- ]) {
3780
- const candidatePath = resolve(config.rootDir, candidate);
3781
- if (cachedExistsSync(candidatePath)) {
3782
- rootTsconfigPath = candidatePath;
3783
- break;
4261
+ else {
4262
+ const tsconfigSearchDirs = options.monorepoRoot ? [config.rootDir, options.monorepoRoot] : [config.rootDir];
4263
+ for (const searchDir of tsconfigSearchDirs) {
4264
+ for (const candidate of TSCONFIG_FILENAMES) {
4265
+ const candidatePath = resolve(searchDir, candidate);
4266
+ if (cachedExistsSync(candidatePath)) {
4267
+ rootTsconfigPath = candidatePath;
4268
+ break;
4269
+ }
4270
+ }
4271
+ if (rootTsconfigPath) break;
3784
4272
  }
3785
4273
  }
3786
4274
  const tsconfigPathCache = /* @__PURE__ */ new Map();
@@ -3789,24 +4277,56 @@ const createResolver = (config, workspacePackages = [], options = {}) => {
3789
4277
  const fileDir = dirname(filePath);
3790
4278
  const cached = tsconfigPathCache.get(fileDir);
3791
4279
  if (cached !== void 0) return cached;
3792
- const tsconfigResult = findNearestTsconfig(fileDir, config.rootDir) ?? rootTsconfigPath;
4280
+ const tsconfigResult = findNearestTsconfig(fileDir, config.rootDir, options.monorepoRoot) ?? rootTsconfigPath;
3793
4281
  tsconfigPathCache.set(fileDir, tsconfigResult);
3794
4282
  return tsconfigResult;
3795
4283
  };
3796
4284
  const tsconfigBaseUrlCache = /* @__PURE__ */ new Map();
3797
- const getBaseUrlDirectory = (tsconfigFile) => {
3798
- const cached = tsconfigBaseUrlCache.get(tsconfigFile);
3799
- if (cached !== void 0) return cached;
4285
+ const resolveExtendsPath = (extendsValue, fromDir) => {
4286
+ if (extendsValue.startsWith(".")) {
4287
+ const absolutePath = resolve(fromDir, extendsValue);
4288
+ if (cachedExistsSync(absolutePath)) return absolutePath;
4289
+ if (cachedExistsSync(absolutePath + ".json")) return absolutePath + ".json";
4290
+ return;
4291
+ }
4292
+ const packagePath = join(options.monorepoRoot ?? config.rootDir, "node_modules", extendsValue);
4293
+ if (cachedExistsSync(packagePath)) return packagePath;
4294
+ if (cachedExistsSync(packagePath + ".json")) return packagePath + ".json";
4295
+ const localPackagePath = join(fromDir, "node_modules", extendsValue);
4296
+ if (cachedExistsSync(localPackagePath)) return localPackagePath;
4297
+ if (cachedExistsSync(localPackagePath + ".json")) return localPackagePath + ".json";
4298
+ };
4299
+ const collectExtendsEntries = (tsconfigJson) => {
4300
+ if (typeof tsconfigJson.extends === "string") return [tsconfigJson.extends];
4301
+ if (Array.isArray(tsconfigJson.extends)) return tsconfigJson.extends.filter((entry) => typeof entry === "string");
4302
+ return [];
4303
+ };
4304
+ const extractBaseUrlFromTsconfig = (tsconfigFile, visitedFiles) => {
4305
+ if (visitedFiles.has(tsconfigFile)) return void 0;
4306
+ visitedFiles.add(tsconfigFile);
3800
4307
  try {
3801
4308
  const cleanedContent = stripJsonComments(cachedReadFileSync(tsconfigFile));
3802
- const baseUrl = JSON.parse(cleanedContent).compilerOptions?.baseUrl;
3803
- if (baseUrl) {
3804
- const absoluteBaseUrl = resolve(dirname(tsconfigFile), baseUrl);
3805
- tsconfigBaseUrlCache.set(tsconfigFile, absoluteBaseUrl);
3806
- return absoluteBaseUrl;
4309
+ const tsconfigJson = JSON.parse(cleanedContent);
4310
+ const tsconfigDir = dirname(tsconfigFile);
4311
+ const baseUrl = tsconfigJson.compilerOptions?.baseUrl;
4312
+ if (baseUrl) return resolve(tsconfigDir, baseUrl);
4313
+ for (const extendsEntry of collectExtendsEntries(tsconfigJson)) {
4314
+ const resolvedPath = resolveExtendsPath(extendsEntry, tsconfigDir);
4315
+ if (resolvedPath) {
4316
+ const result = extractBaseUrlFromTsconfig(resolvedPath, visitedFiles);
4317
+ if (result) return result;
4318
+ }
3807
4319
  }
3808
- } catch {}
3809
- tsconfigBaseUrlCache.set(tsconfigFile, void 0);
4320
+ } catch {
4321
+ return;
4322
+ }
4323
+ };
4324
+ const getBaseUrlDirectory = (tsconfigFile) => {
4325
+ const cached = tsconfigBaseUrlCache.get(tsconfigFile);
4326
+ if (cached !== void 0) return cached;
4327
+ const result = extractBaseUrlFromTsconfig(tsconfigFile, /* @__PURE__ */ new Set());
4328
+ tsconfigBaseUrlCache.set(tsconfigFile, result);
4329
+ return result;
3810
4330
  };
3811
4331
  const hasNextJsDependency = (() => {
3812
4332
  try {
@@ -3819,25 +4339,83 @@ const createResolver = (config, workspacePackages = [], options = {}) => {
3819
4339
  return false;
3820
4340
  }
3821
4341
  })();
3822
- const getPathAliases = (tsconfigFile) => {
3823
- const cached = tsconfigPathAliasCache.get(tsconfigFile);
4342
+ const packageDependencyCache = /* @__PURE__ */ new Map();
4343
+ const readPackageDependencies = (directory) => {
4344
+ const cached = packageDependencyCache.get(directory);
3824
4345
  if (cached) return cached;
3825
- const aliasMap = /* @__PURE__ */ new Map();
3826
- const tsconfigDir = dirname(tsconfigFile);
4346
+ const dependencies = /* @__PURE__ */ new Set();
4347
+ const packageJsonPath = join(directory, "package.json");
4348
+ try {
4349
+ const packageJson = JSON.parse(cachedReadFileSync(packageJsonPath));
4350
+ const dependencySections = [
4351
+ packageJson.dependencies,
4352
+ packageJson.devDependencies,
4353
+ packageJson.optionalDependencies
4354
+ ];
4355
+ for (const dependencySection of dependencySections) {
4356
+ if (!dependencySection || typeof dependencySection !== "object") continue;
4357
+ for (const dependencyName of Object.keys(dependencySection)) dependencies.add(dependencyName);
4358
+ }
4359
+ } catch {}
4360
+ packageDependencyCache.set(directory, dependencies);
4361
+ return dependencies;
4362
+ };
4363
+ const findNearestPackageSrcDirectoryWithDependency = (filePath, dependencyNames) => {
4364
+ let currentDirectory = dirname(filePath);
4365
+ const stopAt = options.monorepoRoot ? resolve(options.monorepoRoot) : resolve(config.rootDir);
4366
+ while (currentDirectory.length >= stopAt.length) {
4367
+ if (cachedExistsSync(join(currentDirectory, "package.json"))) {
4368
+ const dependencies = readPackageDependencies(currentDirectory);
4369
+ if (dependencyNames.some((dependencyName) => dependencies.has(dependencyName))) {
4370
+ const srcDirectory = join(currentDirectory, "src");
4371
+ return cachedExistsSync(srcDirectory) ? srcDirectory : void 0;
4372
+ }
4373
+ }
4374
+ const parentDirectory = dirname(currentDirectory);
4375
+ if (parentDirectory === currentDirectory) break;
4376
+ currentDirectory = parentDirectory;
4377
+ }
4378
+ };
4379
+ const extractPathsFromTsconfig = (tsconfigFile, visitedFiles) => {
4380
+ if (visitedFiles.has(tsconfigFile)) return void 0;
4381
+ visitedFiles.add(tsconfigFile);
3827
4382
  try {
3828
4383
  const tsconfigContent = cachedReadFileSync(tsconfigFile).trim();
3829
- if (tsconfigContent.length > 0) {
3830
- const cleanedContent = stripJsonComments(tsconfigContent);
3831
- const tsconfigJson = JSON.parse(cleanedContent);
3832
- const paths = tsconfigJson.compilerOptions?.paths;
3833
- const baseUrl = tsconfigJson.compilerOptions?.baseUrl ?? ".";
3834
- if (paths && typeof paths === "object") {
3835
- for (const [pattern, targets] of Object.entries(paths)) if (Array.isArray(targets)) aliasMap.set(pattern, targets.map((target) => resolve(tsconfigDir, baseUrl, target)));
4384
+ if (tsconfigContent.length === 0) return void 0;
4385
+ const cleanedContent = stripJsonComments(tsconfigContent);
4386
+ const tsconfigJson = JSON.parse(cleanedContent);
4387
+ const tsconfigDir = dirname(tsconfigFile);
4388
+ const paths = tsconfigJson.compilerOptions?.paths;
4389
+ const baseUrl = tsconfigJson.compilerOptions?.baseUrl;
4390
+ if (paths && typeof paths === "object") return {
4391
+ paths,
4392
+ baseUrl: baseUrl ?? ".",
4393
+ tsconfigDir
4394
+ };
4395
+ for (const extendsEntry of collectExtendsEntries(tsconfigJson)) {
4396
+ const resolvedPath = resolveExtendsPath(extendsEntry, tsconfigDir);
4397
+ if (resolvedPath) {
4398
+ const result = extractPathsFromTsconfig(resolvedPath, visitedFiles);
4399
+ if (result) return result;
3836
4400
  }
3837
4401
  }
3838
- } catch {}
3839
- if (aliasMap.size === 0 && hasNextJsDependency) if (cachedExistsSync(resolve(tsconfigDir, "src"))) aliasMap.set("@/*", [resolve(tsconfigDir, "src/*")]);
3840
- else aliasMap.set("@/*", [resolve(tsconfigDir, "*")]);
4402
+ } catch {
4403
+ return;
4404
+ }
4405
+ };
4406
+ const getPathAliases = (tsconfigFile) => {
4407
+ const cached = tsconfigPathAliasCache.get(tsconfigFile);
4408
+ if (cached) return cached;
4409
+ const aliasMap = /* @__PURE__ */ new Map();
4410
+ const extracted = extractPathsFromTsconfig(tsconfigFile, /* @__PURE__ */ new Set());
4411
+ if (extracted) {
4412
+ for (const [pattern, targets] of Object.entries(extracted.paths)) if (Array.isArray(targets)) aliasMap.set(pattern, targets.map((target) => resolve(extracted.tsconfigDir, extracted.baseUrl, target)));
4413
+ }
4414
+ if (aliasMap.size === 0 && hasNextJsDependency) {
4415
+ const tsconfigDir = dirname(tsconfigFile);
4416
+ if (cachedExistsSync(resolve(tsconfigDir, "src"))) aliasMap.set("@/*", [resolve(tsconfigDir, "src/*")]);
4417
+ else aliasMap.set("@/*", [resolve(tsconfigDir, "*")]);
4418
+ }
3841
4419
  tsconfigPathAliasCache.set(tsconfigFile, aliasMap);
3842
4420
  return aliasMap;
3843
4421
  };
@@ -3874,6 +4452,28 @@ const createResolver = (config, workspacePackages = [], options = {}) => {
3874
4452
  }
3875
4453
  }
3876
4454
  };
4455
+ const tryResolveFromDirectory = (directory, specifier) => {
4456
+ const candidatePath = resolvePathWithExtensionFallback(resolve(directory, specifier));
4457
+ if (existsAsFile(candidatePath)) return candidatePath;
4458
+ };
4459
+ const tryResolveViaWebpackConfig = (specifier, fromFile) => {
4460
+ if (webpackResolverConfigs.length === 0) return void 0;
4461
+ if (!isBareSpecifier(specifier)) return void 0;
4462
+ for (const webpackConfig of webpackResolverConfigs) {
4463
+ if (!isInsideDirectory(fromFile, webpackConfig.scopeDirectory)) continue;
4464
+ for (const alias of webpackConfig.aliases) {
4465
+ if (alias.isExact && specifier !== alias.name) continue;
4466
+ const suffix = specifier === alias.name ? "" : specifier.startsWith(`${alias.name}/`) ? specifier.slice(alias.name.length + 1) : void 0;
4467
+ if (suffix === void 0) continue;
4468
+ const aliasCandidate = tryResolveFromDirectory(alias.targetDirectory, suffix);
4469
+ if (aliasCandidate) return aliasCandidate;
4470
+ }
4471
+ for (const moduleDirectory of webpackConfig.moduleDirectories) {
4472
+ const moduleCandidate = tryResolveFromDirectory(moduleDirectory, specifier);
4473
+ if (moduleCandidate) return moduleCandidate;
4474
+ }
4475
+ }
4476
+ };
3877
4477
  const resolveModule = (specifier, fromFile) => {
3878
4478
  const queryIndex = specifier.indexOf("?");
3879
4479
  const cleanedSpecifier = queryIndex !== -1 ? specifier.slice(0, queryIndex) : specifier;
@@ -4037,6 +4637,16 @@ const createResolver = (config, workspacePackages = [], options = {}) => {
4037
4637
  resolveResultCache.set(cacheKey, resolvedResult);
4038
4638
  return resolvedResult;
4039
4639
  }
4640
+ const webpackResolved = tryResolveViaWebpackConfig(cleanedSpecifier, fromFile);
4641
+ if (webpackResolved) {
4642
+ const resolvedResult = {
4643
+ resolvedPath: webpackResolved,
4644
+ isExternal: false,
4645
+ packageName: void 0
4646
+ };
4647
+ resolveResultCache.set(cacheKey, resolvedResult);
4648
+ return resolvedResult;
4649
+ }
4040
4650
  if (isBareSpecifier(cleanedSpecifier)) {
4041
4651
  const tsconfigFile = findTsconfigForFile(fromFile);
4042
4652
  if (tsconfigFile) {
@@ -4070,6 +4680,19 @@ const createResolver = (config, workspacePackages = [], options = {}) => {
4070
4680
  }
4071
4681
  }
4072
4682
  }
4683
+ const createReactAppSrcDirectory = findNearestPackageSrcDirectoryWithDependency(fromFile, ["react-scripts", "react-app-rewired"]);
4684
+ if (createReactAppSrcDirectory) {
4685
+ const craResolved = tryResolveFromDirectory(createReactAppSrcDirectory, cleanedSpecifier);
4686
+ if (craResolved) {
4687
+ const resolvedResult = {
4688
+ resolvedPath: craResolved,
4689
+ isExternal: false,
4690
+ packageName: void 0
4691
+ };
4692
+ resolveResultCache.set(cacheKey, resolvedResult);
4693
+ return resolvedResult;
4694
+ }
4695
+ }
4073
4696
  const resolvedResult = {
4074
4697
  resolvedPath: void 0,
4075
4698
  isExternal: true,
@@ -4533,12 +5156,16 @@ const detectDeadExports = (graph, config) => {
4533
5156
  if (!module.isReachable) continue;
4534
5157
  if (module.isDeclarationFile) continue;
4535
5158
  if (module.isEntryPoint && !config.includeEntryExports) continue;
5159
+ const defaultExportLinkedNames = /* @__PURE__ */ new Set();
5160
+ for (const exportInfo of module.exports) if (exportInfo.isDefault && exportInfo.defaultExportLocalName && usageMap.has(`${module.fileId.path}::default`)) defaultExportLinkedNames.add(exportInfo.defaultExportLocalName);
4536
5161
  for (const exportInfo of module.exports) {
4537
5162
  if (exportInfo.name === "*" && exportInfo.isNamespaceReExport) continue;
4538
5163
  if (exportInfo.isReExport && exportInfo.reExportOriginalName) continue;
4539
5164
  if (!config.reportTypes && exportInfo.isTypeOnly) continue;
4540
5165
  const usageKey = `${module.fileId.path}::${exportInfo.name}`;
4541
- if (!usageMap.has(usageKey)) unusedExports.push({
5166
+ if (usageMap.has(usageKey)) continue;
5167
+ if (!exportInfo.isDefault && defaultExportLinkedNames.has(exportInfo.name)) continue;
5168
+ unusedExports.push({
4542
5169
  path: module.fileId.path,
4543
5170
  name: exportInfo.name,
4544
5171
  line: exportInfo.line,
@@ -4654,62 +5281,18 @@ const followReExportChain = (reExporterModuleIndex, exportInfo, graph, sourceToT
4654
5281
  //#endregion
4655
5282
  //#region src/utils/package-name.ts
4656
5283
  const extractPackageName = (specifier) => {
4657
- if (specifier.startsWith(".") || specifier.startsWith("/")) return void 0;
5284
+ const normalizedSpecifier = specifier.startsWith("~") ? specifier.slice(1) : specifier;
5285
+ if (normalizedSpecifier.startsWith(".") || normalizedSpecifier.startsWith("/")) return void 0;
4658
5286
  if (specifier.startsWith("node:")) return void 0;
4659
- if (specifier.startsWith("@")) {
4660
- const parts = specifier.split("/");
5287
+ if (normalizedSpecifier.startsWith("@")) {
5288
+ const parts = normalizedSpecifier.split("/");
4661
5289
  return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : void 0;
4662
5290
  }
4663
- return specifier.split("/")[0];
5291
+ return normalizedSpecifier.split("/")[0];
4664
5292
  };
4665
5293
 
4666
5294
  //#endregion
4667
5295
  //#region src/report/packages.ts
4668
- const MONOREPO_ROOT_MARKERS = [
4669
- "pnpm-workspace.yaml",
4670
- "pnpm-workspace.yml",
4671
- "lerna.json",
4672
- "nx.json",
4673
- "turbo.json",
4674
- "rush.json"
4675
- ];
4676
- const LOCKFILE_MARKERS = [
4677
- "pnpm-lock.yaml",
4678
- "yarn.lock",
4679
- "package-lock.json",
4680
- "bun.lockb",
4681
- "bun.lock"
4682
- ];
4683
- const MAX_MONOREPO_WALK_DEPTH = 5;
4684
- const findMonorepoRoot = (rootDir) => {
4685
- let currentDirectory = resolve(rootDir);
4686
- let walkedDepth = 0;
4687
- while (walkedDepth < MAX_MONOREPO_WALK_DEPTH) {
4688
- const parentDirectory = dirname(currentDirectory);
4689
- if (parentDirectory === currentDirectory) break;
4690
- currentDirectory = parentDirectory;
4691
- walkedDepth++;
4692
- if (existsSync(join(currentDirectory, ".git"))) {
4693
- for (const marker of MONOREPO_ROOT_MARKERS) if (existsSync(join(currentDirectory, marker))) return currentDirectory;
4694
- const packageJsonPath = join(currentDirectory, "package.json");
4695
- if (existsSync(packageJsonPath)) try {
4696
- const content = readFileSync(packageJsonPath, "utf-8");
4697
- if (JSON.parse(content).workspaces) return currentDirectory;
4698
- } catch {}
4699
- for (const lockfile of LOCKFILE_MARKERS) if (existsSync(join(currentDirectory, lockfile))) return currentDirectory;
4700
- return;
4701
- }
4702
- for (const marker of MONOREPO_ROOT_MARKERS) if (existsSync(join(currentDirectory, marker))) return currentDirectory;
4703
- const packageJsonPath = join(currentDirectory, "package.json");
4704
- if (existsSync(packageJsonPath)) try {
4705
- const content = readFileSync(packageJsonPath, "utf-8");
4706
- if (JSON.parse(content).workspaces) return currentDirectory;
4707
- } catch {
4708
- continue;
4709
- }
4710
- for (const lockfile of LOCKFILE_MARKERS) if (existsSync(join(currentDirectory, lockfile))) return currentDirectory;
4711
- }
4712
- };
4713
5296
  const discoverAllPackageJsonPaths = (rootDir) => {
4714
5297
  const paths = [join(rootDir, "package.json")];
4715
5298
  const workspacePackageJsons = fg.sync("**/package.json", {
@@ -4757,6 +5340,8 @@ const detectStalePackages = (graph, config) => {
4757
5340
  const packageJsonConfigReferenced = collectPackageJsonConfigReferences(workspacePackageJsonPath, declaredNames);
4758
5341
  for (const packageName of packageJsonConfigReferenced) usedPackageNames.add(packageName);
4759
5342
  }
5343
+ const nxProjectReferenced = collectNxProjectJsonReferences(config.rootDir, declaredNames, binToPackage);
5344
+ for (const packageName of nxProjectReferenced) usedPackageNames.add(packageName);
4760
5345
  const configSearchRoots = monorepoRoot && monorepoRoot !== config.rootDir ? [config.rootDir, monorepoRoot] : [config.rootDir];
4761
5346
  for (const configSearchRoot of configSearchRoots) {
4762
5347
  const configReferenced = collectConfigReferencedPackages(configSearchRoot, graph, declaredNames);
@@ -4770,8 +5355,36 @@ const detectStalePackages = (graph, config) => {
4770
5355
  if (declaredNames.has("react-native")) usedPackageNames.add("react-native");
4771
5356
  if (declaredNames.has("react-native-web")) usedPackageNames.add("react-native-web");
4772
5357
  }
5358
+ if (declaredNames.has("react-dom")) {
5359
+ if ([
5360
+ "next",
5361
+ "gatsby",
5362
+ "@remix-run/react",
5363
+ "react-router-dom",
5364
+ "vite",
5365
+ "@docusaurus/core",
5366
+ "react-scripts",
5367
+ "astro",
5368
+ "@tanstack/react-router",
5369
+ "@tanstack/react-start",
5370
+ "react-app-rewired"
5371
+ ].some((framework) => declaredNames.has(framework) || usedPackageNames.has(framework))) usedPackageNames.add("react-dom");
5372
+ }
5373
+ if (declaredNames.has("react") && declaredNames.has("react-dom")) {
5374
+ const packageJsonPath = resolve(config.rootDir, "package.json");
5375
+ try {
5376
+ const content = readFileSync(packageJsonPath, "utf-8");
5377
+ const peerDeps = JSON.parse(content).peerDependencies ?? {};
5378
+ if ("react" in peerDeps && declaredDependencies.get("react") === true) usedPackageNames.add("react");
5379
+ if ("react-dom" in peerDeps && declaredDependencies.get("react-dom") === true) usedPackageNames.add("react-dom");
5380
+ } catch {}
5381
+ }
4773
5382
  const peerSatisfied = collectPeerSatisfiedPackages(nodeModulesRoot, declaredNames, usedPackageNames);
4774
5383
  for (const packageName of peerSatisfied) usedPackageNames.add(packageName);
5384
+ const staticPeerSatisfied = collectStaticPeerSatisfiedPackages(declaredNames, usedPackageNames);
5385
+ for (const packageName of staticPeerSatisfied) usedPackageNames.add(packageName);
5386
+ const implicitCompanionPackages = collectImplicitCompanionPackages(declaredNames, usedPackageNames);
5387
+ for (const packageName of implicitCompanionPackages) usedPackageNames.add(packageName);
4775
5388
  const candidateUnused = /* @__PURE__ */ new Set();
4776
5389
  for (const [dependencyName] of declaredDependencies) {
4777
5390
  if (isAlwaysConsideredUsed(dependencyName)) continue;
@@ -4825,11 +5438,75 @@ const collectPeerSatisfiedPackages = (rootDir, declaredNames, confirmedUsedNames
4825
5438
  }
4826
5439
  return peerSatisfied;
4827
5440
  };
5441
+ const STATIC_PEER_DEPENDENCY_MAP = {
5442
+ "@apollo/client": ["graphql"],
5443
+ "@docusaurus/core": ["@mdx-js/react"],
5444
+ "@fortawesome/react-fontawesome": ["@fortawesome/fontawesome-svg-core"],
5445
+ "@gorhom/bottom-sheet": ["react-native-gesture-handler", "react-native-reanimated"],
5446
+ "@hookform/resolvers": ["zod"],
5447
+ "@mdx-js/loader": ["@mdx-js/react"],
5448
+ "@mui/material": ["react-transition-group", "styled-components"],
5449
+ "@stripe/react-stripe-js": ["@stripe/stripe-js"],
5450
+ "@tiptap/core": ["@tiptap/pm"],
5451
+ "@tiptap/react": ["@tiptap/pm"],
5452
+ "@trpc/server": ["zod"],
5453
+ "chart.js": [],
5454
+ "fumadocs-core": ["@mdx-js/react"],
5455
+ "fumadocs-mdx": ["@mdx-js/react"],
5456
+ "fumadocs-ui": ["@mdx-js/react"],
5457
+ "graphql-request": ["graphql"],
5458
+ nextra: ["@mdx-js/react"],
5459
+ "nextra-theme-blog": ["@mdx-js/react"],
5460
+ "nextra-theme-docs": ["@mdx-js/react"],
5461
+ "react-app-polyfill": ["core-js"],
5462
+ "react-bootstrap": ["react-transition-group"],
5463
+ "react-chartjs-2": ["chart.js"],
5464
+ "react-redux": ["redux"],
5465
+ "react-router-dom": ["react-router"],
5466
+ "redux-thunk": ["redux"],
5467
+ sanity: ["styled-components"],
5468
+ sequelize: ["pg"],
5469
+ "stylis-plugin-rtl": ["stylis"],
5470
+ urql: ["graphql"],
5471
+ "use-immer": ["immer"],
5472
+ zustand: ["immer"]
5473
+ };
5474
+ const collectStaticPeerSatisfiedPackages = (declaredNames, confirmedUsedNames) => {
5475
+ const peerSatisfied = /* @__PURE__ */ new Set();
5476
+ for (const [packageName, peerNames] of Object.entries(STATIC_PEER_DEPENDENCY_MAP)) {
5477
+ if (!confirmedUsedNames.has(packageName)) continue;
5478
+ for (const peerName of peerNames) if (declaredNames.has(peerName)) peerSatisfied.add(peerName);
5479
+ }
5480
+ return peerSatisfied;
5481
+ };
5482
+ const IMPLICIT_COMPANION_DEPENDENCY_MAP = {
5483
+ jest: ["jest-config"],
5484
+ "jest-cli": ["jest-config"]
5485
+ };
5486
+ const collectImplicitCompanionPackages = (declaredNames, confirmedUsedNames) => {
5487
+ const companions = /* @__PURE__ */ new Set();
5488
+ for (const [packageName, companionNames] of Object.entries(IMPLICIT_COMPANION_DEPENDENCY_MAP)) {
5489
+ if (!confirmedUsedNames.has(packageName)) continue;
5490
+ for (const companionName of companionNames) if (declaredNames.has(companionName)) companions.add(companionName);
5491
+ }
5492
+ return companions;
5493
+ };
4828
5494
  const SHELL_SPLIT_PATTERN = /\s*(?:&&|\|\||[;&|])\s*/;
4829
5495
  const CLI_BINARY_TO_PACKAGE = {
5496
+ "babel-node": "@babel/node",
5497
+ "trigger.dev": "trigger.dev",
5498
+ "@formatjs/cli": "@formatjs/cli",
4830
5499
  "react-scripts": "react-scripts",
4831
5500
  "webpack-cli": "webpack-cli",
4832
5501
  "webpack-dev-server": "webpack-dev-server",
5502
+ babel: "@babel/cli",
5503
+ chokidar: "chokidar-cli",
5504
+ "replace-in-file": "replace-in-file",
5505
+ tauri: "@tauri-apps/cli",
5506
+ tinacms: "@tinacms/cli",
5507
+ "tsc-alias": "tsc-alias",
5508
+ formatjs: "@formatjs/cli",
5509
+ prompt: "prompt",
4833
5510
  vitest: "vitest",
4834
5511
  jest: "jest",
4835
5512
  prisma: "prisma",
@@ -4847,6 +5524,10 @@ const CLI_BINARY_TO_PACKAGE = {
4847
5524
  "generate-arg-types": "@webstudio-is/generate-arg-types",
4848
5525
  email: "@react-email/preview-server"
4849
5526
  };
5527
+ const CLI_BINARY_FALLBACK_PACKAGES = {
5528
+ babel: ["babel-cli"],
5529
+ jest: ["jest-cli"]
5530
+ };
4850
5531
  const ENV_WRAPPER_BINARY_SET = new Set([
4851
5532
  "cross-env",
4852
5533
  "dotenv",
@@ -4878,36 +5559,43 @@ const collectScriptReferencedPackages = (packageJsonPath, declaredNames, binToPa
4878
5559
  if (!scripts || typeof scripts !== "object") return referenced;
4879
5560
  for (const scriptCommand of Object.values(scripts)) {
4880
5561
  if (typeof scriptCommand !== "string") continue;
4881
- const segments = scriptCommand.split(SHELL_SPLIT_PATTERN);
4882
- for (const segment of segments) {
4883
- const tokens = segment.trim().split(/\s+/);
4884
- if (tokens.length === 0) continue;
4885
- let binaryIndex = 0;
4886
- const firstToken = tokens[0].replace(/^.*\//, "");
4887
- if (ENV_WRAPPER_BINARY_SET.has(firstToken)) {
4888
- const envPackage = binToPackage.get(firstToken);
4889
- if (envPackage && declaredNames.has(envPackage)) referenced.add(envPackage);
4890
- binaryIndex = 1;
4891
- while (binaryIndex < tokens.length && INLINE_ENV_VAR_PATTERN.test(tokens[binaryIndex])) binaryIndex++;
4892
- if (binaryIndex >= tokens.length) continue;
4893
- }
4894
- while (binaryIndex < tokens.length && INLINE_ENV_VAR_PATTERN.test(tokens[binaryIndex])) binaryIndex++;
4895
- if (binaryIndex >= tokens.length) continue;
4896
- const binaryToken = tokens[binaryIndex].replace(/^.*\//, "");
4897
- const effectiveBinary = binaryToken === "npx" || binaryToken === "pnpx" || binaryToken === "bunx" ? tokens[binaryIndex + 1]?.replace(/^.*\//, "") ?? "" : binaryToken;
4898
- for (const candidateBinary of [binaryToken, effectiveBinary]) {
4899
- if (!candidateBinary) continue;
4900
- const mappedPackage = binToPackage.get(candidateBinary);
4901
- if (mappedPackage && declaredNames.has(mappedPackage)) referenced.add(mappedPackage);
4902
- if (declaredNames.has(candidateBinary)) referenced.add(candidateBinary);
4903
- }
4904
- }
5562
+ const commandReferenced = collectCommandReferencedPackages(scriptCommand, declaredNames, binToPackage);
5563
+ for (const packageName of commandReferenced) referenced.add(packageName);
4905
5564
  }
4906
5565
  } catch {
4907
5566
  return referenced;
4908
5567
  }
4909
5568
  return referenced;
4910
5569
  };
5570
+ const collectCommandReferencedPackages = (command, declaredNames, binToPackage) => {
5571
+ const referenced = /* @__PURE__ */ new Set();
5572
+ const segments = command.split(SHELL_SPLIT_PATTERN);
5573
+ for (const segment of segments) {
5574
+ const tokens = segment.trim().split(/\s+/);
5575
+ if (tokens.length === 0) continue;
5576
+ let binaryIndex = 0;
5577
+ const firstToken = tokens[0].replace(/^.*\//, "");
5578
+ if (ENV_WRAPPER_BINARY_SET.has(firstToken)) {
5579
+ const envPackage = binToPackage.get(firstToken);
5580
+ if (envPackage && declaredNames.has(envPackage)) referenced.add(envPackage);
5581
+ binaryIndex = 1;
5582
+ while (binaryIndex < tokens.length && INLINE_ENV_VAR_PATTERN.test(tokens[binaryIndex])) binaryIndex++;
5583
+ if (binaryIndex >= tokens.length) continue;
5584
+ }
5585
+ while (binaryIndex < tokens.length && INLINE_ENV_VAR_PATTERN.test(tokens[binaryIndex])) binaryIndex++;
5586
+ if (binaryIndex >= tokens.length) continue;
5587
+ const binaryToken = tokens[binaryIndex].replace(/^.*\//, "");
5588
+ const effectiveBinary = binaryToken === "npx" || binaryToken === "pnpx" || binaryToken === "bunx" ? tokens[binaryIndex + 1]?.replace(/^.*\//, "") ?? "" : binaryToken;
5589
+ for (const candidateBinary of [binaryToken, effectiveBinary]) {
5590
+ if (!candidateBinary) continue;
5591
+ const mappedPackage = binToPackage.get(candidateBinary);
5592
+ if (mappedPackage && declaredNames.has(mappedPackage)) referenced.add(mappedPackage);
5593
+ for (const fallbackPackage of CLI_BINARY_FALLBACK_PACKAGES[candidateBinary] ?? []) if (declaredNames.has(fallbackPackage)) referenced.add(fallbackPackage);
5594
+ if (declaredNames.has(candidateBinary)) referenced.add(candidateBinary);
5595
+ }
5596
+ }
5597
+ return referenced;
5598
+ };
4911
5599
  const CONFIG_FILE_GLOBS = [
4912
5600
  "postcss.config.{js,cjs,mjs,ts}",
4913
5601
  ".babelrc",
@@ -5004,6 +5692,39 @@ const collectPackageJsonConfigReferences = (packageJsonPath, declaredNames) => {
5004
5692
  }
5005
5693
  return referenced;
5006
5694
  };
5695
+ const collectNxProjectJsonReferences = (rootDir, declaredNames, binToPackage) => {
5696
+ const referenced = /* @__PURE__ */ new Set();
5697
+ const projectJsonPaths = fg.sync(["project.json", "**/project.json"], {
5698
+ cwd: rootDir,
5699
+ absolute: true,
5700
+ onlyFiles: true,
5701
+ ignore: [
5702
+ "**/node_modules/**",
5703
+ "**/dist/**",
5704
+ "**/build/**"
5705
+ ],
5706
+ deep: 5
5707
+ });
5708
+ for (const projectJsonPath of projectJsonPaths) try {
5709
+ const content = readFileSync(projectJsonPath, "utf-8");
5710
+ const projectJson = JSON.parse(content);
5711
+ const projectText = JSON.stringify(projectJson);
5712
+ for (const packageName of declaredNames) if (projectText.includes(packageName)) referenced.add(packageName);
5713
+ for (const stringValue of collectStringValues(projectJson)) {
5714
+ const commandReferenced = collectCommandReferencedPackages(stringValue, declaredNames, binToPackage);
5715
+ for (const packageName of commandReferenced) referenced.add(packageName);
5716
+ }
5717
+ } catch {
5718
+ continue;
5719
+ }
5720
+ return referenced;
5721
+ };
5722
+ const collectStringValues = (value) => {
5723
+ if (typeof value === "string") return [value];
5724
+ if (!value || typeof value !== "object") return [];
5725
+ if (Array.isArray(value)) return value.flatMap(collectStringValues);
5726
+ return Object.values(value).flatMap(collectStringValues);
5727
+ };
5007
5728
  const TSCONFIG_GLOBS = [
5008
5729
  "tsconfig.json",
5009
5730
  "tsconfig.*.json",
@@ -5362,7 +6083,13 @@ const defineConfig = (options) => ({
5362
6083
  const analyze = async (config) => {
5363
6084
  const pipelineStartTime = performance.now();
5364
6085
  const workspaceDiscovery = resolveWorkspaces(resolve(config.rootDir));
5365
- const workspacePackages = workspaceDiscovery.packages;
6086
+ const workspacePackages = [...workspaceDiscovery.packages];
6087
+ const monorepoRoot = findMonorepoRoot(config.rootDir);
6088
+ if (monorepoRoot) {
6089
+ const monorepoWorkspaces = resolveWorkspaces(monorepoRoot);
6090
+ const existingDirectories = new Set(workspacePackages.map((workspacePackage) => workspacePackage.directory));
6091
+ for (const monorepoPackage of monorepoWorkspaces.packages) if (!existingDirectories.has(monorepoPackage.directory)) workspacePackages.push(monorepoPackage);
6092
+ }
5366
6093
  const frameworkIgnorePatterns = getFrameworkExclusions(config.rootDir);
5367
6094
  const absoluteRoot = resolve(config.rootDir);
5368
6095
  const outputDirectoryExclusions = OUTPUT_DIRECTORIES.flatMap((outputDirectory) => {
@@ -5388,7 +6115,10 @@ const analyze = async (config) => {
5388
6115
  const moduleResolver = createResolver(config, workspacePackages.map((workspacePackage) => ({
5389
6116
  name: workspacePackage.name,
5390
6117
  directory: workspacePackage.directory
5391
- })), { hasReactNative });
6118
+ })), {
6119
+ hasReactNative,
6120
+ monorepoRoot
6121
+ });
5392
6122
  const graphInputs = [];
5393
6123
  for (const file of files) {
5394
6124
  const parsedModule = parseSourceFile(file.path);