@weerachai06/tw-scanner 1.0.2 → 1.0.4
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 +27 -0
- package/dist/scanner.js +5 -3
- package/dist/validator.js +9 -2
- package/package.json +1 -1
package/dist/extractor.js
CHANGED
|
@@ -210,6 +210,33 @@ function walk(node, file, source, results, visited = new WeakSet()) {
|
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
}
|
|
213
|
+
// ─── CSS @apply extractor ─────────────────────────────────────────────────────
|
|
214
|
+
export function extractClassesFromCss(file) {
|
|
215
|
+
if (!fs.existsSync(file))
|
|
216
|
+
return [];
|
|
217
|
+
const source = fs.readFileSync(file, 'utf8');
|
|
218
|
+
const results = [];
|
|
219
|
+
const lines = source.split('\n');
|
|
220
|
+
for (let i = 0; i < lines.length; i++) {
|
|
221
|
+
const line = lines[i];
|
|
222
|
+
const match = line.match(/^\s*@apply\s+(.+?)\s*;/);
|
|
223
|
+
if (!match)
|
|
224
|
+
continue;
|
|
225
|
+
const classStr = match[1];
|
|
226
|
+
const col = line.indexOf('@apply');
|
|
227
|
+
classStr.split(/\s+/).filter(Boolean).forEach((cls) => {
|
|
228
|
+
results.push({
|
|
229
|
+
value: cls,
|
|
230
|
+
file,
|
|
231
|
+
line: i + 1,
|
|
232
|
+
col,
|
|
233
|
+
isDynamic: false,
|
|
234
|
+
context: line.trim(),
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
return results;
|
|
239
|
+
}
|
|
213
240
|
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
214
241
|
export function extractClassesFromFile(file) {
|
|
215
242
|
if (!fs.existsSync(file))
|
package/dist/scanner.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { globSync } from 'glob';
|
|
2
2
|
import * as path from 'path';
|
|
3
|
-
import { extractClassesFromFile } from './extractor.js';
|
|
3
|
+
import { extractClassesFromFile, extractClassesFromCss } from './extractor.js';
|
|
4
4
|
import { loadTailwindContext, validateBatch } from './validator.js';
|
|
5
|
-
const DEFAULT_INCLUDE = ['**/*.{ts,tsx,js,jsx}'];
|
|
5
|
+
const DEFAULT_INCLUDE = ['**/*.{ts,tsx,js,jsx,css}'];
|
|
6
6
|
const DEFAULT_EXCLUDE = [
|
|
7
7
|
'**/node_modules/**',
|
|
8
8
|
'**/dist/**',
|
|
@@ -31,7 +31,9 @@ export async function scan(opts) {
|
|
|
31
31
|
// ── 3. Extract classes from all files ─────────────────────────────────────
|
|
32
32
|
const allExtracted = [];
|
|
33
33
|
for (const file of files) {
|
|
34
|
-
const extracted =
|
|
34
|
+
const extracted = file.endsWith('.css')
|
|
35
|
+
? extractClassesFromCss(file)
|
|
36
|
+
: extractClassesFromFile(file);
|
|
35
37
|
allExtracted.push(...extracted);
|
|
36
38
|
}
|
|
37
39
|
// ── 4. Separate static vs dynamic ─────────────────────────────────────────
|
package/dist/validator.js
CHANGED
|
@@ -48,9 +48,13 @@ function selectorInOutput(selector, output) {
|
|
|
48
48
|
const next = output[idx + selector.length];
|
|
49
49
|
return next === '{' || next === ' ' || next === ':' || next === '[' || next === ',';
|
|
50
50
|
}
|
|
51
|
+
// Marker classes that are valid but generate no CSS of their own
|
|
52
|
+
const MARKER_CLASS_RE = /^(group|peer)(\/\S+)?$/;
|
|
51
53
|
// ─── Validation cache: per-context ───────────────────────────────────────────
|
|
52
54
|
const validityCache = new Map();
|
|
53
55
|
export function isValidClass(cls, context) {
|
|
56
|
+
if (MARKER_CLASS_RE.test(cls))
|
|
57
|
+
return true;
|
|
54
58
|
if (!validityCache.has(context))
|
|
55
59
|
validityCache.set(context, new Map());
|
|
56
60
|
const cache = validityCache.get(context);
|
|
@@ -69,9 +73,12 @@ export function validateBatch(classes, context) {
|
|
|
69
73
|
const cache = validityCache.get(context) ?? new Map();
|
|
70
74
|
if (!validityCache.has(context))
|
|
71
75
|
validityCache.set(context, cache);
|
|
72
|
-
// Use cache first
|
|
76
|
+
// Use cache first; skip marker classes
|
|
73
77
|
for (const cls of classes) {
|
|
74
|
-
if (
|
|
78
|
+
if (MARKER_CLASS_RE.test(cls)) {
|
|
79
|
+
result.set(cls, true);
|
|
80
|
+
}
|
|
81
|
+
else if (cache.has(cls)) {
|
|
75
82
|
result.set(cls, cache.get(cls));
|
|
76
83
|
}
|
|
77
84
|
else {
|