rainbowindex 0.6.0 → 0.7.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +543 -0
  2. package/LICENSE +16 -17
  3. package/NOTICE.md +106 -0
  4. package/README.md +219 -65
  5. package/dist/browser.d.ts +4 -2
  6. package/dist/browser.mjs +12 -4
  7. package/dist/chunk-2T7V5XLK.mjs +912 -0
  8. package/dist/chunk-6OORICWF.mjs +16 -0
  9. package/dist/{chunk-KSNYSR3C.mjs → chunk-FJOZJIKB.mjs} +2499 -329
  10. package/dist/chunk-L56IRO7A.mjs +491 -0
  11. package/dist/chunk-PZDVDEZJ.mjs +196 -0
  12. package/dist/{chunk-3LWJTLOJ.mjs → chunk-RC6DDE4L.mjs} +23 -15
  13. package/dist/chunk-TQJYVQPE.mjs +217 -0
  14. package/dist/chunk-W756NVYI.mjs +33 -0
  15. package/dist/chunk-WBESS2ZD.mjs +598 -0
  16. package/dist/{chunk-3HRMFZGE.mjs → chunk-X66Z2YHT.mjs} +2 -1
  17. package/dist/{chunk-6U4IOFOS.mjs → chunk-XQGSG2HK.mjs} +199 -555
  18. package/dist/cli.mjs +1077 -123
  19. package/dist/{index-DSgpB6bS.d.ts → context-DcBtnnan.d.ts} +47 -103
  20. package/dist/editor.d.ts +71 -433
  21. package/dist/editor.mjs +51 -368
  22. package/dist/eslint.d.ts +16 -0
  23. package/dist/eslint.mjs +32 -0
  24. package/dist/{index-4Kyaq3IZ.d.ts → imports-C9esHd5Q.d.ts} +78 -84
  25. package/dist/index-CNqdL5U0.d.ts +56 -0
  26. package/dist/index-Czx-EUwh.d.ts +138 -0
  27. package/dist/index-DW8YSxTz.d.ts +104 -0
  28. package/dist/index.d.ts +46 -5
  29. package/dist/index.mjs +33 -9
  30. package/dist/oxlint.d.ts +21 -3
  31. package/dist/oxlint.mjs +19 -1
  32. package/dist/recipe.d.ts +111 -0
  33. package/dist/recipe.mjs +71 -0
  34. package/dist/safelist-CH3_PywB.d.ts +43 -0
  35. package/dist/session-CMaskdB7.d.ts +543 -0
  36. package/dist/tailwind.css +644 -0
  37. package/dist/theme-CIZiGlce.d.ts +115 -0
  38. package/dist/vite.d.ts +10 -1
  39. package/dist/vite.mjs +266 -118
  40. package/package.json +27 -5
  41. package/dist/chunk-WK6S4HTC.mjs +0 -1921
  42. package/dist/chunk-ZR7XJMUN.mjs +0 -251
  43. package/dist/safelist-CGCtF-Fr.d.ts +0 -96
