deslop-js 0.0.7 → 0.0.8

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 +134 -43
  2. package/dist/index.mjs +134 -43
  3. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -3719,12 +3719,13 @@ const TSCONFIG_FILENAMES = [
3719
3719
  "tsconfig.json",
3720
3720
  "tsconfig.web.json",
3721
3721
  "tsconfig.app.json",
3722
- "tsconfig.base.json"
3722
+ "tsconfig.base.json",
3723
+ "jsconfig.json"
3723
3724
  ];
3724
- const findNearestTsconfig = (fromDir, rootDir) => {
3725
+ const findNearestTsconfig = (fromDir, rootDir, monorepoRootDir) => {
3725
3726
  let currentDirectory = fromDir;
3726
- const normalizedRoot = (0, node_path.resolve)(rootDir);
3727
- while (currentDirectory.length >= normalizedRoot.length) {
3727
+ const stopAt = monorepoRootDir ? (0, node_path.resolve)(monorepoRootDir) : (0, node_path.resolve)(rootDir);
3728
+ while (currentDirectory.length >= stopAt.length) {
3728
3729
  for (const tsconfigFilename of TSCONFIG_FILENAMES) {
3729
3730
  const tsconfigCandidate = (0, node_path.join)(currentDirectory, tsconfigFilename);
3730
3731
  if (cachedExistsSync(tsconfigCandidate)) return tsconfigCandidate;
@@ -3801,16 +3802,17 @@ const createResolver = (config, workspacePackages = [], options = {}) => {
3801
3802
  for (const workspacePackage of workspacePackages) workspaceNameToDirectory.set(workspacePackage.name, workspacePackage.directory);
3802
3803
  let rootTsconfigPath;
3803
3804
  if (config.tsConfigPath) rootTsconfigPath = (0, node_path.resolve)(config.rootDir, config.tsConfigPath);
3804
- else for (const candidate of [
3805
- "tsconfig.json",
3806
- "tsconfig.web.json",
3807
- "tsconfig.app.json",
3808
- "tsconfig.base.json"
3809
- ]) {
3810
- const candidatePath = (0, node_path.resolve)(config.rootDir, candidate);
3811
- if (cachedExistsSync(candidatePath)) {
3812
- rootTsconfigPath = candidatePath;
3813
- break;
3805
+ else {
3806
+ const tsconfigSearchDirs = options.monorepoRoot ? [config.rootDir, options.monorepoRoot] : [config.rootDir];
3807
+ for (const searchDir of tsconfigSearchDirs) {
3808
+ for (const candidate of TSCONFIG_FILENAMES) {
3809
+ const candidatePath = (0, node_path.resolve)(searchDir, candidate);
3810
+ if (cachedExistsSync(candidatePath)) {
3811
+ rootTsconfigPath = candidatePath;
3812
+ break;
3813
+ }
3814
+ }
3815
+ if (rootTsconfigPath) break;
3814
3816
  }
3815
3817
  }
3816
3818
  const tsconfigPathCache = /* @__PURE__ */ new Map();
@@ -3819,24 +3821,56 @@ const createResolver = (config, workspacePackages = [], options = {}) => {
3819
3821
  const fileDir = (0, node_path.dirname)(filePath);
3820
3822
  const cached = tsconfigPathCache.get(fileDir);
3821
3823
  if (cached !== void 0) return cached;
3822
- const tsconfigResult = findNearestTsconfig(fileDir, config.rootDir) ?? rootTsconfigPath;
3824
+ const tsconfigResult = findNearestTsconfig(fileDir, config.rootDir, options.monorepoRoot) ?? rootTsconfigPath;
3823
3825
  tsconfigPathCache.set(fileDir, tsconfigResult);
3824
3826
  return tsconfigResult;
3825
3827
  };
3826
3828
  const tsconfigBaseUrlCache = /* @__PURE__ */ new Map();
3827
- const getBaseUrlDirectory = (tsconfigFile) => {
3828
- const cached = tsconfigBaseUrlCache.get(tsconfigFile);
3829
- if (cached !== void 0) return cached;
3829
+ const resolveExtendsPath = (extendsValue, fromDir) => {
3830
+ if (extendsValue.startsWith(".")) {
3831
+ const absolutePath = (0, node_path.resolve)(fromDir, extendsValue);
3832
+ if (cachedExistsSync(absolutePath)) return absolutePath;
3833
+ if (cachedExistsSync(absolutePath + ".json")) return absolutePath + ".json";
3834
+ return;
3835
+ }
3836
+ const packagePath = (0, node_path.join)(options.monorepoRoot ?? config.rootDir, "node_modules", extendsValue);
3837
+ if (cachedExistsSync(packagePath)) return packagePath;
3838
+ if (cachedExistsSync(packagePath + ".json")) return packagePath + ".json";
3839
+ const localPackagePath = (0, node_path.join)(fromDir, "node_modules", extendsValue);
3840
+ if (cachedExistsSync(localPackagePath)) return localPackagePath;
3841
+ if (cachedExistsSync(localPackagePath + ".json")) return localPackagePath + ".json";
3842
+ };
3843
+ const collectExtendsEntries = (tsconfigJson) => {
3844
+ if (typeof tsconfigJson.extends === "string") return [tsconfigJson.extends];
3845
+ if (Array.isArray(tsconfigJson.extends)) return tsconfigJson.extends.filter((entry) => typeof entry === "string");
3846
+ return [];
3847
+ };
3848
+ const extractBaseUrlFromTsconfig = (tsconfigFile, visitedFiles) => {
3849
+ if (visitedFiles.has(tsconfigFile)) return void 0;
3850
+ visitedFiles.add(tsconfigFile);
3830
3851
  try {
3831
3852
  const cleanedContent = stripJsonComments(cachedReadFileSync(tsconfigFile));
3832
- const baseUrl = JSON.parse(cleanedContent).compilerOptions?.baseUrl;
3833
- if (baseUrl) {
3834
- const absoluteBaseUrl = (0, node_path.resolve)((0, node_path.dirname)(tsconfigFile), baseUrl);
3835
- tsconfigBaseUrlCache.set(tsconfigFile, absoluteBaseUrl);
3836
- return absoluteBaseUrl;
3853
+ const tsconfigJson = JSON.parse(cleanedContent);
3854
+ const tsconfigDir = (0, node_path.dirname)(tsconfigFile);
3855
+ const baseUrl = tsconfigJson.compilerOptions?.baseUrl;
3856
+ if (baseUrl) return (0, node_path.resolve)(tsconfigDir, baseUrl);
3857
+ for (const extendsEntry of collectExtendsEntries(tsconfigJson)) {
3858
+ const resolvedPath = resolveExtendsPath(extendsEntry, tsconfigDir);
3859
+ if (resolvedPath) {
3860
+ const result = extractBaseUrlFromTsconfig(resolvedPath, visitedFiles);
3861
+ if (result) return result;
3862
+ }
3837
3863
  }
3838
- } catch {}
3839
- tsconfigBaseUrlCache.set(tsconfigFile, void 0);
3864
+ } catch {
3865
+ return;
3866
+ }
3867
+ };
3868
+ const getBaseUrlDirectory = (tsconfigFile) => {
3869
+ const cached = tsconfigBaseUrlCache.get(tsconfigFile);
3870
+ if (cached !== void 0) return cached;
3871
+ const result = extractBaseUrlFromTsconfig(tsconfigFile, /* @__PURE__ */ new Set());
3872
+ tsconfigBaseUrlCache.set(tsconfigFile, result);
3873
+ return result;
3840
3874
  };
3841
3875
  const hasNextJsDependency = (() => {
3842
3876
  try {
@@ -3849,25 +3883,46 @@ const createResolver = (config, workspacePackages = [], options = {}) => {
3849
3883
  return false;
3850
3884
  }
3851
3885
  })();
3852
- const getPathAliases = (tsconfigFile) => {
3853
- const cached = tsconfigPathAliasCache.get(tsconfigFile);
3854
- if (cached) return cached;
3855
- const aliasMap = /* @__PURE__ */ new Map();
3856
- const tsconfigDir = (0, node_path.dirname)(tsconfigFile);
3886
+ const extractPathsFromTsconfig = (tsconfigFile, visitedFiles) => {
3887
+ if (visitedFiles.has(tsconfigFile)) return void 0;
3888
+ visitedFiles.add(tsconfigFile);
3857
3889
  try {
3858
3890
  const tsconfigContent = cachedReadFileSync(tsconfigFile).trim();
3859
- if (tsconfigContent.length > 0) {
3860
- const cleanedContent = stripJsonComments(tsconfigContent);
3861
- const tsconfigJson = JSON.parse(cleanedContent);
3862
- const paths = tsconfigJson.compilerOptions?.paths;
3863
- const baseUrl = tsconfigJson.compilerOptions?.baseUrl ?? ".";
3864
- if (paths && typeof paths === "object") {
3865
- for (const [pattern, targets] of Object.entries(paths)) if (Array.isArray(targets)) aliasMap.set(pattern, targets.map((target) => (0, node_path.resolve)(tsconfigDir, baseUrl, target)));
3891
+ if (tsconfigContent.length === 0) return void 0;
3892
+ const cleanedContent = stripJsonComments(tsconfigContent);
3893
+ const tsconfigJson = JSON.parse(cleanedContent);
3894
+ const tsconfigDir = (0, node_path.dirname)(tsconfigFile);
3895
+ const paths = tsconfigJson.compilerOptions?.paths;
3896
+ const baseUrl = tsconfigJson.compilerOptions?.baseUrl;
3897
+ if (paths && typeof paths === "object") return {
3898
+ paths,
3899
+ baseUrl: baseUrl ?? ".",
3900
+ tsconfigDir
3901
+ };
3902
+ for (const extendsEntry of collectExtendsEntries(tsconfigJson)) {
3903
+ const resolvedPath = resolveExtendsPath(extendsEntry, tsconfigDir);
3904
+ if (resolvedPath) {
3905
+ const result = extractPathsFromTsconfig(resolvedPath, visitedFiles);
3906
+ if (result) return result;
3866
3907
  }
3867
3908
  }
3868
- } catch {}
3869
- if (aliasMap.size === 0 && hasNextJsDependency) if (cachedExistsSync((0, node_path.resolve)(tsconfigDir, "src"))) aliasMap.set("@/*", [(0, node_path.resolve)(tsconfigDir, "src/*")]);
3870
- else aliasMap.set("@/*", [(0, node_path.resolve)(tsconfigDir, "*")]);
3909
+ } catch {
3910
+ return;
3911
+ }
3912
+ };
3913
+ const getPathAliases = (tsconfigFile) => {
3914
+ const cached = tsconfigPathAliasCache.get(tsconfigFile);
3915
+ if (cached) return cached;
3916
+ const aliasMap = /* @__PURE__ */ new Map();
3917
+ const extracted = extractPathsFromTsconfig(tsconfigFile, /* @__PURE__ */ new Set());
3918
+ if (extracted) {
3919
+ for (const [pattern, targets] of Object.entries(extracted.paths)) if (Array.isArray(targets)) aliasMap.set(pattern, targets.map((target) => (0, node_path.resolve)(extracted.tsconfigDir, extracted.baseUrl, target)));
3920
+ }
3921
+ if (aliasMap.size === 0 && hasNextJsDependency) {
3922
+ const tsconfigDir = (0, node_path.dirname)(tsconfigFile);
3923
+ if (cachedExistsSync((0, node_path.resolve)(tsconfigDir, "src"))) aliasMap.set("@/*", [(0, node_path.resolve)(tsconfigDir, "src/*")]);
3924
+ else aliasMap.set("@/*", [(0, node_path.resolve)(tsconfigDir, "*")]);
3925
+ }
3871
3926
  tsconfigPathAliasCache.set(tsconfigFile, aliasMap);
3872
3927
  return aliasMap;
3873
3928
  };
@@ -4694,7 +4749,7 @@ const extractPackageName = (specifier) => {
4694
4749
  };
4695
4750
 
4696
4751
  //#endregion
4697
- //#region src/report/packages.ts
4752
+ //#region src/utils/find-monorepo-root.ts
4698
4753
  const MONOREPO_ROOT_MARKERS = [
4699
4754
  "pnpm-workspace.yaml",
4700
4755
  "pnpm-workspace.yml",
@@ -4740,6 +4795,9 @@ const findMonorepoRoot = (rootDir) => {
4740
4795
  for (const lockfile of LOCKFILE_MARKERS) if ((0, node_fs.existsSync)((0, node_path.join)(currentDirectory, lockfile))) return currentDirectory;
4741
4796
  }
4742
4797
  };
4798
+
4799
+ //#endregion
4800
+ //#region src/report/packages.ts
4743
4801
  const discoverAllPackageJsonPaths = (rootDir) => {
4744
4802
  const paths = [(0, node_path.join)(rootDir, "package.json")];
4745
4803
  const workspacePackageJsons = fast_glob.default.sync("**/package.json", {
@@ -4800,6 +4858,30 @@ const detectStalePackages = (graph, config) => {
4800
4858
  if (declaredNames.has("react-native")) usedPackageNames.add("react-native");
4801
4859
  if (declaredNames.has("react-native-web")) usedPackageNames.add("react-native-web");
4802
4860
  }
4861
+ if (declaredNames.has("react-dom")) {
4862
+ if ([
4863
+ "next",
4864
+ "gatsby",
4865
+ "@remix-run/react",
4866
+ "react-router-dom",
4867
+ "vite",
4868
+ "@docusaurus/core",
4869
+ "react-scripts",
4870
+ "astro",
4871
+ "@tanstack/react-router",
4872
+ "@tanstack/react-start",
4873
+ "react-app-rewired"
4874
+ ].some((framework) => declaredNames.has(framework) || usedPackageNames.has(framework))) usedPackageNames.add("react-dom");
4875
+ }
4876
+ if (declaredNames.has("react") && declaredNames.has("react-dom")) {
4877
+ const packageJsonPath = (0, node_path.resolve)(config.rootDir, "package.json");
4878
+ try {
4879
+ const content = (0, node_fs.readFileSync)(packageJsonPath, "utf-8");
4880
+ const peerDeps = JSON.parse(content).peerDependencies ?? {};
4881
+ if ("react" in peerDeps && declaredDependencies.get("react") === true) usedPackageNames.add("react");
4882
+ if ("react-dom" in peerDeps && declaredDependencies.get("react-dom") === true) usedPackageNames.add("react-dom");
4883
+ } catch {}
4884
+ }
4803
4885
  const peerSatisfied = collectPeerSatisfiedPackages(nodeModulesRoot, declaredNames, usedPackageNames);
4804
4886
  for (const packageName of peerSatisfied) usedPackageNames.add(packageName);
4805
4887
  const candidateUnused = /* @__PURE__ */ new Set();
@@ -5392,7 +5474,13 @@ const defineConfig = (options) => ({
5392
5474
  const analyze = async (config) => {
5393
5475
  const pipelineStartTime = performance.now();
5394
5476
  const workspaceDiscovery = resolveWorkspaces((0, node_path.resolve)(config.rootDir));
5395
- const workspacePackages = workspaceDiscovery.packages;
5477
+ const workspacePackages = [...workspaceDiscovery.packages];
5478
+ const monorepoRoot = findMonorepoRoot(config.rootDir);
5479
+ if (monorepoRoot) {
5480
+ const monorepoWorkspaces = resolveWorkspaces(monorepoRoot);
5481
+ const existingDirectories = new Set(workspacePackages.map((workspacePackage) => workspacePackage.directory));
5482
+ for (const monorepoPackage of monorepoWorkspaces.packages) if (!existingDirectories.has(monorepoPackage.directory)) workspacePackages.push(monorepoPackage);
5483
+ }
5396
5484
  const frameworkIgnorePatterns = getFrameworkExclusions(config.rootDir);
5397
5485
  const absoluteRoot = (0, node_path.resolve)(config.rootDir);
5398
5486
  const outputDirectoryExclusions = OUTPUT_DIRECTORIES.flatMap((outputDirectory) => {
@@ -5418,7 +5506,10 @@ const analyze = async (config) => {
5418
5506
  const moduleResolver = createResolver(config, workspacePackages.map((workspacePackage) => ({
5419
5507
  name: workspacePackage.name,
5420
5508
  directory: workspacePackage.directory
5421
- })), { hasReactNative });
5509
+ })), {
5510
+ hasReactNative,
5511
+ monorepoRoot
5512
+ });
5422
5513
  const graphInputs = [];
5423
5514
  for (const file of files) {
5424
5515
  const parsedModule = parseSourceFile(file.path);
package/dist/index.mjs CHANGED
@@ -3689,12 +3689,13 @@ const TSCONFIG_FILENAMES = [
3689
3689
  "tsconfig.json",
3690
3690
  "tsconfig.web.json",
3691
3691
  "tsconfig.app.json",
3692
- "tsconfig.base.json"
3692
+ "tsconfig.base.json",
3693
+ "jsconfig.json"
3693
3694
  ];
3694
- const findNearestTsconfig = (fromDir, rootDir) => {
3695
+ const findNearestTsconfig = (fromDir, rootDir, monorepoRootDir) => {
3695
3696
  let currentDirectory = fromDir;
3696
- const normalizedRoot = resolve(rootDir);
3697
- while (currentDirectory.length >= normalizedRoot.length) {
3697
+ const stopAt = monorepoRootDir ? resolve(monorepoRootDir) : resolve(rootDir);
3698
+ while (currentDirectory.length >= stopAt.length) {
3698
3699
  for (const tsconfigFilename of TSCONFIG_FILENAMES) {
3699
3700
  const tsconfigCandidate = join(currentDirectory, tsconfigFilename);
3700
3701
  if (cachedExistsSync(tsconfigCandidate)) return tsconfigCandidate;
@@ -3771,16 +3772,17 @@ const createResolver = (config, workspacePackages = [], options = {}) => {
3771
3772
  for (const workspacePackage of workspacePackages) workspaceNameToDirectory.set(workspacePackage.name, workspacePackage.directory);
3772
3773
  let rootTsconfigPath;
3773
3774
  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;
3775
+ else {
3776
+ const tsconfigSearchDirs = options.monorepoRoot ? [config.rootDir, options.monorepoRoot] : [config.rootDir];
3777
+ for (const searchDir of tsconfigSearchDirs) {
3778
+ for (const candidate of TSCONFIG_FILENAMES) {
3779
+ const candidatePath = resolve(searchDir, candidate);
3780
+ if (cachedExistsSync(candidatePath)) {
3781
+ rootTsconfigPath = candidatePath;
3782
+ break;
3783
+ }
3784
+ }
3785
+ if (rootTsconfigPath) break;
3784
3786
  }
3785
3787
  }
3786
3788
  const tsconfigPathCache = /* @__PURE__ */ new Map();
@@ -3789,24 +3791,56 @@ const createResolver = (config, workspacePackages = [], options = {}) => {
3789
3791
  const fileDir = dirname(filePath);
3790
3792
  const cached = tsconfigPathCache.get(fileDir);
3791
3793
  if (cached !== void 0) return cached;
3792
- const tsconfigResult = findNearestTsconfig(fileDir, config.rootDir) ?? rootTsconfigPath;
3794
+ const tsconfigResult = findNearestTsconfig(fileDir, config.rootDir, options.monorepoRoot) ?? rootTsconfigPath;
3793
3795
  tsconfigPathCache.set(fileDir, tsconfigResult);
3794
3796
  return tsconfigResult;
3795
3797
  };
3796
3798
  const tsconfigBaseUrlCache = /* @__PURE__ */ new Map();
3797
- const getBaseUrlDirectory = (tsconfigFile) => {
3798
- const cached = tsconfigBaseUrlCache.get(tsconfigFile);
3799
- if (cached !== void 0) return cached;
3799
+ const resolveExtendsPath = (extendsValue, fromDir) => {
3800
+ if (extendsValue.startsWith(".")) {
3801
+ const absolutePath = resolve(fromDir, extendsValue);
3802
+ if (cachedExistsSync(absolutePath)) return absolutePath;
3803
+ if (cachedExistsSync(absolutePath + ".json")) return absolutePath + ".json";
3804
+ return;
3805
+ }
3806
+ const packagePath = join(options.monorepoRoot ?? config.rootDir, "node_modules", extendsValue);
3807
+ if (cachedExistsSync(packagePath)) return packagePath;
3808
+ if (cachedExistsSync(packagePath + ".json")) return packagePath + ".json";
3809
+ const localPackagePath = join(fromDir, "node_modules", extendsValue);
3810
+ if (cachedExistsSync(localPackagePath)) return localPackagePath;
3811
+ if (cachedExistsSync(localPackagePath + ".json")) return localPackagePath + ".json";
3812
+ };
3813
+ const collectExtendsEntries = (tsconfigJson) => {
3814
+ if (typeof tsconfigJson.extends === "string") return [tsconfigJson.extends];
3815
+ if (Array.isArray(tsconfigJson.extends)) return tsconfigJson.extends.filter((entry) => typeof entry === "string");
3816
+ return [];
3817
+ };
3818
+ const extractBaseUrlFromTsconfig = (tsconfigFile, visitedFiles) => {
3819
+ if (visitedFiles.has(tsconfigFile)) return void 0;
3820
+ visitedFiles.add(tsconfigFile);
3800
3821
  try {
3801
3822
  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;
3823
+ const tsconfigJson = JSON.parse(cleanedContent);
3824
+ const tsconfigDir = dirname(tsconfigFile);
3825
+ const baseUrl = tsconfigJson.compilerOptions?.baseUrl;
3826
+ if (baseUrl) return resolve(tsconfigDir, baseUrl);
3827
+ for (const extendsEntry of collectExtendsEntries(tsconfigJson)) {
3828
+ const resolvedPath = resolveExtendsPath(extendsEntry, tsconfigDir);
3829
+ if (resolvedPath) {
3830
+ const result = extractBaseUrlFromTsconfig(resolvedPath, visitedFiles);
3831
+ if (result) return result;
3832
+ }
3807
3833
  }
3808
- } catch {}
3809
- tsconfigBaseUrlCache.set(tsconfigFile, void 0);
3834
+ } catch {
3835
+ return;
3836
+ }
3837
+ };
3838
+ const getBaseUrlDirectory = (tsconfigFile) => {
3839
+ const cached = tsconfigBaseUrlCache.get(tsconfigFile);
3840
+ if (cached !== void 0) return cached;
3841
+ const result = extractBaseUrlFromTsconfig(tsconfigFile, /* @__PURE__ */ new Set());
3842
+ tsconfigBaseUrlCache.set(tsconfigFile, result);
3843
+ return result;
3810
3844
  };
3811
3845
  const hasNextJsDependency = (() => {
3812
3846
  try {
@@ -3819,25 +3853,46 @@ const createResolver = (config, workspacePackages = [], options = {}) => {
3819
3853
  return false;
3820
3854
  }
3821
3855
  })();
3822
- const getPathAliases = (tsconfigFile) => {
3823
- const cached = tsconfigPathAliasCache.get(tsconfigFile);
3824
- if (cached) return cached;
3825
- const aliasMap = /* @__PURE__ */ new Map();
3826
- const tsconfigDir = dirname(tsconfigFile);
3856
+ const extractPathsFromTsconfig = (tsconfigFile, visitedFiles) => {
3857
+ if (visitedFiles.has(tsconfigFile)) return void 0;
3858
+ visitedFiles.add(tsconfigFile);
3827
3859
  try {
3828
3860
  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)));
3861
+ if (tsconfigContent.length === 0) return void 0;
3862
+ const cleanedContent = stripJsonComments(tsconfigContent);
3863
+ const tsconfigJson = JSON.parse(cleanedContent);
3864
+ const tsconfigDir = dirname(tsconfigFile);
3865
+ const paths = tsconfigJson.compilerOptions?.paths;
3866
+ const baseUrl = tsconfigJson.compilerOptions?.baseUrl;
3867
+ if (paths && typeof paths === "object") return {
3868
+ paths,
3869
+ baseUrl: baseUrl ?? ".",
3870
+ tsconfigDir
3871
+ };
3872
+ for (const extendsEntry of collectExtendsEntries(tsconfigJson)) {
3873
+ const resolvedPath = resolveExtendsPath(extendsEntry, tsconfigDir);
3874
+ if (resolvedPath) {
3875
+ const result = extractPathsFromTsconfig(resolvedPath, visitedFiles);
3876
+ if (result) return result;
3836
3877
  }
3837
3878
  }
3838
- } catch {}
3839
- if (aliasMap.size === 0 && hasNextJsDependency) if (cachedExistsSync(resolve(tsconfigDir, "src"))) aliasMap.set("@/*", [resolve(tsconfigDir, "src/*")]);
3840
- else aliasMap.set("@/*", [resolve(tsconfigDir, "*")]);
3879
+ } catch {
3880
+ return;
3881
+ }
3882
+ };
3883
+ const getPathAliases = (tsconfigFile) => {
3884
+ const cached = tsconfigPathAliasCache.get(tsconfigFile);
3885
+ if (cached) return cached;
3886
+ const aliasMap = /* @__PURE__ */ new Map();
3887
+ const extracted = extractPathsFromTsconfig(tsconfigFile, /* @__PURE__ */ new Set());
3888
+ if (extracted) {
3889
+ 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)));
3890
+ }
3891
+ if (aliasMap.size === 0 && hasNextJsDependency) {
3892
+ const tsconfigDir = dirname(tsconfigFile);
3893
+ if (cachedExistsSync(resolve(tsconfigDir, "src"))) aliasMap.set("@/*", [resolve(tsconfigDir, "src/*")]);
3894
+ else aliasMap.set("@/*", [resolve(tsconfigDir, "*")]);
3895
+ }
3841
3896
  tsconfigPathAliasCache.set(tsconfigFile, aliasMap);
3842
3897
  return aliasMap;
3843
3898
  };
@@ -4664,7 +4719,7 @@ const extractPackageName = (specifier) => {
4664
4719
  };
4665
4720
 
4666
4721
  //#endregion
4667
- //#region src/report/packages.ts
4722
+ //#region src/utils/find-monorepo-root.ts
4668
4723
  const MONOREPO_ROOT_MARKERS = [
4669
4724
  "pnpm-workspace.yaml",
4670
4725
  "pnpm-workspace.yml",
@@ -4710,6 +4765,9 @@ const findMonorepoRoot = (rootDir) => {
4710
4765
  for (const lockfile of LOCKFILE_MARKERS) if (existsSync(join(currentDirectory, lockfile))) return currentDirectory;
4711
4766
  }
4712
4767
  };
4768
+
4769
+ //#endregion
4770
+ //#region src/report/packages.ts
4713
4771
  const discoverAllPackageJsonPaths = (rootDir) => {
4714
4772
  const paths = [join(rootDir, "package.json")];
4715
4773
  const workspacePackageJsons = fg.sync("**/package.json", {
@@ -4770,6 +4828,30 @@ const detectStalePackages = (graph, config) => {
4770
4828
  if (declaredNames.has("react-native")) usedPackageNames.add("react-native");
4771
4829
  if (declaredNames.has("react-native-web")) usedPackageNames.add("react-native-web");
4772
4830
  }
4831
+ if (declaredNames.has("react-dom")) {
4832
+ if ([
4833
+ "next",
4834
+ "gatsby",
4835
+ "@remix-run/react",
4836
+ "react-router-dom",
4837
+ "vite",
4838
+ "@docusaurus/core",
4839
+ "react-scripts",
4840
+ "astro",
4841
+ "@tanstack/react-router",
4842
+ "@tanstack/react-start",
4843
+ "react-app-rewired"
4844
+ ].some((framework) => declaredNames.has(framework) || usedPackageNames.has(framework))) usedPackageNames.add("react-dom");
4845
+ }
4846
+ if (declaredNames.has("react") && declaredNames.has("react-dom")) {
4847
+ const packageJsonPath = resolve(config.rootDir, "package.json");
4848
+ try {
4849
+ const content = readFileSync(packageJsonPath, "utf-8");
4850
+ const peerDeps = JSON.parse(content).peerDependencies ?? {};
4851
+ if ("react" in peerDeps && declaredDependencies.get("react") === true) usedPackageNames.add("react");
4852
+ if ("react-dom" in peerDeps && declaredDependencies.get("react-dom") === true) usedPackageNames.add("react-dom");
4853
+ } catch {}
4854
+ }
4773
4855
  const peerSatisfied = collectPeerSatisfiedPackages(nodeModulesRoot, declaredNames, usedPackageNames);
4774
4856
  for (const packageName of peerSatisfied) usedPackageNames.add(packageName);
4775
4857
  const candidateUnused = /* @__PURE__ */ new Set();
@@ -5362,7 +5444,13 @@ const defineConfig = (options) => ({
5362
5444
  const analyze = async (config) => {
5363
5445
  const pipelineStartTime = performance.now();
5364
5446
  const workspaceDiscovery = resolveWorkspaces(resolve(config.rootDir));
5365
- const workspacePackages = workspaceDiscovery.packages;
5447
+ const workspacePackages = [...workspaceDiscovery.packages];
5448
+ const monorepoRoot = findMonorepoRoot(config.rootDir);
5449
+ if (monorepoRoot) {
5450
+ const monorepoWorkspaces = resolveWorkspaces(monorepoRoot);
5451
+ const existingDirectories = new Set(workspacePackages.map((workspacePackage) => workspacePackage.directory));
5452
+ for (const monorepoPackage of monorepoWorkspaces.packages) if (!existingDirectories.has(monorepoPackage.directory)) workspacePackages.push(monorepoPackage);
5453
+ }
5366
5454
  const frameworkIgnorePatterns = getFrameworkExclusions(config.rootDir);
5367
5455
  const absoluteRoot = resolve(config.rootDir);
5368
5456
  const outputDirectoryExclusions = OUTPUT_DIRECTORIES.flatMap((outputDirectory) => {
@@ -5388,7 +5476,10 @@ const analyze = async (config) => {
5388
5476
  const moduleResolver = createResolver(config, workspacePackages.map((workspacePackage) => ({
5389
5477
  name: workspacePackage.name,
5390
5478
  directory: workspacePackage.directory
5391
- })), { hasReactNative });
5479
+ })), {
5480
+ hasReactNative,
5481
+ monorepoRoot
5482
+ });
5392
5483
  const graphInputs = [];
5393
5484
  for (const file of files) {
5394
5485
  const parsedModule = parseSourceFile(file.path);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deslop-js",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "description": "Deslop JavaScript code",
5
5
  "keywords": [
6
6
  "dead-code",