qleaner 1.0.11 → 1.0.12
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/bin/cli.js +20 -26
- package/command.js +152 -109
- package/controllers/list.js +60 -0
- package/package.json +4 -2
- package/unused-check-cache.json +180 -0
- package/utils/cache.js +38 -0
- package/utils/resolver.js +32 -0
- package/utils/utils.js +0 -1
package/bin/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
const { Command } = require("commander");
|
|
3
|
-
const {
|
|
4
|
-
|
|
3
|
+
const { list, scan } = require("../controllers/list");
|
|
4
|
+
|
|
5
5
|
|
|
6
6
|
async function loadChalk() {
|
|
7
7
|
return (await import("chalk")).default;
|
|
@@ -31,13 +31,7 @@ async function loadChalk() {
|
|
|
31
31
|
)
|
|
32
32
|
.option("-t, --table", "Print the results in a table")
|
|
33
33
|
.action(async (path, options) => {
|
|
34
|
-
|
|
35
|
-
if(options.table){
|
|
36
|
-
console.log(chalk.yellow('***************** Imported Files *****************'));
|
|
37
|
-
console.log(tableImports.toString());
|
|
38
|
-
console.log(chalk.green('***************** List Files *****************'));
|
|
39
|
-
console.log(tableFiles.toString());
|
|
40
|
-
}
|
|
34
|
+
await list(chalk, path, options);
|
|
41
35
|
});
|
|
42
36
|
|
|
43
37
|
program
|
|
@@ -51,24 +45,24 @@ async function loadChalk() {
|
|
|
51
45
|
"Scan but don't print the excluded files"
|
|
52
46
|
)
|
|
53
47
|
.option("-t, --table", "Print the results in a table")
|
|
48
|
+
.option("-d, --dry-run", "Show what would be deleted without actually deleting (skips prompt)")
|
|
54
49
|
.action(async (path, options) => {
|
|
55
|
-
|
|
56
|
-
// console.clear()
|
|
57
|
-
if(options.table){
|
|
58
|
-
const table = new Table({
|
|
59
|
-
head: ['Unused Files'],
|
|
60
|
-
colWidths: [50]
|
|
61
|
-
})
|
|
62
|
-
unusedFiles.forEach(file => {
|
|
63
|
-
table.push([file])
|
|
64
|
-
})
|
|
65
|
-
console.log(table.toString())
|
|
66
|
-
|
|
67
|
-
}else {
|
|
68
|
-
unusedFiles.forEach((file) => {
|
|
69
|
-
console.log(chalk.red(file));
|
|
70
|
-
});
|
|
71
|
-
}
|
|
50
|
+
await scan(chalk, path, options);
|
|
72
51
|
});
|
|
52
|
+
|
|
53
|
+
program
|
|
54
|
+
.command('qlean-image')
|
|
55
|
+
.description("Scan the project for unused images")
|
|
56
|
+
.argument("<path>", "The path to the directory to scan for unused images")
|
|
57
|
+
.option("-e, --exclude-dir <dir...>", "Exclude directories from the scan")
|
|
58
|
+
.option("-f, --exclude-file <file...>", "Exclude files from the scan")
|
|
59
|
+
.option(
|
|
60
|
+
"-F, --exclude-file-print <files...>",
|
|
61
|
+
"Scan but don't print the excluded files"
|
|
62
|
+
)
|
|
63
|
+
.option("-t, --table", "Print the results in a table")
|
|
64
|
+
.action(async (path, options) => {
|
|
65
|
+
|
|
66
|
+
});
|
|
73
67
|
program.parse(process.argv);
|
|
74
68
|
})();
|
package/command.js
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
const fg = require("fast-glob");
|
|
2
2
|
const fs = require("fs");
|
|
3
|
-
const Table = require(
|
|
3
|
+
const Table = require("cli-table3");
|
|
4
4
|
const parser = require("@babel/parser");
|
|
5
5
|
const traverse = require("@babel/traverse").default;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
const path = require("path");
|
|
7
|
+
const { createResolver } = require("./utils/resolver");
|
|
8
|
+
const { loadCache, getFileHash, needsRebuild, saveCache } = require("./utils/cache");
|
|
9
9
|
|
|
10
10
|
async function getFiles(directory = "src", options, chalk) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
11
|
+
const contentPaths = [`${directory}/**/*.{tsx,ts,js,jsx}`];
|
|
12
|
+
if (options.excludeDir && options.excludeDir.length > 0) {
|
|
13
|
+
options.excludeDir.forEach((dir) => {
|
|
14
|
+
contentPaths.push(`!${dir}/**`);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
if (options.excludeFile && options.excludeFile.length > 0) {
|
|
18
|
+
options.excludeFile.forEach((file) => {
|
|
19
|
+
contentPaths.push(`!${directory}/**/${file}`);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const files = await fg(contentPaths);
|
|
23
24
|
const imports = [];
|
|
24
25
|
for (const file of files) {
|
|
25
26
|
const code = fs.readFileSync(file, "utf8");
|
|
@@ -30,13 +31,12 @@ async function getFiles(directory = "src", options, chalk) {
|
|
|
30
31
|
traverse(ast, {
|
|
31
32
|
ImportDeclaration: ({ node }) => {
|
|
32
33
|
imports.push({
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
from: node.source.value,
|
|
35
|
+
file: file,
|
|
36
|
+
line: node.loc.start.line,
|
|
37
|
+
column: node.loc.start.column,
|
|
37
38
|
});
|
|
38
39
|
},
|
|
39
|
-
|
|
40
40
|
});
|
|
41
41
|
// ExportNamedDeclaration: ({ node }) => {
|
|
42
42
|
// if (node.declaration.declarations && node.declaration.declarations[0].id && node.declaration.declarations[0].id.name) {
|
|
@@ -51,123 +51,166 @@ async function getFiles(directory = "src", options, chalk) {
|
|
|
51
51
|
// },
|
|
52
52
|
// });
|
|
53
53
|
}
|
|
54
|
-
|
|
54
|
+
|
|
55
55
|
if (options.table) {
|
|
56
56
|
const tableImports = new Table({
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
head: ["File", "Line", "Column", "Import"],
|
|
58
|
+
colWidths: [20, 10, 10, 20],
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const tableFiles = new Table({
|
|
62
|
+
head: ["File"],
|
|
63
|
+
colWidths: [20],
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
if (options.listFiles) {
|
|
67
|
+
files.forEach((file) => {
|
|
68
|
+
tableFiles.push([file]);
|
|
59
69
|
});
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
70
|
+
}
|
|
71
|
+
if (options.listImports) {
|
|
72
|
+
imports.forEach((importStatement) => {
|
|
73
|
+
tableImports.push([
|
|
74
|
+
importStatement.file,
|
|
75
|
+
importStatement.line,
|
|
76
|
+
importStatement.column,
|
|
77
|
+
importStatement.from,
|
|
78
|
+
]);
|
|
64
79
|
});
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
tableFiles.push([file]);
|
|
69
|
-
})
|
|
70
|
-
}
|
|
71
|
-
if (options.listImports) {
|
|
72
|
-
imports.forEach((importStatement) => {
|
|
73
|
-
tableImports.push([importStatement.file, importStatement.line, importStatement.column, importStatement.from]);
|
|
74
|
-
})
|
|
75
|
-
}
|
|
76
|
-
return { tableImports, tableFiles };
|
|
77
|
-
}else{
|
|
80
|
+
}
|
|
81
|
+
return { tableImports, tableFiles };
|
|
82
|
+
} else {
|
|
78
83
|
if (options.listFiles) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
84
|
+
console.log(chalk.green("***************** Files *****************"));
|
|
85
|
+
files.forEach((file) => {
|
|
86
|
+
console.log(chalk.green(file));
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
if (options.listImports) {
|
|
90
|
+
console.log(chalk.yellow("***************** Imports *****************"));
|
|
91
|
+
imports.forEach((importStatement) => {
|
|
92
|
+
console.log(
|
|
93
|
+
chalk.yellow(
|
|
94
|
+
`${importStatement.file}:${importStatement.line}:${importStatement.column} ${importStatement.from}`
|
|
95
|
+
)
|
|
96
|
+
);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return { tableImports: imports, tableFiles: files };
|
|
90
100
|
}
|
|
91
101
|
}
|
|
92
102
|
|
|
93
|
-
async function unUsedFiles(directory = "src", options) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
103
|
+
async function unUsedFiles(chalk, directory = "src", options) {
|
|
104
|
+
console.time('unUsedFiles');
|
|
105
|
+
const resolver = createResolver(directory);
|
|
106
|
+
const cache = loadCache(process.cwd());
|
|
107
|
+
const contentPaths = [`${directory}/**/*.{tsx,ts,js,jsx}`];
|
|
108
|
+
if (options.excludeDir && options.excludeDir.length > 0) {
|
|
109
|
+
options.excludeDir.forEach((dir) => {
|
|
110
|
+
contentPaths.push(`!${dir}/**`);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
if (options.excludeFile && options.excludeFile.length > 0) {
|
|
114
|
+
options.excludeFile.forEach((file) => {
|
|
115
|
+
contentPaths.push(`!${directory}/**/${file}`);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const files = await fg(contentPaths);
|
|
120
|
+
const imports = [];
|
|
121
|
+
const unusedFiles = [];
|
|
122
|
+
|
|
123
|
+
// debug log
|
|
124
|
+
// let debugCount = 0;
|
|
125
|
+
// console.log('total files---', files.length);
|
|
126
|
+
for (const file of files) {
|
|
127
|
+
const code = fs.readFileSync(file, "utf8");
|
|
128
|
+
if(needsRebuild(file, code, cache)) {
|
|
111
129
|
const ast = parser.parse(code, {
|
|
112
130
|
sourceType: "module",
|
|
113
|
-
plugins: [
|
|
114
|
-
"jsx",
|
|
115
|
-
"typescript",
|
|
116
|
-
],
|
|
131
|
+
plugins: ["jsx", "typescript"],
|
|
117
132
|
});
|
|
118
|
-
|
|
133
|
+
cache[file] = {
|
|
134
|
+
hash: getFileHash(code),
|
|
135
|
+
imports: [],
|
|
136
|
+
isImported: false,
|
|
137
|
+
lastModified: fs.statSync(file).mtime.getTime(),
|
|
138
|
+
};
|
|
119
139
|
traverse(ast, {
|
|
120
140
|
ImportDeclaration: ({ node }) => {
|
|
121
141
|
imports.push({
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
142
|
+
from: node.source.value,
|
|
143
|
+
file: file,
|
|
144
|
+
line: node.loc.start.line,
|
|
145
|
+
column: node.loc.start.column,
|
|
146
|
+
});
|
|
147
|
+
cache[file].imports.push({
|
|
148
|
+
from: node.source.value,
|
|
149
|
+
file: file,
|
|
150
|
+
line: node.loc.start.line,
|
|
151
|
+
column: node.loc.start.column,
|
|
152
|
+
lastModified: fs.statSync(file).mtime.getTime(),
|
|
126
153
|
});
|
|
127
154
|
},
|
|
128
155
|
});
|
|
156
|
+
}else {
|
|
157
|
+
// debugCount++;
|
|
158
|
+
// console.log('cache hit', debugCount);
|
|
129
159
|
}
|
|
160
|
+
}
|
|
130
161
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
162
|
+
// console.log('imports', imports);
|
|
163
|
+
// console.log('files', files);
|
|
164
|
+
// debugCount = 0;
|
|
165
|
+
// console.log('total files', files.length);
|
|
166
|
+
for (const file of files) {
|
|
167
|
+
const code = fs.readFileSync(file, "utf8");
|
|
168
|
+
if(!cache[file].isImported || needsRebuild(file, code, cache)) {
|
|
169
|
+
let i = 0;
|
|
170
|
+
// console.log('Checking', file);
|
|
171
|
+
let isFound = false;
|
|
172
|
+
while (!isFound && i < imports.length) {
|
|
173
|
+
const importFilePath = await resolver(
|
|
174
|
+
chalk,
|
|
175
|
+
imports[i].file,
|
|
176
|
+
imports[i].from
|
|
177
|
+
);
|
|
178
|
+
// console.log(chalk.blue('importFilePath'), importFilePath);
|
|
179
|
+
if (compareFiles(path.resolve(file), importFilePath)) {
|
|
180
|
+
isFound = true;
|
|
181
|
+
cache[file].isImported = true;
|
|
182
|
+
break;
|
|
183
|
+
} else if (i === imports.length - 1) {
|
|
184
|
+
if (options.excludeFilePrint && options.excludeFilePrint.length > 0) {
|
|
185
|
+
if (!isExcludedFile(file, options.excludeFilePrint)) {
|
|
186
|
+
unusedFiles.push(file);
|
|
151
187
|
}
|
|
152
|
-
|
|
188
|
+
} else {
|
|
189
|
+
unusedFiles.push(file);
|
|
190
|
+
}
|
|
191
|
+
break;
|
|
153
192
|
}
|
|
193
|
+
i++;
|
|
194
|
+
}
|
|
195
|
+
}else {
|
|
196
|
+
// debugCount++;
|
|
197
|
+
// console.log('debug hit', debugCount);
|
|
154
198
|
}
|
|
155
|
-
|
|
199
|
+
}
|
|
200
|
+
console.timeEnd('unUsedFiles');
|
|
201
|
+
saveCache(process.cwd(), cache);
|
|
202
|
+
return unusedFiles;
|
|
156
203
|
}
|
|
157
204
|
|
|
158
205
|
function isExcludedFile(file, excludeFiles) {
|
|
159
|
-
|
|
206
|
+
return excludeFiles.some((exclude) => file.includes(exclude));
|
|
160
207
|
}
|
|
161
208
|
|
|
162
|
-
function compareFiles(filePath, importPath) {
|
|
163
|
-
|
|
164
|
-
const prefixImportPath = importNoExt.replace(/^(?:\.{1,2}\/|[@~]+\/)+/, "");
|
|
165
|
-
// console.log('importNoExt', importNoExt, ' prefixImportPath', prefixImportPath, ' filePath', filePath, ' ', filePath.includes(prefixImportPath));
|
|
166
|
-
|
|
167
|
-
return filePath.includes(prefixImportPath);
|
|
209
|
+
function compareFiles(filePath, importPath) {
|
|
210
|
+
return filePath === importPath;
|
|
168
211
|
}
|
|
169
212
|
|
|
170
213
|
module.exports = {
|
|
171
214
|
getFiles,
|
|
172
215
|
unUsedFiles,
|
|
173
|
-
};
|
|
216
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
const { getFiles, unUsedFiles } = require("../command");
|
|
2
|
+
const Table = require('cli-table3');
|
|
3
|
+
const askDeleteFiles = require("../utils/utils");
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
async function list(chalk, path, options) {
|
|
7
|
+
const { tableImports, tableFiles } = await getFiles(path, options, chalk);
|
|
8
|
+
if(options.table){
|
|
9
|
+
console.log(chalk.yellow('***************** Imported Files *****************'));
|
|
10
|
+
console.log(tableImports.toString());
|
|
11
|
+
console.log(chalk.green('***************** List Files *****************'));
|
|
12
|
+
console.log(tableFiles.toString());
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async function scan(chalk, path, options) {
|
|
17
|
+
const unusedFiles = await unUsedFiles(chalk,path, options);
|
|
18
|
+
// console.clear()
|
|
19
|
+
|
|
20
|
+
if (options.dryRun) {
|
|
21
|
+
console.log(chalk.cyan('\n[DRY RUN MODE] No files will be deleted\n'));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if(options.table){
|
|
25
|
+
const table = new Table({
|
|
26
|
+
head: options.dryRun ? ['Unused Files (Would Delete)'] : ['Unused Files'],
|
|
27
|
+
colWidths: [50]
|
|
28
|
+
})
|
|
29
|
+
unusedFiles.forEach(file => {
|
|
30
|
+
table.push([file])
|
|
31
|
+
})
|
|
32
|
+
console.log(table.toString())
|
|
33
|
+
|
|
34
|
+
}else {
|
|
35
|
+
unusedFiles.forEach((file) => {
|
|
36
|
+
console.log(chalk.red(file));
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (options.dryRun && unusedFiles.length > 0) {
|
|
41
|
+
console.log(chalk.cyan(`\n[DRY RUN] Would delete ${unusedFiles.length} file(s)`));
|
|
42
|
+
console.log(chalk.cyan('Run without --dry-run to actually delete files\n'));
|
|
43
|
+
} else if (!options.dryRun && unusedFiles.length > 0) {
|
|
44
|
+
askDeleteFiles(unusedFiles);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function image(chalk, path, options) {
|
|
49
|
+
const unusedImages = await unUsedImages(chalk,path, options);
|
|
50
|
+
if(options.table){
|
|
51
|
+
console.log(chalk.yellow('***************** Unused Images *****************'));
|
|
52
|
+
console.log(unusedImages.toString());
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
module.exports = {
|
|
58
|
+
list,
|
|
59
|
+
scan
|
|
60
|
+
};
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qleaner",
|
|
3
3
|
"packageManager": "yarn@4.6.0",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.12",
|
|
5
5
|
"main": "command.js",
|
|
6
6
|
"bin": "./bin/cli.js",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"start": "node ./bin/cli.js"
|
|
8
|
+
"start": "node ./bin/cli.js",
|
|
9
|
+
"resolve": "node ./utils/resolver.js"
|
|
9
10
|
},
|
|
10
11
|
"devDependencies": {
|
|
11
12
|
"@types/node": "^20.10.5",
|
|
@@ -17,6 +18,7 @@
|
|
|
17
18
|
"chalk": "^5.6.2",
|
|
18
19
|
"cli-table3": "^0.6.5",
|
|
19
20
|
"commander": "^14.0.2",
|
|
21
|
+
"enhanced-resolve": "^5.18.3",
|
|
20
22
|
"fast-glob": "^3.3.3",
|
|
21
23
|
"prompts": "^2.4.2"
|
|
22
24
|
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
{
|
|
2
|
+
"src/hello.find.tsx": {
|
|
3
|
+
"hash": "13088ef1169a758d26b7fde99ca67d5a",
|
|
4
|
+
"imports": [
|
|
5
|
+
{
|
|
6
|
+
"from": "./demo/functions",
|
|
7
|
+
"file": "src/hello.find.tsx",
|
|
8
|
+
"line": 1,
|
|
9
|
+
"column": 0,
|
|
10
|
+
"lastModified": 1764776380790
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"from": "~/demo/book/hidden",
|
|
14
|
+
"file": "src/hello.find.tsx",
|
|
15
|
+
"line": 2,
|
|
16
|
+
"column": 0,
|
|
17
|
+
"lastModified": 1764776380790
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"isImported": true,
|
|
21
|
+
"lastModified": 1764776380790
|
|
22
|
+
},
|
|
23
|
+
"src/jambo.tsx": {
|
|
24
|
+
"hash": "6b9a7f99ad2bd68e567368a35bc2831c",
|
|
25
|
+
"imports": [
|
|
26
|
+
{
|
|
27
|
+
"from": "./demo/functions",
|
|
28
|
+
"file": "src/jambo.tsx",
|
|
29
|
+
"line": 1,
|
|
30
|
+
"column": 0,
|
|
31
|
+
"lastModified": 1764776380792
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"from": "hello.find",
|
|
35
|
+
"file": "src/jambo.tsx",
|
|
36
|
+
"line": 2,
|
|
37
|
+
"column": 0,
|
|
38
|
+
"lastModified": 1764776380792
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"isImported": true,
|
|
42
|
+
"lastModified": 1764776380792
|
|
43
|
+
},
|
|
44
|
+
"src/main.js": {
|
|
45
|
+
"hash": "961f4425237e1551bb8ec8a136f12a66",
|
|
46
|
+
"imports": [
|
|
47
|
+
{
|
|
48
|
+
"from": "jambo",
|
|
49
|
+
"file": "src/main.js",
|
|
50
|
+
"line": 1,
|
|
51
|
+
"column": 0,
|
|
52
|
+
"lastModified": 1764776380796
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"from": "poa",
|
|
56
|
+
"file": "src/main.js",
|
|
57
|
+
"line": 2,
|
|
58
|
+
"column": 0,
|
|
59
|
+
"lastModified": 1764776380796
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"from": "./style.css",
|
|
63
|
+
"file": "src/main.js",
|
|
64
|
+
"line": 3,
|
|
65
|
+
"column": 0,
|
|
66
|
+
"lastModified": 1764776380796
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"from": "./demo/demo",
|
|
70
|
+
"file": "src/main.js",
|
|
71
|
+
"line": 4,
|
|
72
|
+
"column": 0,
|
|
73
|
+
"lastModified": 1764776380796
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"from": "./jambo",
|
|
77
|
+
"file": "src/main.js",
|
|
78
|
+
"line": 5,
|
|
79
|
+
"column": 0,
|
|
80
|
+
"lastModified": 1764776380796
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"from": "@/demo/book/hidden",
|
|
84
|
+
"file": "src/main.js",
|
|
85
|
+
"line": 6,
|
|
86
|
+
"column": 0,
|
|
87
|
+
"lastModified": 1764776380796
|
|
88
|
+
}
|
|
89
|
+
],
|
|
90
|
+
"isImported": true,
|
|
91
|
+
"lastModified": 1764776380796
|
|
92
|
+
},
|
|
93
|
+
"src/poa.tsx": {
|
|
94
|
+
"hash": "09d1c8072d500780c9d6b223f5609cc5",
|
|
95
|
+
"imports": [
|
|
96
|
+
{
|
|
97
|
+
"from": "one.png",
|
|
98
|
+
"file": "src/poa.tsx",
|
|
99
|
+
"line": 1,
|
|
100
|
+
"column": 0,
|
|
101
|
+
"lastModified": 1764776380809
|
|
102
|
+
}
|
|
103
|
+
],
|
|
104
|
+
"isImported": true,
|
|
105
|
+
"lastModified": 1764776380809
|
|
106
|
+
},
|
|
107
|
+
"src/demo/demo.tsx": {
|
|
108
|
+
"hash": "fe20d628c85aad8b491b3e45e6559ce4",
|
|
109
|
+
"imports": [
|
|
110
|
+
{
|
|
111
|
+
"from": "../hello.find",
|
|
112
|
+
"file": "src/demo/demo.tsx",
|
|
113
|
+
"line": 1,
|
|
114
|
+
"column": 0,
|
|
115
|
+
"lastModified": 1764828590237
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"from": "../demo/book/hidden",
|
|
119
|
+
"file": "src/demo/demo.tsx",
|
|
120
|
+
"line": 2,
|
|
121
|
+
"column": 0,
|
|
122
|
+
"lastModified": 1764828590237
|
|
123
|
+
}
|
|
124
|
+
],
|
|
125
|
+
"isImported": true,
|
|
126
|
+
"lastModified": 1764828590237
|
|
127
|
+
},
|
|
128
|
+
"src/demo/functions.js": {
|
|
129
|
+
"hash": "091a10616a5be2b7c7803a3f7513453e",
|
|
130
|
+
"imports": [],
|
|
131
|
+
"isImported": true,
|
|
132
|
+
"lastModified": 1764776380788
|
|
133
|
+
},
|
|
134
|
+
"src/demo/public.tsx": {
|
|
135
|
+
"hash": "d41d8cd98f00b204e9800998ecf8427e",
|
|
136
|
+
"imports": [],
|
|
137
|
+
"isImported": false,
|
|
138
|
+
"lastModified": 1764690373726
|
|
139
|
+
},
|
|
140
|
+
"src/shell/main.js": {
|
|
141
|
+
"hash": "d41d8cd98f00b204e9800998ecf8427e",
|
|
142
|
+
"imports": [],
|
|
143
|
+
"isImported": false,
|
|
144
|
+
"lastModified": 1764822800241
|
|
145
|
+
},
|
|
146
|
+
"src/demo/book/hidden.tsx": {
|
|
147
|
+
"hash": "6c3fb783f6f246ad67252489ba9367f4",
|
|
148
|
+
"imports": [
|
|
149
|
+
{
|
|
150
|
+
"from": "../../main",
|
|
151
|
+
"file": "src/demo/book/hidden.tsx",
|
|
152
|
+
"line": 1,
|
|
153
|
+
"column": 0,
|
|
154
|
+
"lastModified": 1764776380785
|
|
155
|
+
}
|
|
156
|
+
],
|
|
157
|
+
"isImported": true,
|
|
158
|
+
"lastModified": 1764776380785
|
|
159
|
+
},
|
|
160
|
+
"src/demo/book/public.tsx": {
|
|
161
|
+
"hash": "d41d8cd98f00b204e9800998ecf8427e",
|
|
162
|
+
"imports": [],
|
|
163
|
+
"isImported": false,
|
|
164
|
+
"lastModified": 1764690329997
|
|
165
|
+
},
|
|
166
|
+
"src/layer/shell/shell.tsx": {
|
|
167
|
+
"hash": "659029bd48113a93f0ce44bc1e8005d3",
|
|
168
|
+
"imports": [
|
|
169
|
+
{
|
|
170
|
+
"from": "../../demo/book/hidden",
|
|
171
|
+
"file": "src/layer/shell/shell.tsx",
|
|
172
|
+
"line": 1,
|
|
173
|
+
"column": 0,
|
|
174
|
+
"lastModified": 1764776380795
|
|
175
|
+
}
|
|
176
|
+
],
|
|
177
|
+
"isImported": false,
|
|
178
|
+
"lastModified": 1764776380795
|
|
179
|
+
}
|
|
180
|
+
}
|
package/utils/cache.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const crypto = require('crypto');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
function loadCache(rootPath) {
|
|
7
|
+
const file = path.join(rootPath, "unused-check-cache.json");
|
|
8
|
+
if(!fs.existsSync(file)) return {};
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
return JSON.parse(fs.readFileSync(file, 'utf8'))
|
|
12
|
+
} catch{
|
|
13
|
+
return {};
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function getFileHash(content) {
|
|
18
|
+
return crypto.createHash('md5').update(content).digest('hex');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
function needsRebuild(file, content, cache) {
|
|
23
|
+
const hash = getFileHash(content);
|
|
24
|
+
return !cache[file] || cache[file].hash !== hash
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
function saveCache(rootPath, cache) {
|
|
29
|
+
const file = path.join(rootPath, "unused-check-cache.json");
|
|
30
|
+
fs.writeFileSync(file, JSON.stringify(cache, null, 2))
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
module.exports = {
|
|
34
|
+
loadCache,
|
|
35
|
+
getFileHash,
|
|
36
|
+
needsRebuild,
|
|
37
|
+
saveCache
|
|
38
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const {create} = require('enhanced-resolve');
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
function createResolver(directory) {
|
|
6
|
+
const resolver = create({
|
|
7
|
+
extensions: [".js", ".jsx", ".ts", ".tsx"],
|
|
8
|
+
alias: {
|
|
9
|
+
"@": path.resolve(directory),
|
|
10
|
+
"~": path.resolve(directory)
|
|
11
|
+
},
|
|
12
|
+
mainFiles: ["index"],
|
|
13
|
+
// Where resolution begins
|
|
14
|
+
modules: [
|
|
15
|
+
path.resolve(directory)
|
|
16
|
+
]
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
return function resolveImport(chalk,sourceFile, importPath) {
|
|
20
|
+
// console.log(chalk.yellow('sourceFile--resolver'), sourceFile, chalk.yellow('importPath--resolver'), importPath);
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
resolver(path.dirname(sourceFile), importPath, (err, result) => {
|
|
23
|
+
if (err) return resolve(null);
|
|
24
|
+
resolve(path.resolve(result));
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = {
|
|
31
|
+
createResolver
|
|
32
|
+
};
|