deslop-js 0.0.5 → 0.0.7

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,14 @@ 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",
200
+ "esbuild",
201
+ "typedoc",
202
+ "commitizen",
203
+ "cz-conventional-changelog"
197
204
  ]);
198
205
  const BUILTIN_MODULES = new Set([
199
206
  "assert",
@@ -4498,13 +4505,23 @@ const buildSourceTargetMap = (graph) => {
4498
4505
  const EXCLUDED_EXTENSIONS = new Set([
4499
4506
  ".html",
4500
4507
  ".mdx",
4501
- ".md"
4508
+ ".md",
4509
+ ".css",
4510
+ ".scss",
4511
+ ".less",
4512
+ ".sass",
4513
+ ".graphql",
4514
+ ".gql"
4502
4515
  ]);
4516
+ const TEST_FILE_PATTERN = /(?:\.(?:test|spec|stories|story|cy)\.|(?:^|\/)__tests__\/)/;
4517
+ const EXCLUDED_DIRECTORY_PATTERN = /(?:^|\/)(?:e2e|cypress|playwright|__fixtures__|__snapshots__|scripts)\/(?!.*node_modules)/;
4518
+ const CONFIG_FILE_PATTERN = /(?:^|\/)(?:[^/]+\.config\.[tj]sx?$|[^/]+\.setup\.[tj]sx?$|setupTests\.[tj]sx?$|jest\.setup\.[tj]sx?$|vitest\.setup\.[tj]sx?$)/;
4503
4519
  const hasExcludedExtension = (filePath) => {
4504
4520
  const lastDot = filePath.lastIndexOf(".");
4505
4521
  if (lastDot === -1) return false;
4506
4522
  return EXCLUDED_EXTENSIONS.has(filePath.slice(lastDot));
4507
4523
  };
4524
+ const isExcludedByPattern = (filePath) => TEST_FILE_PATTERN.test(filePath) || EXCLUDED_DIRECTORY_PATTERN.test(filePath) || CONFIG_FILE_PATTERN.test(filePath);
4508
4525
  const detectOrphanFiles = (graph) => {
4509
4526
  const unusedFiles = [];
4510
4527
  for (const module of graph.modules) {
@@ -4513,6 +4530,7 @@ const detectOrphanFiles = (graph) => {
4513
4530
  if (module.isDeclarationFile) continue;
4514
4531
  if (module.isConfigFile) continue;
4515
4532
  if (hasExcludedExtension(module.fileId.path)) continue;
4533
+ if (isExcludedByPattern(module.fileId.path)) continue;
4516
4534
  if (isBarrelWithReachableSources(module, graph)) continue;
4517
4535
  if (hasReachableDirectImporter(module.fileId.index, graph)) continue;
4518
4536
  unusedFiles.push({ path: module.fileId.path });
@@ -4692,12 +4710,25 @@ const LOCKFILE_MARKERS = [
4692
4710
  "bun.lockb",
4693
4711
  "bun.lock"
4694
4712
  ];
4713
+ const MAX_MONOREPO_WALK_DEPTH = 5;
4695
4714
  const findMonorepoRoot = (rootDir) => {
4696
4715
  let currentDirectory = (0, node_path.resolve)(rootDir);
4697
- while (true) {
4716
+ let walkedDepth = 0;
4717
+ while (walkedDepth < MAX_MONOREPO_WALK_DEPTH) {
4698
4718
  const parentDirectory = (0, node_path.dirname)(currentDirectory);
4699
4719
  if (parentDirectory === currentDirectory) break;
4700
4720
  currentDirectory = parentDirectory;
4721
+ walkedDepth++;
4722
+ if ((0, node_fs.existsSync)((0, node_path.join)(currentDirectory, ".git"))) {
4723
+ for (const marker of MONOREPO_ROOT_MARKERS) if ((0, node_fs.existsSync)((0, node_path.join)(currentDirectory, marker))) return currentDirectory;
4724
+ const packageJsonPath = (0, node_path.join)(currentDirectory, "package.json");
4725
+ if ((0, node_fs.existsSync)(packageJsonPath)) try {
4726
+ const content = (0, node_fs.readFileSync)(packageJsonPath, "utf-8");
4727
+ if (JSON.parse(content).workspaces) return currentDirectory;
4728
+ } catch {}
4729
+ for (const lockfile of LOCKFILE_MARKERS) if ((0, node_fs.existsSync)((0, node_path.join)(currentDirectory, lockfile))) return currentDirectory;
4730
+ return;
4731
+ }
4701
4732
  for (const marker of MONOREPO_ROOT_MARKERS) if ((0, node_fs.existsSync)((0, node_path.join)(currentDirectory, marker))) return currentDirectory;
4702
4733
  const packageJsonPath = (0, node_path.join)(currentDirectory, "package.json");
4703
4734
  if ((0, node_fs.existsSync)(packageJsonPath)) try {
@@ -4771,10 +4802,23 @@ const detectStalePackages = (graph, config) => {
4771
4802
  }
4772
4803
  const peerSatisfied = collectPeerSatisfiedPackages(nodeModulesRoot, declaredNames, usedPackageNames);
4773
4804
  for (const packageName of peerSatisfied) usedPackageNames.add(packageName);
4774
- const unusedDependencies = [];
4775
- for (const [dependencyName, isDevDependency] of declaredDependencies) {
4805
+ const candidateUnused = /* @__PURE__ */ new Set();
4806
+ for (const [dependencyName] of declaredDependencies) {
4776
4807
  if (isAlwaysConsideredUsed(dependencyName)) continue;
4777
- if (!usedPackageNames.has(dependencyName)) unusedDependencies.push({
4808
+ if (usedPackageNames.has(dependencyName)) continue;
4809
+ candidateUnused.add(dependencyName);
4810
+ }
4811
+ if (candidateUnused.size > 0) {
4812
+ const sourceFileRescued = scanSourceFilesForPackageImports(config.rootDir, candidateUnused);
4813
+ for (const packageName of sourceFileRescued) {
4814
+ usedPackageNames.add(packageName);
4815
+ candidateUnused.delete(packageName);
4816
+ }
4817
+ }
4818
+ const unusedDependencies = [];
4819
+ for (const dependencyName of candidateUnused) {
4820
+ const isDevDependency = declaredDependencies.get(dependencyName) ?? false;
4821
+ unusedDependencies.push({
4778
4822
  name: dependencyName,
4779
4823
  isDevDependency
4780
4824
  });
@@ -4968,7 +5012,11 @@ const PACKAGE_JSON_CONFIG_SECTIONS = [
4968
5012
  "commitlint",
4969
5013
  "browserslist",
4970
5014
  "postcss",
4971
- "ava"
5015
+ "ava",
5016
+ "config",
5017
+ "pnpm",
5018
+ "resolutions",
5019
+ "overrides"
4972
5020
  ];
4973
5021
  const collectPackageJsonConfigReferences = (packageJsonPath, declaredNames) => {
4974
5022
  const referenced = /* @__PURE__ */ new Set();
@@ -5037,6 +5085,41 @@ const extractExtendsPackageName = (extendsValue) => {
5037
5085
  }
5038
5086
  return extendsValue.split("/")[0];
5039
5087
  };
5088
+ const SOURCE_FILE_GLOBS = ["**/*.{ts,tsx,js,jsx,mts,mjs,cts,cjs}"];
5089
+ const SOURCE_FILE_IGNORES = [
5090
+ "**/node_modules/**",
5091
+ "**/dist/**",
5092
+ "**/build/**",
5093
+ "**/out/**",
5094
+ "**/.git/**",
5095
+ "**/coverage/**",
5096
+ "**/*.min.js",
5097
+ "**/*.d.ts"
5098
+ ];
5099
+ const scanSourceFilesForPackageImports = (rootDir, candidatePackages) => {
5100
+ const found = /* @__PURE__ */ new Set();
5101
+ if (candidatePackages.size === 0) return found;
5102
+ const sourceFiles = fast_glob.default.sync(SOURCE_FILE_GLOBS, {
5103
+ cwd: rootDir,
5104
+ absolute: true,
5105
+ onlyFiles: true,
5106
+ ignore: SOURCE_FILE_IGNORES,
5107
+ deep: 15
5108
+ });
5109
+ for (const filePath of sourceFiles) {
5110
+ if (candidatePackages.size === 0) break;
5111
+ try {
5112
+ const content = (0, node_fs.readFileSync)(filePath, "utf-8");
5113
+ for (const packageName of candidatePackages) if (content.includes(`'${packageName}'`) || content.includes(`"${packageName}"`) || content.includes(`'${packageName}/`) || content.includes(`"${packageName}/`)) {
5114
+ found.add(packageName);
5115
+ candidatePackages.delete(packageName);
5116
+ }
5117
+ } catch {
5118
+ continue;
5119
+ }
5120
+ }
5121
+ return found;
5122
+ };
5040
5123
  const ALWAYS_USED_PREFIXES = [
5041
5124
  "@types/",
5042
5125
  "eslint-config-",
@@ -5072,6 +5155,7 @@ const ALWAYS_USED_PREFIXES = [
5072
5155
  "postcss-",
5073
5156
  "@tailwindcss/",
5074
5157
  "rollup-plugin-",
5158
+ "@rollup/",
5075
5159
  "vite-plugin-",
5076
5160
  "@vitejs/",
5077
5161
  "webpack-",
@@ -5080,15 +5164,20 @@ const ALWAYS_USED_PREFIXES = [
5080
5164
  "@lingui/",
5081
5165
  "@emotion/",
5082
5166
  "tslint-config-",
5167
+ "eslint-import-resolver-",
5083
5168
  "@changesets/",
5169
+ "@react-navigation/",
5084
5170
  "@vercel/",
5085
5171
  "@expo/",
5086
5172
  "expo-",
5087
5173
  "react-native-"
5088
5174
  ];
5175
+ const ALWAYS_USED_SUFFIXES = ["-loader"];
5089
5176
  const isAlwaysConsideredUsed = (dependencyName) => {
5090
5177
  if (IMPLICIT_DEPENDENCIES.has(dependencyName)) return true;
5091
- return ALWAYS_USED_PREFIXES.some((prefix) => dependencyName.startsWith(prefix));
5178
+ if (ALWAYS_USED_PREFIXES.some((prefix) => dependencyName.startsWith(prefix))) return true;
5179
+ if (ALWAYS_USED_SUFFIXES.some((suffix) => dependencyName.endsWith(suffix))) return true;
5180
+ return false;
5092
5181
  };
5093
5182
 
5094
5183
  //#endregion
package/dist/index.mjs CHANGED
@@ -163,7 +163,14 @@ 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",
170
+ "esbuild",
171
+ "typedoc",
172
+ "commitizen",
173
+ "cz-conventional-changelog"
167
174
  ]);
168
175
  const BUILTIN_MODULES = new Set([
169
176
  "assert",
@@ -4468,13 +4475,23 @@ const buildSourceTargetMap = (graph) => {
4468
4475
  const EXCLUDED_EXTENSIONS = new Set([
4469
4476
  ".html",
4470
4477
  ".mdx",
4471
- ".md"
4478
+ ".md",
4479
+ ".css",
4480
+ ".scss",
4481
+ ".less",
4482
+ ".sass",
4483
+ ".graphql",
4484
+ ".gql"
4472
4485
  ]);
4486
+ const TEST_FILE_PATTERN = /(?:\.(?:test|spec|stories|story|cy)\.|(?:^|\/)__tests__\/)/;
4487
+ const EXCLUDED_DIRECTORY_PATTERN = /(?:^|\/)(?:e2e|cypress|playwright|__fixtures__|__snapshots__|scripts)\/(?!.*node_modules)/;
4488
+ const CONFIG_FILE_PATTERN = /(?:^|\/)(?:[^/]+\.config\.[tj]sx?$|[^/]+\.setup\.[tj]sx?$|setupTests\.[tj]sx?$|jest\.setup\.[tj]sx?$|vitest\.setup\.[tj]sx?$)/;
4473
4489
  const hasExcludedExtension = (filePath) => {
4474
4490
  const lastDot = filePath.lastIndexOf(".");
4475
4491
  if (lastDot === -1) return false;
4476
4492
  return EXCLUDED_EXTENSIONS.has(filePath.slice(lastDot));
4477
4493
  };
4494
+ const isExcludedByPattern = (filePath) => TEST_FILE_PATTERN.test(filePath) || EXCLUDED_DIRECTORY_PATTERN.test(filePath) || CONFIG_FILE_PATTERN.test(filePath);
4478
4495
  const detectOrphanFiles = (graph) => {
4479
4496
  const unusedFiles = [];
4480
4497
  for (const module of graph.modules) {
@@ -4483,6 +4500,7 @@ const detectOrphanFiles = (graph) => {
4483
4500
  if (module.isDeclarationFile) continue;
4484
4501
  if (module.isConfigFile) continue;
4485
4502
  if (hasExcludedExtension(module.fileId.path)) continue;
4503
+ if (isExcludedByPattern(module.fileId.path)) continue;
4486
4504
  if (isBarrelWithReachableSources(module, graph)) continue;
4487
4505
  if (hasReachableDirectImporter(module.fileId.index, graph)) continue;
4488
4506
  unusedFiles.push({ path: module.fileId.path });
@@ -4662,12 +4680,25 @@ const LOCKFILE_MARKERS = [
4662
4680
  "bun.lockb",
4663
4681
  "bun.lock"
4664
4682
  ];
4683
+ const MAX_MONOREPO_WALK_DEPTH = 5;
4665
4684
  const findMonorepoRoot = (rootDir) => {
4666
4685
  let currentDirectory = resolve(rootDir);
4667
- while (true) {
4686
+ let walkedDepth = 0;
4687
+ while (walkedDepth < MAX_MONOREPO_WALK_DEPTH) {
4668
4688
  const parentDirectory = dirname(currentDirectory);
4669
4689
  if (parentDirectory === currentDirectory) break;
4670
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
+ }
4671
4702
  for (const marker of MONOREPO_ROOT_MARKERS) if (existsSync(join(currentDirectory, marker))) return currentDirectory;
4672
4703
  const packageJsonPath = join(currentDirectory, "package.json");
4673
4704
  if (existsSync(packageJsonPath)) try {
@@ -4741,10 +4772,23 @@ const detectStalePackages = (graph, config) => {
4741
4772
  }
4742
4773
  const peerSatisfied = collectPeerSatisfiedPackages(nodeModulesRoot, declaredNames, usedPackageNames);
4743
4774
  for (const packageName of peerSatisfied) usedPackageNames.add(packageName);
4744
- const unusedDependencies = [];
4745
- for (const [dependencyName, isDevDependency] of declaredDependencies) {
4775
+ const candidateUnused = /* @__PURE__ */ new Set();
4776
+ for (const [dependencyName] of declaredDependencies) {
4746
4777
  if (isAlwaysConsideredUsed(dependencyName)) continue;
4747
- if (!usedPackageNames.has(dependencyName)) unusedDependencies.push({
4778
+ if (usedPackageNames.has(dependencyName)) continue;
4779
+ candidateUnused.add(dependencyName);
4780
+ }
4781
+ if (candidateUnused.size > 0) {
4782
+ const sourceFileRescued = scanSourceFilesForPackageImports(config.rootDir, candidateUnused);
4783
+ for (const packageName of sourceFileRescued) {
4784
+ usedPackageNames.add(packageName);
4785
+ candidateUnused.delete(packageName);
4786
+ }
4787
+ }
4788
+ const unusedDependencies = [];
4789
+ for (const dependencyName of candidateUnused) {
4790
+ const isDevDependency = declaredDependencies.get(dependencyName) ?? false;
4791
+ unusedDependencies.push({
4748
4792
  name: dependencyName,
4749
4793
  isDevDependency
4750
4794
  });
@@ -4938,7 +4982,11 @@ const PACKAGE_JSON_CONFIG_SECTIONS = [
4938
4982
  "commitlint",
4939
4983
  "browserslist",
4940
4984
  "postcss",
4941
- "ava"
4985
+ "ava",
4986
+ "config",
4987
+ "pnpm",
4988
+ "resolutions",
4989
+ "overrides"
4942
4990
  ];
4943
4991
  const collectPackageJsonConfigReferences = (packageJsonPath, declaredNames) => {
4944
4992
  const referenced = /* @__PURE__ */ new Set();
@@ -5007,6 +5055,41 @@ const extractExtendsPackageName = (extendsValue) => {
5007
5055
  }
5008
5056
  return extendsValue.split("/")[0];
5009
5057
  };
5058
+ const SOURCE_FILE_GLOBS = ["**/*.{ts,tsx,js,jsx,mts,mjs,cts,cjs}"];
5059
+ const SOURCE_FILE_IGNORES = [
5060
+ "**/node_modules/**",
5061
+ "**/dist/**",
5062
+ "**/build/**",
5063
+ "**/out/**",
5064
+ "**/.git/**",
5065
+ "**/coverage/**",
5066
+ "**/*.min.js",
5067
+ "**/*.d.ts"
5068
+ ];
5069
+ const scanSourceFilesForPackageImports = (rootDir, candidatePackages) => {
5070
+ const found = /* @__PURE__ */ new Set();
5071
+ if (candidatePackages.size === 0) return found;
5072
+ const sourceFiles = fg.sync(SOURCE_FILE_GLOBS, {
5073
+ cwd: rootDir,
5074
+ absolute: true,
5075
+ onlyFiles: true,
5076
+ ignore: SOURCE_FILE_IGNORES,
5077
+ deep: 15
5078
+ });
5079
+ for (const filePath of sourceFiles) {
5080
+ if (candidatePackages.size === 0) break;
5081
+ try {
5082
+ const content = readFileSync(filePath, "utf-8");
5083
+ for (const packageName of candidatePackages) if (content.includes(`'${packageName}'`) || content.includes(`"${packageName}"`) || content.includes(`'${packageName}/`) || content.includes(`"${packageName}/`)) {
5084
+ found.add(packageName);
5085
+ candidatePackages.delete(packageName);
5086
+ }
5087
+ } catch {
5088
+ continue;
5089
+ }
5090
+ }
5091
+ return found;
5092
+ };
5010
5093
  const ALWAYS_USED_PREFIXES = [
5011
5094
  "@types/",
5012
5095
  "eslint-config-",
@@ -5042,6 +5125,7 @@ const ALWAYS_USED_PREFIXES = [
5042
5125
  "postcss-",
5043
5126
  "@tailwindcss/",
5044
5127
  "rollup-plugin-",
5128
+ "@rollup/",
5045
5129
  "vite-plugin-",
5046
5130
  "@vitejs/",
5047
5131
  "webpack-",
@@ -5050,15 +5134,20 @@ const ALWAYS_USED_PREFIXES = [
5050
5134
  "@lingui/",
5051
5135
  "@emotion/",
5052
5136
  "tslint-config-",
5137
+ "eslint-import-resolver-",
5053
5138
  "@changesets/",
5139
+ "@react-navigation/",
5054
5140
  "@vercel/",
5055
5141
  "@expo/",
5056
5142
  "expo-",
5057
5143
  "react-native-"
5058
5144
  ];
5145
+ const ALWAYS_USED_SUFFIXES = ["-loader"];
5059
5146
  const isAlwaysConsideredUsed = (dependencyName) => {
5060
5147
  if (IMPLICIT_DEPENDENCIES.has(dependencyName)) return true;
5061
- return ALWAYS_USED_PREFIXES.some((prefix) => dependencyName.startsWith(prefix));
5148
+ if (ALWAYS_USED_PREFIXES.some((prefix) => dependencyName.startsWith(prefix))) return true;
5149
+ if (ALWAYS_USED_SUFFIXES.some((suffix) => dependencyName.endsWith(suffix))) return true;
5150
+ return false;
5062
5151
  };
5063
5152
 
5064
5153
  //#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.7",
4
4
  "description": "Deslop JavaScript code",
5
5
  "keywords": [
6
6
  "dead-code",