qleaner 1.0.0
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/.pnp.cjs +7954 -0
- package/.pnp.loader.mjs +2126 -0
- package/.yarn/install-state.gz +0 -0
- package/AssetInCode.js +90 -0
- package/README.md +1 -0
- package/assets.js +37 -0
- package/bin/cli.js +13 -0
- package/command.js +55 -0
- package/cssImages.js +33 -0
- package/package.json +21 -0
|
Binary file
|
package/AssetInCode.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const fg = require("fast-glob");
|
|
3
|
+
const parser = require("@babel/parser");
|
|
4
|
+
const traverse = require("@babel/traverse").default;
|
|
5
|
+
|
|
6
|
+
async function getAssetInCode() {
|
|
7
|
+
const usedImages = new Set();
|
|
8
|
+
|
|
9
|
+
const imageRegex = /\.(png|jpg|jpeg|svg|gif|webp)$/i;
|
|
10
|
+
|
|
11
|
+
const codeFiles = await fg([
|
|
12
|
+
"src/**/*.{tsx,ts,js,jsx}"
|
|
13
|
+
]);
|
|
14
|
+
console.log(codeFiles);
|
|
15
|
+
for (const file of codeFiles) {
|
|
16
|
+
const code = fs.readFileSync(file, "utf8");
|
|
17
|
+
const ast = parser.parse(code, {
|
|
18
|
+
sourceType: "module",
|
|
19
|
+
plugins: ["jsx", "typescript"],
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
traverse(ast, {
|
|
23
|
+
// <img src="...">
|
|
24
|
+
JSXAttribute(path) {
|
|
25
|
+
if (path.node.name.name !== "src") return;
|
|
26
|
+
|
|
27
|
+
const value = path.node.value;
|
|
28
|
+
|
|
29
|
+
if (value.type === "StringLiteral") {
|
|
30
|
+
if (imageRegex.test(value.value)) {
|
|
31
|
+
usedImages.add(value.value);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (value.type === "JSXExpressionContainer") {
|
|
36
|
+
const expr = value.expression;
|
|
37
|
+
|
|
38
|
+
if (expr.type === "StringLiteral" && imageRegex.test(expr.value)) {
|
|
39
|
+
usedImages.add(expr.value);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (expr.type === "TemplateLiteral") {
|
|
43
|
+
expr.quasis.forEach((q) => {
|
|
44
|
+
if (imageRegex.test(q.value.raw)) {
|
|
45
|
+
usedImages.add(q.value.raw);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
// String literals anywhere in code
|
|
53
|
+
StringLiteral(path) {
|
|
54
|
+
if (imageRegex.test(path.node.value)) {
|
|
55
|
+
usedImages.add(path.node.value);
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
// Template literals: `/images/${name}.png`
|
|
60
|
+
TemplateLiteral(path) {
|
|
61
|
+
path.node.quasis.forEach((quasi) => {
|
|
62
|
+
if (imageRegex.test(quasi.value.raw)) {
|
|
63
|
+
usedImages.add(quasi.value.raw);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
// Arrays: ["img/a.png", "img/b.png"]
|
|
69
|
+
ArrayExpression(path) {
|
|
70
|
+
path.node.elements.forEach((el) => {
|
|
71
|
+
if (el?.type === "StringLiteral" && imageRegex.test(el.value)) {
|
|
72
|
+
usedImages.add(el.value);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
// Objects: { image: "img/a.png" }
|
|
78
|
+
ObjectProperty(path) {
|
|
79
|
+
const val = path.node.value;
|
|
80
|
+
if (val.type === "StringLiteral" && imageRegex.test(val.value)) {
|
|
81
|
+
usedImages.add(val.value);
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
console.log(Array.from(usedImages));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
getAssetInCode();
|
|
90
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# react-cleaner
|
package/assets.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const fg = require('fast-glob');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const parser = require('@babel/parser');
|
|
4
|
+
const traverse = require('@babel/traverse').default;
|
|
5
|
+
|
|
6
|
+
async function getFiles() {
|
|
7
|
+
const assets = [];
|
|
8
|
+
const files = await fg([ "src/**/*.{png,jpg,jpeg,svg,gif,webp}",
|
|
9
|
+
"public/**/*.{png,jpg,jpeg,svg,gif,webp}",]);
|
|
10
|
+
const codeFiles = await fg([ "src/**/*.{js,jsx,ts,tsx}",
|
|
11
|
+
"src/**/*.css",
|
|
12
|
+
"src/**/*.json"]);
|
|
13
|
+
|
|
14
|
+
for (const file of codeFiles) {
|
|
15
|
+
const code = fs.readFileSync(file, 'utf8');
|
|
16
|
+
const ast = parser.parse(code, {
|
|
17
|
+
sourceType: 'module',
|
|
18
|
+
plugins: ['jsx', 'typescript'],
|
|
19
|
+
});
|
|
20
|
+
traverse(ast, {
|
|
21
|
+
ImportDeclaration: ({ node }) => {
|
|
22
|
+
if(typeof node.source.value === 'string' && /\.(png|jpg|jpeg|svg|gif|webp)$/.test(node.source.value)){
|
|
23
|
+
assets.push(node.source.value);
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
CallExpression: ({ node }) => {
|
|
27
|
+
if(node.callee.name === 'require' && typeof node.arguments[0].value === 'string' && /\.(png|jpg|jpeg|svg|gif|webp)$/.test(node.arguments[0].value)){
|
|
28
|
+
assets.push(node.arguments[0].value);
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
console.log(assets);
|
|
34
|
+
console.log(files);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
getFiles();
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const {Command} = require('commander');
|
|
2
|
+
const getFiles = require('../command');
|
|
3
|
+
|
|
4
|
+
const program = new Command();
|
|
5
|
+
|
|
6
|
+
program.name('qleaner').description('A tool to clean up your React code').version('1.0.0');
|
|
7
|
+
|
|
8
|
+
program.command('qlean').description('List all the imports in the project').action(async () => {
|
|
9
|
+
const imports = await getFiles();
|
|
10
|
+
console.log(imports);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
program.parse(process.argv);
|
package/command.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const fg = require("fast-glob");
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const parser = require("@babel/parser");
|
|
4
|
+
const traverse = require("@babel/traverse").default;
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
module.exports = async function getFiles() {
|
|
8
|
+
const files = await fg(["app/**/*.{tsx,ts,js,jsx}"]);
|
|
9
|
+
const imports = [];
|
|
10
|
+
for (const file of files) {
|
|
11
|
+
const code = fs.readFileSync(file, "utf8");
|
|
12
|
+
const ast = parser.parse(code, {
|
|
13
|
+
sourceType: "module",
|
|
14
|
+
plugins: [
|
|
15
|
+
"jsx",
|
|
16
|
+
"typescript",
|
|
17
|
+
],
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
traverse(ast, {
|
|
21
|
+
ImportDeclaration: ({ node }) => {
|
|
22
|
+
imports.push({
|
|
23
|
+
from: node.source.value,
|
|
24
|
+
file: file,
|
|
25
|
+
line: node.loc.start.line,
|
|
26
|
+
column: node.loc.start.column,
|
|
27
|
+
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// ExportNamedDeclaration: ({ node }) => {
|
|
34
|
+
// if (node.declaration.declarations && node.declaration.declarations[0].id && node.declaration.declarations[0].id.name) {
|
|
35
|
+
// exports.push(node.declaration.declarations[0].id.name);
|
|
36
|
+
// }
|
|
37
|
+
// },
|
|
38
|
+
// FunctionDeclaration: ({ node }) => {
|
|
39
|
+
// console.log('FunctionDeclaration', node.id);
|
|
40
|
+
// if (node.id && node.id.name) {
|
|
41
|
+
// exports.push(node.id.name);
|
|
42
|
+
// }
|
|
43
|
+
// },
|
|
44
|
+
// });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
console.log('***************** Files *****************');
|
|
48
|
+
files.forEach((file) => {
|
|
49
|
+
console.log(file);
|
|
50
|
+
})
|
|
51
|
+
console.log('***************** Imports *****************');
|
|
52
|
+
imports.forEach((importStatement) => {
|
|
53
|
+
console.log(`${importStatement.file}:${importStatement.line}:${importStatement.column} ${importStatement.from}`);
|
|
54
|
+
})
|
|
55
|
+
}
|
package/cssImages.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const fg = require('fast-glob');
|
|
3
|
+
|
|
4
|
+
function extractCssImages(cssContent) {
|
|
5
|
+
const urlRegex = /url\((['"]?)(.*?)\1\)/g;
|
|
6
|
+
const images = new Set();
|
|
7
|
+
let match;
|
|
8
|
+
|
|
9
|
+
while ((match = urlRegex.exec(cssContent)) !== null) {
|
|
10
|
+
const url = match[2];
|
|
11
|
+
|
|
12
|
+
// Only collect image file types
|
|
13
|
+
if (/\.(png|jpg|jpeg|svg|gif|webp)$/i.test(url)) {
|
|
14
|
+
images.add(url);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return Array.from(images);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function getCssImages() {
|
|
22
|
+
const cssFiles = await fg([
|
|
23
|
+
"src/**/*.{css,scss}",
|
|
24
|
+
]);
|
|
25
|
+
for (const file of cssFiles) {
|
|
26
|
+
const css = fs.readFileSync(file, "utf-8");
|
|
27
|
+
const images = extractCssImages(css);
|
|
28
|
+
console.log(images);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
getCssImages();
|
|
33
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "qleaner",
|
|
3
|
+
"packageManager": "yarn@4.6.0",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"main": "command.js",
|
|
6
|
+
"bin": "./bin/cli.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"start": "node bin/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"@types/node": "^20.10.5",
|
|
12
|
+
"typescript": "^5.3.3"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@babel/parser": "^7.28.5",
|
|
16
|
+
"@babel/traverse": "^7.28.5",
|
|
17
|
+
"chalk": "^5.6.2",
|
|
18
|
+
"commander": "^14.0.2",
|
|
19
|
+
"fast-glob": "^3.3.3"
|
|
20
|
+
}
|
|
21
|
+
}
|