@styleframe/scanner 2.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.
@@ -0,0 +1,419 @@
1
+ import { ModifierFactory } from '@styleframe/core';
2
+ import { Root } from '@styleframe/core';
3
+ import { Utility } from '@styleframe/core';
4
+ import { UtilityFactory } from '@styleframe/core';
5
+
6
+ /**
7
+ * Pattern to extract the value from an arbitrary value bracket notation.
8
+ * Matches: [16px], [#1E3A8A], [10px_20px], etc.
9
+ */
10
+ export declare const ARBITRARY_VALUE_PATTERN: RegExp;
11
+
12
+ /**
13
+ * Cache entry for a scanned file
14
+ */
15
+ export declare interface CacheEntry {
16
+ /** Content hash for change detection */
17
+ hash: string;
18
+ /** Cached scan result */
19
+ result: FileScanResult;
20
+ /** Cache timestamp */
21
+ timestamp: number;
22
+ }
23
+
24
+ /**
25
+ * Generate the raw utility class name from options (without CSS escaping).
26
+ */
27
+ export declare function classNameFromUtilityOptions(options: UtilitySelectorOptions): string;
28
+
29
+ /**
30
+ * Create a scanner cache instance.
31
+ *
32
+ * The cache stores scan results keyed by file path and validates
33
+ * entries using content hashing.
34
+ */
35
+ export declare function createCache(): ScannerCache;
36
+
37
+ /**
38
+ * Create a file change handler with debouncing.
39
+ *
40
+ * This is a utility for integrating with external file watchers.
41
+ * The actual file watching should be done at the plugin level
42
+ * using Vite's HMR or chokidar.
43
+ *
44
+ * @param callback Function to call when files change
45
+ * @param options Watcher options
46
+ * @returns A debounced change handler
47
+ */
48
+ export declare function createChangeHandler(callback: (changedFiles: string[]) => void, options?: WatcherOptions): {
49
+ onChange: (filePath: string) => void;
50
+ flush: () => void;
51
+ };
52
+
53
+ /**
54
+ * Create a scanner that only scans specific content.
55
+ *
56
+ * Useful for testing or one-off scans.
57
+ */
58
+ export declare function createContentScanner(customExtractors?: Extractor[]): (content: string, filePath?: string) => ParsedUtility[];
59
+
60
+ /**
61
+ * Create a scanner instance for detecting utility classes in content files.
62
+ *
63
+ * @param config Scanner configuration
64
+ * @returns Scanner instance
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * const scanner = createScanner({
69
+ * content: ['./src/components/*.tsx', './src/pages/*.vue'],
70
+ * });
71
+ *
72
+ * const result = await scanner.scan();
73
+ * const matches = scanner.match(result.allParsed, root);
74
+ * ```
75
+ */
76
+ export declare function createScanner(config: ScannerConfig): Scanner;
77
+
78
+ /**
79
+ * Create a filter function that checks if a utility is in the used set.
80
+ *
81
+ * @param usedClasses Set of used utility class names
82
+ * @returns Filter function for utilities
83
+ */
84
+ export declare function createUtilityFilter(usedClasses: Set<string>): (utility: Utility) => boolean;
85
+
86
+ /**
87
+ * Simple debounce utility
88
+ */
89
+ export declare function debounce<T extends (...args: unknown[]) => void>(fn: T, delay: number): (...args: Parameters<T>) => void;
90
+
91
+ /**
92
+ * Default file extensions to scan for utility classes
93
+ */
94
+ export declare const DEFAULT_EXTENSIONS: string[];
95
+
96
+ /**
97
+ * Glob patterns to ignore when scanning
98
+ */
99
+ export declare const DEFAULT_IGNORE_PATTERNS: string[];
100
+
101
+ /**
102
+ * Extract utility classes from file content.
103
+ *
104
+ * @param content The file content
105
+ * @param filePath The file path (used to determine extractor)
106
+ * @param customExtractors Optional custom extractors to use in addition to defaults
107
+ * @returns Array of unique utility class names found
108
+ */
109
+ export declare function extractClasses(content: string, filePath: string, customExtractors?: Extractor[]): string[];
110
+
111
+ /**
112
+ * Extract utility classes from Astro content.
113
+ * Handles both HTML-like and JSX-like patterns.
114
+ */
115
+ export declare function extractFromAstro(content: string): string[];
116
+
117
+ /**
118
+ * Extract utility classes from HTML-like content.
119
+ * Handles class="..." attributes.
120
+ */
121
+ export declare function extractFromHTML(content: string): string[];
122
+
123
+ /**
124
+ * Extract utility classes from JSX/TSX content.
125
+ * Handles className="..." and className={...} patterns.
126
+ */
127
+ export declare function extractFromJSX(content: string): string[];
128
+
129
+ /**
130
+ * Extract utility classes from MDX content.
131
+ * Handles both Markdown and JSX patterns.
132
+ */
133
+ export declare function extractFromMDX(content: string): string[];
134
+
135
+ /**
136
+ * Extract utility classes from string literals in JavaScript/TypeScript code.
137
+ * Handles single quotes, double quotes, and template literals.
138
+ *
139
+ * Note: Template literals with interpolations (e.g., `_margin:${size}`) will only
140
+ * extract the static portions. Dynamic class names cannot be statically analyzed.
141
+ * For full coverage, use explicit string arrays or safelist patterns.
142
+ */
143
+ export declare function extractFromStringLiterals(content: string): string[];
144
+
145
+ /**
146
+ * Extract utility classes from Svelte content.
147
+ * Handles class="...", class:directive={condition}, and class={...} patterns.
148
+ */
149
+ export declare function extractFromSvelte(content: string): string[];
150
+
151
+ /**
152
+ * Extract utility classes from Vue SFC content.
153
+ * Handles class="...", :class="...", and :class="{...}" patterns.
154
+ */
155
+ export declare function extractFromVue(content: string): string[];
156
+
157
+ /**
158
+ * Custom extractor function type
159
+ */
160
+ export declare type Extractor = (content: string, filePath: string) => string[];
161
+
162
+ /**
163
+ * Extract all utility class names from a content string.
164
+ *
165
+ * @param content The content to search
166
+ * @returns Array of unique utility class names found
167
+ */
168
+ export declare function extractUtilityClasses(content: string): string[];
169
+
170
+ /**
171
+ * Scan result for a single file
172
+ */
173
+ export declare interface FileScanResult {
174
+ /** Absolute file path */
175
+ path: string;
176
+ /** Set of raw class names found */
177
+ classes: Set<string>;
178
+ /** Parsed utility classes */
179
+ parsed: ParsedUtility[];
180
+ /** Timestamp of last scan */
181
+ lastScanned: number;
182
+ }
183
+
184
+ /**
185
+ * Filter root children to only include used utilities.
186
+ *
187
+ * @param root The Styleframe root instance
188
+ * @param usedClasses Set of used utility class names
189
+ * @returns Array of used children (utilities are filtered, other types pass through)
190
+ */
191
+ export declare function filterUtilities(root: Root, usedClasses: Set<string>): Root["children"];
192
+
193
+ /**
194
+ * Generate a utility selector string from components.
195
+ * This is the inverse of parseUtilityClass.
196
+ *
197
+ * @param name Utility name
198
+ * @param value Utility value
199
+ * @param modifiers Array of modifier names
200
+ * @returns The utility class name (without CSS escaping)
201
+ */
202
+ export declare function generateUtilityClassName(name: string, value: string, modifiers?: string[]): string;
203
+
204
+ /**
205
+ * Generate the CSS selector for a utility instance.
206
+ *
207
+ * This mirrors the logic from @styleframe/transpiler/defaults.ts
208
+ */
209
+ export declare function generateUtilitySelector(options: UtilitySelectorOptions): string;
210
+
211
+ /**
212
+ * Get matches for arbitrary values.
213
+ */
214
+ export declare function getArbitraryMatches(matches: UtilityMatch[]): UtilityMatch[];
215
+
216
+ /**
217
+ * Get matches that exist in the registered values.
218
+ */
219
+ export declare function getExistingMatches(matches: UtilityMatch[]): UtilityMatch[];
220
+
221
+ /**
222
+ * Get all unique utility class names from matches.
223
+ */
224
+ export declare function getUsedClassNames(matches: UtilityMatch[]): Set<string>;
225
+
226
+ /**
227
+ * Get matches that have a corresponding utility factory.
228
+ */
229
+ export declare function getValidMatches(matches: UtilityMatch[]): UtilityMatch[];
230
+
231
+ /**
232
+ * Create a simple hash from content for change detection.
233
+ * Uses a hash * 31 algorithm (similar to Java's String.hashCode),
234
+ * combined with content length to reduce collision probability.
235
+ */
236
+ export declare function hashContent(content: string): string;
237
+
238
+ /**
239
+ * Check if a file path matches any of the given glob patterns.
240
+ *
241
+ * This is a simple check that looks for common pattern matches.
242
+ * For full glob support, use a library like micromatch.
243
+ */
244
+ export declare function matchesPatterns(filePath: string, patterns: string[]): boolean;
245
+
246
+ /**
247
+ * Match parsed utility classes against registered utilities in the root.
248
+ *
249
+ * @param parsed Array of parsed utility classes
250
+ * @param root The Styleframe root instance
251
+ * @returns Array of match results
252
+ */
253
+ export declare function matchUtilities(parsed: ParsedUtility[], root: Root): UtilityMatch[];
254
+
255
+ /**
256
+ * Parsed utility class structure
257
+ */
258
+ export declare interface ParsedUtility {
259
+ /** Original class name as found in content (e.g., "_margin:sm") */
260
+ raw: string;
261
+ /** Utility name (e.g., "margin", "background") */
262
+ name: string;
263
+ /** Value key (e.g., "sm", "primary", "[16px]") */
264
+ value: string;
265
+ /** Applied modifiers in order (e.g., ["hover", "dark"]) */
266
+ modifiers: string[];
267
+ /** Whether this uses arbitrary value syntax [value] */
268
+ isArbitrary: boolean;
269
+ /** The arbitrary value if isArbitrary is true (e.g., "16px") */
270
+ arbitraryValue?: string;
271
+ }
272
+
273
+ /**
274
+ * Parse a utility class name into its components.
275
+ *
276
+ * The utility class format is: _[modifiers:]name[:value]
277
+ *
278
+ * Examples:
279
+ * - "_margin:sm" → { name: "margin", value: "sm", modifiers: [] }
280
+ * - "_hover:margin:sm" → { name: "margin", value: "sm", modifiers: ["hover"] }
281
+ * - "_dark:hover:bg:primary" → { name: "bg", value: "primary", modifiers: ["dark", "hover"] }
282
+ * - "_margin:[16px]" → { name: "margin", value: "[16px]", isArbitrary: true, arbitraryValue: "16px" }
283
+ * - "_hidden" → { name: "hidden", value: "default", modifiers: [] }
284
+ *
285
+ * @param className The utility class name to parse
286
+ * @returns Parsed utility object or null if invalid
287
+ */
288
+ export declare function parseUtilityClass(className: string): ParsedUtility | null;
289
+
290
+ /**
291
+ * Quick utility to scan content and get parsed utilities.
292
+ *
293
+ * @param content Content string to scan
294
+ * @param filePath Optional file path hint for extractor selection
295
+ * @returns Array of parsed utilities
296
+ */
297
+ export declare function quickScan(content: string, filePath?: string): ParsedUtility[];
298
+
299
+ /**
300
+ * Scanner instance interface
301
+ */
302
+ export declare interface Scanner {
303
+ /** Scan all content files */
304
+ scan(): Promise<ScanResult>;
305
+ /** Scan a single file */
306
+ scanFile(filePath: string): Promise<FileScanResult>;
307
+ /** Scan content string directly */
308
+ scanContent(content: string, filePath?: string): ParsedUtility[];
309
+ /** Match parsed utilities against a root instance */
310
+ match(parsed: ParsedUtility[], root: Root): UtilityMatch[];
311
+ /** Start watching content files for changes */
312
+ watch(callback: (result: ScanResult) => void): () => void;
313
+ /** Invalidate cache for a file or all files */
314
+ invalidate(filePath?: string): void;
315
+ }
316
+
317
+ /**
318
+ * Scanner cache interface
319
+ */
320
+ export declare interface ScannerCache {
321
+ /** Get cached result for a file */
322
+ get(filePath: string): FileScanResult | null;
323
+ /** Cache a scan result */
324
+ set(filePath: string, result: FileScanResult, contentHash: string): void;
325
+ /** Check if a file has valid cache */
326
+ isValid(filePath: string, contentHash: string): boolean;
327
+ /** Get cached result if valid, null otherwise (single lookup) */
328
+ getIfValid(filePath: string, contentHash: string): FileScanResult | null;
329
+ /** Invalidate cache for a file */
330
+ invalidate(filePath: string): void;
331
+ /** Clear all cache entries */
332
+ clear(): void;
333
+ }
334
+
335
+ /**
336
+ * Configuration for the content scanner
337
+ */
338
+ export declare interface ScannerConfig {
339
+ /** Glob patterns for files to scan */
340
+ content: string[];
341
+ /** Custom extraction functions */
342
+ extractors?: Extractor[];
343
+ /** Base directory for glob resolution (defaults to process.cwd()) */
344
+ cwd?: string;
345
+ }
346
+
347
+ /**
348
+ * Complete scan result across all files
349
+ */
350
+ export declare interface ScanResult {
351
+ /** Map of file path to scan result */
352
+ files: Map<string, FileScanResult>;
353
+ /** All unique class names found */
354
+ allClasses: Set<string>;
355
+ /** All parsed utilities */
356
+ allParsed: ParsedUtility[];
357
+ }
358
+
359
+ /**
360
+ * Regex pattern to match Styleframe utility class names.
361
+ *
362
+ * Matches patterns like:
363
+ * - _margin:sm (base utility)
364
+ * - _hover:margin:sm (with modifier)
365
+ * - _dark:hover:background:primary (multiple modifiers)
366
+ * - _margin:[16px] (arbitrary value)
367
+ * - _background:[#1E3A8A] (arbitrary color)
368
+ * - _hidden (default value, no suffix)
369
+ * - _background:color.primary (dotted reference)
370
+ *
371
+ * Pattern breakdown:
372
+ * - `_` - Required prefix
373
+ * - `[a-zA-Z][a-zA-Z0-9-]*` - First segment (modifier or name)
374
+ * - `(?::[a-zA-Z0-9._-]+|\:\[[^\]]+\])*` - Additional segments with `:` separator
375
+ */
376
+ export declare const UTILITY_CLASS_PATTERN: RegExp;
377
+
378
+ /**
379
+ * Filter function for utilities
380
+ */
381
+ export declare type UtilityFilterFn = (utility: Utility) => boolean;
382
+
383
+ /**
384
+ * Match result between a parsed class and a utility factory
385
+ */
386
+ export declare interface UtilityMatch {
387
+ /** The parsed utility class */
388
+ parsed: ParsedUtility;
389
+ /** The matched utility factory, or null if not found */
390
+ factory: UtilityFactory | null;
391
+ /** Matched modifier factories */
392
+ modifierFactories: ModifierFactory[];
393
+ /** Whether the utility value exists in the factory */
394
+ exists: boolean;
395
+ }
396
+
397
+ /**
398
+ * Utility selector generation options
399
+ */
400
+ export declare interface UtilitySelectorOptions {
401
+ name: string;
402
+ value: string;
403
+ modifiers: string[];
404
+ }
405
+
406
+ /**
407
+ * Callback type for file change events
408
+ */
409
+ export declare type WatchCallback = (result: ScanResult) => void;
410
+
411
+ /**
412
+ * Options for creating a watcher
413
+ */
414
+ export declare interface WatcherOptions {
415
+ /** Debounce time in milliseconds (default: 100) */
416
+ debounce?: number;
417
+ }
418
+
419
+ export { }