deslop-js 0.0.2 → 0.0.5
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 +477 -11
- package/dist/index.mjs +477 -11
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -165,7 +165,35 @@ const IMPLICIT_DEPENDENCIES = new Set([
|
|
|
165
165
|
"prettier",
|
|
166
166
|
"husky",
|
|
167
167
|
"lint-staged",
|
|
168
|
-
"tslib"
|
|
168
|
+
"tslib",
|
|
169
|
+
"@babel/core",
|
|
170
|
+
"@babel/runtime",
|
|
171
|
+
"babel-core",
|
|
172
|
+
"babel-jest",
|
|
173
|
+
"babel-loader",
|
|
174
|
+
"postcss",
|
|
175
|
+
"cross-env",
|
|
176
|
+
"sass",
|
|
177
|
+
"node-sass",
|
|
178
|
+
"less",
|
|
179
|
+
"oxlint",
|
|
180
|
+
"biome",
|
|
181
|
+
"@biomejs/biome",
|
|
182
|
+
"patch-package",
|
|
183
|
+
"simple-git-hooks",
|
|
184
|
+
"lefthook",
|
|
185
|
+
"ts-node",
|
|
186
|
+
"ts-jest",
|
|
187
|
+
"tsx",
|
|
188
|
+
"jsdom",
|
|
189
|
+
"rimraf",
|
|
190
|
+
"concurrently",
|
|
191
|
+
"npm-run-all",
|
|
192
|
+
"npm-run-all2",
|
|
193
|
+
"dotenv-cli",
|
|
194
|
+
"webpack",
|
|
195
|
+
"rollup",
|
|
196
|
+
"terser"
|
|
169
197
|
]);
|
|
170
198
|
const BUILTIN_MODULES = new Set([
|
|
171
199
|
"assert",
|
|
@@ -1877,7 +1905,9 @@ const extractPackageJsonEntries = async (packageJsonPath) => {
|
|
|
1877
1905
|
"module",
|
|
1878
1906
|
"browser",
|
|
1879
1907
|
"types",
|
|
1880
|
-
"typings"
|
|
1908
|
+
"typings",
|
|
1909
|
+
"style",
|
|
1910
|
+
"source"
|
|
1881
1911
|
]) if (typeof packageJson[field] === "string") entries.push(resolveEntryPath(packageJson[field], rootDir));
|
|
1882
1912
|
if (packageJson.exports) {
|
|
1883
1913
|
const exportEntries = [];
|
|
@@ -2677,7 +2707,9 @@ const TEST_FRAMEWORK_PATTERNS = [
|
|
|
2677
2707
|
enablers: [
|
|
2678
2708
|
"jest",
|
|
2679
2709
|
"@jest/core",
|
|
2680
|
-
"ts-jest"
|
|
2710
|
+
"ts-jest",
|
|
2711
|
+
"react-scripts",
|
|
2712
|
+
"react-app-rewired"
|
|
2681
2713
|
],
|
|
2682
2714
|
configFileActivators: [
|
|
2683
2715
|
"jest.config.ts",
|
|
@@ -2922,6 +2954,51 @@ const FRAMEWORK_PATTERNS = [
|
|
|
2922
2954
|
],
|
|
2923
2955
|
contentIgnorePatterns: ["versioned_sidebars/**"]
|
|
2924
2956
|
},
|
|
2957
|
+
{
|
|
2958
|
+
enablers: [
|
|
2959
|
+
"fumadocs-core",
|
|
2960
|
+
"fumadocs-ui",
|
|
2961
|
+
"fumadocs-mdx"
|
|
2962
|
+
],
|
|
2963
|
+
enablerPrefixes: ["fumadocs-"],
|
|
2964
|
+
entryPatterns: ["content/**/*.{md,mdx}", "content/**/*.{ts,tsx,js,jsx}"],
|
|
2965
|
+
alwaysUsed: ["source.config.{ts,js,mjs}"]
|
|
2966
|
+
},
|
|
2967
|
+
{
|
|
2968
|
+
enablers: [
|
|
2969
|
+
"nextra",
|
|
2970
|
+
"nextra-theme-docs",
|
|
2971
|
+
"nextra-theme-blog"
|
|
2972
|
+
],
|
|
2973
|
+
enablerPrefixes: ["nextra-"],
|
|
2974
|
+
entryPatterns: [
|
|
2975
|
+
"pages/**/*.{md,mdx}",
|
|
2976
|
+
"src/pages/**/*.{md,mdx}",
|
|
2977
|
+
"content/**/*.{md,mdx}"
|
|
2978
|
+
],
|
|
2979
|
+
alwaysUsed: []
|
|
2980
|
+
},
|
|
2981
|
+
{
|
|
2982
|
+
enablers: [
|
|
2983
|
+
"contentlayer",
|
|
2984
|
+
"contentlayer2",
|
|
2985
|
+
"contentlayer-source-files"
|
|
2986
|
+
],
|
|
2987
|
+
enablerPrefixes: ["contentlayer"],
|
|
2988
|
+
entryPatterns: ["content/**/*.{md,mdx}", "posts/**/*.{md,mdx}"],
|
|
2989
|
+
alwaysUsed: ["contentlayer.config.{ts,js,mjs}"]
|
|
2990
|
+
},
|
|
2991
|
+
{
|
|
2992
|
+
enablers: ["@graphql-codegen/cli", "@graphql-codegen/core"],
|
|
2993
|
+
enablerPrefixes: ["@graphql-codegen/"],
|
|
2994
|
+
entryPatterns: ["**/*.graphql", "**/*.gql"],
|
|
2995
|
+
alwaysUsed: [
|
|
2996
|
+
"codegen.{ts,js,yml,yaml}",
|
|
2997
|
+
"codegen.config.{ts,js}",
|
|
2998
|
+
".graphqlrc.{ts,js,json,yml,yaml}",
|
|
2999
|
+
"graphql.config.{ts,js,json,yml,yaml}"
|
|
3000
|
+
]
|
|
3001
|
+
},
|
|
2925
3002
|
{
|
|
2926
3003
|
enablers: ["eslint", "@eslint/js"],
|
|
2927
3004
|
enablerPrefixes: [],
|
|
@@ -4418,8 +4495,15 @@ const buildSourceTargetMap = (graph) => {
|
|
|
4418
4495
|
|
|
4419
4496
|
//#endregion
|
|
4420
4497
|
//#region src/report/files.ts
|
|
4421
|
-
const
|
|
4422
|
-
|
|
4498
|
+
const EXCLUDED_EXTENSIONS = new Set([
|
|
4499
|
+
".html",
|
|
4500
|
+
".mdx",
|
|
4501
|
+
".md"
|
|
4502
|
+
]);
|
|
4503
|
+
const hasExcludedExtension = (filePath) => {
|
|
4504
|
+
const lastDot = filePath.lastIndexOf(".");
|
|
4505
|
+
if (lastDot === -1) return false;
|
|
4506
|
+
return EXCLUDED_EXTENSIONS.has(filePath.slice(lastDot));
|
|
4423
4507
|
};
|
|
4424
4508
|
const detectOrphanFiles = (graph) => {
|
|
4425
4509
|
const unusedFiles = [];
|
|
@@ -4428,7 +4512,7 @@ const detectOrphanFiles = (graph) => {
|
|
|
4428
4512
|
if (module.isEntryPoint) continue;
|
|
4429
4513
|
if (module.isDeclarationFile) continue;
|
|
4430
4514
|
if (module.isConfigFile) continue;
|
|
4431
|
-
if (
|
|
4515
|
+
if (hasExcludedExtension(module.fileId.path)) continue;
|
|
4432
4516
|
if (isBarrelWithReachableSources(module, graph)) continue;
|
|
4433
4517
|
if (hasReachableDirectImporter(module.fileId.index, graph)) continue;
|
|
4434
4518
|
unusedFiles.push({ path: module.fileId.path });
|
|
@@ -4480,6 +4564,16 @@ const detectDeadExports = (graph, config) => {
|
|
|
4480
4564
|
const buildUsageMap = (graph) => {
|
|
4481
4565
|
const usedExportKeys = /* @__PURE__ */ new Set();
|
|
4482
4566
|
const sourceToTargetMap = buildSourceToTargetsMap(graph);
|
|
4567
|
+
for (const module of graph.modules) {
|
|
4568
|
+
if (!module.isEntryPoint) continue;
|
|
4569
|
+
for (const edge of graph.edges) {
|
|
4570
|
+
if (edge.source !== module.fileId.index || !edge.isReExportEdge) continue;
|
|
4571
|
+
const targetModule = graph.modules[edge.target];
|
|
4572
|
+
if (!targetModule) continue;
|
|
4573
|
+
if (edge.reExportedNames.includes("*")) markAllExportsUsedRecursive(targetModule, graph, sourceToTargetMap, usedExportKeys, /* @__PURE__ */ new Set());
|
|
4574
|
+
else for (const mapping of edge.reExportMappings) markExportUsedRecursive(targetModule.fileId.path, mapping.originalName, graph, sourceToTargetMap, usedExportKeys, /* @__PURE__ */ new Set());
|
|
4575
|
+
}
|
|
4576
|
+
}
|
|
4483
4577
|
for (const edge of graph.edges) {
|
|
4484
4578
|
const targetModule = graph.modules[edge.target];
|
|
4485
4579
|
if (!targetModule) continue;
|
|
@@ -4583,6 +4677,55 @@ const extractPackageName = (specifier) => {
|
|
|
4583
4677
|
|
|
4584
4678
|
//#endregion
|
|
4585
4679
|
//#region src/report/packages.ts
|
|
4680
|
+
const MONOREPO_ROOT_MARKERS = [
|
|
4681
|
+
"pnpm-workspace.yaml",
|
|
4682
|
+
"pnpm-workspace.yml",
|
|
4683
|
+
"lerna.json",
|
|
4684
|
+
"nx.json",
|
|
4685
|
+
"turbo.json",
|
|
4686
|
+
"rush.json"
|
|
4687
|
+
];
|
|
4688
|
+
const LOCKFILE_MARKERS = [
|
|
4689
|
+
"pnpm-lock.yaml",
|
|
4690
|
+
"yarn.lock",
|
|
4691
|
+
"package-lock.json",
|
|
4692
|
+
"bun.lockb",
|
|
4693
|
+
"bun.lock"
|
|
4694
|
+
];
|
|
4695
|
+
const findMonorepoRoot = (rootDir) => {
|
|
4696
|
+
let currentDirectory = (0, node_path.resolve)(rootDir);
|
|
4697
|
+
while (true) {
|
|
4698
|
+
const parentDirectory = (0, node_path.dirname)(currentDirectory);
|
|
4699
|
+
if (parentDirectory === currentDirectory) break;
|
|
4700
|
+
currentDirectory = parentDirectory;
|
|
4701
|
+
for (const marker of MONOREPO_ROOT_MARKERS) if ((0, node_fs.existsSync)((0, node_path.join)(currentDirectory, marker))) return currentDirectory;
|
|
4702
|
+
const packageJsonPath = (0, node_path.join)(currentDirectory, "package.json");
|
|
4703
|
+
if ((0, node_fs.existsSync)(packageJsonPath)) try {
|
|
4704
|
+
const content = (0, node_fs.readFileSync)(packageJsonPath, "utf-8");
|
|
4705
|
+
if (JSON.parse(content).workspaces) return currentDirectory;
|
|
4706
|
+
} catch {
|
|
4707
|
+
continue;
|
|
4708
|
+
}
|
|
4709
|
+
for (const lockfile of LOCKFILE_MARKERS) if ((0, node_fs.existsSync)((0, node_path.join)(currentDirectory, lockfile))) return currentDirectory;
|
|
4710
|
+
}
|
|
4711
|
+
};
|
|
4712
|
+
const discoverAllPackageJsonPaths = (rootDir) => {
|
|
4713
|
+
const paths = [(0, node_path.join)(rootDir, "package.json")];
|
|
4714
|
+
const workspacePackageJsons = fast_glob.default.sync("**/package.json", {
|
|
4715
|
+
cwd: rootDir,
|
|
4716
|
+
absolute: true,
|
|
4717
|
+
onlyFiles: true,
|
|
4718
|
+
ignore: [
|
|
4719
|
+
"**/node_modules/**",
|
|
4720
|
+
"**/dist/**",
|
|
4721
|
+
"**/build/**",
|
|
4722
|
+
"**/.git/**"
|
|
4723
|
+
],
|
|
4724
|
+
deep: 5
|
|
4725
|
+
});
|
|
4726
|
+
for (const workspacePath of workspacePackageJsons) if (workspacePath !== paths[0] && !paths.includes(workspacePath)) paths.push(workspacePath);
|
|
4727
|
+
return paths;
|
|
4728
|
+
};
|
|
4586
4729
|
const detectStalePackages = (graph, config) => {
|
|
4587
4730
|
const packageJsonPath = (0, node_path.resolve)(config.rootDir, "package.json");
|
|
4588
4731
|
let packageJson;
|
|
@@ -4597,7 +4740,37 @@ const detectStalePackages = (graph, config) => {
|
|
|
4597
4740
|
const declaredDependencies = /* @__PURE__ */ new Map();
|
|
4598
4741
|
for (const dependencyName of Object.keys(dependencies)) declaredDependencies.set(dependencyName, false);
|
|
4599
4742
|
for (const dependencyName of Object.keys(devDependencies)) declaredDependencies.set(dependencyName, true);
|
|
4743
|
+
const declaredNames = new Set(declaredDependencies.keys());
|
|
4600
4744
|
const usedPackageNames = collectUsedPackages(graph);
|
|
4745
|
+
const monorepoRoot = findMonorepoRoot(config.rootDir);
|
|
4746
|
+
const nodeModulesRoot = monorepoRoot ?? config.rootDir;
|
|
4747
|
+
const allPackageJsonPaths = discoverAllPackageJsonPaths(config.rootDir);
|
|
4748
|
+
if (monorepoRoot) {
|
|
4749
|
+
const monorepoPackageJson = (0, node_path.join)(monorepoRoot, "package.json");
|
|
4750
|
+
if (!allPackageJsonPaths.includes(monorepoPackageJson) && (0, node_fs.existsSync)(monorepoPackageJson)) allPackageJsonPaths.push(monorepoPackageJson);
|
|
4751
|
+
}
|
|
4752
|
+
const binToPackage = buildBinToPackageMap(nodeModulesRoot, declaredNames);
|
|
4753
|
+
for (const workspacePackageJsonPath of allPackageJsonPaths) {
|
|
4754
|
+
const scriptReferenced = collectScriptReferencedPackages(workspacePackageJsonPath, declaredNames, binToPackage);
|
|
4755
|
+
for (const packageName of scriptReferenced) usedPackageNames.add(packageName);
|
|
4756
|
+
const packageJsonConfigReferenced = collectPackageJsonConfigReferences(workspacePackageJsonPath, declaredNames);
|
|
4757
|
+
for (const packageName of packageJsonConfigReferenced) usedPackageNames.add(packageName);
|
|
4758
|
+
}
|
|
4759
|
+
const configSearchRoots = monorepoRoot && monorepoRoot !== config.rootDir ? [config.rootDir, monorepoRoot] : [config.rootDir];
|
|
4760
|
+
for (const configSearchRoot of configSearchRoots) {
|
|
4761
|
+
const configReferenced = collectConfigReferencedPackages(configSearchRoot, graph, declaredNames);
|
|
4762
|
+
for (const packageName of configReferenced) usedPackageNames.add(packageName);
|
|
4763
|
+
const tsconfigReferenced = collectTsconfigReferencedPackages(configSearchRoot);
|
|
4764
|
+
for (const packageName of tsconfigReferenced) usedPackageNames.add(packageName);
|
|
4765
|
+
}
|
|
4766
|
+
if (hasJsxFiles(graph)) {
|
|
4767
|
+
if (declaredNames.has("react")) usedPackageNames.add("react");
|
|
4768
|
+
if (declaredNames.has("react-dom")) usedPackageNames.add("react-dom");
|
|
4769
|
+
if (declaredNames.has("react-native")) usedPackageNames.add("react-native");
|
|
4770
|
+
if (declaredNames.has("react-native-web")) usedPackageNames.add("react-native-web");
|
|
4771
|
+
}
|
|
4772
|
+
const peerSatisfied = collectPeerSatisfiedPackages(nodeModulesRoot, declaredNames, usedPackageNames);
|
|
4773
|
+
for (const packageName of peerSatisfied) usedPackageNames.add(packageName);
|
|
4601
4774
|
const unusedDependencies = [];
|
|
4602
4775
|
for (const [dependencyName, isDevDependency] of declaredDependencies) {
|
|
4603
4776
|
if (isAlwaysConsideredUsed(dependencyName)) continue;
|
|
@@ -4616,13 +4789,306 @@ const collectUsedPackages = (graph) => {
|
|
|
4616
4789
|
}
|
|
4617
4790
|
return usedPackages;
|
|
4618
4791
|
};
|
|
4792
|
+
const hasJsxFiles = (graph) => graph.modules.some((module) => {
|
|
4793
|
+
const filePath = module.fileId.path;
|
|
4794
|
+
return filePath.endsWith(".tsx") || filePath.endsWith(".jsx");
|
|
4795
|
+
});
|
|
4796
|
+
const collectPeerSatisfiedPackages = (rootDir, declaredNames, confirmedUsedNames) => {
|
|
4797
|
+
const peerSatisfied = /* @__PURE__ */ new Set();
|
|
4798
|
+
const nodeModulesDir = (0, node_path.join)(rootDir, "node_modules");
|
|
4799
|
+
for (const installedName of declaredNames) {
|
|
4800
|
+
if (!confirmedUsedNames.has(installedName)) continue;
|
|
4801
|
+
const packageJsonPath = installedName.startsWith("@") ? (0, node_path.join)(nodeModulesDir, ...installedName.split("/"), "package.json") : (0, node_path.join)(nodeModulesDir, installedName, "package.json");
|
|
4802
|
+
try {
|
|
4803
|
+
const content = (0, node_fs.readFileSync)(packageJsonPath, "utf-8");
|
|
4804
|
+
const peerDeps = JSON.parse(content).peerDependencies;
|
|
4805
|
+
if (peerDeps && typeof peerDeps === "object") {
|
|
4806
|
+
for (const peerName of Object.keys(peerDeps)) if (declaredNames.has(peerName)) peerSatisfied.add(peerName);
|
|
4807
|
+
}
|
|
4808
|
+
} catch {
|
|
4809
|
+
continue;
|
|
4810
|
+
}
|
|
4811
|
+
}
|
|
4812
|
+
return peerSatisfied;
|
|
4813
|
+
};
|
|
4814
|
+
const SHELL_SPLIT_PATTERN = /\s*(?:&&|\|\||[;&|])\s*/;
|
|
4815
|
+
const CLI_BINARY_TO_PACKAGE = {
|
|
4816
|
+
"react-scripts": "react-scripts",
|
|
4817
|
+
"webpack-cli": "webpack-cli",
|
|
4818
|
+
"webpack-dev-server": "webpack-dev-server",
|
|
4819
|
+
vitest: "vitest",
|
|
4820
|
+
jest: "jest",
|
|
4821
|
+
prisma: "prisma",
|
|
4822
|
+
sequelize: "sequelize-cli",
|
|
4823
|
+
rimraf: "rimraf",
|
|
4824
|
+
concurrently: "concurrently",
|
|
4825
|
+
parcel: "parcel",
|
|
4826
|
+
rescript: "rescript",
|
|
4827
|
+
webstudio: "webstudio",
|
|
4828
|
+
cap: "@capacitor/cli",
|
|
4829
|
+
"source-map-explorer": "source-map-explorer",
|
|
4830
|
+
"ts-standard": "ts-standard",
|
|
4831
|
+
"rndebugger-open": "react-native-debugger-open",
|
|
4832
|
+
"simple-git-hooks": "simple-git-hooks",
|
|
4833
|
+
"generate-arg-types": "@webstudio-is/generate-arg-types",
|
|
4834
|
+
email: "@react-email/preview-server"
|
|
4835
|
+
};
|
|
4836
|
+
const ENV_WRAPPER_BINARY_SET = new Set([
|
|
4837
|
+
"cross-env",
|
|
4838
|
+
"dotenv",
|
|
4839
|
+
"dotenv-flow",
|
|
4840
|
+
"env-cmd"
|
|
4841
|
+
]);
|
|
4842
|
+
const INLINE_ENV_VAR_PATTERN = /^[A-Z_][A-Z0-9_]*=/;
|
|
4843
|
+
const buildBinToPackageMap = (rootDir, declaredNames) => {
|
|
4844
|
+
const binToPackage = /* @__PURE__ */ new Map();
|
|
4845
|
+
for (const [binary, packageName] of Object.entries(CLI_BINARY_TO_PACKAGE)) binToPackage.set(binary, packageName);
|
|
4846
|
+
for (const packageName of declaredNames) {
|
|
4847
|
+
const packageBinJsonPath = packageName.startsWith("@") ? (0, node_path.join)(rootDir, "node_modules", ...packageName.split("/"), "package.json") : (0, node_path.join)(rootDir, "node_modules", packageName, "package.json");
|
|
4848
|
+
try {
|
|
4849
|
+
const binContent = (0, node_fs.readFileSync)(packageBinJsonPath, "utf-8");
|
|
4850
|
+
const binPackageJson = JSON.parse(binContent);
|
|
4851
|
+
if (typeof binPackageJson.bin === "string") binToPackage.set(packageName.split("/").pop(), packageName);
|
|
4852
|
+
else if (typeof binPackageJson.bin === "object" && binPackageJson.bin !== null) for (const binaryName of Object.keys(binPackageJson.bin)) binToPackage.set(binaryName, packageName);
|
|
4853
|
+
} catch {
|
|
4854
|
+
continue;
|
|
4855
|
+
}
|
|
4856
|
+
}
|
|
4857
|
+
return binToPackage;
|
|
4858
|
+
};
|
|
4859
|
+
const collectScriptReferencedPackages = (packageJsonPath, declaredNames, binToPackage) => {
|
|
4860
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
4861
|
+
try {
|
|
4862
|
+
const content = (0, node_fs.readFileSync)(packageJsonPath, "utf-8");
|
|
4863
|
+
const scripts = JSON.parse(content).scripts;
|
|
4864
|
+
if (!scripts || typeof scripts !== "object") return referenced;
|
|
4865
|
+
for (const scriptCommand of Object.values(scripts)) {
|
|
4866
|
+
if (typeof scriptCommand !== "string") continue;
|
|
4867
|
+
const segments = scriptCommand.split(SHELL_SPLIT_PATTERN);
|
|
4868
|
+
for (const segment of segments) {
|
|
4869
|
+
const tokens = segment.trim().split(/\s+/);
|
|
4870
|
+
if (tokens.length === 0) continue;
|
|
4871
|
+
let binaryIndex = 0;
|
|
4872
|
+
const firstToken = tokens[0].replace(/^.*\//, "");
|
|
4873
|
+
if (ENV_WRAPPER_BINARY_SET.has(firstToken)) {
|
|
4874
|
+
const envPackage = binToPackage.get(firstToken);
|
|
4875
|
+
if (envPackage && declaredNames.has(envPackage)) referenced.add(envPackage);
|
|
4876
|
+
binaryIndex = 1;
|
|
4877
|
+
while (binaryIndex < tokens.length && INLINE_ENV_VAR_PATTERN.test(tokens[binaryIndex])) binaryIndex++;
|
|
4878
|
+
if (binaryIndex >= tokens.length) continue;
|
|
4879
|
+
}
|
|
4880
|
+
while (binaryIndex < tokens.length && INLINE_ENV_VAR_PATTERN.test(tokens[binaryIndex])) binaryIndex++;
|
|
4881
|
+
if (binaryIndex >= tokens.length) continue;
|
|
4882
|
+
const binaryToken = tokens[binaryIndex].replace(/^.*\//, "");
|
|
4883
|
+
const effectiveBinary = binaryToken === "npx" || binaryToken === "pnpx" || binaryToken === "bunx" ? tokens[binaryIndex + 1]?.replace(/^.*\//, "") ?? "" : binaryToken;
|
|
4884
|
+
for (const candidateBinary of [binaryToken, effectiveBinary]) {
|
|
4885
|
+
if (!candidateBinary) continue;
|
|
4886
|
+
const mappedPackage = binToPackage.get(candidateBinary);
|
|
4887
|
+
if (mappedPackage && declaredNames.has(mappedPackage)) referenced.add(mappedPackage);
|
|
4888
|
+
if (declaredNames.has(candidateBinary)) referenced.add(candidateBinary);
|
|
4889
|
+
}
|
|
4890
|
+
}
|
|
4891
|
+
}
|
|
4892
|
+
} catch {
|
|
4893
|
+
return referenced;
|
|
4894
|
+
}
|
|
4895
|
+
return referenced;
|
|
4896
|
+
};
|
|
4897
|
+
const CONFIG_FILE_GLOBS = [
|
|
4898
|
+
"postcss.config.{js,cjs,mjs,ts}",
|
|
4899
|
+
".babelrc",
|
|
4900
|
+
".babelrc.{js,cjs,mjs,json}",
|
|
4901
|
+
"babel.config.{js,cjs,mjs,json,ts}",
|
|
4902
|
+
".eslintrc",
|
|
4903
|
+
".eslintrc.{js,cjs,mjs,json,yaml,yml}",
|
|
4904
|
+
"eslint.config.{js,cjs,mjs,ts,mts,cts}",
|
|
4905
|
+
"webpack.config.{js,ts,mjs,cjs}",
|
|
4906
|
+
"**/webpack*.config.{js,ts,mjs,cjs}",
|
|
4907
|
+
"**/webpack*.config*.{js,ts,mjs,cjs}",
|
|
4908
|
+
"**/webpack*.babel.{js,ts}",
|
|
4909
|
+
"vite.config.{js,ts,mjs,mts}",
|
|
4910
|
+
"rollup.config.{js,ts,mjs,cjs}",
|
|
4911
|
+
".storybook/main.{js,ts,mjs,cjs}",
|
|
4912
|
+
".storybook/preview.{js,ts,mjs,cjs,tsx,jsx}",
|
|
4913
|
+
"docusaurus.config.{js,ts,mjs}",
|
|
4914
|
+
"next.config.{js,ts,mjs,mts}",
|
|
4915
|
+
"tailwind.config.{js,ts,cjs,mjs}",
|
|
4916
|
+
"jest.config.{js,ts,mjs,cjs}",
|
|
4917
|
+
"vitest.config.{js,ts,mjs,mts}",
|
|
4918
|
+
"app.json",
|
|
4919
|
+
"forge.config.{js,ts,cjs}",
|
|
4920
|
+
"wrangler.toml",
|
|
4921
|
+
"wrangler.json",
|
|
4922
|
+
"wrangler.jsonc",
|
|
4923
|
+
"metro.config.{js,ts}",
|
|
4924
|
+
"electron.vite.config.{js,ts,mjs}",
|
|
4925
|
+
"api-extractor.json",
|
|
4926
|
+
"codegen.{ts,js,yml,yaml}",
|
|
4927
|
+
".graphqlrc.{ts,js,json,yml,yaml}",
|
|
4928
|
+
"graphql.config.{ts,js,json,yml,yaml}",
|
|
4929
|
+
".lintstagedrc.{js,cjs,mjs,json}",
|
|
4930
|
+
"commitlint.config.{js,cjs,mjs,ts}",
|
|
4931
|
+
".commitlintrc.{js,cjs,mjs,json,yaml,yml}",
|
|
4932
|
+
"tslint.json"
|
|
4933
|
+
];
|
|
4934
|
+
const collectConfigReferencedPackages = (rootDir, graph, declaredNames) => {
|
|
4935
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
4936
|
+
for (const module of graph.modules) {
|
|
4937
|
+
if (!module.isConfigFile) continue;
|
|
4938
|
+
try {
|
|
4939
|
+
const content = (0, node_fs.readFileSync)(module.fileId.path, "utf-8");
|
|
4940
|
+
for (const packageName of declaredNames) if (content.includes(packageName)) referenced.add(packageName);
|
|
4941
|
+
} catch {
|
|
4942
|
+
continue;
|
|
4943
|
+
}
|
|
4944
|
+
}
|
|
4945
|
+
const configFiles = fast_glob.default.sync(CONFIG_FILE_GLOBS, {
|
|
4946
|
+
cwd: rootDir,
|
|
4947
|
+
absolute: true,
|
|
4948
|
+
onlyFiles: true,
|
|
4949
|
+
ignore: ["**/node_modules/**"],
|
|
4950
|
+
dot: true,
|
|
4951
|
+
deep: 3
|
|
4952
|
+
});
|
|
4953
|
+
for (const configPath of configFiles) try {
|
|
4954
|
+
const content = (0, node_fs.readFileSync)(configPath, "utf-8");
|
|
4955
|
+
for (const packageName of declaredNames) if (content.includes(packageName)) referenced.add(packageName);
|
|
4956
|
+
} catch {
|
|
4957
|
+
continue;
|
|
4958
|
+
}
|
|
4959
|
+
return referenced;
|
|
4960
|
+
};
|
|
4961
|
+
const PACKAGE_JSON_CONFIG_SECTIONS = [
|
|
4962
|
+
"jest",
|
|
4963
|
+
"babel",
|
|
4964
|
+
"eslintConfig",
|
|
4965
|
+
"prettier",
|
|
4966
|
+
"stylelint",
|
|
4967
|
+
"lint-staged",
|
|
4968
|
+
"commitlint",
|
|
4969
|
+
"browserslist",
|
|
4970
|
+
"postcss",
|
|
4971
|
+
"ava"
|
|
4972
|
+
];
|
|
4973
|
+
const collectPackageJsonConfigReferences = (packageJsonPath, declaredNames) => {
|
|
4974
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
4975
|
+
try {
|
|
4976
|
+
const content = (0, node_fs.readFileSync)(packageJsonPath, "utf-8");
|
|
4977
|
+
const packageJson = JSON.parse(content);
|
|
4978
|
+
for (const sectionName of PACKAGE_JSON_CONFIG_SECTIONS) {
|
|
4979
|
+
const sectionValue = packageJson[sectionName];
|
|
4980
|
+
if (!sectionValue || typeof sectionValue !== "object") continue;
|
|
4981
|
+
const sectionText = JSON.stringify(sectionValue);
|
|
4982
|
+
for (const packageName of declaredNames) if (sectionText.includes(packageName)) referenced.add(packageName);
|
|
4983
|
+
}
|
|
4984
|
+
} catch {
|
|
4985
|
+
return referenced;
|
|
4986
|
+
}
|
|
4987
|
+
return referenced;
|
|
4988
|
+
};
|
|
4989
|
+
const TSCONFIG_GLOBS = [
|
|
4990
|
+
"tsconfig.json",
|
|
4991
|
+
"tsconfig.*.json",
|
|
4992
|
+
"jsconfig.json",
|
|
4993
|
+
"**/tsconfig.json",
|
|
4994
|
+
"**/tsconfig.*.json"
|
|
4995
|
+
];
|
|
4996
|
+
const collectTsconfigReferencedPackages = (rootDir) => {
|
|
4997
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
4998
|
+
const tsconfigFiles = fast_glob.default.sync(TSCONFIG_GLOBS, {
|
|
4999
|
+
cwd: rootDir,
|
|
5000
|
+
absolute: true,
|
|
5001
|
+
onlyFiles: true,
|
|
5002
|
+
ignore: ["**/node_modules/**"],
|
|
5003
|
+
dot: false,
|
|
5004
|
+
deep: 4
|
|
5005
|
+
});
|
|
5006
|
+
for (const tsconfigPath of tsconfigFiles) try {
|
|
5007
|
+
const cleaned = (0, node_fs.readFileSync)(tsconfigPath, "utf-8").replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
5008
|
+
const parsed = JSON.parse(cleaned);
|
|
5009
|
+
if (typeof parsed.extends === "string") {
|
|
5010
|
+
const extendsPackage = extractExtendsPackageName(parsed.extends);
|
|
5011
|
+
if (extendsPackage) referenced.add(extendsPackage);
|
|
5012
|
+
}
|
|
5013
|
+
if (Array.isArray(parsed.extends)) {
|
|
5014
|
+
for (const extendsEntry of parsed.extends) if (typeof extendsEntry === "string") {
|
|
5015
|
+
const extendsPackage = extractExtendsPackageName(extendsEntry);
|
|
5016
|
+
if (extendsPackage) referenced.add(extendsPackage);
|
|
5017
|
+
}
|
|
5018
|
+
}
|
|
5019
|
+
const compilerOptions = parsed.compilerOptions;
|
|
5020
|
+
if (compilerOptions?.jsxImportSource && typeof compilerOptions.jsxImportSource === "string") referenced.add(compilerOptions.jsxImportSource);
|
|
5021
|
+
if (Array.isArray(compilerOptions?.types)) {
|
|
5022
|
+
for (const typesEntry of compilerOptions.types) if (typeof typesEntry === "string") {
|
|
5023
|
+
const typesPackage = extractPackageName(typesEntry);
|
|
5024
|
+
if (typesPackage) referenced.add(typesPackage);
|
|
5025
|
+
}
|
|
5026
|
+
}
|
|
5027
|
+
} catch {
|
|
5028
|
+
continue;
|
|
5029
|
+
}
|
|
5030
|
+
return referenced;
|
|
5031
|
+
};
|
|
5032
|
+
const extractExtendsPackageName = (extendsValue) => {
|
|
5033
|
+
if (extendsValue.startsWith(".") || extendsValue.startsWith("/")) return void 0;
|
|
5034
|
+
if (extendsValue.startsWith("@")) {
|
|
5035
|
+
const parts = extendsValue.split("/");
|
|
5036
|
+
return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : void 0;
|
|
5037
|
+
}
|
|
5038
|
+
return extendsValue.split("/")[0];
|
|
5039
|
+
};
|
|
5040
|
+
const ALWAYS_USED_PREFIXES = [
|
|
5041
|
+
"@types/",
|
|
5042
|
+
"eslint-config-",
|
|
5043
|
+
"eslint-plugin-",
|
|
5044
|
+
"@eslint/",
|
|
5045
|
+
"prettier-plugin-",
|
|
5046
|
+
"@commitlint/",
|
|
5047
|
+
"babel-plugin-",
|
|
5048
|
+
"babel-preset-",
|
|
5049
|
+
"@babel/plugin-",
|
|
5050
|
+
"@babel/preset-",
|
|
5051
|
+
"@fontsource/",
|
|
5052
|
+
"@next/",
|
|
5053
|
+
"@svgr/",
|
|
5054
|
+
"@docusaurus/",
|
|
5055
|
+
"stylelint-config-",
|
|
5056
|
+
"stylelint-plugin-",
|
|
5057
|
+
"@testing-library/",
|
|
5058
|
+
"@vitest/",
|
|
5059
|
+
"@playwright/",
|
|
5060
|
+
"@storybook/",
|
|
5061
|
+
"jest-environment-",
|
|
5062
|
+
"@graphql-codegen/",
|
|
5063
|
+
"@size-limit/",
|
|
5064
|
+
"@nestjs/",
|
|
5065
|
+
"@swc/",
|
|
5066
|
+
"@electron-forge/",
|
|
5067
|
+
"@parcel/",
|
|
5068
|
+
"@wyw-in-js/",
|
|
5069
|
+
"@typescript-eslint/",
|
|
5070
|
+
"@react-native/",
|
|
5071
|
+
"@react-native-community/",
|
|
5072
|
+
"postcss-",
|
|
5073
|
+
"@tailwindcss/",
|
|
5074
|
+
"rollup-plugin-",
|
|
5075
|
+
"vite-plugin-",
|
|
5076
|
+
"@vitejs/",
|
|
5077
|
+
"webpack-",
|
|
5078
|
+
"esbuild-",
|
|
5079
|
+
"@esbuild-plugins/",
|
|
5080
|
+
"@lingui/",
|
|
5081
|
+
"@emotion/",
|
|
5082
|
+
"tslint-config-",
|
|
5083
|
+
"@changesets/",
|
|
5084
|
+
"@vercel/",
|
|
5085
|
+
"@expo/",
|
|
5086
|
+
"expo-",
|
|
5087
|
+
"react-native-"
|
|
5088
|
+
];
|
|
4619
5089
|
const isAlwaysConsideredUsed = (dependencyName) => {
|
|
4620
5090
|
if (IMPLICIT_DEPENDENCIES.has(dependencyName)) return true;
|
|
4621
|
-
|
|
4622
|
-
if (dependencyName.startsWith("eslint-config-")) return true;
|
|
4623
|
-
if (dependencyName.startsWith("eslint-plugin-")) return true;
|
|
4624
|
-
if (dependencyName.startsWith("prettier-plugin-")) return true;
|
|
4625
|
-
return false;
|
|
5091
|
+
return ALWAYS_USED_PREFIXES.some((prefix) => dependencyName.startsWith(prefix));
|
|
4626
5092
|
};
|
|
4627
5093
|
|
|
4628
5094
|
//#endregion
|
package/dist/index.mjs
CHANGED
|
@@ -135,7 +135,35 @@ const IMPLICIT_DEPENDENCIES = new Set([
|
|
|
135
135
|
"prettier",
|
|
136
136
|
"husky",
|
|
137
137
|
"lint-staged",
|
|
138
|
-
"tslib"
|
|
138
|
+
"tslib",
|
|
139
|
+
"@babel/core",
|
|
140
|
+
"@babel/runtime",
|
|
141
|
+
"babel-core",
|
|
142
|
+
"babel-jest",
|
|
143
|
+
"babel-loader",
|
|
144
|
+
"postcss",
|
|
145
|
+
"cross-env",
|
|
146
|
+
"sass",
|
|
147
|
+
"node-sass",
|
|
148
|
+
"less",
|
|
149
|
+
"oxlint",
|
|
150
|
+
"biome",
|
|
151
|
+
"@biomejs/biome",
|
|
152
|
+
"patch-package",
|
|
153
|
+
"simple-git-hooks",
|
|
154
|
+
"lefthook",
|
|
155
|
+
"ts-node",
|
|
156
|
+
"ts-jest",
|
|
157
|
+
"tsx",
|
|
158
|
+
"jsdom",
|
|
159
|
+
"rimraf",
|
|
160
|
+
"concurrently",
|
|
161
|
+
"npm-run-all",
|
|
162
|
+
"npm-run-all2",
|
|
163
|
+
"dotenv-cli",
|
|
164
|
+
"webpack",
|
|
165
|
+
"rollup",
|
|
166
|
+
"terser"
|
|
139
167
|
]);
|
|
140
168
|
const BUILTIN_MODULES = new Set([
|
|
141
169
|
"assert",
|
|
@@ -1847,7 +1875,9 @@ const extractPackageJsonEntries = async (packageJsonPath) => {
|
|
|
1847
1875
|
"module",
|
|
1848
1876
|
"browser",
|
|
1849
1877
|
"types",
|
|
1850
|
-
"typings"
|
|
1878
|
+
"typings",
|
|
1879
|
+
"style",
|
|
1880
|
+
"source"
|
|
1851
1881
|
]) if (typeof packageJson[field] === "string") entries.push(resolveEntryPath(packageJson[field], rootDir));
|
|
1852
1882
|
if (packageJson.exports) {
|
|
1853
1883
|
const exportEntries = [];
|
|
@@ -2647,7 +2677,9 @@ const TEST_FRAMEWORK_PATTERNS = [
|
|
|
2647
2677
|
enablers: [
|
|
2648
2678
|
"jest",
|
|
2649
2679
|
"@jest/core",
|
|
2650
|
-
"ts-jest"
|
|
2680
|
+
"ts-jest",
|
|
2681
|
+
"react-scripts",
|
|
2682
|
+
"react-app-rewired"
|
|
2651
2683
|
],
|
|
2652
2684
|
configFileActivators: [
|
|
2653
2685
|
"jest.config.ts",
|
|
@@ -2892,6 +2924,51 @@ const FRAMEWORK_PATTERNS = [
|
|
|
2892
2924
|
],
|
|
2893
2925
|
contentIgnorePatterns: ["versioned_sidebars/**"]
|
|
2894
2926
|
},
|
|
2927
|
+
{
|
|
2928
|
+
enablers: [
|
|
2929
|
+
"fumadocs-core",
|
|
2930
|
+
"fumadocs-ui",
|
|
2931
|
+
"fumadocs-mdx"
|
|
2932
|
+
],
|
|
2933
|
+
enablerPrefixes: ["fumadocs-"],
|
|
2934
|
+
entryPatterns: ["content/**/*.{md,mdx}", "content/**/*.{ts,tsx,js,jsx}"],
|
|
2935
|
+
alwaysUsed: ["source.config.{ts,js,mjs}"]
|
|
2936
|
+
},
|
|
2937
|
+
{
|
|
2938
|
+
enablers: [
|
|
2939
|
+
"nextra",
|
|
2940
|
+
"nextra-theme-docs",
|
|
2941
|
+
"nextra-theme-blog"
|
|
2942
|
+
],
|
|
2943
|
+
enablerPrefixes: ["nextra-"],
|
|
2944
|
+
entryPatterns: [
|
|
2945
|
+
"pages/**/*.{md,mdx}",
|
|
2946
|
+
"src/pages/**/*.{md,mdx}",
|
|
2947
|
+
"content/**/*.{md,mdx}"
|
|
2948
|
+
],
|
|
2949
|
+
alwaysUsed: []
|
|
2950
|
+
},
|
|
2951
|
+
{
|
|
2952
|
+
enablers: [
|
|
2953
|
+
"contentlayer",
|
|
2954
|
+
"contentlayer2",
|
|
2955
|
+
"contentlayer-source-files"
|
|
2956
|
+
],
|
|
2957
|
+
enablerPrefixes: ["contentlayer"],
|
|
2958
|
+
entryPatterns: ["content/**/*.{md,mdx}", "posts/**/*.{md,mdx}"],
|
|
2959
|
+
alwaysUsed: ["contentlayer.config.{ts,js,mjs}"]
|
|
2960
|
+
},
|
|
2961
|
+
{
|
|
2962
|
+
enablers: ["@graphql-codegen/cli", "@graphql-codegen/core"],
|
|
2963
|
+
enablerPrefixes: ["@graphql-codegen/"],
|
|
2964
|
+
entryPatterns: ["**/*.graphql", "**/*.gql"],
|
|
2965
|
+
alwaysUsed: [
|
|
2966
|
+
"codegen.{ts,js,yml,yaml}",
|
|
2967
|
+
"codegen.config.{ts,js}",
|
|
2968
|
+
".graphqlrc.{ts,js,json,yml,yaml}",
|
|
2969
|
+
"graphql.config.{ts,js,json,yml,yaml}"
|
|
2970
|
+
]
|
|
2971
|
+
},
|
|
2895
2972
|
{
|
|
2896
2973
|
enablers: ["eslint", "@eslint/js"],
|
|
2897
2974
|
enablerPrefixes: [],
|
|
@@ -4388,8 +4465,15 @@ const buildSourceTargetMap = (graph) => {
|
|
|
4388
4465
|
|
|
4389
4466
|
//#endregion
|
|
4390
4467
|
//#region src/report/files.ts
|
|
4391
|
-
const
|
|
4392
|
-
|
|
4468
|
+
const EXCLUDED_EXTENSIONS = new Set([
|
|
4469
|
+
".html",
|
|
4470
|
+
".mdx",
|
|
4471
|
+
".md"
|
|
4472
|
+
]);
|
|
4473
|
+
const hasExcludedExtension = (filePath) => {
|
|
4474
|
+
const lastDot = filePath.lastIndexOf(".");
|
|
4475
|
+
if (lastDot === -1) return false;
|
|
4476
|
+
return EXCLUDED_EXTENSIONS.has(filePath.slice(lastDot));
|
|
4393
4477
|
};
|
|
4394
4478
|
const detectOrphanFiles = (graph) => {
|
|
4395
4479
|
const unusedFiles = [];
|
|
@@ -4398,7 +4482,7 @@ const detectOrphanFiles = (graph) => {
|
|
|
4398
4482
|
if (module.isEntryPoint) continue;
|
|
4399
4483
|
if (module.isDeclarationFile) continue;
|
|
4400
4484
|
if (module.isConfigFile) continue;
|
|
4401
|
-
if (
|
|
4485
|
+
if (hasExcludedExtension(module.fileId.path)) continue;
|
|
4402
4486
|
if (isBarrelWithReachableSources(module, graph)) continue;
|
|
4403
4487
|
if (hasReachableDirectImporter(module.fileId.index, graph)) continue;
|
|
4404
4488
|
unusedFiles.push({ path: module.fileId.path });
|
|
@@ -4450,6 +4534,16 @@ const detectDeadExports = (graph, config) => {
|
|
|
4450
4534
|
const buildUsageMap = (graph) => {
|
|
4451
4535
|
const usedExportKeys = /* @__PURE__ */ new Set();
|
|
4452
4536
|
const sourceToTargetMap = buildSourceToTargetsMap(graph);
|
|
4537
|
+
for (const module of graph.modules) {
|
|
4538
|
+
if (!module.isEntryPoint) continue;
|
|
4539
|
+
for (const edge of graph.edges) {
|
|
4540
|
+
if (edge.source !== module.fileId.index || !edge.isReExportEdge) continue;
|
|
4541
|
+
const targetModule = graph.modules[edge.target];
|
|
4542
|
+
if (!targetModule) continue;
|
|
4543
|
+
if (edge.reExportedNames.includes("*")) markAllExportsUsedRecursive(targetModule, graph, sourceToTargetMap, usedExportKeys, /* @__PURE__ */ new Set());
|
|
4544
|
+
else for (const mapping of edge.reExportMappings) markExportUsedRecursive(targetModule.fileId.path, mapping.originalName, graph, sourceToTargetMap, usedExportKeys, /* @__PURE__ */ new Set());
|
|
4545
|
+
}
|
|
4546
|
+
}
|
|
4453
4547
|
for (const edge of graph.edges) {
|
|
4454
4548
|
const targetModule = graph.modules[edge.target];
|
|
4455
4549
|
if (!targetModule) continue;
|
|
@@ -4553,6 +4647,55 @@ const extractPackageName = (specifier) => {
|
|
|
4553
4647
|
|
|
4554
4648
|
//#endregion
|
|
4555
4649
|
//#region src/report/packages.ts
|
|
4650
|
+
const MONOREPO_ROOT_MARKERS = [
|
|
4651
|
+
"pnpm-workspace.yaml",
|
|
4652
|
+
"pnpm-workspace.yml",
|
|
4653
|
+
"lerna.json",
|
|
4654
|
+
"nx.json",
|
|
4655
|
+
"turbo.json",
|
|
4656
|
+
"rush.json"
|
|
4657
|
+
];
|
|
4658
|
+
const LOCKFILE_MARKERS = [
|
|
4659
|
+
"pnpm-lock.yaml",
|
|
4660
|
+
"yarn.lock",
|
|
4661
|
+
"package-lock.json",
|
|
4662
|
+
"bun.lockb",
|
|
4663
|
+
"bun.lock"
|
|
4664
|
+
];
|
|
4665
|
+
const findMonorepoRoot = (rootDir) => {
|
|
4666
|
+
let currentDirectory = resolve(rootDir);
|
|
4667
|
+
while (true) {
|
|
4668
|
+
const parentDirectory = dirname(currentDirectory);
|
|
4669
|
+
if (parentDirectory === currentDirectory) break;
|
|
4670
|
+
currentDirectory = parentDirectory;
|
|
4671
|
+
for (const marker of MONOREPO_ROOT_MARKERS) if (existsSync(join(currentDirectory, marker))) return currentDirectory;
|
|
4672
|
+
const packageJsonPath = join(currentDirectory, "package.json");
|
|
4673
|
+
if (existsSync(packageJsonPath)) try {
|
|
4674
|
+
const content = readFileSync(packageJsonPath, "utf-8");
|
|
4675
|
+
if (JSON.parse(content).workspaces) return currentDirectory;
|
|
4676
|
+
} catch {
|
|
4677
|
+
continue;
|
|
4678
|
+
}
|
|
4679
|
+
for (const lockfile of LOCKFILE_MARKERS) if (existsSync(join(currentDirectory, lockfile))) return currentDirectory;
|
|
4680
|
+
}
|
|
4681
|
+
};
|
|
4682
|
+
const discoverAllPackageJsonPaths = (rootDir) => {
|
|
4683
|
+
const paths = [join(rootDir, "package.json")];
|
|
4684
|
+
const workspacePackageJsons = fg.sync("**/package.json", {
|
|
4685
|
+
cwd: rootDir,
|
|
4686
|
+
absolute: true,
|
|
4687
|
+
onlyFiles: true,
|
|
4688
|
+
ignore: [
|
|
4689
|
+
"**/node_modules/**",
|
|
4690
|
+
"**/dist/**",
|
|
4691
|
+
"**/build/**",
|
|
4692
|
+
"**/.git/**"
|
|
4693
|
+
],
|
|
4694
|
+
deep: 5
|
|
4695
|
+
});
|
|
4696
|
+
for (const workspacePath of workspacePackageJsons) if (workspacePath !== paths[0] && !paths.includes(workspacePath)) paths.push(workspacePath);
|
|
4697
|
+
return paths;
|
|
4698
|
+
};
|
|
4556
4699
|
const detectStalePackages = (graph, config) => {
|
|
4557
4700
|
const packageJsonPath = resolve(config.rootDir, "package.json");
|
|
4558
4701
|
let packageJson;
|
|
@@ -4567,7 +4710,37 @@ const detectStalePackages = (graph, config) => {
|
|
|
4567
4710
|
const declaredDependencies = /* @__PURE__ */ new Map();
|
|
4568
4711
|
for (const dependencyName of Object.keys(dependencies)) declaredDependencies.set(dependencyName, false);
|
|
4569
4712
|
for (const dependencyName of Object.keys(devDependencies)) declaredDependencies.set(dependencyName, true);
|
|
4713
|
+
const declaredNames = new Set(declaredDependencies.keys());
|
|
4570
4714
|
const usedPackageNames = collectUsedPackages(graph);
|
|
4715
|
+
const monorepoRoot = findMonorepoRoot(config.rootDir);
|
|
4716
|
+
const nodeModulesRoot = monorepoRoot ?? config.rootDir;
|
|
4717
|
+
const allPackageJsonPaths = discoverAllPackageJsonPaths(config.rootDir);
|
|
4718
|
+
if (monorepoRoot) {
|
|
4719
|
+
const monorepoPackageJson = join(monorepoRoot, "package.json");
|
|
4720
|
+
if (!allPackageJsonPaths.includes(monorepoPackageJson) && existsSync(monorepoPackageJson)) allPackageJsonPaths.push(monorepoPackageJson);
|
|
4721
|
+
}
|
|
4722
|
+
const binToPackage = buildBinToPackageMap(nodeModulesRoot, declaredNames);
|
|
4723
|
+
for (const workspacePackageJsonPath of allPackageJsonPaths) {
|
|
4724
|
+
const scriptReferenced = collectScriptReferencedPackages(workspacePackageJsonPath, declaredNames, binToPackage);
|
|
4725
|
+
for (const packageName of scriptReferenced) usedPackageNames.add(packageName);
|
|
4726
|
+
const packageJsonConfigReferenced = collectPackageJsonConfigReferences(workspacePackageJsonPath, declaredNames);
|
|
4727
|
+
for (const packageName of packageJsonConfigReferenced) usedPackageNames.add(packageName);
|
|
4728
|
+
}
|
|
4729
|
+
const configSearchRoots = monorepoRoot && monorepoRoot !== config.rootDir ? [config.rootDir, monorepoRoot] : [config.rootDir];
|
|
4730
|
+
for (const configSearchRoot of configSearchRoots) {
|
|
4731
|
+
const configReferenced = collectConfigReferencedPackages(configSearchRoot, graph, declaredNames);
|
|
4732
|
+
for (const packageName of configReferenced) usedPackageNames.add(packageName);
|
|
4733
|
+
const tsconfigReferenced = collectTsconfigReferencedPackages(configSearchRoot);
|
|
4734
|
+
for (const packageName of tsconfigReferenced) usedPackageNames.add(packageName);
|
|
4735
|
+
}
|
|
4736
|
+
if (hasJsxFiles(graph)) {
|
|
4737
|
+
if (declaredNames.has("react")) usedPackageNames.add("react");
|
|
4738
|
+
if (declaredNames.has("react-dom")) usedPackageNames.add("react-dom");
|
|
4739
|
+
if (declaredNames.has("react-native")) usedPackageNames.add("react-native");
|
|
4740
|
+
if (declaredNames.has("react-native-web")) usedPackageNames.add("react-native-web");
|
|
4741
|
+
}
|
|
4742
|
+
const peerSatisfied = collectPeerSatisfiedPackages(nodeModulesRoot, declaredNames, usedPackageNames);
|
|
4743
|
+
for (const packageName of peerSatisfied) usedPackageNames.add(packageName);
|
|
4571
4744
|
const unusedDependencies = [];
|
|
4572
4745
|
for (const [dependencyName, isDevDependency] of declaredDependencies) {
|
|
4573
4746
|
if (isAlwaysConsideredUsed(dependencyName)) continue;
|
|
@@ -4586,13 +4759,306 @@ const collectUsedPackages = (graph) => {
|
|
|
4586
4759
|
}
|
|
4587
4760
|
return usedPackages;
|
|
4588
4761
|
};
|
|
4762
|
+
const hasJsxFiles = (graph) => graph.modules.some((module) => {
|
|
4763
|
+
const filePath = module.fileId.path;
|
|
4764
|
+
return filePath.endsWith(".tsx") || filePath.endsWith(".jsx");
|
|
4765
|
+
});
|
|
4766
|
+
const collectPeerSatisfiedPackages = (rootDir, declaredNames, confirmedUsedNames) => {
|
|
4767
|
+
const peerSatisfied = /* @__PURE__ */ new Set();
|
|
4768
|
+
const nodeModulesDir = join(rootDir, "node_modules");
|
|
4769
|
+
for (const installedName of declaredNames) {
|
|
4770
|
+
if (!confirmedUsedNames.has(installedName)) continue;
|
|
4771
|
+
const packageJsonPath = installedName.startsWith("@") ? join(nodeModulesDir, ...installedName.split("/"), "package.json") : join(nodeModulesDir, installedName, "package.json");
|
|
4772
|
+
try {
|
|
4773
|
+
const content = readFileSync(packageJsonPath, "utf-8");
|
|
4774
|
+
const peerDeps = JSON.parse(content).peerDependencies;
|
|
4775
|
+
if (peerDeps && typeof peerDeps === "object") {
|
|
4776
|
+
for (const peerName of Object.keys(peerDeps)) if (declaredNames.has(peerName)) peerSatisfied.add(peerName);
|
|
4777
|
+
}
|
|
4778
|
+
} catch {
|
|
4779
|
+
continue;
|
|
4780
|
+
}
|
|
4781
|
+
}
|
|
4782
|
+
return peerSatisfied;
|
|
4783
|
+
};
|
|
4784
|
+
const SHELL_SPLIT_PATTERN = /\s*(?:&&|\|\||[;&|])\s*/;
|
|
4785
|
+
const CLI_BINARY_TO_PACKAGE = {
|
|
4786
|
+
"react-scripts": "react-scripts",
|
|
4787
|
+
"webpack-cli": "webpack-cli",
|
|
4788
|
+
"webpack-dev-server": "webpack-dev-server",
|
|
4789
|
+
vitest: "vitest",
|
|
4790
|
+
jest: "jest",
|
|
4791
|
+
prisma: "prisma",
|
|
4792
|
+
sequelize: "sequelize-cli",
|
|
4793
|
+
rimraf: "rimraf",
|
|
4794
|
+
concurrently: "concurrently",
|
|
4795
|
+
parcel: "parcel",
|
|
4796
|
+
rescript: "rescript",
|
|
4797
|
+
webstudio: "webstudio",
|
|
4798
|
+
cap: "@capacitor/cli",
|
|
4799
|
+
"source-map-explorer": "source-map-explorer",
|
|
4800
|
+
"ts-standard": "ts-standard",
|
|
4801
|
+
"rndebugger-open": "react-native-debugger-open",
|
|
4802
|
+
"simple-git-hooks": "simple-git-hooks",
|
|
4803
|
+
"generate-arg-types": "@webstudio-is/generate-arg-types",
|
|
4804
|
+
email: "@react-email/preview-server"
|
|
4805
|
+
};
|
|
4806
|
+
const ENV_WRAPPER_BINARY_SET = new Set([
|
|
4807
|
+
"cross-env",
|
|
4808
|
+
"dotenv",
|
|
4809
|
+
"dotenv-flow",
|
|
4810
|
+
"env-cmd"
|
|
4811
|
+
]);
|
|
4812
|
+
const INLINE_ENV_VAR_PATTERN = /^[A-Z_][A-Z0-9_]*=/;
|
|
4813
|
+
const buildBinToPackageMap = (rootDir, declaredNames) => {
|
|
4814
|
+
const binToPackage = /* @__PURE__ */ new Map();
|
|
4815
|
+
for (const [binary, packageName] of Object.entries(CLI_BINARY_TO_PACKAGE)) binToPackage.set(binary, packageName);
|
|
4816
|
+
for (const packageName of declaredNames) {
|
|
4817
|
+
const packageBinJsonPath = packageName.startsWith("@") ? join(rootDir, "node_modules", ...packageName.split("/"), "package.json") : join(rootDir, "node_modules", packageName, "package.json");
|
|
4818
|
+
try {
|
|
4819
|
+
const binContent = readFileSync(packageBinJsonPath, "utf-8");
|
|
4820
|
+
const binPackageJson = JSON.parse(binContent);
|
|
4821
|
+
if (typeof binPackageJson.bin === "string") binToPackage.set(packageName.split("/").pop(), packageName);
|
|
4822
|
+
else if (typeof binPackageJson.bin === "object" && binPackageJson.bin !== null) for (const binaryName of Object.keys(binPackageJson.bin)) binToPackage.set(binaryName, packageName);
|
|
4823
|
+
} catch {
|
|
4824
|
+
continue;
|
|
4825
|
+
}
|
|
4826
|
+
}
|
|
4827
|
+
return binToPackage;
|
|
4828
|
+
};
|
|
4829
|
+
const collectScriptReferencedPackages = (packageJsonPath, declaredNames, binToPackage) => {
|
|
4830
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
4831
|
+
try {
|
|
4832
|
+
const content = readFileSync(packageJsonPath, "utf-8");
|
|
4833
|
+
const scripts = JSON.parse(content).scripts;
|
|
4834
|
+
if (!scripts || typeof scripts !== "object") return referenced;
|
|
4835
|
+
for (const scriptCommand of Object.values(scripts)) {
|
|
4836
|
+
if (typeof scriptCommand !== "string") continue;
|
|
4837
|
+
const segments = scriptCommand.split(SHELL_SPLIT_PATTERN);
|
|
4838
|
+
for (const segment of segments) {
|
|
4839
|
+
const tokens = segment.trim().split(/\s+/);
|
|
4840
|
+
if (tokens.length === 0) continue;
|
|
4841
|
+
let binaryIndex = 0;
|
|
4842
|
+
const firstToken = tokens[0].replace(/^.*\//, "");
|
|
4843
|
+
if (ENV_WRAPPER_BINARY_SET.has(firstToken)) {
|
|
4844
|
+
const envPackage = binToPackage.get(firstToken);
|
|
4845
|
+
if (envPackage && declaredNames.has(envPackage)) referenced.add(envPackage);
|
|
4846
|
+
binaryIndex = 1;
|
|
4847
|
+
while (binaryIndex < tokens.length && INLINE_ENV_VAR_PATTERN.test(tokens[binaryIndex])) binaryIndex++;
|
|
4848
|
+
if (binaryIndex >= tokens.length) continue;
|
|
4849
|
+
}
|
|
4850
|
+
while (binaryIndex < tokens.length && INLINE_ENV_VAR_PATTERN.test(tokens[binaryIndex])) binaryIndex++;
|
|
4851
|
+
if (binaryIndex >= tokens.length) continue;
|
|
4852
|
+
const binaryToken = tokens[binaryIndex].replace(/^.*\//, "");
|
|
4853
|
+
const effectiveBinary = binaryToken === "npx" || binaryToken === "pnpx" || binaryToken === "bunx" ? tokens[binaryIndex + 1]?.replace(/^.*\//, "") ?? "" : binaryToken;
|
|
4854
|
+
for (const candidateBinary of [binaryToken, effectiveBinary]) {
|
|
4855
|
+
if (!candidateBinary) continue;
|
|
4856
|
+
const mappedPackage = binToPackage.get(candidateBinary);
|
|
4857
|
+
if (mappedPackage && declaredNames.has(mappedPackage)) referenced.add(mappedPackage);
|
|
4858
|
+
if (declaredNames.has(candidateBinary)) referenced.add(candidateBinary);
|
|
4859
|
+
}
|
|
4860
|
+
}
|
|
4861
|
+
}
|
|
4862
|
+
} catch {
|
|
4863
|
+
return referenced;
|
|
4864
|
+
}
|
|
4865
|
+
return referenced;
|
|
4866
|
+
};
|
|
4867
|
+
const CONFIG_FILE_GLOBS = [
|
|
4868
|
+
"postcss.config.{js,cjs,mjs,ts}",
|
|
4869
|
+
".babelrc",
|
|
4870
|
+
".babelrc.{js,cjs,mjs,json}",
|
|
4871
|
+
"babel.config.{js,cjs,mjs,json,ts}",
|
|
4872
|
+
".eslintrc",
|
|
4873
|
+
".eslintrc.{js,cjs,mjs,json,yaml,yml}",
|
|
4874
|
+
"eslint.config.{js,cjs,mjs,ts,mts,cts}",
|
|
4875
|
+
"webpack.config.{js,ts,mjs,cjs}",
|
|
4876
|
+
"**/webpack*.config.{js,ts,mjs,cjs}",
|
|
4877
|
+
"**/webpack*.config*.{js,ts,mjs,cjs}",
|
|
4878
|
+
"**/webpack*.babel.{js,ts}",
|
|
4879
|
+
"vite.config.{js,ts,mjs,mts}",
|
|
4880
|
+
"rollup.config.{js,ts,mjs,cjs}",
|
|
4881
|
+
".storybook/main.{js,ts,mjs,cjs}",
|
|
4882
|
+
".storybook/preview.{js,ts,mjs,cjs,tsx,jsx}",
|
|
4883
|
+
"docusaurus.config.{js,ts,mjs}",
|
|
4884
|
+
"next.config.{js,ts,mjs,mts}",
|
|
4885
|
+
"tailwind.config.{js,ts,cjs,mjs}",
|
|
4886
|
+
"jest.config.{js,ts,mjs,cjs}",
|
|
4887
|
+
"vitest.config.{js,ts,mjs,mts}",
|
|
4888
|
+
"app.json",
|
|
4889
|
+
"forge.config.{js,ts,cjs}",
|
|
4890
|
+
"wrangler.toml",
|
|
4891
|
+
"wrangler.json",
|
|
4892
|
+
"wrangler.jsonc",
|
|
4893
|
+
"metro.config.{js,ts}",
|
|
4894
|
+
"electron.vite.config.{js,ts,mjs}",
|
|
4895
|
+
"api-extractor.json",
|
|
4896
|
+
"codegen.{ts,js,yml,yaml}",
|
|
4897
|
+
".graphqlrc.{ts,js,json,yml,yaml}",
|
|
4898
|
+
"graphql.config.{ts,js,json,yml,yaml}",
|
|
4899
|
+
".lintstagedrc.{js,cjs,mjs,json}",
|
|
4900
|
+
"commitlint.config.{js,cjs,mjs,ts}",
|
|
4901
|
+
".commitlintrc.{js,cjs,mjs,json,yaml,yml}",
|
|
4902
|
+
"tslint.json"
|
|
4903
|
+
];
|
|
4904
|
+
const collectConfigReferencedPackages = (rootDir, graph, declaredNames) => {
|
|
4905
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
4906
|
+
for (const module of graph.modules) {
|
|
4907
|
+
if (!module.isConfigFile) continue;
|
|
4908
|
+
try {
|
|
4909
|
+
const content = readFileSync(module.fileId.path, "utf-8");
|
|
4910
|
+
for (const packageName of declaredNames) if (content.includes(packageName)) referenced.add(packageName);
|
|
4911
|
+
} catch {
|
|
4912
|
+
continue;
|
|
4913
|
+
}
|
|
4914
|
+
}
|
|
4915
|
+
const configFiles = fg.sync(CONFIG_FILE_GLOBS, {
|
|
4916
|
+
cwd: rootDir,
|
|
4917
|
+
absolute: true,
|
|
4918
|
+
onlyFiles: true,
|
|
4919
|
+
ignore: ["**/node_modules/**"],
|
|
4920
|
+
dot: true,
|
|
4921
|
+
deep: 3
|
|
4922
|
+
});
|
|
4923
|
+
for (const configPath of configFiles) try {
|
|
4924
|
+
const content = readFileSync(configPath, "utf-8");
|
|
4925
|
+
for (const packageName of declaredNames) if (content.includes(packageName)) referenced.add(packageName);
|
|
4926
|
+
} catch {
|
|
4927
|
+
continue;
|
|
4928
|
+
}
|
|
4929
|
+
return referenced;
|
|
4930
|
+
};
|
|
4931
|
+
const PACKAGE_JSON_CONFIG_SECTIONS = [
|
|
4932
|
+
"jest",
|
|
4933
|
+
"babel",
|
|
4934
|
+
"eslintConfig",
|
|
4935
|
+
"prettier",
|
|
4936
|
+
"stylelint",
|
|
4937
|
+
"lint-staged",
|
|
4938
|
+
"commitlint",
|
|
4939
|
+
"browserslist",
|
|
4940
|
+
"postcss",
|
|
4941
|
+
"ava"
|
|
4942
|
+
];
|
|
4943
|
+
const collectPackageJsonConfigReferences = (packageJsonPath, declaredNames) => {
|
|
4944
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
4945
|
+
try {
|
|
4946
|
+
const content = readFileSync(packageJsonPath, "utf-8");
|
|
4947
|
+
const packageJson = JSON.parse(content);
|
|
4948
|
+
for (const sectionName of PACKAGE_JSON_CONFIG_SECTIONS) {
|
|
4949
|
+
const sectionValue = packageJson[sectionName];
|
|
4950
|
+
if (!sectionValue || typeof sectionValue !== "object") continue;
|
|
4951
|
+
const sectionText = JSON.stringify(sectionValue);
|
|
4952
|
+
for (const packageName of declaredNames) if (sectionText.includes(packageName)) referenced.add(packageName);
|
|
4953
|
+
}
|
|
4954
|
+
} catch {
|
|
4955
|
+
return referenced;
|
|
4956
|
+
}
|
|
4957
|
+
return referenced;
|
|
4958
|
+
};
|
|
4959
|
+
const TSCONFIG_GLOBS = [
|
|
4960
|
+
"tsconfig.json",
|
|
4961
|
+
"tsconfig.*.json",
|
|
4962
|
+
"jsconfig.json",
|
|
4963
|
+
"**/tsconfig.json",
|
|
4964
|
+
"**/tsconfig.*.json"
|
|
4965
|
+
];
|
|
4966
|
+
const collectTsconfigReferencedPackages = (rootDir) => {
|
|
4967
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
4968
|
+
const tsconfigFiles = fg.sync(TSCONFIG_GLOBS, {
|
|
4969
|
+
cwd: rootDir,
|
|
4970
|
+
absolute: true,
|
|
4971
|
+
onlyFiles: true,
|
|
4972
|
+
ignore: ["**/node_modules/**"],
|
|
4973
|
+
dot: false,
|
|
4974
|
+
deep: 4
|
|
4975
|
+
});
|
|
4976
|
+
for (const tsconfigPath of tsconfigFiles) try {
|
|
4977
|
+
const cleaned = readFileSync(tsconfigPath, "utf-8").replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
4978
|
+
const parsed = JSON.parse(cleaned);
|
|
4979
|
+
if (typeof parsed.extends === "string") {
|
|
4980
|
+
const extendsPackage = extractExtendsPackageName(parsed.extends);
|
|
4981
|
+
if (extendsPackage) referenced.add(extendsPackage);
|
|
4982
|
+
}
|
|
4983
|
+
if (Array.isArray(parsed.extends)) {
|
|
4984
|
+
for (const extendsEntry of parsed.extends) if (typeof extendsEntry === "string") {
|
|
4985
|
+
const extendsPackage = extractExtendsPackageName(extendsEntry);
|
|
4986
|
+
if (extendsPackage) referenced.add(extendsPackage);
|
|
4987
|
+
}
|
|
4988
|
+
}
|
|
4989
|
+
const compilerOptions = parsed.compilerOptions;
|
|
4990
|
+
if (compilerOptions?.jsxImportSource && typeof compilerOptions.jsxImportSource === "string") referenced.add(compilerOptions.jsxImportSource);
|
|
4991
|
+
if (Array.isArray(compilerOptions?.types)) {
|
|
4992
|
+
for (const typesEntry of compilerOptions.types) if (typeof typesEntry === "string") {
|
|
4993
|
+
const typesPackage = extractPackageName(typesEntry);
|
|
4994
|
+
if (typesPackage) referenced.add(typesPackage);
|
|
4995
|
+
}
|
|
4996
|
+
}
|
|
4997
|
+
} catch {
|
|
4998
|
+
continue;
|
|
4999
|
+
}
|
|
5000
|
+
return referenced;
|
|
5001
|
+
};
|
|
5002
|
+
const extractExtendsPackageName = (extendsValue) => {
|
|
5003
|
+
if (extendsValue.startsWith(".") || extendsValue.startsWith("/")) return void 0;
|
|
5004
|
+
if (extendsValue.startsWith("@")) {
|
|
5005
|
+
const parts = extendsValue.split("/");
|
|
5006
|
+
return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : void 0;
|
|
5007
|
+
}
|
|
5008
|
+
return extendsValue.split("/")[0];
|
|
5009
|
+
};
|
|
5010
|
+
const ALWAYS_USED_PREFIXES = [
|
|
5011
|
+
"@types/",
|
|
5012
|
+
"eslint-config-",
|
|
5013
|
+
"eslint-plugin-",
|
|
5014
|
+
"@eslint/",
|
|
5015
|
+
"prettier-plugin-",
|
|
5016
|
+
"@commitlint/",
|
|
5017
|
+
"babel-plugin-",
|
|
5018
|
+
"babel-preset-",
|
|
5019
|
+
"@babel/plugin-",
|
|
5020
|
+
"@babel/preset-",
|
|
5021
|
+
"@fontsource/",
|
|
5022
|
+
"@next/",
|
|
5023
|
+
"@svgr/",
|
|
5024
|
+
"@docusaurus/",
|
|
5025
|
+
"stylelint-config-",
|
|
5026
|
+
"stylelint-plugin-",
|
|
5027
|
+
"@testing-library/",
|
|
5028
|
+
"@vitest/",
|
|
5029
|
+
"@playwright/",
|
|
5030
|
+
"@storybook/",
|
|
5031
|
+
"jest-environment-",
|
|
5032
|
+
"@graphql-codegen/",
|
|
5033
|
+
"@size-limit/",
|
|
5034
|
+
"@nestjs/",
|
|
5035
|
+
"@swc/",
|
|
5036
|
+
"@electron-forge/",
|
|
5037
|
+
"@parcel/",
|
|
5038
|
+
"@wyw-in-js/",
|
|
5039
|
+
"@typescript-eslint/",
|
|
5040
|
+
"@react-native/",
|
|
5041
|
+
"@react-native-community/",
|
|
5042
|
+
"postcss-",
|
|
5043
|
+
"@tailwindcss/",
|
|
5044
|
+
"rollup-plugin-",
|
|
5045
|
+
"vite-plugin-",
|
|
5046
|
+
"@vitejs/",
|
|
5047
|
+
"webpack-",
|
|
5048
|
+
"esbuild-",
|
|
5049
|
+
"@esbuild-plugins/",
|
|
5050
|
+
"@lingui/",
|
|
5051
|
+
"@emotion/",
|
|
5052
|
+
"tslint-config-",
|
|
5053
|
+
"@changesets/",
|
|
5054
|
+
"@vercel/",
|
|
5055
|
+
"@expo/",
|
|
5056
|
+
"expo-",
|
|
5057
|
+
"react-native-"
|
|
5058
|
+
];
|
|
4589
5059
|
const isAlwaysConsideredUsed = (dependencyName) => {
|
|
4590
5060
|
if (IMPLICIT_DEPENDENCIES.has(dependencyName)) return true;
|
|
4591
|
-
|
|
4592
|
-
if (dependencyName.startsWith("eslint-config-")) return true;
|
|
4593
|
-
if (dependencyName.startsWith("eslint-plugin-")) return true;
|
|
4594
|
-
if (dependencyName.startsWith("prettier-plugin-")) return true;
|
|
4595
|
-
return false;
|
|
5061
|
+
return ALWAYS_USED_PREFIXES.some((prefix) => dependencyName.startsWith(prefix));
|
|
4596
5062
|
};
|
|
4597
5063
|
|
|
4598
5064
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deslop-js",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Deslop JavaScript code",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dead-code",
|
|
7
|
-
"
|
|
7
|
+
"dependencies",
|
|
8
8
|
"exports",
|
|
9
9
|
"files",
|
|
10
|
-
"dependencies",
|
|
11
|
-
"typescript",
|
|
12
10
|
"javascript",
|
|
13
|
-
"oxc"
|
|
11
|
+
"oxc",
|
|
12
|
+
"typescript",
|
|
13
|
+
"unused"
|
|
14
14
|
],
|
|
15
15
|
"license": "MIT",
|
|
16
16
|
"author": {
|