deslop-js 0.0.2 → 0.0.3
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 +369 -8
- package/dist/index.mjs +369 -8
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -165,7 +165,19 @@ const IMPLICIT_DEPENDENCIES = new Set([
|
|
|
165
165
|
"prettier",
|
|
166
166
|
"husky",
|
|
167
167
|
"lint-staged",
|
|
168
|
-
"tslib"
|
|
168
|
+
"tslib",
|
|
169
|
+
"@babel/core",
|
|
170
|
+
"postcss",
|
|
171
|
+
"cross-env",
|
|
172
|
+
"sass",
|
|
173
|
+
"node-sass",
|
|
174
|
+
"less",
|
|
175
|
+
"oxlint",
|
|
176
|
+
"biome",
|
|
177
|
+
"@biomejs/biome",
|
|
178
|
+
"patch-package",
|
|
179
|
+
"simple-git-hooks",
|
|
180
|
+
"lefthook"
|
|
169
181
|
]);
|
|
170
182
|
const BUILTIN_MODULES = new Set([
|
|
171
183
|
"assert",
|
|
@@ -1877,7 +1889,9 @@ const extractPackageJsonEntries = async (packageJsonPath) => {
|
|
|
1877
1889
|
"module",
|
|
1878
1890
|
"browser",
|
|
1879
1891
|
"types",
|
|
1880
|
-
"typings"
|
|
1892
|
+
"typings",
|
|
1893
|
+
"style",
|
|
1894
|
+
"source"
|
|
1881
1895
|
]) if (typeof packageJson[field] === "string") entries.push(resolveEntryPath(packageJson[field], rootDir));
|
|
1882
1896
|
if (packageJson.exports) {
|
|
1883
1897
|
const exportEntries = [];
|
|
@@ -2677,7 +2691,9 @@ const TEST_FRAMEWORK_PATTERNS = [
|
|
|
2677
2691
|
enablers: [
|
|
2678
2692
|
"jest",
|
|
2679
2693
|
"@jest/core",
|
|
2680
|
-
"ts-jest"
|
|
2694
|
+
"ts-jest",
|
|
2695
|
+
"react-scripts",
|
|
2696
|
+
"react-app-rewired"
|
|
2681
2697
|
],
|
|
2682
2698
|
configFileActivators: [
|
|
2683
2699
|
"jest.config.ts",
|
|
@@ -2922,6 +2938,51 @@ const FRAMEWORK_PATTERNS = [
|
|
|
2922
2938
|
],
|
|
2923
2939
|
contentIgnorePatterns: ["versioned_sidebars/**"]
|
|
2924
2940
|
},
|
|
2941
|
+
{
|
|
2942
|
+
enablers: [
|
|
2943
|
+
"fumadocs-core",
|
|
2944
|
+
"fumadocs-ui",
|
|
2945
|
+
"fumadocs-mdx"
|
|
2946
|
+
],
|
|
2947
|
+
enablerPrefixes: ["fumadocs-"],
|
|
2948
|
+
entryPatterns: ["content/**/*.{md,mdx}", "content/**/*.{ts,tsx,js,jsx}"],
|
|
2949
|
+
alwaysUsed: ["source.config.{ts,js,mjs}"]
|
|
2950
|
+
},
|
|
2951
|
+
{
|
|
2952
|
+
enablers: [
|
|
2953
|
+
"nextra",
|
|
2954
|
+
"nextra-theme-docs",
|
|
2955
|
+
"nextra-theme-blog"
|
|
2956
|
+
],
|
|
2957
|
+
enablerPrefixes: ["nextra-"],
|
|
2958
|
+
entryPatterns: [
|
|
2959
|
+
"pages/**/*.{md,mdx}",
|
|
2960
|
+
"src/pages/**/*.{md,mdx}",
|
|
2961
|
+
"content/**/*.{md,mdx}"
|
|
2962
|
+
],
|
|
2963
|
+
alwaysUsed: []
|
|
2964
|
+
},
|
|
2965
|
+
{
|
|
2966
|
+
enablers: [
|
|
2967
|
+
"contentlayer",
|
|
2968
|
+
"contentlayer2",
|
|
2969
|
+
"contentlayer-source-files"
|
|
2970
|
+
],
|
|
2971
|
+
enablerPrefixes: ["contentlayer"],
|
|
2972
|
+
entryPatterns: ["content/**/*.{md,mdx}", "posts/**/*.{md,mdx}"],
|
|
2973
|
+
alwaysUsed: ["contentlayer.config.{ts,js,mjs}"]
|
|
2974
|
+
},
|
|
2975
|
+
{
|
|
2976
|
+
enablers: ["@graphql-codegen/cli", "@graphql-codegen/core"],
|
|
2977
|
+
enablerPrefixes: ["@graphql-codegen/"],
|
|
2978
|
+
entryPatterns: ["**/*.graphql", "**/*.gql"],
|
|
2979
|
+
alwaysUsed: [
|
|
2980
|
+
"codegen.{ts,js,yml,yaml}",
|
|
2981
|
+
"codegen.config.{ts,js}",
|
|
2982
|
+
".graphqlrc.{ts,js,json,yml,yaml}",
|
|
2983
|
+
"graphql.config.{ts,js,json,yml,yaml}"
|
|
2984
|
+
]
|
|
2985
|
+
},
|
|
2925
2986
|
{
|
|
2926
2987
|
enablers: ["eslint", "@eslint/js"],
|
|
2927
2988
|
enablerPrefixes: [],
|
|
@@ -4480,6 +4541,16 @@ const detectDeadExports = (graph, config) => {
|
|
|
4480
4541
|
const buildUsageMap = (graph) => {
|
|
4481
4542
|
const usedExportKeys = /* @__PURE__ */ new Set();
|
|
4482
4543
|
const sourceToTargetMap = buildSourceToTargetsMap(graph);
|
|
4544
|
+
for (const module of graph.modules) {
|
|
4545
|
+
if (!module.isEntryPoint) continue;
|
|
4546
|
+
for (const edge of graph.edges) {
|
|
4547
|
+
if (edge.source !== module.fileId.index || !edge.isReExportEdge) continue;
|
|
4548
|
+
const targetModule = graph.modules[edge.target];
|
|
4549
|
+
if (!targetModule) continue;
|
|
4550
|
+
if (edge.reExportedNames.includes("*")) markAllExportsUsedRecursive(targetModule, graph, sourceToTargetMap, usedExportKeys, /* @__PURE__ */ new Set());
|
|
4551
|
+
else for (const mapping of edge.reExportMappings) markExportUsedRecursive(targetModule.fileId.path, mapping.originalName, graph, sourceToTargetMap, usedExportKeys, /* @__PURE__ */ new Set());
|
|
4552
|
+
}
|
|
4553
|
+
}
|
|
4483
4554
|
for (const edge of graph.edges) {
|
|
4484
4555
|
const targetModule = graph.modules[edge.target];
|
|
4485
4556
|
if (!targetModule) continue;
|
|
@@ -4583,6 +4654,23 @@ const extractPackageName = (specifier) => {
|
|
|
4583
4654
|
|
|
4584
4655
|
//#endregion
|
|
4585
4656
|
//#region src/report/packages.ts
|
|
4657
|
+
const discoverAllPackageJsonPaths = (rootDir) => {
|
|
4658
|
+
const paths = [(0, node_path.join)(rootDir, "package.json")];
|
|
4659
|
+
const workspacePackageJsons = fast_glob.default.sync("**/package.json", {
|
|
4660
|
+
cwd: rootDir,
|
|
4661
|
+
absolute: true,
|
|
4662
|
+
onlyFiles: true,
|
|
4663
|
+
ignore: [
|
|
4664
|
+
"**/node_modules/**",
|
|
4665
|
+
"**/dist/**",
|
|
4666
|
+
"**/build/**",
|
|
4667
|
+
"**/.git/**"
|
|
4668
|
+
],
|
|
4669
|
+
deep: 5
|
|
4670
|
+
});
|
|
4671
|
+
for (const workspacePath of workspacePackageJsons) if (workspacePath !== paths[0] && !paths.includes(workspacePath)) paths.push(workspacePath);
|
|
4672
|
+
return paths;
|
|
4673
|
+
};
|
|
4586
4674
|
const detectStalePackages = (graph, config) => {
|
|
4587
4675
|
const packageJsonPath = (0, node_path.resolve)(config.rootDir, "package.json");
|
|
4588
4676
|
let packageJson;
|
|
@@ -4597,7 +4685,28 @@ const detectStalePackages = (graph, config) => {
|
|
|
4597
4685
|
const declaredDependencies = /* @__PURE__ */ new Map();
|
|
4598
4686
|
for (const dependencyName of Object.keys(dependencies)) declaredDependencies.set(dependencyName, false);
|
|
4599
4687
|
for (const dependencyName of Object.keys(devDependencies)) declaredDependencies.set(dependencyName, true);
|
|
4688
|
+
const declaredNames = new Set(declaredDependencies.keys());
|
|
4600
4689
|
const usedPackageNames = collectUsedPackages(graph);
|
|
4690
|
+
const allPackageJsonPaths = discoverAllPackageJsonPaths(config.rootDir);
|
|
4691
|
+
const binToPackage = buildBinToPackageMap(config.rootDir, declaredNames);
|
|
4692
|
+
for (const workspacePackageJsonPath of allPackageJsonPaths) {
|
|
4693
|
+
const scriptReferenced = collectScriptReferencedPackages(workspacePackageJsonPath, declaredNames, binToPackage);
|
|
4694
|
+
for (const packageName of scriptReferenced) usedPackageNames.add(packageName);
|
|
4695
|
+
const packageJsonConfigReferenced = collectPackageJsonConfigReferences(workspacePackageJsonPath, declaredNames);
|
|
4696
|
+
for (const packageName of packageJsonConfigReferenced) usedPackageNames.add(packageName);
|
|
4697
|
+
}
|
|
4698
|
+
const configReferenced = collectConfigReferencedPackages(config.rootDir, graph, declaredNames);
|
|
4699
|
+
for (const packageName of configReferenced) usedPackageNames.add(packageName);
|
|
4700
|
+
const tsconfigReferenced = collectTsconfigReferencedPackages(config.rootDir);
|
|
4701
|
+
for (const packageName of tsconfigReferenced) usedPackageNames.add(packageName);
|
|
4702
|
+
if (hasJsxFiles(graph)) {
|
|
4703
|
+
if (declaredNames.has("react")) usedPackageNames.add("react");
|
|
4704
|
+
if (declaredNames.has("react-dom")) usedPackageNames.add("react-dom");
|
|
4705
|
+
if (declaredNames.has("react-native")) usedPackageNames.add("react-native");
|
|
4706
|
+
if (declaredNames.has("react-native-web")) usedPackageNames.add("react-native-web");
|
|
4707
|
+
}
|
|
4708
|
+
const peerSatisfied = collectPeerSatisfiedPackages(config.rootDir, declaredNames, usedPackageNames);
|
|
4709
|
+
for (const packageName of peerSatisfied) usedPackageNames.add(packageName);
|
|
4601
4710
|
const unusedDependencies = [];
|
|
4602
4711
|
for (const [dependencyName, isDevDependency] of declaredDependencies) {
|
|
4603
4712
|
if (isAlwaysConsideredUsed(dependencyName)) continue;
|
|
@@ -4616,13 +4725,265 @@ const collectUsedPackages = (graph) => {
|
|
|
4616
4725
|
}
|
|
4617
4726
|
return usedPackages;
|
|
4618
4727
|
};
|
|
4728
|
+
const hasJsxFiles = (graph) => graph.modules.some((module) => {
|
|
4729
|
+
const filePath = module.fileId.path;
|
|
4730
|
+
return filePath.endsWith(".tsx") || filePath.endsWith(".jsx");
|
|
4731
|
+
});
|
|
4732
|
+
const collectPeerSatisfiedPackages = (rootDir, declaredNames, confirmedUsedNames) => {
|
|
4733
|
+
const peerSatisfied = /* @__PURE__ */ new Set();
|
|
4734
|
+
const nodeModulesDir = (0, node_path.join)(rootDir, "node_modules");
|
|
4735
|
+
for (const installedName of declaredNames) {
|
|
4736
|
+
if (!confirmedUsedNames.has(installedName)) continue;
|
|
4737
|
+
const packageJsonPath = installedName.startsWith("@") ? (0, node_path.join)(nodeModulesDir, ...installedName.split("/"), "package.json") : (0, node_path.join)(nodeModulesDir, installedName, "package.json");
|
|
4738
|
+
try {
|
|
4739
|
+
const content = (0, node_fs.readFileSync)(packageJsonPath, "utf-8");
|
|
4740
|
+
const peerDeps = JSON.parse(content).peerDependencies;
|
|
4741
|
+
if (peerDeps && typeof peerDeps === "object") {
|
|
4742
|
+
for (const peerName of Object.keys(peerDeps)) if (declaredNames.has(peerName)) peerSatisfied.add(peerName);
|
|
4743
|
+
}
|
|
4744
|
+
} catch {
|
|
4745
|
+
continue;
|
|
4746
|
+
}
|
|
4747
|
+
}
|
|
4748
|
+
return peerSatisfied;
|
|
4749
|
+
};
|
|
4750
|
+
const SHELL_SPLIT_PATTERN = /\s*(?:&&|\|\||[;&|])\s*/;
|
|
4751
|
+
const CLI_BINARY_TO_PACKAGE = {
|
|
4752
|
+
"react-scripts": "react-scripts",
|
|
4753
|
+
"webpack-cli": "webpack-cli",
|
|
4754
|
+
"webpack-dev-server": "webpack-dev-server",
|
|
4755
|
+
vitest: "vitest",
|
|
4756
|
+
jest: "jest",
|
|
4757
|
+
prisma: "prisma",
|
|
4758
|
+
sequelize: "sequelize-cli",
|
|
4759
|
+
rimraf: "rimraf",
|
|
4760
|
+
concurrently: "concurrently",
|
|
4761
|
+
parcel: "parcel",
|
|
4762
|
+
rescript: "rescript",
|
|
4763
|
+
webstudio: "webstudio",
|
|
4764
|
+
cap: "@capacitor/cli",
|
|
4765
|
+
"source-map-explorer": "source-map-explorer",
|
|
4766
|
+
"ts-standard": "ts-standard",
|
|
4767
|
+
"rndebugger-open": "react-native-debugger-open",
|
|
4768
|
+
"simple-git-hooks": "simple-git-hooks",
|
|
4769
|
+
"generate-arg-types": "@webstudio-is/generate-arg-types",
|
|
4770
|
+
email: "@react-email/preview-server"
|
|
4771
|
+
};
|
|
4772
|
+
const ENV_WRAPPER_BINARY_SET = new Set([
|
|
4773
|
+
"cross-env",
|
|
4774
|
+
"dotenv",
|
|
4775
|
+
"dotenv-flow",
|
|
4776
|
+
"env-cmd"
|
|
4777
|
+
]);
|
|
4778
|
+
const INLINE_ENV_VAR_PATTERN = /^[A-Z_][A-Z0-9_]*=/;
|
|
4779
|
+
const buildBinToPackageMap = (rootDir, declaredNames) => {
|
|
4780
|
+
const binToPackage = /* @__PURE__ */ new Map();
|
|
4781
|
+
for (const [binary, packageName] of Object.entries(CLI_BINARY_TO_PACKAGE)) binToPackage.set(binary, packageName);
|
|
4782
|
+
for (const packageName of declaredNames) {
|
|
4783
|
+
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");
|
|
4784
|
+
try {
|
|
4785
|
+
const binContent = (0, node_fs.readFileSync)(packageBinJsonPath, "utf-8");
|
|
4786
|
+
const binPackageJson = JSON.parse(binContent);
|
|
4787
|
+
if (typeof binPackageJson.bin === "string") binToPackage.set(packageName.split("/").pop(), packageName);
|
|
4788
|
+
else if (typeof binPackageJson.bin === "object" && binPackageJson.bin !== null) for (const binaryName of Object.keys(binPackageJson.bin)) binToPackage.set(binaryName, packageName);
|
|
4789
|
+
} catch {
|
|
4790
|
+
continue;
|
|
4791
|
+
}
|
|
4792
|
+
}
|
|
4793
|
+
return binToPackage;
|
|
4794
|
+
};
|
|
4795
|
+
const collectScriptReferencedPackages = (packageJsonPath, declaredNames, binToPackage) => {
|
|
4796
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
4797
|
+
try {
|
|
4798
|
+
const content = (0, node_fs.readFileSync)(packageJsonPath, "utf-8");
|
|
4799
|
+
const scripts = JSON.parse(content).scripts;
|
|
4800
|
+
if (!scripts || typeof scripts !== "object") return referenced;
|
|
4801
|
+
for (const scriptCommand of Object.values(scripts)) {
|
|
4802
|
+
if (typeof scriptCommand !== "string") continue;
|
|
4803
|
+
const segments = scriptCommand.split(SHELL_SPLIT_PATTERN);
|
|
4804
|
+
for (const segment of segments) {
|
|
4805
|
+
const tokens = segment.trim().split(/\s+/);
|
|
4806
|
+
if (tokens.length === 0) continue;
|
|
4807
|
+
let binaryIndex = 0;
|
|
4808
|
+
const firstToken = tokens[0].replace(/^.*\//, "");
|
|
4809
|
+
if (ENV_WRAPPER_BINARY_SET.has(firstToken)) {
|
|
4810
|
+
const envPackage = binToPackage.get(firstToken);
|
|
4811
|
+
if (envPackage && declaredNames.has(envPackage)) referenced.add(envPackage);
|
|
4812
|
+
binaryIndex = 1;
|
|
4813
|
+
while (binaryIndex < tokens.length && INLINE_ENV_VAR_PATTERN.test(tokens[binaryIndex])) binaryIndex++;
|
|
4814
|
+
if (binaryIndex >= tokens.length) continue;
|
|
4815
|
+
}
|
|
4816
|
+
while (binaryIndex < tokens.length && INLINE_ENV_VAR_PATTERN.test(tokens[binaryIndex])) binaryIndex++;
|
|
4817
|
+
if (binaryIndex >= tokens.length) continue;
|
|
4818
|
+
const binaryToken = tokens[binaryIndex].replace(/^.*\//, "");
|
|
4819
|
+
const effectiveBinary = binaryToken === "npx" || binaryToken === "pnpx" || binaryToken === "bunx" ? tokens[binaryIndex + 1]?.replace(/^.*\//, "") ?? "" : binaryToken;
|
|
4820
|
+
for (const candidateBinary of [binaryToken, effectiveBinary]) {
|
|
4821
|
+
if (!candidateBinary) continue;
|
|
4822
|
+
const mappedPackage = binToPackage.get(candidateBinary);
|
|
4823
|
+
if (mappedPackage && declaredNames.has(mappedPackage)) referenced.add(mappedPackage);
|
|
4824
|
+
if (declaredNames.has(candidateBinary)) referenced.add(candidateBinary);
|
|
4825
|
+
}
|
|
4826
|
+
}
|
|
4827
|
+
}
|
|
4828
|
+
} catch {
|
|
4829
|
+
return referenced;
|
|
4830
|
+
}
|
|
4831
|
+
return referenced;
|
|
4832
|
+
};
|
|
4833
|
+
const CONFIG_FILE_GLOBS = [
|
|
4834
|
+
"postcss.config.{js,cjs,mjs,ts}",
|
|
4835
|
+
".babelrc",
|
|
4836
|
+
".babelrc.{js,cjs,mjs,json}",
|
|
4837
|
+
"babel.config.{js,cjs,mjs,json,ts}",
|
|
4838
|
+
".eslintrc",
|
|
4839
|
+
".eslintrc.{js,cjs,mjs,json,yaml,yml}",
|
|
4840
|
+
"eslint.config.{js,cjs,mjs,ts,mts,cts}",
|
|
4841
|
+
"webpack.config.{js,ts,mjs,cjs}",
|
|
4842
|
+
"**/webpack*.config.{js,ts,mjs,cjs}",
|
|
4843
|
+
"vite.config.{js,ts,mjs,mts}",
|
|
4844
|
+
"rollup.config.{js,ts,mjs,cjs}",
|
|
4845
|
+
".storybook/main.{js,ts,mjs,cjs}",
|
|
4846
|
+
"docusaurus.config.{js,ts,mjs}",
|
|
4847
|
+
"next.config.{js,ts,mjs,mts}",
|
|
4848
|
+
"tailwind.config.{js,ts,cjs,mjs}",
|
|
4849
|
+
"jest.config.{js,ts,mjs,cjs}",
|
|
4850
|
+
"vitest.config.{js,ts,mjs,mts}",
|
|
4851
|
+
"app.json",
|
|
4852
|
+
"forge.config.{js,ts,cjs}",
|
|
4853
|
+
"wrangler.toml",
|
|
4854
|
+
"wrangler.json",
|
|
4855
|
+
"wrangler.jsonc",
|
|
4856
|
+
"metro.config.{js,ts}",
|
|
4857
|
+
"electron.vite.config.{js,ts,mjs}",
|
|
4858
|
+
"api-extractor.json"
|
|
4859
|
+
];
|
|
4860
|
+
const collectConfigReferencedPackages = (rootDir, graph, declaredNames) => {
|
|
4861
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
4862
|
+
for (const module of graph.modules) {
|
|
4863
|
+
if (!module.isConfigFile) continue;
|
|
4864
|
+
try {
|
|
4865
|
+
const content = (0, node_fs.readFileSync)(module.fileId.path, "utf-8");
|
|
4866
|
+
for (const packageName of declaredNames) if (content.includes(packageName)) referenced.add(packageName);
|
|
4867
|
+
} catch {
|
|
4868
|
+
continue;
|
|
4869
|
+
}
|
|
4870
|
+
}
|
|
4871
|
+
const configFiles = fast_glob.default.sync(CONFIG_FILE_GLOBS, {
|
|
4872
|
+
cwd: rootDir,
|
|
4873
|
+
absolute: true,
|
|
4874
|
+
onlyFiles: true,
|
|
4875
|
+
ignore: ["**/node_modules/**"],
|
|
4876
|
+
dot: true,
|
|
4877
|
+
deep: 3
|
|
4878
|
+
});
|
|
4879
|
+
for (const configPath of configFiles) try {
|
|
4880
|
+
const content = (0, node_fs.readFileSync)(configPath, "utf-8");
|
|
4881
|
+
for (const packageName of declaredNames) if (content.includes(packageName)) referenced.add(packageName);
|
|
4882
|
+
} catch {
|
|
4883
|
+
continue;
|
|
4884
|
+
}
|
|
4885
|
+
return referenced;
|
|
4886
|
+
};
|
|
4887
|
+
const PACKAGE_JSON_CONFIG_SECTIONS = [
|
|
4888
|
+
"jest",
|
|
4889
|
+
"babel",
|
|
4890
|
+
"eslintConfig",
|
|
4891
|
+
"prettier",
|
|
4892
|
+
"stylelint",
|
|
4893
|
+
"lint-staged",
|
|
4894
|
+
"commitlint",
|
|
4895
|
+
"browserslist",
|
|
4896
|
+
"postcss",
|
|
4897
|
+
"ava"
|
|
4898
|
+
];
|
|
4899
|
+
const collectPackageJsonConfigReferences = (packageJsonPath, declaredNames) => {
|
|
4900
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
4901
|
+
try {
|
|
4902
|
+
const content = (0, node_fs.readFileSync)(packageJsonPath, "utf-8");
|
|
4903
|
+
const packageJson = JSON.parse(content);
|
|
4904
|
+
for (const sectionName of PACKAGE_JSON_CONFIG_SECTIONS) {
|
|
4905
|
+
const sectionValue = packageJson[sectionName];
|
|
4906
|
+
if (!sectionValue || typeof sectionValue !== "object") continue;
|
|
4907
|
+
const sectionText = JSON.stringify(sectionValue);
|
|
4908
|
+
for (const packageName of declaredNames) if (sectionText.includes(packageName)) referenced.add(packageName);
|
|
4909
|
+
}
|
|
4910
|
+
} catch {
|
|
4911
|
+
return referenced;
|
|
4912
|
+
}
|
|
4913
|
+
return referenced;
|
|
4914
|
+
};
|
|
4915
|
+
const TSCONFIG_GLOBS = [
|
|
4916
|
+
"tsconfig.json",
|
|
4917
|
+
"tsconfig.*.json",
|
|
4918
|
+
"jsconfig.json",
|
|
4919
|
+
"**/tsconfig.json",
|
|
4920
|
+
"**/tsconfig.*.json"
|
|
4921
|
+
];
|
|
4922
|
+
const collectTsconfigReferencedPackages = (rootDir) => {
|
|
4923
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
4924
|
+
const tsconfigFiles = fast_glob.default.sync(TSCONFIG_GLOBS, {
|
|
4925
|
+
cwd: rootDir,
|
|
4926
|
+
absolute: true,
|
|
4927
|
+
onlyFiles: true,
|
|
4928
|
+
ignore: ["**/node_modules/**"],
|
|
4929
|
+
dot: false,
|
|
4930
|
+
deep: 4
|
|
4931
|
+
});
|
|
4932
|
+
for (const tsconfigPath of tsconfigFiles) try {
|
|
4933
|
+
const cleaned = (0, node_fs.readFileSync)(tsconfigPath, "utf-8").replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
4934
|
+
const parsed = JSON.parse(cleaned);
|
|
4935
|
+
if (typeof parsed.extends === "string") {
|
|
4936
|
+
const extendsPackage = extractExtendsPackageName(parsed.extends);
|
|
4937
|
+
if (extendsPackage) referenced.add(extendsPackage);
|
|
4938
|
+
}
|
|
4939
|
+
if (Array.isArray(parsed.extends)) {
|
|
4940
|
+
for (const extendsEntry of parsed.extends) if (typeof extendsEntry === "string") {
|
|
4941
|
+
const extendsPackage = extractExtendsPackageName(extendsEntry);
|
|
4942
|
+
if (extendsPackage) referenced.add(extendsPackage);
|
|
4943
|
+
}
|
|
4944
|
+
}
|
|
4945
|
+
const compilerOptions = parsed.compilerOptions;
|
|
4946
|
+
if (compilerOptions?.jsxImportSource && typeof compilerOptions.jsxImportSource === "string") referenced.add(compilerOptions.jsxImportSource);
|
|
4947
|
+
if (Array.isArray(compilerOptions?.types)) {
|
|
4948
|
+
for (const typesEntry of compilerOptions.types) if (typeof typesEntry === "string") {
|
|
4949
|
+
const typesPackage = extractPackageName(typesEntry);
|
|
4950
|
+
if (typesPackage) referenced.add(typesPackage);
|
|
4951
|
+
}
|
|
4952
|
+
}
|
|
4953
|
+
} catch {
|
|
4954
|
+
continue;
|
|
4955
|
+
}
|
|
4956
|
+
return referenced;
|
|
4957
|
+
};
|
|
4958
|
+
const extractExtendsPackageName = (extendsValue) => {
|
|
4959
|
+
if (extendsValue.startsWith(".") || extendsValue.startsWith("/")) return void 0;
|
|
4960
|
+
if (extendsValue.startsWith("@")) {
|
|
4961
|
+
const parts = extendsValue.split("/");
|
|
4962
|
+
return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : void 0;
|
|
4963
|
+
}
|
|
4964
|
+
return extendsValue.split("/")[0];
|
|
4965
|
+
};
|
|
4966
|
+
const ALWAYS_USED_PREFIXES = [
|
|
4967
|
+
"@types/",
|
|
4968
|
+
"eslint-config-",
|
|
4969
|
+
"eslint-plugin-",
|
|
4970
|
+
"@eslint/",
|
|
4971
|
+
"prettier-plugin-",
|
|
4972
|
+
"@commitlint/",
|
|
4973
|
+
"babel-plugin-",
|
|
4974
|
+
"babel-preset-",
|
|
4975
|
+
"@babel/plugin-",
|
|
4976
|
+
"@babel/preset-",
|
|
4977
|
+
"@fontsource/",
|
|
4978
|
+
"@next/",
|
|
4979
|
+
"@svgr/",
|
|
4980
|
+
"@docusaurus/",
|
|
4981
|
+
"stylelint-config-",
|
|
4982
|
+
"stylelint-plugin-"
|
|
4983
|
+
];
|
|
4619
4984
|
const isAlwaysConsideredUsed = (dependencyName) => {
|
|
4620
4985
|
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;
|
|
4986
|
+
return ALWAYS_USED_PREFIXES.some((prefix) => dependencyName.startsWith(prefix));
|
|
4626
4987
|
};
|
|
4627
4988
|
|
|
4628
4989
|
//#endregion
|
package/dist/index.mjs
CHANGED
|
@@ -135,7 +135,19 @@ const IMPLICIT_DEPENDENCIES = new Set([
|
|
|
135
135
|
"prettier",
|
|
136
136
|
"husky",
|
|
137
137
|
"lint-staged",
|
|
138
|
-
"tslib"
|
|
138
|
+
"tslib",
|
|
139
|
+
"@babel/core",
|
|
140
|
+
"postcss",
|
|
141
|
+
"cross-env",
|
|
142
|
+
"sass",
|
|
143
|
+
"node-sass",
|
|
144
|
+
"less",
|
|
145
|
+
"oxlint",
|
|
146
|
+
"biome",
|
|
147
|
+
"@biomejs/biome",
|
|
148
|
+
"patch-package",
|
|
149
|
+
"simple-git-hooks",
|
|
150
|
+
"lefthook"
|
|
139
151
|
]);
|
|
140
152
|
const BUILTIN_MODULES = new Set([
|
|
141
153
|
"assert",
|
|
@@ -1847,7 +1859,9 @@ const extractPackageJsonEntries = async (packageJsonPath) => {
|
|
|
1847
1859
|
"module",
|
|
1848
1860
|
"browser",
|
|
1849
1861
|
"types",
|
|
1850
|
-
"typings"
|
|
1862
|
+
"typings",
|
|
1863
|
+
"style",
|
|
1864
|
+
"source"
|
|
1851
1865
|
]) if (typeof packageJson[field] === "string") entries.push(resolveEntryPath(packageJson[field], rootDir));
|
|
1852
1866
|
if (packageJson.exports) {
|
|
1853
1867
|
const exportEntries = [];
|
|
@@ -2647,7 +2661,9 @@ const TEST_FRAMEWORK_PATTERNS = [
|
|
|
2647
2661
|
enablers: [
|
|
2648
2662
|
"jest",
|
|
2649
2663
|
"@jest/core",
|
|
2650
|
-
"ts-jest"
|
|
2664
|
+
"ts-jest",
|
|
2665
|
+
"react-scripts",
|
|
2666
|
+
"react-app-rewired"
|
|
2651
2667
|
],
|
|
2652
2668
|
configFileActivators: [
|
|
2653
2669
|
"jest.config.ts",
|
|
@@ -2892,6 +2908,51 @@ const FRAMEWORK_PATTERNS = [
|
|
|
2892
2908
|
],
|
|
2893
2909
|
contentIgnorePatterns: ["versioned_sidebars/**"]
|
|
2894
2910
|
},
|
|
2911
|
+
{
|
|
2912
|
+
enablers: [
|
|
2913
|
+
"fumadocs-core",
|
|
2914
|
+
"fumadocs-ui",
|
|
2915
|
+
"fumadocs-mdx"
|
|
2916
|
+
],
|
|
2917
|
+
enablerPrefixes: ["fumadocs-"],
|
|
2918
|
+
entryPatterns: ["content/**/*.{md,mdx}", "content/**/*.{ts,tsx,js,jsx}"],
|
|
2919
|
+
alwaysUsed: ["source.config.{ts,js,mjs}"]
|
|
2920
|
+
},
|
|
2921
|
+
{
|
|
2922
|
+
enablers: [
|
|
2923
|
+
"nextra",
|
|
2924
|
+
"nextra-theme-docs",
|
|
2925
|
+
"nextra-theme-blog"
|
|
2926
|
+
],
|
|
2927
|
+
enablerPrefixes: ["nextra-"],
|
|
2928
|
+
entryPatterns: [
|
|
2929
|
+
"pages/**/*.{md,mdx}",
|
|
2930
|
+
"src/pages/**/*.{md,mdx}",
|
|
2931
|
+
"content/**/*.{md,mdx}"
|
|
2932
|
+
],
|
|
2933
|
+
alwaysUsed: []
|
|
2934
|
+
},
|
|
2935
|
+
{
|
|
2936
|
+
enablers: [
|
|
2937
|
+
"contentlayer",
|
|
2938
|
+
"contentlayer2",
|
|
2939
|
+
"contentlayer-source-files"
|
|
2940
|
+
],
|
|
2941
|
+
enablerPrefixes: ["contentlayer"],
|
|
2942
|
+
entryPatterns: ["content/**/*.{md,mdx}", "posts/**/*.{md,mdx}"],
|
|
2943
|
+
alwaysUsed: ["contentlayer.config.{ts,js,mjs}"]
|
|
2944
|
+
},
|
|
2945
|
+
{
|
|
2946
|
+
enablers: ["@graphql-codegen/cli", "@graphql-codegen/core"],
|
|
2947
|
+
enablerPrefixes: ["@graphql-codegen/"],
|
|
2948
|
+
entryPatterns: ["**/*.graphql", "**/*.gql"],
|
|
2949
|
+
alwaysUsed: [
|
|
2950
|
+
"codegen.{ts,js,yml,yaml}",
|
|
2951
|
+
"codegen.config.{ts,js}",
|
|
2952
|
+
".graphqlrc.{ts,js,json,yml,yaml}",
|
|
2953
|
+
"graphql.config.{ts,js,json,yml,yaml}"
|
|
2954
|
+
]
|
|
2955
|
+
},
|
|
2895
2956
|
{
|
|
2896
2957
|
enablers: ["eslint", "@eslint/js"],
|
|
2897
2958
|
enablerPrefixes: [],
|
|
@@ -4450,6 +4511,16 @@ const detectDeadExports = (graph, config) => {
|
|
|
4450
4511
|
const buildUsageMap = (graph) => {
|
|
4451
4512
|
const usedExportKeys = /* @__PURE__ */ new Set();
|
|
4452
4513
|
const sourceToTargetMap = buildSourceToTargetsMap(graph);
|
|
4514
|
+
for (const module of graph.modules) {
|
|
4515
|
+
if (!module.isEntryPoint) continue;
|
|
4516
|
+
for (const edge of graph.edges) {
|
|
4517
|
+
if (edge.source !== module.fileId.index || !edge.isReExportEdge) continue;
|
|
4518
|
+
const targetModule = graph.modules[edge.target];
|
|
4519
|
+
if (!targetModule) continue;
|
|
4520
|
+
if (edge.reExportedNames.includes("*")) markAllExportsUsedRecursive(targetModule, graph, sourceToTargetMap, usedExportKeys, /* @__PURE__ */ new Set());
|
|
4521
|
+
else for (const mapping of edge.reExportMappings) markExportUsedRecursive(targetModule.fileId.path, mapping.originalName, graph, sourceToTargetMap, usedExportKeys, /* @__PURE__ */ new Set());
|
|
4522
|
+
}
|
|
4523
|
+
}
|
|
4453
4524
|
for (const edge of graph.edges) {
|
|
4454
4525
|
const targetModule = graph.modules[edge.target];
|
|
4455
4526
|
if (!targetModule) continue;
|
|
@@ -4553,6 +4624,23 @@ const extractPackageName = (specifier) => {
|
|
|
4553
4624
|
|
|
4554
4625
|
//#endregion
|
|
4555
4626
|
//#region src/report/packages.ts
|
|
4627
|
+
const discoverAllPackageJsonPaths = (rootDir) => {
|
|
4628
|
+
const paths = [join(rootDir, "package.json")];
|
|
4629
|
+
const workspacePackageJsons = fg.sync("**/package.json", {
|
|
4630
|
+
cwd: rootDir,
|
|
4631
|
+
absolute: true,
|
|
4632
|
+
onlyFiles: true,
|
|
4633
|
+
ignore: [
|
|
4634
|
+
"**/node_modules/**",
|
|
4635
|
+
"**/dist/**",
|
|
4636
|
+
"**/build/**",
|
|
4637
|
+
"**/.git/**"
|
|
4638
|
+
],
|
|
4639
|
+
deep: 5
|
|
4640
|
+
});
|
|
4641
|
+
for (const workspacePath of workspacePackageJsons) if (workspacePath !== paths[0] && !paths.includes(workspacePath)) paths.push(workspacePath);
|
|
4642
|
+
return paths;
|
|
4643
|
+
};
|
|
4556
4644
|
const detectStalePackages = (graph, config) => {
|
|
4557
4645
|
const packageJsonPath = resolve(config.rootDir, "package.json");
|
|
4558
4646
|
let packageJson;
|
|
@@ -4567,7 +4655,28 @@ const detectStalePackages = (graph, config) => {
|
|
|
4567
4655
|
const declaredDependencies = /* @__PURE__ */ new Map();
|
|
4568
4656
|
for (const dependencyName of Object.keys(dependencies)) declaredDependencies.set(dependencyName, false);
|
|
4569
4657
|
for (const dependencyName of Object.keys(devDependencies)) declaredDependencies.set(dependencyName, true);
|
|
4658
|
+
const declaredNames = new Set(declaredDependencies.keys());
|
|
4570
4659
|
const usedPackageNames = collectUsedPackages(graph);
|
|
4660
|
+
const allPackageJsonPaths = discoverAllPackageJsonPaths(config.rootDir);
|
|
4661
|
+
const binToPackage = buildBinToPackageMap(config.rootDir, declaredNames);
|
|
4662
|
+
for (const workspacePackageJsonPath of allPackageJsonPaths) {
|
|
4663
|
+
const scriptReferenced = collectScriptReferencedPackages(workspacePackageJsonPath, declaredNames, binToPackage);
|
|
4664
|
+
for (const packageName of scriptReferenced) usedPackageNames.add(packageName);
|
|
4665
|
+
const packageJsonConfigReferenced = collectPackageJsonConfigReferences(workspacePackageJsonPath, declaredNames);
|
|
4666
|
+
for (const packageName of packageJsonConfigReferenced) usedPackageNames.add(packageName);
|
|
4667
|
+
}
|
|
4668
|
+
const configReferenced = collectConfigReferencedPackages(config.rootDir, graph, declaredNames);
|
|
4669
|
+
for (const packageName of configReferenced) usedPackageNames.add(packageName);
|
|
4670
|
+
const tsconfigReferenced = collectTsconfigReferencedPackages(config.rootDir);
|
|
4671
|
+
for (const packageName of tsconfigReferenced) usedPackageNames.add(packageName);
|
|
4672
|
+
if (hasJsxFiles(graph)) {
|
|
4673
|
+
if (declaredNames.has("react")) usedPackageNames.add("react");
|
|
4674
|
+
if (declaredNames.has("react-dom")) usedPackageNames.add("react-dom");
|
|
4675
|
+
if (declaredNames.has("react-native")) usedPackageNames.add("react-native");
|
|
4676
|
+
if (declaredNames.has("react-native-web")) usedPackageNames.add("react-native-web");
|
|
4677
|
+
}
|
|
4678
|
+
const peerSatisfied = collectPeerSatisfiedPackages(config.rootDir, declaredNames, usedPackageNames);
|
|
4679
|
+
for (const packageName of peerSatisfied) usedPackageNames.add(packageName);
|
|
4571
4680
|
const unusedDependencies = [];
|
|
4572
4681
|
for (const [dependencyName, isDevDependency] of declaredDependencies) {
|
|
4573
4682
|
if (isAlwaysConsideredUsed(dependencyName)) continue;
|
|
@@ -4586,13 +4695,265 @@ const collectUsedPackages = (graph) => {
|
|
|
4586
4695
|
}
|
|
4587
4696
|
return usedPackages;
|
|
4588
4697
|
};
|
|
4698
|
+
const hasJsxFiles = (graph) => graph.modules.some((module) => {
|
|
4699
|
+
const filePath = module.fileId.path;
|
|
4700
|
+
return filePath.endsWith(".tsx") || filePath.endsWith(".jsx");
|
|
4701
|
+
});
|
|
4702
|
+
const collectPeerSatisfiedPackages = (rootDir, declaredNames, confirmedUsedNames) => {
|
|
4703
|
+
const peerSatisfied = /* @__PURE__ */ new Set();
|
|
4704
|
+
const nodeModulesDir = join(rootDir, "node_modules");
|
|
4705
|
+
for (const installedName of declaredNames) {
|
|
4706
|
+
if (!confirmedUsedNames.has(installedName)) continue;
|
|
4707
|
+
const packageJsonPath = installedName.startsWith("@") ? join(nodeModulesDir, ...installedName.split("/"), "package.json") : join(nodeModulesDir, installedName, "package.json");
|
|
4708
|
+
try {
|
|
4709
|
+
const content = readFileSync(packageJsonPath, "utf-8");
|
|
4710
|
+
const peerDeps = JSON.parse(content).peerDependencies;
|
|
4711
|
+
if (peerDeps && typeof peerDeps === "object") {
|
|
4712
|
+
for (const peerName of Object.keys(peerDeps)) if (declaredNames.has(peerName)) peerSatisfied.add(peerName);
|
|
4713
|
+
}
|
|
4714
|
+
} catch {
|
|
4715
|
+
continue;
|
|
4716
|
+
}
|
|
4717
|
+
}
|
|
4718
|
+
return peerSatisfied;
|
|
4719
|
+
};
|
|
4720
|
+
const SHELL_SPLIT_PATTERN = /\s*(?:&&|\|\||[;&|])\s*/;
|
|
4721
|
+
const CLI_BINARY_TO_PACKAGE = {
|
|
4722
|
+
"react-scripts": "react-scripts",
|
|
4723
|
+
"webpack-cli": "webpack-cli",
|
|
4724
|
+
"webpack-dev-server": "webpack-dev-server",
|
|
4725
|
+
vitest: "vitest",
|
|
4726
|
+
jest: "jest",
|
|
4727
|
+
prisma: "prisma",
|
|
4728
|
+
sequelize: "sequelize-cli",
|
|
4729
|
+
rimraf: "rimraf",
|
|
4730
|
+
concurrently: "concurrently",
|
|
4731
|
+
parcel: "parcel",
|
|
4732
|
+
rescript: "rescript",
|
|
4733
|
+
webstudio: "webstudio",
|
|
4734
|
+
cap: "@capacitor/cli",
|
|
4735
|
+
"source-map-explorer": "source-map-explorer",
|
|
4736
|
+
"ts-standard": "ts-standard",
|
|
4737
|
+
"rndebugger-open": "react-native-debugger-open",
|
|
4738
|
+
"simple-git-hooks": "simple-git-hooks",
|
|
4739
|
+
"generate-arg-types": "@webstudio-is/generate-arg-types",
|
|
4740
|
+
email: "@react-email/preview-server"
|
|
4741
|
+
};
|
|
4742
|
+
const ENV_WRAPPER_BINARY_SET = new Set([
|
|
4743
|
+
"cross-env",
|
|
4744
|
+
"dotenv",
|
|
4745
|
+
"dotenv-flow",
|
|
4746
|
+
"env-cmd"
|
|
4747
|
+
]);
|
|
4748
|
+
const INLINE_ENV_VAR_PATTERN = /^[A-Z_][A-Z0-9_]*=/;
|
|
4749
|
+
const buildBinToPackageMap = (rootDir, declaredNames) => {
|
|
4750
|
+
const binToPackage = /* @__PURE__ */ new Map();
|
|
4751
|
+
for (const [binary, packageName] of Object.entries(CLI_BINARY_TO_PACKAGE)) binToPackage.set(binary, packageName);
|
|
4752
|
+
for (const packageName of declaredNames) {
|
|
4753
|
+
const packageBinJsonPath = packageName.startsWith("@") ? join(rootDir, "node_modules", ...packageName.split("/"), "package.json") : join(rootDir, "node_modules", packageName, "package.json");
|
|
4754
|
+
try {
|
|
4755
|
+
const binContent = readFileSync(packageBinJsonPath, "utf-8");
|
|
4756
|
+
const binPackageJson = JSON.parse(binContent);
|
|
4757
|
+
if (typeof binPackageJson.bin === "string") binToPackage.set(packageName.split("/").pop(), packageName);
|
|
4758
|
+
else if (typeof binPackageJson.bin === "object" && binPackageJson.bin !== null) for (const binaryName of Object.keys(binPackageJson.bin)) binToPackage.set(binaryName, packageName);
|
|
4759
|
+
} catch {
|
|
4760
|
+
continue;
|
|
4761
|
+
}
|
|
4762
|
+
}
|
|
4763
|
+
return binToPackage;
|
|
4764
|
+
};
|
|
4765
|
+
const collectScriptReferencedPackages = (packageJsonPath, declaredNames, binToPackage) => {
|
|
4766
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
4767
|
+
try {
|
|
4768
|
+
const content = readFileSync(packageJsonPath, "utf-8");
|
|
4769
|
+
const scripts = JSON.parse(content).scripts;
|
|
4770
|
+
if (!scripts || typeof scripts !== "object") return referenced;
|
|
4771
|
+
for (const scriptCommand of Object.values(scripts)) {
|
|
4772
|
+
if (typeof scriptCommand !== "string") continue;
|
|
4773
|
+
const segments = scriptCommand.split(SHELL_SPLIT_PATTERN);
|
|
4774
|
+
for (const segment of segments) {
|
|
4775
|
+
const tokens = segment.trim().split(/\s+/);
|
|
4776
|
+
if (tokens.length === 0) continue;
|
|
4777
|
+
let binaryIndex = 0;
|
|
4778
|
+
const firstToken = tokens[0].replace(/^.*\//, "");
|
|
4779
|
+
if (ENV_WRAPPER_BINARY_SET.has(firstToken)) {
|
|
4780
|
+
const envPackage = binToPackage.get(firstToken);
|
|
4781
|
+
if (envPackage && declaredNames.has(envPackage)) referenced.add(envPackage);
|
|
4782
|
+
binaryIndex = 1;
|
|
4783
|
+
while (binaryIndex < tokens.length && INLINE_ENV_VAR_PATTERN.test(tokens[binaryIndex])) binaryIndex++;
|
|
4784
|
+
if (binaryIndex >= tokens.length) continue;
|
|
4785
|
+
}
|
|
4786
|
+
while (binaryIndex < tokens.length && INLINE_ENV_VAR_PATTERN.test(tokens[binaryIndex])) binaryIndex++;
|
|
4787
|
+
if (binaryIndex >= tokens.length) continue;
|
|
4788
|
+
const binaryToken = tokens[binaryIndex].replace(/^.*\//, "");
|
|
4789
|
+
const effectiveBinary = binaryToken === "npx" || binaryToken === "pnpx" || binaryToken === "bunx" ? tokens[binaryIndex + 1]?.replace(/^.*\//, "") ?? "" : binaryToken;
|
|
4790
|
+
for (const candidateBinary of [binaryToken, effectiveBinary]) {
|
|
4791
|
+
if (!candidateBinary) continue;
|
|
4792
|
+
const mappedPackage = binToPackage.get(candidateBinary);
|
|
4793
|
+
if (mappedPackage && declaredNames.has(mappedPackage)) referenced.add(mappedPackage);
|
|
4794
|
+
if (declaredNames.has(candidateBinary)) referenced.add(candidateBinary);
|
|
4795
|
+
}
|
|
4796
|
+
}
|
|
4797
|
+
}
|
|
4798
|
+
} catch {
|
|
4799
|
+
return referenced;
|
|
4800
|
+
}
|
|
4801
|
+
return referenced;
|
|
4802
|
+
};
|
|
4803
|
+
const CONFIG_FILE_GLOBS = [
|
|
4804
|
+
"postcss.config.{js,cjs,mjs,ts}",
|
|
4805
|
+
".babelrc",
|
|
4806
|
+
".babelrc.{js,cjs,mjs,json}",
|
|
4807
|
+
"babel.config.{js,cjs,mjs,json,ts}",
|
|
4808
|
+
".eslintrc",
|
|
4809
|
+
".eslintrc.{js,cjs,mjs,json,yaml,yml}",
|
|
4810
|
+
"eslint.config.{js,cjs,mjs,ts,mts,cts}",
|
|
4811
|
+
"webpack.config.{js,ts,mjs,cjs}",
|
|
4812
|
+
"**/webpack*.config.{js,ts,mjs,cjs}",
|
|
4813
|
+
"vite.config.{js,ts,mjs,mts}",
|
|
4814
|
+
"rollup.config.{js,ts,mjs,cjs}",
|
|
4815
|
+
".storybook/main.{js,ts,mjs,cjs}",
|
|
4816
|
+
"docusaurus.config.{js,ts,mjs}",
|
|
4817
|
+
"next.config.{js,ts,mjs,mts}",
|
|
4818
|
+
"tailwind.config.{js,ts,cjs,mjs}",
|
|
4819
|
+
"jest.config.{js,ts,mjs,cjs}",
|
|
4820
|
+
"vitest.config.{js,ts,mjs,mts}",
|
|
4821
|
+
"app.json",
|
|
4822
|
+
"forge.config.{js,ts,cjs}",
|
|
4823
|
+
"wrangler.toml",
|
|
4824
|
+
"wrangler.json",
|
|
4825
|
+
"wrangler.jsonc",
|
|
4826
|
+
"metro.config.{js,ts}",
|
|
4827
|
+
"electron.vite.config.{js,ts,mjs}",
|
|
4828
|
+
"api-extractor.json"
|
|
4829
|
+
];
|
|
4830
|
+
const collectConfigReferencedPackages = (rootDir, graph, declaredNames) => {
|
|
4831
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
4832
|
+
for (const module of graph.modules) {
|
|
4833
|
+
if (!module.isConfigFile) continue;
|
|
4834
|
+
try {
|
|
4835
|
+
const content = readFileSync(module.fileId.path, "utf-8");
|
|
4836
|
+
for (const packageName of declaredNames) if (content.includes(packageName)) referenced.add(packageName);
|
|
4837
|
+
} catch {
|
|
4838
|
+
continue;
|
|
4839
|
+
}
|
|
4840
|
+
}
|
|
4841
|
+
const configFiles = fg.sync(CONFIG_FILE_GLOBS, {
|
|
4842
|
+
cwd: rootDir,
|
|
4843
|
+
absolute: true,
|
|
4844
|
+
onlyFiles: true,
|
|
4845
|
+
ignore: ["**/node_modules/**"],
|
|
4846
|
+
dot: true,
|
|
4847
|
+
deep: 3
|
|
4848
|
+
});
|
|
4849
|
+
for (const configPath of configFiles) try {
|
|
4850
|
+
const content = readFileSync(configPath, "utf-8");
|
|
4851
|
+
for (const packageName of declaredNames) if (content.includes(packageName)) referenced.add(packageName);
|
|
4852
|
+
} catch {
|
|
4853
|
+
continue;
|
|
4854
|
+
}
|
|
4855
|
+
return referenced;
|
|
4856
|
+
};
|
|
4857
|
+
const PACKAGE_JSON_CONFIG_SECTIONS = [
|
|
4858
|
+
"jest",
|
|
4859
|
+
"babel",
|
|
4860
|
+
"eslintConfig",
|
|
4861
|
+
"prettier",
|
|
4862
|
+
"stylelint",
|
|
4863
|
+
"lint-staged",
|
|
4864
|
+
"commitlint",
|
|
4865
|
+
"browserslist",
|
|
4866
|
+
"postcss",
|
|
4867
|
+
"ava"
|
|
4868
|
+
];
|
|
4869
|
+
const collectPackageJsonConfigReferences = (packageJsonPath, declaredNames) => {
|
|
4870
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
4871
|
+
try {
|
|
4872
|
+
const content = readFileSync(packageJsonPath, "utf-8");
|
|
4873
|
+
const packageJson = JSON.parse(content);
|
|
4874
|
+
for (const sectionName of PACKAGE_JSON_CONFIG_SECTIONS) {
|
|
4875
|
+
const sectionValue = packageJson[sectionName];
|
|
4876
|
+
if (!sectionValue || typeof sectionValue !== "object") continue;
|
|
4877
|
+
const sectionText = JSON.stringify(sectionValue);
|
|
4878
|
+
for (const packageName of declaredNames) if (sectionText.includes(packageName)) referenced.add(packageName);
|
|
4879
|
+
}
|
|
4880
|
+
} catch {
|
|
4881
|
+
return referenced;
|
|
4882
|
+
}
|
|
4883
|
+
return referenced;
|
|
4884
|
+
};
|
|
4885
|
+
const TSCONFIG_GLOBS = [
|
|
4886
|
+
"tsconfig.json",
|
|
4887
|
+
"tsconfig.*.json",
|
|
4888
|
+
"jsconfig.json",
|
|
4889
|
+
"**/tsconfig.json",
|
|
4890
|
+
"**/tsconfig.*.json"
|
|
4891
|
+
];
|
|
4892
|
+
const collectTsconfigReferencedPackages = (rootDir) => {
|
|
4893
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
4894
|
+
const tsconfigFiles = fg.sync(TSCONFIG_GLOBS, {
|
|
4895
|
+
cwd: rootDir,
|
|
4896
|
+
absolute: true,
|
|
4897
|
+
onlyFiles: true,
|
|
4898
|
+
ignore: ["**/node_modules/**"],
|
|
4899
|
+
dot: false,
|
|
4900
|
+
deep: 4
|
|
4901
|
+
});
|
|
4902
|
+
for (const tsconfigPath of tsconfigFiles) try {
|
|
4903
|
+
const cleaned = readFileSync(tsconfigPath, "utf-8").replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
4904
|
+
const parsed = JSON.parse(cleaned);
|
|
4905
|
+
if (typeof parsed.extends === "string") {
|
|
4906
|
+
const extendsPackage = extractExtendsPackageName(parsed.extends);
|
|
4907
|
+
if (extendsPackage) referenced.add(extendsPackage);
|
|
4908
|
+
}
|
|
4909
|
+
if (Array.isArray(parsed.extends)) {
|
|
4910
|
+
for (const extendsEntry of parsed.extends) if (typeof extendsEntry === "string") {
|
|
4911
|
+
const extendsPackage = extractExtendsPackageName(extendsEntry);
|
|
4912
|
+
if (extendsPackage) referenced.add(extendsPackage);
|
|
4913
|
+
}
|
|
4914
|
+
}
|
|
4915
|
+
const compilerOptions = parsed.compilerOptions;
|
|
4916
|
+
if (compilerOptions?.jsxImportSource && typeof compilerOptions.jsxImportSource === "string") referenced.add(compilerOptions.jsxImportSource);
|
|
4917
|
+
if (Array.isArray(compilerOptions?.types)) {
|
|
4918
|
+
for (const typesEntry of compilerOptions.types) if (typeof typesEntry === "string") {
|
|
4919
|
+
const typesPackage = extractPackageName(typesEntry);
|
|
4920
|
+
if (typesPackage) referenced.add(typesPackage);
|
|
4921
|
+
}
|
|
4922
|
+
}
|
|
4923
|
+
} catch {
|
|
4924
|
+
continue;
|
|
4925
|
+
}
|
|
4926
|
+
return referenced;
|
|
4927
|
+
};
|
|
4928
|
+
const extractExtendsPackageName = (extendsValue) => {
|
|
4929
|
+
if (extendsValue.startsWith(".") || extendsValue.startsWith("/")) return void 0;
|
|
4930
|
+
if (extendsValue.startsWith("@")) {
|
|
4931
|
+
const parts = extendsValue.split("/");
|
|
4932
|
+
return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : void 0;
|
|
4933
|
+
}
|
|
4934
|
+
return extendsValue.split("/")[0];
|
|
4935
|
+
};
|
|
4936
|
+
const ALWAYS_USED_PREFIXES = [
|
|
4937
|
+
"@types/",
|
|
4938
|
+
"eslint-config-",
|
|
4939
|
+
"eslint-plugin-",
|
|
4940
|
+
"@eslint/",
|
|
4941
|
+
"prettier-plugin-",
|
|
4942
|
+
"@commitlint/",
|
|
4943
|
+
"babel-plugin-",
|
|
4944
|
+
"babel-preset-",
|
|
4945
|
+
"@babel/plugin-",
|
|
4946
|
+
"@babel/preset-",
|
|
4947
|
+
"@fontsource/",
|
|
4948
|
+
"@next/",
|
|
4949
|
+
"@svgr/",
|
|
4950
|
+
"@docusaurus/",
|
|
4951
|
+
"stylelint-config-",
|
|
4952
|
+
"stylelint-plugin-"
|
|
4953
|
+
];
|
|
4589
4954
|
const isAlwaysConsideredUsed = (dependencyName) => {
|
|
4590
4955
|
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;
|
|
4956
|
+
return ALWAYS_USED_PREFIXES.some((prefix) => dependencyName.startsWith(prefix));
|
|
4596
4957
|
};
|
|
4597
4958
|
|
|
4598
4959
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deslop-js",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
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": {
|