deslop-js 0.0.5 → 0.0.6

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/index.cjs CHANGED
@@ -193,7 +193,10 @@ const IMPLICIT_DEPENDENCIES = new Set([
193
193
  "dotenv-cli",
194
194
  "webpack",
195
195
  "rollup",
196
- "terser"
196
+ "terser",
197
+ "autoprefixer",
198
+ "tailwindcss",
199
+ "react-test-renderer"
197
200
  ]);
198
201
  const BUILTIN_MODULES = new Set([
199
202
  "assert",
@@ -4498,13 +4501,21 @@ const buildSourceTargetMap = (graph) => {
4498
4501
  const EXCLUDED_EXTENSIONS = new Set([
4499
4502
  ".html",
4500
4503
  ".mdx",
4501
- ".md"
4504
+ ".md",
4505
+ ".css",
4506
+ ".scss",
4507
+ ".less",
4508
+ ".sass",
4509
+ ".graphql",
4510
+ ".gql"
4502
4511
  ]);
4512
+ const TEST_FILE_PATTERN = /(?:\.(?:test|spec|stories|story)\.|(?:^|\/)__tests__\/)/;
4503
4513
  const hasExcludedExtension = (filePath) => {
4504
4514
  const lastDot = filePath.lastIndexOf(".");
4505
4515
  if (lastDot === -1) return false;
4506
4516
  return EXCLUDED_EXTENSIONS.has(filePath.slice(lastDot));
4507
4517
  };
4518
+ const isTestFile = (filePath) => TEST_FILE_PATTERN.test(filePath);
4508
4519
  const detectOrphanFiles = (graph) => {
4509
4520
  const unusedFiles = [];
4510
4521
  for (const module of graph.modules) {
@@ -4513,6 +4524,7 @@ const detectOrphanFiles = (graph) => {
4513
4524
  if (module.isDeclarationFile) continue;
4514
4525
  if (module.isConfigFile) continue;
4515
4526
  if (hasExcludedExtension(module.fileId.path)) continue;
4527
+ if (isTestFile(module.fileId.path)) continue;
4516
4528
  if (isBarrelWithReachableSources(module, graph)) continue;
4517
4529
  if (hasReachableDirectImporter(module.fileId.index, graph)) continue;
4518
4530
  unusedFiles.push({ path: module.fileId.path });
@@ -4692,12 +4704,25 @@ const LOCKFILE_MARKERS = [
4692
4704
  "bun.lockb",
4693
4705
  "bun.lock"
4694
4706
  ];
4707
+ const MAX_MONOREPO_WALK_DEPTH = 5;
4695
4708
  const findMonorepoRoot = (rootDir) => {
4696
4709
  let currentDirectory = (0, node_path.resolve)(rootDir);
4697
- while (true) {
4710
+ let walkedDepth = 0;
4711
+ while (walkedDepth < MAX_MONOREPO_WALK_DEPTH) {
4698
4712
  const parentDirectory = (0, node_path.dirname)(currentDirectory);
4699
4713
  if (parentDirectory === currentDirectory) break;
4700
4714
  currentDirectory = parentDirectory;
4715
+ walkedDepth++;
4716
+ if ((0, node_fs.existsSync)((0, node_path.join)(currentDirectory, ".git"))) {
4717
+ for (const marker of MONOREPO_ROOT_MARKERS) if ((0, node_fs.existsSync)((0, node_path.join)(currentDirectory, marker))) return currentDirectory;
4718
+ const packageJsonPath = (0, node_path.join)(currentDirectory, "package.json");
4719
+ if ((0, node_fs.existsSync)(packageJsonPath)) try {
4720
+ const content = (0, node_fs.readFileSync)(packageJsonPath, "utf-8");
4721
+ if (JSON.parse(content).workspaces) return currentDirectory;
4722
+ } catch {}
4723
+ for (const lockfile of LOCKFILE_MARKERS) if ((0, node_fs.existsSync)((0, node_path.join)(currentDirectory, lockfile))) return currentDirectory;
4724
+ return;
4725
+ }
4701
4726
  for (const marker of MONOREPO_ROOT_MARKERS) if ((0, node_fs.existsSync)((0, node_path.join)(currentDirectory, marker))) return currentDirectory;
4702
4727
  const packageJsonPath = (0, node_path.join)(currentDirectory, "package.json");
4703
4728
  if ((0, node_fs.existsSync)(packageJsonPath)) try {
@@ -4771,10 +4796,23 @@ const detectStalePackages = (graph, config) => {
4771
4796
  }
4772
4797
  const peerSatisfied = collectPeerSatisfiedPackages(nodeModulesRoot, declaredNames, usedPackageNames);
4773
4798
  for (const packageName of peerSatisfied) usedPackageNames.add(packageName);
4774
- const unusedDependencies = [];
4775
- for (const [dependencyName, isDevDependency] of declaredDependencies) {
4799
+ const candidateUnused = /* @__PURE__ */ new Set();
4800
+ for (const [dependencyName] of declaredDependencies) {
4776
4801
  if (isAlwaysConsideredUsed(dependencyName)) continue;
4777
- if (!usedPackageNames.has(dependencyName)) unusedDependencies.push({
4802
+ if (usedPackageNames.has(dependencyName)) continue;
4803
+ candidateUnused.add(dependencyName);
4804
+ }
4805
+ if (candidateUnused.size > 0) {
4806
+ const sourceFileRescued = scanSourceFilesForPackageImports(config.rootDir, candidateUnused);
4807
+ for (const packageName of sourceFileRescued) {
4808
+ usedPackageNames.add(packageName);
4809
+ candidateUnused.delete(packageName);
4810
+ }
4811
+ }
4812
+ const unusedDependencies = [];
4813
+ for (const dependencyName of candidateUnused) {
4814
+ const isDevDependency = declaredDependencies.get(dependencyName) ?? false;
4815
+ unusedDependencies.push({
4778
4816
  name: dependencyName,
4779
4817
  isDevDependency
4780
4818
  });
@@ -5037,6 +5075,41 @@ const extractExtendsPackageName = (extendsValue) => {
5037
5075
  }
5038
5076
  return extendsValue.split("/")[0];
5039
5077
  };
5078
+ const SOURCE_FILE_GLOBS = ["**/*.{ts,tsx,js,jsx,mts,mjs,cts,cjs}"];
5079
+ const SOURCE_FILE_IGNORES = [
5080
+ "**/node_modules/**",
5081
+ "**/dist/**",
5082
+ "**/build/**",
5083
+ "**/out/**",
5084
+ "**/.git/**",
5085
+ "**/coverage/**",
5086
+ "**/*.min.js",
5087
+ "**/*.d.ts"
5088
+ ];
5089
+ const scanSourceFilesForPackageImports = (rootDir, candidatePackages) => {
5090
+ const found = /* @__PURE__ */ new Set();
5091
+ if (candidatePackages.size === 0) return found;
5092
+ const sourceFiles = fast_glob.default.sync(SOURCE_FILE_GLOBS, {
5093
+ cwd: rootDir,
5094
+ absolute: true,
5095
+ onlyFiles: true,
5096
+ ignore: SOURCE_FILE_IGNORES,
5097
+ deep: 15
5098
+ });
5099
+ for (const filePath of sourceFiles) {
5100
+ if (candidatePackages.size === 0) break;
5101
+ try {
5102
+ const content = (0, node_fs.readFileSync)(filePath, "utf-8");
5103
+ for (const packageName of candidatePackages) if (content.includes(`'${packageName}'`) || content.includes(`"${packageName}"`) || content.includes(`'${packageName}/`) || content.includes(`"${packageName}/`)) {
5104
+ found.add(packageName);
5105
+ candidatePackages.delete(packageName);
5106
+ }
5107
+ } catch {
5108
+ continue;
5109
+ }
5110
+ }
5111
+ return found;
5112
+ };
5040
5113
  const ALWAYS_USED_PREFIXES = [
5041
5114
  "@types/",
5042
5115
  "eslint-config-",
@@ -5080,15 +5153,20 @@ const ALWAYS_USED_PREFIXES = [
5080
5153
  "@lingui/",
5081
5154
  "@emotion/",
5082
5155
  "tslint-config-",
5156
+ "eslint-import-resolver-",
5083
5157
  "@changesets/",
5158
+ "@react-navigation/",
5084
5159
  "@vercel/",
5085
5160
  "@expo/",
5086
5161
  "expo-",
5087
5162
  "react-native-"
5088
5163
  ];
5164
+ const ALWAYS_USED_SUFFIXES = ["-loader"];
5089
5165
  const isAlwaysConsideredUsed = (dependencyName) => {
5090
5166
  if (IMPLICIT_DEPENDENCIES.has(dependencyName)) return true;
5091
- return ALWAYS_USED_PREFIXES.some((prefix) => dependencyName.startsWith(prefix));
5167
+ if (ALWAYS_USED_PREFIXES.some((prefix) => dependencyName.startsWith(prefix))) return true;
5168
+ if (ALWAYS_USED_SUFFIXES.some((suffix) => dependencyName.endsWith(suffix))) return true;
5169
+ return false;
5092
5170
  };
5093
5171
 
5094
5172
  //#endregion
package/dist/index.mjs CHANGED
@@ -163,7 +163,10 @@ const IMPLICIT_DEPENDENCIES = new Set([
163
163
  "dotenv-cli",
164
164
  "webpack",
165
165
  "rollup",
166
- "terser"
166
+ "terser",
167
+ "autoprefixer",
168
+ "tailwindcss",
169
+ "react-test-renderer"
167
170
  ]);
168
171
  const BUILTIN_MODULES = new Set([
169
172
  "assert",
@@ -4468,13 +4471,21 @@ const buildSourceTargetMap = (graph) => {
4468
4471
  const EXCLUDED_EXTENSIONS = new Set([
4469
4472
  ".html",
4470
4473
  ".mdx",
4471
- ".md"
4474
+ ".md",
4475
+ ".css",
4476
+ ".scss",
4477
+ ".less",
4478
+ ".sass",
4479
+ ".graphql",
4480
+ ".gql"
4472
4481
  ]);
4482
+ const TEST_FILE_PATTERN = /(?:\.(?:test|spec|stories|story)\.|(?:^|\/)__tests__\/)/;
4473
4483
  const hasExcludedExtension = (filePath) => {
4474
4484
  const lastDot = filePath.lastIndexOf(".");
4475
4485
  if (lastDot === -1) return false;
4476
4486
  return EXCLUDED_EXTENSIONS.has(filePath.slice(lastDot));
4477
4487
  };
4488
+ const isTestFile = (filePath) => TEST_FILE_PATTERN.test(filePath);
4478
4489
  const detectOrphanFiles = (graph) => {
4479
4490
  const unusedFiles = [];
4480
4491
  for (const module of graph.modules) {
@@ -4483,6 +4494,7 @@ const detectOrphanFiles = (graph) => {
4483
4494
  if (module.isDeclarationFile) continue;
4484
4495
  if (module.isConfigFile) continue;
4485
4496
  if (hasExcludedExtension(module.fileId.path)) continue;
4497
+ if (isTestFile(module.fileId.path)) continue;
4486
4498
  if (isBarrelWithReachableSources(module, graph)) continue;
4487
4499
  if (hasReachableDirectImporter(module.fileId.index, graph)) continue;
4488
4500
  unusedFiles.push({ path: module.fileId.path });
@@ -4662,12 +4674,25 @@ const LOCKFILE_MARKERS = [
4662
4674
  "bun.lockb",
4663
4675
  "bun.lock"
4664
4676
  ];
4677
+ const MAX_MONOREPO_WALK_DEPTH = 5;
4665
4678
  const findMonorepoRoot = (rootDir) => {
4666
4679
  let currentDirectory = resolve(rootDir);
4667
- while (true) {
4680
+ let walkedDepth = 0;
4681
+ while (walkedDepth < MAX_MONOREPO_WALK_DEPTH) {
4668
4682
  const parentDirectory = dirname(currentDirectory);
4669
4683
  if (parentDirectory === currentDirectory) break;
4670
4684
  currentDirectory = parentDirectory;
4685
+ walkedDepth++;
4686
+ if (existsSync(join(currentDirectory, ".git"))) {
4687
+ for (const marker of MONOREPO_ROOT_MARKERS) if (existsSync(join(currentDirectory, marker))) return currentDirectory;
4688
+ const packageJsonPath = join(currentDirectory, "package.json");
4689
+ if (existsSync(packageJsonPath)) try {
4690
+ const content = readFileSync(packageJsonPath, "utf-8");
4691
+ if (JSON.parse(content).workspaces) return currentDirectory;
4692
+ } catch {}
4693
+ for (const lockfile of LOCKFILE_MARKERS) if (existsSync(join(currentDirectory, lockfile))) return currentDirectory;
4694
+ return;
4695
+ }
4671
4696
  for (const marker of MONOREPO_ROOT_MARKERS) if (existsSync(join(currentDirectory, marker))) return currentDirectory;
4672
4697
  const packageJsonPath = join(currentDirectory, "package.json");
4673
4698
  if (existsSync(packageJsonPath)) try {
@@ -4741,10 +4766,23 @@ const detectStalePackages = (graph, config) => {
4741
4766
  }
4742
4767
  const peerSatisfied = collectPeerSatisfiedPackages(nodeModulesRoot, declaredNames, usedPackageNames);
4743
4768
  for (const packageName of peerSatisfied) usedPackageNames.add(packageName);
4744
- const unusedDependencies = [];
4745
- for (const [dependencyName, isDevDependency] of declaredDependencies) {
4769
+ const candidateUnused = /* @__PURE__ */ new Set();
4770
+ for (const [dependencyName] of declaredDependencies) {
4746
4771
  if (isAlwaysConsideredUsed(dependencyName)) continue;
4747
- if (!usedPackageNames.has(dependencyName)) unusedDependencies.push({
4772
+ if (usedPackageNames.has(dependencyName)) continue;
4773
+ candidateUnused.add(dependencyName);
4774
+ }
4775
+ if (candidateUnused.size > 0) {
4776
+ const sourceFileRescued = scanSourceFilesForPackageImports(config.rootDir, candidateUnused);
4777
+ for (const packageName of sourceFileRescued) {
4778
+ usedPackageNames.add(packageName);
4779
+ candidateUnused.delete(packageName);
4780
+ }
4781
+ }
4782
+ const unusedDependencies = [];
4783
+ for (const dependencyName of candidateUnused) {
4784
+ const isDevDependency = declaredDependencies.get(dependencyName) ?? false;
4785
+ unusedDependencies.push({
4748
4786
  name: dependencyName,
4749
4787
  isDevDependency
4750
4788
  });
@@ -5007,6 +5045,41 @@ const extractExtendsPackageName = (extendsValue) => {
5007
5045
  }
5008
5046
  return extendsValue.split("/")[0];
5009
5047
  };
5048
+ const SOURCE_FILE_GLOBS = ["**/*.{ts,tsx,js,jsx,mts,mjs,cts,cjs}"];
5049
+ const SOURCE_FILE_IGNORES = [
5050
+ "**/node_modules/**",
5051
+ "**/dist/**",
5052
+ "**/build/**",
5053
+ "**/out/**",
5054
+ "**/.git/**",
5055
+ "**/coverage/**",
5056
+ "**/*.min.js",
5057
+ "**/*.d.ts"
5058
+ ];
5059
+ const scanSourceFilesForPackageImports = (rootDir, candidatePackages) => {
5060
+ const found = /* @__PURE__ */ new Set();
5061
+ if (candidatePackages.size === 0) return found;
5062
+ const sourceFiles = fg.sync(SOURCE_FILE_GLOBS, {
5063
+ cwd: rootDir,
5064
+ absolute: true,
5065
+ onlyFiles: true,
5066
+ ignore: SOURCE_FILE_IGNORES,
5067
+ deep: 15
5068
+ });
5069
+ for (const filePath of sourceFiles) {
5070
+ if (candidatePackages.size === 0) break;
5071
+ try {
5072
+ const content = readFileSync(filePath, "utf-8");
5073
+ for (const packageName of candidatePackages) if (content.includes(`'${packageName}'`) || content.includes(`"${packageName}"`) || content.includes(`'${packageName}/`) || content.includes(`"${packageName}/`)) {
5074
+ found.add(packageName);
5075
+ candidatePackages.delete(packageName);
5076
+ }
5077
+ } catch {
5078
+ continue;
5079
+ }
5080
+ }
5081
+ return found;
5082
+ };
5010
5083
  const ALWAYS_USED_PREFIXES = [
5011
5084
  "@types/",
5012
5085
  "eslint-config-",
@@ -5050,15 +5123,20 @@ const ALWAYS_USED_PREFIXES = [
5050
5123
  "@lingui/",
5051
5124
  "@emotion/",
5052
5125
  "tslint-config-",
5126
+ "eslint-import-resolver-",
5053
5127
  "@changesets/",
5128
+ "@react-navigation/",
5054
5129
  "@vercel/",
5055
5130
  "@expo/",
5056
5131
  "expo-",
5057
5132
  "react-native-"
5058
5133
  ];
5134
+ const ALWAYS_USED_SUFFIXES = ["-loader"];
5059
5135
  const isAlwaysConsideredUsed = (dependencyName) => {
5060
5136
  if (IMPLICIT_DEPENDENCIES.has(dependencyName)) return true;
5061
- return ALWAYS_USED_PREFIXES.some((prefix) => dependencyName.startsWith(prefix));
5137
+ if (ALWAYS_USED_PREFIXES.some((prefix) => dependencyName.startsWith(prefix))) return true;
5138
+ if (ALWAYS_USED_SUFFIXES.some((suffix) => dependencyName.endsWith(suffix))) return true;
5139
+ return false;
5062
5140
  };
5063
5141
 
5064
5142
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deslop-js",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "Deslop JavaScript code",
5
5
  "keywords": [
6
6
  "dead-code",