@@ -0,0 +1,598 @@
1
+ import {
2
+ ANIMATION_STATIC_NAMES,
3
+ BACKGROUND_STATIC_NAMES,
4
+ BORDER_STATIC_NAMES,
5
+ EFFECTS_STATIC_NAMES,
6
+ LAYOUT_STATIC_NAMES,
7
+ PREFIX_DISPATCH,
8
+ ROOT_GROUPS,
9
+ ROUNDED_CORNER_NAMES,
10
+ ROUNDED_SIDE_NAMES,
11
+ SPACING_SAMPLES,
12
+ STATIC_UTILITIES,
13
+ SVG_STATIC_NAMES,
14
+ TYPOGRAPHY_STATIC_NAMES,
15
+ buildBreakpointWeights,
16
+ codepointCompare,
17
+ compileUtility,
18
+ createEmptyCompilationResult,
19
+ escapeSelector,
20
+ findClosest,
21
+ listVariants,
22
+ parseUtility,
23
+ resolveUtilityDeclarations
24
+ } from "./chunk-FJOZJIKB.mjs";
25
+ import {
26
+ computeDarkStop,
27
+ formatOklch,
28
+ generateStop,
29
+ linearToSrgb,
30
+ oklabToLinearSrgb,
31
+ oklchToOklab
32
+ } from "./chunk-L56IRO7A.mjs";
33
+ import {
34
+ SPECIAL_COLORS
35
+ } from "./chunk-XQGSG2HK.mjs";
36
+
37
+ // src/project/css-entry.ts
38
+ var CSS_ENTRY_CANDIDATES = Object.freeze([
39
+ "src/index.css",
40
+ "src/style.css",
41
+ "src/styles.css",
42
+ "src/app.css",
43
+ "src/global.css",
44
+ "index.css",
45
+ "style.css",
46
+ "styles.css",
47
+ "app.css",
48
+ "global.css"
49
+ ]);
50
+
51
+ // src/theme/swatch.ts
52
+ var CANONICAL_COLOR_STOPS = Object.freeze([
53
+ 50,
54
+ 100,
55
+ 150,
56
+ 200,
57
+ 250,
58
+ 300,
59
+ 350,
60
+ 400,
61
+ 450,
62
+ 500,
63
+ 550,
64
+ 600,
65
+ 650,
66
+ 700,
67
+ 750,
68
+ 800,
69
+ 850,
70
+ 900,
71
+ 950
72
+ ]);
73
+ function channelHex(value) {
74
+ return Math.round(Math.min(1, Math.max(0, value)) * 255).toString(16).padStart(2, "0");
75
+ }
76
+ function oklchToHex(l, c, h) {
77
+ const [labL, labA, labB] = oklchToOklab(l, c, h);
78
+ const [r, g, b] = oklabToLinearSrgb(labL, labA, labB);
79
+ return `#${channelHex(linearToSrgb(r))}${channelHex(linearToSrgb(g))}${channelHex(linearToSrgb(b))}`;
80
+ }
81
+ var OKLCH_TEXT_RE = /^oklch\(\s*([\d.]+%?)\s+([\d.]+)\s+([\d.-]+)\s*(?:\/\s*[\d.]+%?\s*)?\)$/i;
82
+ var HEX_TEXT_RE = /^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;
83
+ function cssColorToHex(css) {
84
+ const text = css.trim();
85
+ if (HEX_TEXT_RE.test(text)) {
86
+ if (text.length === 4 || text.length === 5) {
87
+ return `#${text[1]}${text[1]}${text[2]}${text[2]}${text[3]}${text[3]}`.toLowerCase();
88
+ }
89
+ return text.slice(0, 7).toLowerCase();
90
+ }
91
+ const match = OKLCH_TEXT_RE.exec(text);
92
+ if (match) {
93
+ const rawL = match[1];
94
+ const l = rawL.endsWith("%") ? Number.parseFloat(rawL) / 100 : Number.parseFloat(rawL);
95
+ const c = Number.parseFloat(match[2]);
96
+ const h = Number.parseFloat(match[3]);
97
+ if (Number.isFinite(l) && Number.isFinite(c) && Number.isFinite(h)) {
98
+ return oklchToHex(l, c, h);
99
+ }
100
+ }
101
+ return null;
102
+ }
103
+ var MAX_ALIAS_HOPS = 8;
104
+ var SEMANTIC_SWATCHES = Object.freeze({
105
+ paper: {
106
+ light: { css: "oklch(1 0 0)", hex: "#ffffff" },
107
+ dark: { css: "oklch(0 0 0)", hex: "#000000" }
108
+ },
109
+ ink: {
110
+ light: { css: "oklch(0 0 0)", hex: "#000000" },
111
+ dark: { css: "oklch(1 0 0)", hex: "#ffffff" }
112
+ },
113
+ white: {
114
+ light: { css: "oklch(1 0 0)", hex: "#ffffff" },
115
+ dark: null
116
+ },
117
+ black: {
118
+ light: { css: "oklch(0 0 0)", hex: "#000000" },
119
+ dark: null
120
+ }
121
+ });
122
+ function swatchFromCss(css) {
123
+ return { css, hex: cssColorToHex(css) };
124
+ }
125
+ function resolveColorSwatch(theme, name, stop = 500) {
126
+ let def = theme.colors[name];
127
+ for (let hop = 0; def && def.type === "alias" && hop < MAX_ALIAS_HOPS; hop++) {
128
+ def = theme.colors[def.source];
129
+ }
130
+ if (!def || def.type === "alias") {
131
+ return SEMANTIC_SWATCHES[name] ?? null;
132
+ }
133
+ switch (def.type) {
134
+ case "generative": {
135
+ const light = generateStop(def, stop);
136
+ const lightSwatch = {
137
+ css: formatOklch(light.l, light.c, light.h),
138
+ hex: oklchToHex(light.l, light.c, light.h)
139
+ };
140
+ if (theme.darkConfig.mode === "off" || def.dark?.strategy === "fixed") {
141
+ return { light: lightSwatch, dark: null };
142
+ }
143
+ const dark = computeDarkStop(def, stop, theme.darkConfig, def.dark);
144
+ return {
145
+ light: lightSwatch,
146
+ dark: {
147
+ css: formatOklch(dark.l, dark.c, dark.h),
148
+ hex: oklchToHex(dark.l, dark.c, dark.h)
149
+ }
150
+ };
151
+ }
152
+ case "explicit":
153
+ return { light: swatchFromCss(def.value), dark: null };
154
+ case "pair":
155
+ return {
156
+ light: swatchFromCss(def.light),
157
+ dark: theme.darkConfig.mode === "off" ? null : swatchFromCss(def.dark)
158
+ };
159
+ case "keyword":
160
+ return null;
161
+ }
162
+ }
163
+ function listThemeTokens(theme) {
164
+ return {
165
+ colors: Object.entries(theme.colors).map(([name, def]) => ({ name, kind: def.type })),
166
+ colorStops: CANONICAL_COLOR_STOPS,
167
+ spacingBase: theme.spacing.base,
168
+ textSizes: Object.entries(theme.text).map(([name, def]) => ({
169
+ name,
170
+ fontSize: def.fontSize,
171
+ lineHeight: def.lineHeight
172
+ })),
173
+ breakpoints: { ...theme.breakpoints },
174
+ shadows: { ...theme.shadows },
175
+ weights: { ...theme.weights },
176
+ easing: { ...theme.easing },
177
+ blur: { ...theme.blur },
178
+ z: { ...theme.z },
179
+ leading: { ...theme.leading },
180
+ tracking: { ...theme.tracking },
181
+ opacity: { ...theme.opacity },
182
+ duration: { ...theme.duration },
183
+ radii: { ...theme.radii },
184
+ fluidRanges: Object.fromEntries(
185
+ Object.entries(theme.fluidRanges).map(([name, range]) => [
186
+ name,
187
+ { min: range.min, max: range.max }
188
+ ])
189
+ ),
190
+ fonts: theme.fonts.map((slot) => ({ slot: slot.slot, family: slot.family })),
191
+ animations: Object.keys(theme.animations)
192
+ };
193
+ }
194
+
195
+ // src/utilities/enumerate.ts
196
+ var COLOR_STOPS = Object.freeze([
197
+ "50",
198
+ "100",
199
+ "150",
200
+ "200",
201
+ "250",
202
+ "300",
203
+ "350",
204
+ "400",
205
+ "450",
206
+ "500",
207
+ "550",
208
+ "600",
209
+ "650",
210
+ "700",
211
+ "750",
212
+ "800",
213
+ "850",
214
+ "900",
215
+ "950"
216
+ ]);
217
+ var FRACTION_SAMPLES = Object.freeze([
218
+ "1/2",
219
+ "1/3",
220
+ "2/3",
221
+ "1/4",
222
+ "3/4",
223
+ "1/5",
224
+ "2/5",
225
+ "3/5",
226
+ "4/5",
227
+ "1/6",
228
+ "5/6"
229
+ ]);
230
+ var INT_SAMPLES = Object.freeze(["0", "1", "2", "3", "4", "6", "8", "10", "12"]);
231
+ var INT_RE = /^\d+$/;
232
+ var WEIGHT_STEPS = Object.freeze(["100", "200", "300", "400", "500", "600", "700", "800", "900"]);
233
+ var PERCENT_SAMPLES = Object.freeze([
234
+ "0",
235
+ "5",
236
+ "10",
237
+ "15",
238
+ "20",
239
+ "25",
240
+ "30",
241
+ "40",
242
+ "50",
243
+ "60",
244
+ "70",
245
+ "75",
246
+ "80",
247
+ "90",
248
+ "95",
249
+ "100"
250
+ ]);
251
+ var BUILTIN_FONT_SLOTS = Object.freeze(["sans", "serif", "mono"]);
252
+ var DURATION_SAMPLES = Object.freeze(["75", "100", "150", "200", "300", "500", "700", "1000"]);
253
+ var ROUNDED_SIDES = Object.freeze([
254
+ ...ROUNDED_SIDE_NAMES,
255
+ ...ROUNDED_CORNER_NAMES
256
+ ]);
257
+ var RADIUS_SAMPLES = Object.freeze([...SPACING_SAMPLES, "none", "full"]);
258
+ function buildValueSpaces() {
259
+ const table = /* @__PURE__ */ new Map();
260
+ for (const { roots, spec } of ROOT_GROUPS) {
261
+ for (const root of roots) {
262
+ let entry = table.get(root);
263
+ if (!entry) {
264
+ entry = { kinds: /* @__PURE__ */ new Set(), keywords: /* @__PURE__ */ new Set() };
265
+ table.set(root, entry);
266
+ }
267
+ for (const kind of spec.kinds) entry.kinds.add(kind);
268
+ for (const kw of spec.keywords ?? []) entry.keywords.add(kw);
269
+ }
270
+ }
271
+ const out = /* @__PURE__ */ new Map();
272
+ for (const [root, entry] of table) {
273
+ out.set(root, {
274
+ kinds: Object.freeze([...entry.kinds]),
275
+ keywords: entry.keywords.size > 0 ? Object.freeze([...entry.keywords]) : void 0
276
+ });
277
+ }
278
+ return out;
279
+ }
280
+ var UTILITY_VALUE_SPACES = buildValueSpaces();
281
+ function candidateValues(kind, theme) {
282
+ switch (kind) {
283
+ case "color": {
284
+ const out = [];
285
+ for (const name of Object.keys(theme.colors)) {
286
+ for (const stop of COLOR_STOPS) out.push(`${name}-${stop}`);
287
+ }
288
+ return out;
289
+ }
290
+ case "special-color":
291
+ return Object.keys(SPECIAL_COLORS);
292
+ case "spacing":
293
+ return [...SPACING_SAMPLES];
294
+ case "fraction":
295
+ return [...FRACTION_SAMPLES];
296
+ case "text-size":
297
+ return Object.keys(theme.text);
298
+ case "fluid-text-size":
299
+ return Object.keys(theme.text).map((size) => `fluid-${size}`);
300
+ case "fluid-range":
301
+ return Object.keys(theme.fluidRanges);
302
+ case "font-slot":
303
+ return [.../* @__PURE__ */ new Set([...BUILTIN_FONT_SLOTS, ...theme.fonts.map((slot) => slot.slot)])];
304
+ case "weight":
305
+ return [...Object.keys(theme.weights), ...WEIGHT_STEPS];
306
+ // Named @rounded radii plus the spacing multiples, the way @weight pairs
307
+ // its tokens with the numeric steps. Without the names, `rounded-roof`
308
+ // compiles but is offered by neither completions nor generated types.
309
+ case "rounded":
310
+ return [...Object.keys(theme.radii), ...RADIUS_SAMPLES];
311
+ case "rounded-side": {
312
+ const out = [];
313
+ const sizes = [...Object.keys(theme.radii), ...RADIUS_SAMPLES];
314
+ for (const side of ROUNDED_SIDES) {
315
+ for (const size of sizes) out.push(`${side}-${size}`);
316
+ }
317
+ return out;
318
+ }
319
+ case "shadow":
320
+ return Object.keys(theme.shadows);
321
+ case "z":
322
+ return Object.keys(theme.z);
323
+ case "ease":
324
+ return Object.keys(theme.easing);
325
+ case "blur":
326
+ return Object.keys(theme.blur);
327
+ case "animation":
328
+ return Object.keys(theme.animations);
329
+ case "leading":
330
+ return Object.keys(theme.leading);
331
+ case "tracking":
332
+ return Object.keys(theme.tracking);
333
+ case "opacity":
334
+ return Object.keys(theme.opacity);
335
+ case "duration":
336
+ return [.../* @__PURE__ */ new Set([...Object.keys(theme.duration), ...DURATION_SAMPLES])];
337
+ case "breakpoint":
338
+ return Object.keys(theme.breakpoints);
339
+ case "int":
340
+ return [...INT_SAMPLES];
341
+ case "percent":
342
+ return [...PERCENT_SAMPLES];
343
+ case "keywords":
344
+ return [];
345
+ }
346
+ }
347
+ function enumerateClassNames(theme) {
348
+ const seen = /* @__PURE__ */ new Set();
349
+ const classes = [];
350
+ const templates = [];
351
+ const probeWarnings = [];
352
+ const resolves = (name) => resolveUtilityDeclarations(parseUtility(name), theme, probeWarnings) !== null;
353
+ const emit = (name, kind, root) => {
354
+ if (seen.has(name)) return;
355
+ if (!resolves(name)) return;
356
+ seen.add(name);
357
+ classes.push({ name, kind, root });
358
+ };
359
+ for (const name of STATIC_UTILITIES) emit(name, "static", null);
360
+ for (const names of [
361
+ ANIMATION_STATIC_NAMES,
362
+ BORDER_STATIC_NAMES,
363
+ BACKGROUND_STATIC_NAMES,
364
+ EFFECTS_STATIC_NAMES,
365
+ LAYOUT_STATIC_NAMES,
366
+ SVG_STATIC_NAMES,
367
+ TYPOGRAPHY_STATIC_NAMES
368
+ ]) {
369
+ for (const name of names) emit(name, "static", null);
370
+ }
371
+ for (const custom of theme.customUtilities) {
372
+ if (custom.functional) {
373
+ templates.push({ root: custom.name, kind: "custom", example: `${custom.name}-value` });
374
+ } else {
375
+ emit(custom.name, "custom", null);
376
+ }
377
+ }
378
+ for (const root of PREFIX_DISPATCH.keys()) {
379
+ const spec = UTILITY_VALUE_SPACES.get(root);
380
+ if (!spec) continue;
381
+ let spacingHit = false;
382
+ let intHit = false;
383
+ for (const kind of spec.kinds) {
384
+ for (const value of candidateValues(kind, theme)) {
385
+ const name = `${root}-${value}`;
386
+ if (seen.has(name)) continue;
387
+ if (!resolves(name)) continue;
388
+ seen.add(name);
389
+ classes.push({ name, kind, root });
390
+ if (kind === "spacing") spacingHit = true;
391
+ if (kind === "int" || kind === "weight" && INT_RE.test(value)) intHit = true;
392
+ }
393
+ }
394
+ for (const keyword of spec.keywords ?? []) {
395
+ emit(`${root}-${keyword}`, "keywords", root);
396
+ }
397
+ if (spacingHit) templates.push({ root, kind: "spacing", example: `${root}-4` });
398
+ else if (intHit) templates.push({ root, kind: "number", example: `${root}-2` });
399
+ }
400
+ classes.sort((a, b) => codepointCompare(a.name, b.name));
401
+ templates.sort((a, b) => codepointCompare(a.root, b.root));
402
+ return { classes, templates };
403
+ }
404
+
405
+ // src/engine/inspector.ts
406
+ var RESOLUTION_CACHE_CAP = 1e4;
407
+ var OK = Object.freeze({ ok: true });
408
+ function createClassInspector(theme) {
409
+ const customVariantMap = new Map(theme.customVariants.map((cv) => [cv.name, cv]));
410
+ const breakpointWeights = buildBreakpointWeights(theme.breakpoints);
411
+ const variantMemo = /* @__PURE__ */ new Map();
412
+ const scratch = createEmptyCompilationResult();
413
+ const warnSeen = /* @__PURE__ */ new Set();
414
+ const detail = { reason: null, variant: null, declarations: null };
415
+ const cache = /* @__PURE__ */ new Map();
416
+ let variantList = null;
417
+ let variantNames = null;
418
+ let utilityCorpus = null;
419
+ function variants() {
420
+ if (!variantList) variantList = Object.freeze(listVariants(theme));
421
+ return variantList;
422
+ }
423
+ function variantSuggestionCorpus() {
424
+ if (!variantNames) {
425
+ const names = [];
426
+ for (const v of variants()) {
427
+ if (v.kind !== "pattern") names.push(v.name);
428
+ }
429
+ variantNames = names;
430
+ }
431
+ return variantNames;
432
+ }
433
+ function utilitySuggestionCorpus() {
434
+ if (!utilityCorpus) {
435
+ const names = new Set(STATIC_UTILITIES);
436
+ for (const custom of theme.customUtilities) {
437
+ if (!custom.functional) names.add(custom.name);
438
+ }
439
+ for (const entry of enumerateClassNames(theme).classes) names.add(entry.name);
440
+ utilityCorpus = [...names];
441
+ }
442
+ return utilityCorpus;
443
+ }
444
+ function baseName(raw, parsed) {
445
+ let base = raw;
446
+ if (parsed.variants.length > 0) {
447
+ const prefix = `${parsed.variants.join(":")}:`;
448
+ if (base.startsWith(prefix)) base = base.slice(prefix.length);
449
+ }
450
+ if (parsed.important && base.endsWith("!")) base = base.slice(0, -1);
451
+ return base;
452
+ }
453
+ function resolve(className) {
454
+ const cached = cache.get(className);
455
+ if (cached) return cached;
456
+ if (cache.size >= RESOLUTION_CACHE_CAP) {
457
+ cache.clear();
458
+ variantMemo.clear();
459
+ }
460
+ scratch.warnings.length = 0;
461
+ warnSeen.clear();
462
+ const parsed = parseUtility(className);
463
+ const rule = compileUtility(
464
+ parsed,
465
+ theme,
466
+ scratch,
467
+ customVariantMap,
468
+ warnSeen,
469
+ breakpointWeights,
470
+ variantMemo,
471
+ detail
472
+ );
473
+ let entry;
474
+ if (rule) {
475
+ entry = {
476
+ validation: OK,
477
+ explanation: {
478
+ parsed,
479
+ declarations: detail.declarations ? [...detail.declarations] : [],
480
+ selector: rule.selector,
481
+ css: rule.css,
482
+ sortKey: rule.sortKey
483
+ }
484
+ };
485
+ } else if (detail.reason === "marker") {
486
+ entry = {
487
+ validation: OK,
488
+ explanation: {
489
+ parsed,
490
+ declarations: [],
491
+ selector: `.${escapeSelector(parsed.utility)}`,
492
+ css: "",
493
+ sortKey: 0,
494
+ marker: true
495
+ }
496
+ };
497
+ } else if (detail.reason === "unknown-variant" && detail.variant !== null) {
498
+ const suggestion = findClosest(detail.variant, variantSuggestionCorpus());
499
+ entry = {
500
+ validation: {
501
+ ok: false,
502
+ reason: "unknown-variant",
503
+ offender: detail.variant,
504
+ ...suggestion ? { suggestion } : {}
505
+ },
506
+ explanation: null
507
+ };
508
+ } else {
509
+ const base = baseName(className, parsed);
510
+ if (parsed.arbitrary || parsed.arbitraryProperty !== null) {
511
+ entry = {
512
+ validation: { ok: false, reason: "invalid-arbitrary", offender: base },
513
+ explanation: null
514
+ };
515
+ } else {
516
+ const suggestion = findClosest(base, utilitySuggestionCorpus());
517
+ entry = {
518
+ validation: {
519
+ ok: false,
520
+ reason: "unknown-utility",
521
+ offender: base,
522
+ ...suggestion ? { suggestion } : {}
523
+ },
524
+ explanation: null
525
+ };
526
+ }
527
+ }
528
+ cache.set(className, entry);
529
+ return entry;
530
+ }
531
+ return {
532
+ theme,
533
+ validate: (className) => resolve(className).validation,
534
+ explain: (className) => resolve(className).explanation,
535
+ variants
536
+ };
537
+ }
538
+
539
+ // src/editor/candidates.ts
540
+ function lastIndexWithStart(starts, value, inclusive) {
541
+ let low = 0;
542
+ let high = starts.length - 1;
543
+ let found = -1;
544
+ while (low <= high) {
545
+ const mid = low + high >> 1;
546
+ if (inclusive ? starts[mid] <= value : starts[mid] < value) {
547
+ found = mid;
548
+ low = mid + 1;
549
+ } else {
550
+ high = mid - 1;
551
+ }
552
+ }
553
+ return found;
554
+ }
555
+ function outermostCandidates(candidates) {
556
+ if (candidates.length < 2) return [...candidates];
557
+ const spans = [];
558
+ for (const candidate of candidates) {
559
+ spans.push({ start: candidate.start, end: candidate.end });
560
+ if (candidate.groupPrefix) spans.push(candidate.groupPrefix);
561
+ }
562
+ spans.sort((a, b) => a.start - b.start || a.end - b.end);
563
+ const starts = spans.map((span) => span.start);
564
+ const prefixMaxEnd = new Array(spans.length);
565
+ let running = Number.NEGATIVE_INFINITY;
566
+ for (let i = 0; i < spans.length; i++) {
567
+ running = Math.max(running, spans[i].end);
568
+ prefixMaxEnd[i] = running;
569
+ }
570
+ const seenSpans = /* @__PURE__ */ new Set();
571
+ const kept = [];
572
+ for (const candidate of candidates) {
573
+ const atOrBefore = lastIndexWithStart(starts, candidate.start, true);
574
+ const before = lastIndexWithStart(starts, candidate.start, false);
575
+ const reachAtOrBefore = atOrBefore === -1 ? Number.NEGATIVE_INFINITY : prefixMaxEnd[atOrBefore];
576
+ const reachBefore = before === -1 ? Number.NEGATIVE_INFINITY : prefixMaxEnd[before];
577
+ if (reachAtOrBefore > candidate.end || reachBefore >= candidate.end) continue;
578
+ const key = `${candidate.start}:${candidate.end}`;
579
+ if (seenSpans.has(key)) continue;
580
+ seenSpans.add(key);
581
+ kept.push(candidate);
582
+ }
583
+ kept.sort((a, b) => a.start - b.start);
584
+ return kept;
585
+ }
586
+
587
+ export {
588
+ CSS_ENTRY_CANDIDATES,
589
+ CANONICAL_COLOR_STOPS,
590
+ oklchToHex,
591
+ cssColorToHex,
592
+ resolveColorSwatch,
593
+ listThemeTokens,
594
+ UTILITY_VALUE_SPACES,
595
+ enumerateClassNames,
596
+ createClassInspector,
597
+ outermostCandidates
598
+ };
@@ -8,7 +8,8 @@ var SOURCE_FILE_EXTENSIONS = Object.freeze([
8
8
  "md",
9
9
  "mdx",
10
10
  "vue",
11
- "svelte"
11
+ "svelte",
12
+ "astro"
12
13
  ]);
13
14
  function isSourceFile(file) {
14
15
  return SOURCE_FILE_EXTENSIONS.some((ext) => file.endsWith(`.${ext}`));