@vueland/utils-jit 0.2.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/dist/index.cjs ADDED
@@ -0,0 +1,840 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+ //#endregion
24
+ let node_fs = require("node:fs");
25
+ node_fs = __toESM(node_fs);
26
+ let node_path = require("node:path");
27
+ node_path = __toESM(node_path);
28
+ //#region src/core.ts
29
+ const DEFAULT_INCLUDE = [/\.(vue|js|ts|jsx|tsx|html)$/];
30
+ const DEFAULT_EXCLUDE = [
31
+ /(^|[/\\])node_modules([/\\]|$)/,
32
+ /(^|[/\\])\.git([/\\]|$)/,
33
+ /(^|[/\\])dist([/\\]|$)/,
34
+ /(^|[/\\])build([/\\]|$)/,
35
+ /(^|[/\\])coverage([/\\]|$)/,
36
+ /(^|[/\\])\.output([/\\]|$)/,
37
+ /(^|[/\\])\.nuxt([/\\]|$)/,
38
+ /(^|[/\\])\.turbo([/\\]|$)/,
39
+ /(^|[/\\])\.generated([/\\]|$)/,
40
+ /(^|[/\\])storybook-static([/\\]|$)/,
41
+ /(^|[/\\])playwright-report([/\\]|$)/
42
+ ];
43
+ const DEFAULT_BREAKPOINTS = {
44
+ sm: 640,
45
+ md: 768,
46
+ lg: 1024,
47
+ xl: 1280,
48
+ "2xl": 1536
49
+ };
50
+ const DEFAULT_VARIANTS = {
51
+ hover: {
52
+ kind: "pseudo",
53
+ value: "hover"
54
+ },
55
+ focus: {
56
+ kind: "pseudo",
57
+ value: "focus"
58
+ },
59
+ "focus-visible": {
60
+ kind: "pseudo",
61
+ value: "focus-visible"
62
+ },
63
+ "focus-within": {
64
+ kind: "pseudo",
65
+ value: "focus-within"
66
+ },
67
+ active: {
68
+ kind: "pseudo",
69
+ value: "active"
70
+ },
71
+ disabled: {
72
+ kind: "pseudo",
73
+ value: "disabled"
74
+ },
75
+ checked: {
76
+ kind: "pseudo",
77
+ value: "checked"
78
+ },
79
+ visited: {
80
+ kind: "pseudo",
81
+ value: "visited"
82
+ },
83
+ first: {
84
+ kind: "pseudo",
85
+ value: "first-child"
86
+ },
87
+ last: {
88
+ kind: "pseudo",
89
+ value: "last-child"
90
+ },
91
+ odd: {
92
+ kind: "pseudo",
93
+ value: "nth-child(odd)"
94
+ },
95
+ even: {
96
+ kind: "pseudo",
97
+ value: "nth-child(even)"
98
+ }
99
+ };
100
+ const MIN_TOKEN_LENGTH = 5;
101
+ const MAX_TOKEN_LENGTH = 180;
102
+ const MAX_VALUE_LENGTH = 160;
103
+ function normalizePath$1(value) {
104
+ return value.replace(/\\/g, "/");
105
+ }
106
+ function matchesPattern$1(value, pattern) {
107
+ const normalized = normalizePath$1(value);
108
+ if (typeof pattern === "string") return normalized.includes(normalizePath$1(pattern));
109
+ pattern.lastIndex = 0;
110
+ return pattern.test(normalized);
111
+ }
112
+ function shouldProcess(id, include = DEFAULT_INCLUDE, exclude = []) {
113
+ const cleanId = id.split("?")[0];
114
+ if (!cleanId) return false;
115
+ if (exclude.some((pattern) => matchesPattern$1(cleanId, pattern))) return false;
116
+ return include.some((pattern) => matchesPattern$1(cleanId, pattern));
117
+ }
118
+ function escapeCssSelector(value) {
119
+ return value.replace(/[^a-zA-Z0-9_-]/g, (char) => `\\${char}`);
120
+ }
121
+ function normalizeValue(value) {
122
+ return value.trim().replace(/\s+/g, " ");
123
+ }
124
+ function isSafeCssValue(value) {
125
+ const normalized = normalizeValue(value);
126
+ if (!normalized) return false;
127
+ if (normalized.length > MAX_VALUE_LENGTH) return false;
128
+ if (/[;{}<>]/.test(normalized)) return false;
129
+ if (/\/\*/.test(normalized) || /\*\//.test(normalized)) return false;
130
+ if (!/[a-zA-Z0-9]/.test(normalized)) return false;
131
+ return /^[-a-zA-Z0-9.%_(),+/*\s[\]#]+$/.test(normalized);
132
+ }
133
+ function stripEdgeGarbage(token) {
134
+ return token.replace(/^['"`{(]+|['"`})>,;]+$/g, "");
135
+ }
136
+ function looksLikeArbitraryUtility(token) {
137
+ if (!token) return false;
138
+ if (token.length < MIN_TOKEN_LENGTH || token.length > MAX_TOKEN_LENGTH) return false;
139
+ if (!token.includes("-[") || !token.endsWith("]")) return false;
140
+ if (token.startsWith("<") || token.startsWith(">")) return false;
141
+ return token.indexOf("-[") > 0;
142
+ }
143
+ function stripComments(code) {
144
+ return code.replace(/<!--[\s\S]*?-->/g, " ").replace(/\/\*[\s\S]*?\*\//g, " ").replace(/(^|[^:])\/\/.*$/gm, "$1 ");
145
+ }
146
+ function extractClassCandidates(code) {
147
+ const candidates = [];
148
+ for (const pattern of [
149
+ /(?:^|[\s<]):class\s*=\s*"([^"]*)"/g,
150
+ /(?:^|[\s<]):class\s*=\s*'([^']*)'/g,
151
+ /(?:^|[\s<])class\s*=\s*"([^"]*)"/g,
152
+ /(?:^|[\s<])class\s*=\s*'([^']*)'/g
153
+ ]) for (const match of code.matchAll(pattern)) {
154
+ const value = match[1];
155
+ if (value) candidates.push(value);
156
+ }
157
+ return candidates;
158
+ }
159
+ function tokenizeChunk(code) {
160
+ const result = /* @__PURE__ */ new Set();
161
+ for (const match of code.matchAll(/(?:[a-zA-Z0-9_-]+:)*[a-zA-Z][a-zA-Z0-9_-]*-\[[^\]\s]+(?:\s+[^\]\s]+)*\]/g)) {
162
+ const raw = match[0];
163
+ const token = stripEdgeGarbage(raw);
164
+ if (looksLikeArbitraryUtility(token)) result.add(token);
165
+ }
166
+ return result;
167
+ }
168
+ function tokenize(code) {
169
+ const cleanCode = stripComments(code);
170
+ const classCandidates = extractClassCandidates(cleanCode);
171
+ if (classCandidates.length > 0) {
172
+ const result = /* @__PURE__ */ new Set();
173
+ for (const candidate of classCandidates) for (const token of tokenizeChunk(candidate)) result.add(token);
174
+ if (result.size > 0) return result;
175
+ }
176
+ return tokenizeChunk(cleanCode);
177
+ }
178
+ function parseToken(token) {
179
+ const parts = token.split(":").filter(Boolean);
180
+ if (!parts.length) return null;
181
+ const utility = parts[parts.length - 1];
182
+ const variants = parts.slice(0, -1);
183
+ if (!utility.includes("-[") || !utility.endsWith("]")) return null;
184
+ return {
185
+ raw: token,
186
+ variants,
187
+ utility
188
+ };
189
+ }
190
+ function camelToKebab(value) {
191
+ if (value.startsWith("--")) return value;
192
+ return value.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`);
193
+ }
194
+ function withImportant(value, important) {
195
+ const normalized = String(value);
196
+ if (!important) return normalized;
197
+ if (/\s!important\s*$/i.test(normalized)) return normalized;
198
+ return `${normalized} !important`;
199
+ }
200
+ function objectToDeclarations(declaration, important) {
201
+ return Object.entries(declaration).map(([prop, value]) => {
202
+ return `${camelToKebab(prop)}: ${withImportant(value, important)};`;
203
+ });
204
+ }
205
+ function normalizeDeclarations(declaration, important) {
206
+ if (Array.isArray(declaration)) return declaration;
207
+ return objectToDeclarations(declaration, important);
208
+ }
209
+ function defineRule(options) {
210
+ const important = options.important ?? true;
211
+ return {
212
+ name: options.name,
213
+ match(utility) {
214
+ options.matcher.lastIndex = 0;
215
+ const match = utility.match(options.matcher);
216
+ if (!match) return null;
217
+ const rawValue = match[1];
218
+ if (!rawValue) return null;
219
+ const value = normalizeValue(rawValue);
220
+ if (!value || !isSafeCssValue(value)) return null;
221
+ if (options.validate && !options.validate(value)) return null;
222
+ return { declarations: normalizeDeclarations(options.declaration(value), important) };
223
+ }
224
+ };
225
+ }
226
+ const createArbitraryRule = defineRule;
227
+ function resolveRule(utility, rules) {
228
+ for (const rule of rules) {
229
+ const match = rule.match(utility);
230
+ if (match) return { declarations: match.declarations };
231
+ }
232
+ return null;
233
+ }
234
+ function formatMathFunctions(value) {
235
+ return value.replace(/\b(calc|min|max|clamp)\(([^()]+)\)/g, (_match, fn, expr) => {
236
+ return `${fn}(${expr.replace(/\s*([+\-*/])\s*/g, " $1 ").replace(/\s+/g, " ").trim()})`;
237
+ });
238
+ }
239
+ function applySelectorVariant(selector, variant) {
240
+ if (variant.kind === "pseudo") return `${selector}:${variant.value}`;
241
+ if (variant.kind === "selector") {
242
+ const template = String(variant.value);
243
+ return template.includes("&") ? template.replace(/&/g, selector) : `${template} ${selector}`;
244
+ }
245
+ if (variant.kind === "attribute") return `${selector}${variant.value}`;
246
+ return null;
247
+ }
248
+ function buildCssRule(parsed, cssBody, breakpoints = DEFAULT_BREAKPOINTS, variants = DEFAULT_VARIANTS) {
249
+ let selector = `.${escapeCssSelector(parsed.raw)}`;
250
+ const mediaVariants = [];
251
+ for (const variantName of parsed.variants) {
252
+ if (variantName in breakpoints) {
253
+ mediaVariants.push(variantName);
254
+ continue;
255
+ }
256
+ const variant = variants[variantName];
257
+ if (!variant) return null;
258
+ if (variant.kind === "media") {
259
+ mediaVariants.push(variantName);
260
+ continue;
261
+ }
262
+ const nextSelector = applySelectorVariant(selector, variant);
263
+ if (!nextSelector) return null;
264
+ selector = nextSelector;
265
+ }
266
+ const body = cssBody.declarations.map((decl) => {
267
+ return decl.replace(/:\s*([^;]+)(;?)$/, (_match, value, semicolon) => {
268
+ return `: ${formatMathFunctions(value.trim())}${semicolon}`;
269
+ });
270
+ }).join("");
271
+ let result = `${selector}{${body}}`;
272
+ for (const variantName of mediaVariants.reverse()) {
273
+ const customVariant = variants[variantName];
274
+ const minWidth = typeof customVariant?.value === "number" ? customVariant.value : breakpoints[variantName];
275
+ if (typeof minWidth !== "number") return null;
276
+ result = `@media (min-width: ${minWidth}px) { ${result} }`;
277
+ }
278
+ return result;
279
+ }
280
+ //#endregion
281
+ //#region src/validators.ts
282
+ const CSS_NUMBER_RE = /^-?(?:\d+|\d*\.\d+)$/;
283
+ const CSS_LENGTH_RE = new RegExp(`^-?(?:\\d+|\\d*\\.\\d+)${/(?:px|r?em|%|vw|vh|svw|svh|lvw|lvh|dvw|dvh|vmin|vmax|ch|ex|cm|mm|in|pt|pc)/.source}$`);
284
+ const CSS_COLOR_KEYWORDS = new Set([
285
+ "transparent",
286
+ "currentColor",
287
+ "inherit",
288
+ "initial",
289
+ "unset",
290
+ "revert"
291
+ ]);
292
+ const CSS_GLOBAL_VALUES = new Set([
293
+ "inherit",
294
+ "initial",
295
+ "unset",
296
+ "revert",
297
+ "revert-layer"
298
+ ]);
299
+ function isNumberValue(value) {
300
+ return CSS_NUMBER_RE.test(value);
301
+ }
302
+ function isZeroValue(value) {
303
+ return value === "0" || value === "-0";
304
+ }
305
+ function isCssGlobalValue(value) {
306
+ return CSS_GLOBAL_VALUES.has(value);
307
+ }
308
+ function isFunctionalCssValue(value) {
309
+ return /^(?:calc|min|max|clamp|var)\(.+\)$/.test(value);
310
+ }
311
+ function isLengthLikeValue(value) {
312
+ return isZeroValue(value) || CSS_LENGTH_RE.test(value) || isFunctionalCssValue(value);
313
+ }
314
+ function isLengthListValue(value, maxItems = 4) {
315
+ const items = value.trim().split(/\s+/);
316
+ if (items.length === 0 || items.length > maxItems) return false;
317
+ return items.every((item) => isLengthLikeValue(item));
318
+ }
319
+ function isSizeValue(value) {
320
+ return isCssGlobalValue(value) || value === "auto" || isLengthLikeValue(value);
321
+ }
322
+ function isPaddingValue(value) {
323
+ return isCssGlobalValue(value) || isLengthListValue(value, 4);
324
+ }
325
+ function isMarginValue(value) {
326
+ if (isCssGlobalValue(value)) return true;
327
+ const items = value.trim().split(/\s+/);
328
+ if (items.length === 0 || items.length > 4) return false;
329
+ return items.every((item) => item === "auto" || isLengthLikeValue(item));
330
+ }
331
+ function isRadiusValue(value) {
332
+ return isCssGlobalValue(value) || isLengthListValue(value, 4);
333
+ }
334
+ function isPositionValue(value) {
335
+ return isCssGlobalValue(value) || value === "auto" || isLengthLikeValue(value);
336
+ }
337
+ function isZIndexValue(value) {
338
+ return isCssGlobalValue(value) || value === "auto" || CSS_NUMBER_RE.test(value) || /^var\(.+\)$/.test(value);
339
+ }
340
+ function isOpacityValue(value) {
341
+ if (isCssGlobalValue(value)) return true;
342
+ if (!CSS_NUMBER_RE.test(value)) return /^var\(.+\)$/.test(value);
343
+ const numeric = Number(value);
344
+ return numeric >= 0 && numeric <= 1;
345
+ }
346
+ function isColorValue(value) {
347
+ return isCssGlobalValue(value) || CSS_COLOR_KEYWORDS.has(value) || /^#[0-9a-fA-F]{3,8}$/.test(value) || /^(?:rgb|rgba|hsl|hsla|oklch|oklab|color)\(.+\)$/.test(value) || /^var\(.+\)$/.test(value);
348
+ }
349
+ //#endregion
350
+ //#region src/rules.ts
351
+ const defaultRules = [
352
+ defineRule({
353
+ name: "width",
354
+ matcher: /^w-\[(.+)\]$/,
355
+ validate: isSizeValue,
356
+ declaration: (value) => ({ width: value })
357
+ }),
358
+ defineRule({
359
+ name: "height",
360
+ matcher: /^h-\[(.+)\]$/,
361
+ validate: isSizeValue,
362
+ declaration: (value) => ({ height: value })
363
+ }),
364
+ defineRule({
365
+ name: "min-width",
366
+ matcher: /^min-w-\[(.+)\]$/,
367
+ validate: isSizeValue,
368
+ declaration: (value) => ({ minWidth: value })
369
+ }),
370
+ defineRule({
371
+ name: "max-width",
372
+ matcher: /^max-w-\[(.+)\]$/,
373
+ validate: isSizeValue,
374
+ declaration: (value) => ({ maxWidth: value })
375
+ }),
376
+ defineRule({
377
+ name: "min-height",
378
+ matcher: /^min-h-\[(.+)\]$/,
379
+ validate: isSizeValue,
380
+ declaration: (value) => ({ minHeight: value })
381
+ }),
382
+ defineRule({
383
+ name: "max-height",
384
+ matcher: /^max-h-\[(.+)\]$/,
385
+ validate: isSizeValue,
386
+ declaration: (value) => ({ maxHeight: value })
387
+ }),
388
+ defineRule({
389
+ name: "z-index",
390
+ matcher: /^z-\[(.+)\]$/,
391
+ validate: isZIndexValue,
392
+ declaration: (value) => ({ zIndex: value })
393
+ }),
394
+ defineRule({
395
+ name: "margin",
396
+ matcher: /^ma-\[(.+)\]$/,
397
+ validate: isMarginValue,
398
+ declaration: (value) => ({ margin: value })
399
+ }),
400
+ defineRule({
401
+ name: "margin-x",
402
+ matcher: /^mx-\[(.+)\]$/,
403
+ validate: isMarginValue,
404
+ declaration: (value) => ({
405
+ marginLeft: value,
406
+ marginRight: value
407
+ })
408
+ }),
409
+ defineRule({
410
+ name: "margin-y",
411
+ matcher: /^my-\[(.+)\]$/,
412
+ validate: isMarginValue,
413
+ declaration: (value) => ({
414
+ marginTop: value,
415
+ marginBottom: value
416
+ })
417
+ }),
418
+ defineRule({
419
+ name: "margin-bottom",
420
+ matcher: /^mb-\[(.+)\]$/,
421
+ validate: isMarginValue,
422
+ declaration: (value) => ({ marginBottom: value })
423
+ }),
424
+ defineRule({
425
+ name: "margin-top",
426
+ matcher: /^mt-\[(.+)\]$/,
427
+ validate: isMarginValue,
428
+ declaration: (value) => ({ marginTop: value })
429
+ }),
430
+ defineRule({
431
+ name: "margin-left",
432
+ matcher: /^ml-\[(.+)\]$/,
433
+ validate: isMarginValue,
434
+ declaration: (value) => ({ marginLeft: value })
435
+ }),
436
+ defineRule({
437
+ name: "margin-right",
438
+ matcher: /^mr-\[(.+)\]$/,
439
+ validate: isMarginValue,
440
+ declaration: (value) => ({ marginRight: value })
441
+ }),
442
+ defineRule({
443
+ name: "padding",
444
+ matcher: /^pa-\[(.+)\]$/,
445
+ validate: isPaddingValue,
446
+ declaration: (value) => ({ padding: value })
447
+ }),
448
+ defineRule({
449
+ name: "padding-x",
450
+ matcher: /^px-\[(.+)\]$/,
451
+ validate: isPaddingValue,
452
+ declaration: (value) => ({
453
+ paddingLeft: value,
454
+ paddingRight: value
455
+ })
456
+ }),
457
+ defineRule({
458
+ name: "padding-y",
459
+ matcher: /^py-\[(.+)\]$/,
460
+ validate: isPaddingValue,
461
+ declaration: (value) => ({
462
+ paddingTop: value,
463
+ paddingBottom: value
464
+ })
465
+ }),
466
+ defineRule({
467
+ name: "padding-bottom",
468
+ matcher: /^pb-\[(.+)\]$/,
469
+ validate: isPaddingValue,
470
+ declaration: (value) => ({ paddingBottom: value })
471
+ }),
472
+ defineRule({
473
+ name: "padding-top",
474
+ matcher: /^pt-\[(.+)\]$/,
475
+ validate: isPaddingValue,
476
+ declaration: (value) => ({ paddingTop: value })
477
+ }),
478
+ defineRule({
479
+ name: "padding-left",
480
+ matcher: /^pl-\[(.+)\]$/,
481
+ validate: isPaddingValue,
482
+ declaration: (value) => ({ paddingLeft: value })
483
+ }),
484
+ defineRule({
485
+ name: "padding-right",
486
+ matcher: /^pr-\[(.+)\]$/,
487
+ validate: isPaddingValue,
488
+ declaration: (value) => ({ paddingRight: value })
489
+ }),
490
+ defineRule({
491
+ name: "left",
492
+ matcher: /^left-\[(.+)\]$/,
493
+ validate: isPositionValue,
494
+ declaration: (value) => ({ left: value })
495
+ }),
496
+ defineRule({
497
+ name: "right",
498
+ matcher: /^right-\[(.+)\]$/,
499
+ validate: isPositionValue,
500
+ declaration: (value) => ({ right: value })
501
+ }),
502
+ defineRule({
503
+ name: "top",
504
+ matcher: /^top-\[(.+)\]$/,
505
+ validate: isPositionValue,
506
+ declaration: (value) => ({ top: value })
507
+ }),
508
+ defineRule({
509
+ name: "bottom",
510
+ matcher: /^bottom-\[(.+)\]$/,
511
+ validate: isPositionValue,
512
+ declaration: (value) => ({ bottom: value })
513
+ }),
514
+ defineRule({
515
+ name: "inset",
516
+ matcher: /^inset-\[(.+)\]$/,
517
+ validate: isPositionValue,
518
+ declaration: (value) => ({ inset: value })
519
+ }),
520
+ defineRule({
521
+ name: "radius",
522
+ matcher: /^radius-\[(.+)\]$/,
523
+ validate: isRadiusValue,
524
+ declaration: (value) => ({ borderRadius: value })
525
+ }),
526
+ defineRule({
527
+ name: "radius-top-left",
528
+ matcher: /^radius-tl-\[(.+)\]$/,
529
+ validate: isRadiusValue,
530
+ declaration: (value) => ({ borderTopLeftRadius: value })
531
+ }),
532
+ defineRule({
533
+ name: "radius-top-right",
534
+ matcher: /^radius-tr-\[(.+)\]$/,
535
+ validate: isRadiusValue,
536
+ declaration: (value) => ({ borderTopRightRadius: value })
537
+ }),
538
+ defineRule({
539
+ name: "radius-bottom-left",
540
+ matcher: /^radius-bl-\[(.+)\]$/,
541
+ validate: isRadiusValue,
542
+ declaration: (value) => ({ borderBottomLeftRadius: value })
543
+ }),
544
+ defineRule({
545
+ name: "radius-bottom-right",
546
+ matcher: /^radius-br-\[(.+)\]$/,
547
+ validate: isRadiusValue,
548
+ declaration: (value) => ({ borderBottomRightRadius: value })
549
+ }),
550
+ defineRule({
551
+ name: "opacity",
552
+ matcher: /^opacity-\[(.+)\]$/,
553
+ validate: isOpacityValue,
554
+ declaration: (value) => ({ opacity: value })
555
+ }),
556
+ defineRule({
557
+ name: "color",
558
+ matcher: /^color-\[(.+)\]$/,
559
+ validate: isColorValue,
560
+ declaration: (value) => ({ color: value })
561
+ }),
562
+ defineRule({
563
+ name: "background-color",
564
+ matcher: /^bg-\[(.+)\]$/,
565
+ validate: isColorValue,
566
+ declaration: (value) => ({ backgroundColor: value })
567
+ })
568
+ ];
569
+ //#endregion
570
+ //#region src/plugin.ts
571
+ function resolveOptions(options = {}) {
572
+ return {
573
+ include: options.include ?? DEFAULT_INCLUDE,
574
+ exclude: [...DEFAULT_EXCLUDE, ...options.exclude ?? []],
575
+ outFile: options.outFile ?? "src/.generated/utils-jit.css",
576
+ breakpoints: {
577
+ ...DEFAULT_BREAKPOINTS,
578
+ ...options.breakpoints ?? {}
579
+ },
580
+ rules: options.rules ?? [],
581
+ variants: {
582
+ ...DEFAULT_VARIANTS,
583
+ ...options.variants ?? {}
584
+ },
585
+ banner: options.banner ?? "/* @vueland/utils-jit: generated utilities */",
586
+ emitEmptyFile: options.emitEmptyFile ?? true,
587
+ debug: options.debug ?? false
588
+ };
589
+ }
590
+ function normalizePath(value) {
591
+ return value.replace(/\\/g, "/");
592
+ }
593
+ function isSameFile(a, b) {
594
+ return normalizePath(node_path.resolve(a)) === normalizePath(node_path.resolve(b));
595
+ }
596
+ function matchesPattern(value, pattern) {
597
+ const normalized = normalizePath(value);
598
+ if (typeof pattern === "string") return normalized.includes(normalizePath(pattern));
599
+ pattern.lastIndex = 0;
600
+ return pattern.test(normalized);
601
+ }
602
+ function isExcluded(file, exclude) {
603
+ return exclude.some((pattern) => matchesPattern(file, pattern));
604
+ }
605
+ function collectProjectFiles(root, options, outFile) {
606
+ const files = [];
607
+ function walk(dir) {
608
+ if (isExcluded(dir, options.exclude)) return;
609
+ let entries;
610
+ try {
611
+ entries = node_fs.readdirSync(dir, { withFileTypes: true });
612
+ } catch {
613
+ return;
614
+ }
615
+ for (const entry of entries) {
616
+ const fullPath = node_path.join(dir, entry.name);
617
+ if (entry.isDirectory()) {
618
+ walk(fullPath);
619
+ continue;
620
+ }
621
+ if (!entry.isFile()) continue;
622
+ if (isSameFile(fullPath, outFile)) continue;
623
+ if (shouldProcess(fullPath, options.include, options.exclude)) files.push(fullPath);
624
+ }
625
+ }
626
+ walk(root);
627
+ return files;
628
+ }
629
+ function readFileSafe(file) {
630
+ try {
631
+ return node_fs.readFileSync(file, "utf8");
632
+ } catch {
633
+ return null;
634
+ }
635
+ }
636
+ function utilsJIT(options) {
637
+ const resolvedOptions = resolveOptions(options);
638
+ let root = process.cwd();
639
+ let outFile = "";
640
+ let devServer = null;
641
+ let currentCss = "";
642
+ const allRules = [...defaultRules, ...resolvedOptions.rules];
643
+ const fileToTokens = /* @__PURE__ */ new Map();
644
+ const tokenRefCount = /* @__PURE__ */ new Map();
645
+ const tokenParseCache = /* @__PURE__ */ new Map();
646
+ const tokenCssCache = /* @__PURE__ */ new Map();
647
+ const activeCssRules = /* @__PURE__ */ new Map();
648
+ function debug(message) {
649
+ if (resolvedOptions.debug) console.info(`[utils-jit] ${message}`);
650
+ }
651
+ function notifyCssChanged() {
652
+ if (!devServer || !outFile) return;
653
+ devServer.watcher.emit("change", outFile);
654
+ }
655
+ function getParsedToken(token) {
656
+ if (tokenParseCache.has(token)) return tokenParseCache.get(token) ?? null;
657
+ const parsed = parseToken(token);
658
+ tokenParseCache.set(token, parsed);
659
+ return parsed;
660
+ }
661
+ function getCssRuleForToken(token) {
662
+ if (tokenCssCache.has(token)) return tokenCssCache.get(token) ?? null;
663
+ const parsed = getParsedToken(token);
664
+ if (!parsed) {
665
+ tokenCssCache.set(token, null);
666
+ return null;
667
+ }
668
+ const cssBody = resolveRule(parsed.utility, allRules);
669
+ if (!cssBody) {
670
+ tokenCssCache.set(token, null);
671
+ return null;
672
+ }
673
+ const cssRule = buildCssRule(parsed, cssBody, resolvedOptions.breakpoints, resolvedOptions.variants);
674
+ tokenCssCache.set(token, cssRule);
675
+ return cssRule;
676
+ }
677
+ function buildFinalCss() {
678
+ if (!activeCssRules.size) return resolvedOptions.emitEmptyFile ? "/* @vueland/utils-jit: no utilities found */\n" : "";
679
+ const sortedRules = Array.from(activeCssRules.entries()).sort(([a], [b]) => a.localeCompare(b)).map(([, cssRule]) => cssRule);
680
+ return [
681
+ resolvedOptions.banner,
682
+ ...sortedRules,
683
+ ""
684
+ ].join("\n");
685
+ }
686
+ function writeCssFile(notify = false) {
687
+ if (!outFile) return;
688
+ const nextCss = buildFinalCss();
689
+ if (nextCss === currentCss) return;
690
+ currentCss = nextCss;
691
+ node_fs.mkdirSync(node_path.dirname(outFile), { recursive: true });
692
+ node_fs.writeFileSync(outFile, currentCss, "utf8");
693
+ if (devServer) devServer.watcher.add(outFile);
694
+ if (notify) notifyCssChanged();
695
+ debug(`wrote ${normalizePath(node_path.relative(root, outFile))}`);
696
+ }
697
+ function activateToken(token) {
698
+ const prevCount = tokenRefCount.get(token) ?? 0;
699
+ const nextCount = prevCount + 1;
700
+ tokenRefCount.set(token, nextCount);
701
+ if (prevCount === 0) {
702
+ const cssRule = getCssRuleForToken(token);
703
+ if (cssRule) activeCssRules.set(token, cssRule);
704
+ }
705
+ }
706
+ function deactivateToken(token) {
707
+ const prevCount = tokenRefCount.get(token) ?? 0;
708
+ if (prevCount <= 0) return;
709
+ const nextCount = prevCount - 1;
710
+ if (nextCount === 0) {
711
+ tokenRefCount.delete(token);
712
+ activeCssRules.delete(token);
713
+ return;
714
+ }
715
+ tokenRefCount.set(token, nextCount);
716
+ }
717
+ function applyFileTokens(file, nextTokens) {
718
+ const normalizedFile = normalizePath(file);
719
+ const prevTokens = fileToTokens.get(normalizedFile) ?? /* @__PURE__ */ new Set();
720
+ for (const token of prevTokens) if (!nextTokens.has(token)) deactivateToken(token);
721
+ for (const token of nextTokens) if (!prevTokens.has(token)) activateToken(token);
722
+ if (nextTokens.size > 0) fileToTokens.set(normalizedFile, nextTokens);
723
+ else fileToTokens.delete(normalizedFile);
724
+ }
725
+ function rebuildAll(notify = false) {
726
+ fileToTokens.clear();
727
+ tokenRefCount.clear();
728
+ activeCssRules.clear();
729
+ const files = collectProjectFiles(root, resolvedOptions, outFile);
730
+ for (const file of files) {
731
+ const code = readFileSafe(file);
732
+ if (code === null) continue;
733
+ const tokens = tokenize(code);
734
+ if (tokens.size > 0) {
735
+ fileToTokens.set(normalizePath(file), tokens);
736
+ for (const token of tokens) {
737
+ const count = tokenRefCount.get(token) ?? 0;
738
+ tokenRefCount.set(token, count + 1);
739
+ }
740
+ }
741
+ }
742
+ for (const [token, count] of tokenRefCount) {
743
+ if (count <= 0) continue;
744
+ const cssRule = getCssRuleForToken(token);
745
+ if (cssRule) activeCssRules.set(token, cssRule);
746
+ }
747
+ writeCssFile(notify);
748
+ debug(`scanned ${files.length} files, found ${activeCssRules.size} utilities`);
749
+ }
750
+ function rebuildOne(file, code, notify = false) {
751
+ if (isSameFile(file, outFile)) return;
752
+ if (!shouldProcess(file, resolvedOptions.include, resolvedOptions.exclude)) return;
753
+ applyFileTokens(file, tokenize(code));
754
+ writeCssFile(notify);
755
+ }
756
+ function removeOne(file, notify = false) {
757
+ if (isSameFile(file, outFile)) return;
758
+ const normalizedFile = normalizePath(file);
759
+ const prevTokens = fileToTokens.get(normalizedFile);
760
+ if (!prevTokens) return;
761
+ for (const token of prevTokens) deactivateToken(token);
762
+ fileToTokens.delete(normalizedFile);
763
+ writeCssFile(notify);
764
+ }
765
+ return {
766
+ name: "utils-jit",
767
+ enforce: "pre",
768
+ configResolved(config) {
769
+ root = config.root;
770
+ outFile = node_path.resolve(root, resolvedOptions.outFile);
771
+ rebuildAll(false);
772
+ },
773
+ configureServer(server) {
774
+ devServer = server;
775
+ if (outFile) server.watcher.add(outFile);
776
+ },
777
+ buildStart() {
778
+ rebuildAll(false);
779
+ },
780
+ transform(code, id) {
781
+ const file = id.split("?")[0];
782
+ if (!file || isSameFile(file, outFile)) return null;
783
+ rebuildOne(file, code, false);
784
+ return null;
785
+ },
786
+ async handleHotUpdate(ctx) {
787
+ const { file } = ctx;
788
+ if (isSameFile(file, outFile)) return;
789
+ if (!shouldProcess(file, resolvedOptions.include, resolvedOptions.exclude)) return;
790
+ rebuildOne(file, await ctx.read(), true);
791
+ },
792
+ watchChange(id, change) {
793
+ const file = id.split("?")[0];
794
+ if (!file || isSameFile(file, outFile)) return;
795
+ if (change.event === "delete") {
796
+ removeOne(file, true);
797
+ return;
798
+ }
799
+ if (!shouldProcess(file, resolvedOptions.include, resolvedOptions.exclude)) return;
800
+ const code = readFileSafe(file);
801
+ if (code !== null) rebuildOne(file, code, true);
802
+ }
803
+ };
804
+ }
805
+ //#endregion
806
+ exports.DEFAULT_BREAKPOINTS = DEFAULT_BREAKPOINTS;
807
+ exports.DEFAULT_EXCLUDE = DEFAULT_EXCLUDE;
808
+ exports.DEFAULT_INCLUDE = DEFAULT_INCLUDE;
809
+ exports.DEFAULT_VARIANTS = DEFAULT_VARIANTS;
810
+ exports.buildCssRule = buildCssRule;
811
+ exports.camelToKebab = camelToKebab;
812
+ exports.createArbitraryRule = createArbitraryRule;
813
+ exports.defaultRules = defaultRules;
814
+ exports.defineRule = defineRule;
815
+ exports.escapeCssSelector = escapeCssSelector;
816
+ exports.extractClassCandidates = extractClassCandidates;
817
+ exports.isColorValue = isColorValue;
818
+ exports.isCssGlobalValue = isCssGlobalValue;
819
+ exports.isFunctionalCssValue = isFunctionalCssValue;
820
+ exports.isLengthLikeValue = isLengthLikeValue;
821
+ exports.isLengthListValue = isLengthListValue;
822
+ exports.isMarginValue = isMarginValue;
823
+ exports.isNumberValue = isNumberValue;
824
+ exports.isOpacityValue = isOpacityValue;
825
+ exports.isPaddingValue = isPaddingValue;
826
+ exports.isPositionValue = isPositionValue;
827
+ exports.isRadiusValue = isRadiusValue;
828
+ exports.isSafeCssValue = isSafeCssValue;
829
+ exports.isSizeValue = isSizeValue;
830
+ exports.isZIndexValue = isZIndexValue;
831
+ exports.isZeroValue = isZeroValue;
832
+ exports.normalizeValue = normalizeValue;
833
+ exports.parseToken = parseToken;
834
+ exports.resolveRule = resolveRule;
835
+ exports.shouldProcess = shouldProcess;
836
+ exports.stripComments = stripComments;
837
+ exports.tokenize = tokenize;
838
+ exports.utilsJIT = utilsJIT;
839
+
840
+ //# sourceMappingURL=index.cjs.map