@weerachai06/tw-scanner 1.0.0 → 1.0.2
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/extractor.js +2 -3
- package/dist/validator.js +25 -16
- package/package.json +1 -1
package/dist/extractor.js
CHANGED
|
@@ -215,15 +215,14 @@ export function extractClassesFromFile(file) {
|
|
|
215
215
|
if (!fs.existsSync(file))
|
|
216
216
|
return [];
|
|
217
217
|
const source = fs.readFileSync(file, 'utf8');
|
|
218
|
-
const
|
|
218
|
+
const isJSX = /\.(tsx|jsx)$/.test(file);
|
|
219
219
|
let ast;
|
|
220
220
|
try {
|
|
221
221
|
ast = parse(source, {
|
|
222
|
-
jsx:
|
|
222
|
+
jsx: isJSX,
|
|
223
223
|
loc: true,
|
|
224
224
|
range: true,
|
|
225
225
|
tolerant: true,
|
|
226
|
-
...(isTS ? {} : {}),
|
|
227
226
|
});
|
|
228
227
|
}
|
|
229
228
|
catch (err) {
|
package/dist/validator.js
CHANGED
|
@@ -18,20 +18,35 @@ export async function loadTailwindContext(cssFile) {
|
|
|
18
18
|
compileCache.set(abs, result);
|
|
19
19
|
return result;
|
|
20
20
|
}
|
|
21
|
-
// ─── Build
|
|
22
|
-
function
|
|
23
|
-
//
|
|
24
|
-
return cls
|
|
25
|
-
.replace(/\//g, '\\/')
|
|
26
|
-
.replace(/\./g, '\\.')
|
|
27
|
-
.replace(/:/g, '\\:')
|
|
21
|
+
// ─── Build CSS selector for string matching ──────────────────────────────────
|
|
22
|
+
function cssSelector(cls) {
|
|
23
|
+
// Produces the escaped selector as it appears in Tailwind's CSS output
|
|
24
|
+
return '.' + cls
|
|
25
|
+
.replace(/\//g, '\\/')
|
|
26
|
+
.replace(/\./g, '\\.')
|
|
27
|
+
.replace(/:/g, '\\:')
|
|
28
28
|
.replace(/\[/g, '\\[')
|
|
29
29
|
.replace(/\]/g, '\\]')
|
|
30
30
|
.replace(/\(/g, '\\(')
|
|
31
31
|
.replace(/\)/g, '\\)')
|
|
32
|
+
.replace(/=/g, '\\=')
|
|
33
|
+
.replace(/>/g, '\\>')
|
|
34
|
+
.replace(/&/g, '\\&')
|
|
35
|
+
.replace(/~/g, '\\~')
|
|
36
|
+
.replace(/\+/g, '\\+')
|
|
32
37
|
.replace(/#/g, '\\#')
|
|
33
38
|
.replace(/%/g, '\\%')
|
|
34
|
-
.replace(/!/g, '\\!')
|
|
39
|
+
.replace(/!/g, '\\!')
|
|
40
|
+
.replace(/,/g, '\\,')
|
|
41
|
+
.replace(/'/g, "\\'")
|
|
42
|
+
.replace(/"/g, '\\"');
|
|
43
|
+
}
|
|
44
|
+
function selectorInOutput(selector, output) {
|
|
45
|
+
const idx = output.indexOf(selector);
|
|
46
|
+
if (idx === -1)
|
|
47
|
+
return false;
|
|
48
|
+
const next = output[idx + selector.length];
|
|
49
|
+
return next === '{' || next === ' ' || next === ':' || next === '[' || next === ',';
|
|
35
50
|
}
|
|
36
51
|
// ─── Validation cache: per-context ───────────────────────────────────────────
|
|
37
52
|
const validityCache = new Map();
|
|
@@ -43,11 +58,7 @@ export function isValidClass(cls, context) {
|
|
|
43
58
|
return cache.get(cls);
|
|
44
59
|
// Build CSS with this single candidate
|
|
45
60
|
const output = context.build([cls]);
|
|
46
|
-
|
|
47
|
-
const escaped = cssEscape(cls);
|
|
48
|
-
// Look for .classname{ or .classname { or .classname:hover{
|
|
49
|
-
const pattern = new RegExp(`\\.${escaped.replace(/\\/g, '\\\\')}[\\s{\\[:]`);
|
|
50
|
-
const valid = pattern.test(output);
|
|
61
|
+
const valid = selectorInOutput(cssSelector(cls), output);
|
|
51
62
|
cache.set(cls, valid);
|
|
52
63
|
return valid;
|
|
53
64
|
}
|
|
@@ -72,9 +83,7 @@ export function validateBatch(classes, context) {
|
|
|
72
83
|
// Build all candidates at once
|
|
73
84
|
const output = context.build(toCheck);
|
|
74
85
|
for (const cls of toCheck) {
|
|
75
|
-
const
|
|
76
|
-
const pattern = new RegExp(`\\.${escaped.replace(/\\/g, '\\\\')}[\\s{\\[:]`);
|
|
77
|
-
const valid = pattern.test(output);
|
|
86
|
+
const valid = selectorInOutput(cssSelector(cls), output);
|
|
78
87
|
result.set(cls, valid);
|
|
79
88
|
cache.set(cls, valid);
|
|
80
89
|
}
|