rainbowindex 0.2.0 → 0.2.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/cli.mjs CHANGED
@@ -1,22 +1,29 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ CSS_ENTRY_CANDIDATES,
4
+ enumerateClassNames
5
+ } from "./chunk-KYDEHYIE.mjs";
2
6
  import {
3
7
  DEFAULT_EXCLUDES,
4
8
  DEFAULT_PATTERNS,
5
- MAX_DIRECTIVE_INPUT_SIZE,
6
- analyzeProjectCSS,
7
9
  collectProjectClasses,
8
- extractDirectives,
9
10
  finalizeProjectCompilation,
10
11
  getFontPreloadLinks,
11
- hasApplyLikeDirective,
12
- hasRIActivation,
13
- resolveDirectives,
14
12
  resolveGoogleFonts,
15
13
  validateGlobPattern
16
- } from "./chunk-RPXZ3O6R.mjs";
14
+ } from "./chunk-FHATRQMN.mjs";
15
+ import {
16
+ MAX_DIRECTIVE_INPUT_SIZE,
17
+ analyzeProjectCSS,
18
+ extractDirectives,
19
+ hasApplyLikeDirective,
20
+ hasRIActivation,
21
+ listVariants,
22
+ resolveDirectives
23
+ } from "./chunk-W6XIBM4M.mjs";
17
24
  import {
18
25
  devWarn
19
- } from "./chunk-5N4GPK26.mjs";
26
+ } from "./chunk-SOMDX7V6.mjs";
20
27
 
21
28
  // src/entries/cli.ts
22
29
  import { realpathSync } from "fs";
@@ -314,21 +321,9 @@ Examples:
314
321
  import { existsSync } from "fs";
315
322
  import { readFile, stat } from "fs/promises";
316
323
  import { resolve as resolve2 } from "path";
317
- var CSS_CANDIDATES = Object.freeze([
318
- "src/index.css",
319
- "src/style.css",
320
- "src/styles.css",
321
- "src/app.css",
322
- "src/global.css",
323
- "index.css",
324
- "style.css",
325
- "styles.css",
326
- "app.css",
327
- "global.css"
328
- ]);
329
324
  var MAX_CSS_FILE_SIZE = MAX_DIRECTIVE_INPUT_SIZE;
330
325
  async function findCSSFileAsync(cwd) {
331
- const candidates = CSS_CANDIDATES;
326
+ const candidates = CSS_ENTRY_CANDIDATES;
332
327
  const results = await Promise.all(
333
328
  candidates.map(async (candidate) => {
334
329
  const full = resolve2(cwd, candidate);
@@ -452,19 +447,37 @@ async function generateTypes(opts, cwd) {
452
447
  return false;
453
448
  });
454
449
  };
450
+ const literalSafe = (names) => names.filter((n) => !n.includes('"') && !n.includes("\\"));
451
+ const enumeration = enumerateClassNames(theme);
452
+ const variants = listVariants(theme);
455
453
  const colorNames = validateNames(Object.keys(theme.colors), "color");
456
454
  const textSizes = validateNames(Object.keys(theme.text), "text");
457
- const breakpoints = validateNames(Object.keys(theme.breakpoints), "breakpoint");
458
455
  const weightNames = validateNames(Object.keys(theme.weights), "weight");
459
- const staticCustomUtilities = validateNames(
460
- theme.customUtilities.filter((u) => !u.functional).map((u) => u.name),
461
- "utility"
456
+ const variantNames = literalSafe(variants.filter((v) => v.kind !== "pattern").map((v) => v.name));
457
+ const finiteClasses = literalSafe(enumeration.classes.map((c) => c.name));
458
+ const spacingRoots = validateNames(
459
+ enumeration.templates.filter((t) => t.kind === "spacing").map((t) => t.root),
460
+ "spacing root"
461
+ );
462
+ const numericRoots = validateNames(
463
+ enumeration.templates.filter((t) => t.kind === "number").map((t) => t.root),
464
+ "numeric root"
462
465
  );
463
466
  const functionalCustomUtilities = validateNames(
464
- theme.customUtilities.filter((u) => u.functional).map((u) => u.name),
467
+ enumeration.templates.filter((t) => t.kind === "custom").map((t) => t.root),
465
468
  "utility"
466
469
  );
467
470
  const union = (names) => names.length > 0 ? names.map((n) => `"${n}"`).join(" | ") : "never";
471
+ const unionLines = (names, perLine) => {
472
+ if (names.length === 0) return [" | never"];
473
+ const lines2 = [];
474
+ for (let i = 0; i < names.length; i += perLine) {
475
+ lines2.push(
476
+ ` | ${names.slice(i, i + perLine).map((n) => `"${n}"`).join(" | ")}`
477
+ );
478
+ }
479
+ return lines2;
480
+ };
468
481
  const lines = [
469
482
  "// rainbowindex-env.d.ts (auto-generated \u2014 do not edit)",
470
483
  "",
@@ -472,25 +485,44 @@ async function generateTypes(opts, cwd) {
472
485
  `type ColorStop = "50" | "100" | "150" | "200" | "250" | "300" | "350" | "400" | "450" | "500" | "550" | "600" | "650" | "700" | "750" | "800" | "850" | "900" | "950";`,
473
486
  "type SpacingToken = `${number}` | `${number}_${number}`;",
474
487
  `type TextSize = ${union(textSizes)};`,
475
- `type Variant = ${union(breakpoints)} | "hover" | "focus" | "focus-visible" | "active" | "disabled" | "dark" | "first" | "last" | "odd" | "even";`,
476
488
  `type WeightName = ${union(weightNames)};`,
477
489
  "",
478
- "type RainbowClass =",
479
- ' | `${"bg" | "text" | "border" | "outline" | "accent" | "caret" | "fill" | "stroke"}-${ColorName}-${ColorStop}`',
480
- ' | `${"p" | "px" | "py" | "pt" | "pb" | "pl" | "pr" | "ps" | "pe" | "pbs" | "pbe" | "m" | "mx" | "my" | "mt" | "mb" | "ml" | "mr" | "ms" | "me" | "mbs" | "mbe" | "gap" | "gap-x" | "gap-y"}-${SpacingToken}`',
481
- " | `text-${TextSize}`",
482
- " | `text-fluid-${TextSize}`",
483
- ' | `font-${"sans" | "serif" | "mono"}`',
484
- " | `font-${WeightName}`",
485
- " | `w-${SpacingToken}` | `h-${SpacingToken}` | `size-${SpacingToken}`"
490
+ "type Variant =",
491
+ ...unionLines(variantNames, 8),
492
+ " ;",
493
+ "",
494
+ "// Every finite class the compiler resolves for this theme \u2014 statics plus",
495
+ "// theme-token expansions, enumerated and probe-verified.",
496
+ "type RainbowStatic =",
497
+ ...unionLines(finiteClasses, 6),
498
+ " ;"
486
499
  ];
487
- if (staticCustomUtilities.length > 0) {
488
- lines.push(` | ${staticCustomUtilities.map((n) => `"${n}"`).join(" | ")}`);
500
+ if (spacingRoots.length > 0) {
501
+ lines.push("", `type SpacingRoot = ${union(spacingRoots)};`);
502
+ }
503
+ if (numericRoots.length > 0) {
504
+ lines.push(`type NumericRoot = ${union(numericRoots)};`);
505
+ }
506
+ lines.push("", "type RainbowBase =", " | RainbowStatic");
507
+ if (spacingRoots.length > 0) {
508
+ lines.push(" | `${SpacingRoot}-${SpacingToken}`");
509
+ }
510
+ if (numericRoots.length > 0) {
511
+ lines.push(" | `${NumericRoot}-${number}`");
489
512
  }
490
513
  if (functionalCustomUtilities.length > 0) {
491
514
  lines.push(` | ${functionalCustomUtilities.map((n) => `\`${n}-\${string}\``).join(" | ")}`);
492
515
  }
493
- lines.push(" | `${Variant}:${Exclude<RainbowClass, `${string}:${string}`>}`");
516
+ lines.push(" ;");
517
+ lines.push(
518
+ "",
519
+ "type RainbowClass =",
520
+ " | RainbowBase",
521
+ " // Variant-prefixed classes validate the variant name (chained prefixes",
522
+ " // match through the open remainder). Expanding Variant \xD7 RainbowBase",
523
+ " // eagerly would exceed TypeScript's union-size limits.",
524
+ " | `${Variant}:${string}`"
525
+ );
494
526
  if (!opts.strict) {
495
527
  lines.push(" | (string & {});");
496
528
  } else {
@@ -1054,7 +1086,7 @@ async function resolveStylesheetPath(cwd, cssFile) {
1054
1086
  if (cssFile) return resolve5(cwd, cssFile);
1055
1087
  const importedCSS = await findImportedStylesheet(cwd);
1056
1088
  if (importedCSS) return importedCSS;
1057
- for (const candidate of CSS_CANDIDATES) {
1089
+ for (const candidate of CSS_ENTRY_CANDIDATES) {
1058
1090
  const fullPath = resolve5(cwd, candidate);
1059
1091
  if (existsSync3(fullPath)) return fullPath;
1060
1092
  }
@@ -1201,7 +1233,7 @@ function readPackageJSONSync(cwd) {
1201
1233
 
1202
1234
  // src/entries/cli.ts
1203
1235
  function getVersion() {
1204
- return true ? "0.2.0" : "unknown";
1236
+ return true ? "0.2.2" : "unknown";
1205
1237
  }
1206
1238
  async function main() {
1207
1239
  const args = process.argv.slice(2);
@@ -0,0 +1,464 @@
1
+ import { P as ParsedDirective, R as ResolvedTheme } from './index-DK6APAGD.js';
2
+ export { b as createThemeSnapshot } from './index-DK6APAGD.js';
3
+ import { C as ColorDefinition, b as CompilationSnapshot, M as MergeAnalysis } from './index-CfDtWufj.js';
4
+ export { n as MergeDrop, o as analyzeMerge, f as defaultTheme } from './index-CfDtWufj.js';
5
+
6
+ /** Helper-call names whose string arguments are walked for class literals.
7
+ * Exported for editor tooling so completion-context detection can match the
8
+ * scanner's own behavior. */
9
+ declare const CLASS_HELPER_NAMES: readonly string[];
10
+ /** Variant-config helper names (`cva`/`tv`) whose config objects are walked. */
11
+ declare const VARIANT_HELPER_NAMES: readonly string[];
12
+ interface SourceExtractionInput {
13
+ path?: string;
14
+ content: string;
15
+ }
16
+ type CandidateOrigin = "attribute" | "helper" | "safelist" | "plain";
17
+ interface ClassCandidate {
18
+ /** The class string in expanded form — for variant-group members this
19
+ * includes the group prefix (`hover:bg-red-500`) even though the span
20
+ * covers only the member token inside the braces. */
21
+ value: string;
22
+ /** Absolute [start, end) span of the visible token in the original source.
23
+ * `source.slice(start, end)` is the member token for group members and
24
+ * `value` itself everywhere else. */
25
+ start: number;
26
+ end: number;
27
+ origin: CandidateOrigin;
28
+ /** The call the class was found in, when origin is "helper"/"safelist". */
29
+ helperName?: string;
30
+ /** For variant-group members: span of the group's variant prefix (`hover:`). */
31
+ groupPrefix?: {
32
+ start: number;
33
+ end: number;
34
+ };
35
+ }
36
+ declare function expandVariantGroups(input: string, warnings?: string[]): string;
37
+ declare function extractClasses(source: string, warnings?: string[]): Set<string>;
38
+ declare function extractClassesFromSource(input: SourceExtractionInput, warnings?: string[]): Set<string>;
39
+ /**
40
+ * Position-aware variant of `extractClassesFromSource` for editor tooling.
41
+ * Same extractors, same filters, same pruning — the value set of the result
42
+ * always equals `extractClassesFromSource(input)`. Each candidate additionally
43
+ * carries its source span, its collection origin, and (for variant-group
44
+ * members) the group's prefix span. Candidates are sorted by position and
45
+ * deduped by span + value; a span found by both the whole-file scan and a
46
+ * context-aware collector reports the collector's origin.
47
+ */
48
+ declare function extractClassCandidates(input: SourceExtractionInput, warnings?: string[]): ClassCandidate[];
49
+
50
+ /**
51
+ * Lightweight source-file detection — no heavy dependencies (tinyglobby, etc.).
52
+ * Kept separate so the Vite integration can import it without pulling in
53
+ * Node-only glob machinery into browser bundles.
54
+ */
55
+ declare function isSourceFile(file: string): boolean;
56
+
57
+ /**
58
+ * Default CSS entry candidates — the paths the CLI, the Vite plugin, and
59
+ * editor tooling probe (in order) when locating the project's Rainbow Index
60
+ * CSS input. Pure data, no filesystem access: IO-free consumers (editor
61
+ * tooling) reuse the exact detection order with their own file access and
62
+ * confirm a hit with `hasRIActivation()` on the file's contents.
63
+ */
64
+ declare const CSS_ENTRY_CANDIDATES: readonly string[];
65
+
66
+ /** Import specifiers that activate RainbowIndex. Single source for the
67
+ * activation scan here, the PostCSS import matcher, and the strip regex. */
68
+ declare const RI_IMPORT_SPECIFIERS: readonly string[];
69
+ /**
70
+ * Detect whether source activates RainbowIndex: any RI directive token
71
+ * (including PostCSS-only `@apply` and `@slot`) or an `@import` of the
72
+ * package CSS, outside comments/strings. One fused scan covers both.
73
+ */
74
+ declare function hasRIActivation(src: string): boolean;
75
+
76
+ /**
77
+ * Structured diagnostics — the typed view of the `[RI-NNNN] message` warning
78
+ * strings, for editor tooling that anchors problems to source spans.
79
+ *
80
+ * The legacy string arrays stay the wire format everywhere (and the warning
81
+ * budget/dedup in warnings.ts keeps operating on them); a Diagnostic carries
82
+ * the same full message text verbatim, plus the parsed code, a severity
83
+ * derived from the documented code-range convention, and — when the emission
84
+ * site knew one — a [start, end) span into the CSS input. Consumers can rely
85
+ * on `diagnostics[i].message === warnings[i]` wherever both are returned.
86
+ */
87
+ type DiagnosticSeverity = "error" | "warning";
88
+ interface Diagnostic {
89
+ /** The RI-NNNN code, or null when the message carries no parseable code. */
90
+ code: string | null;
91
+ severity: DiagnosticSeverity;
92
+ /** The full legacy warning text, including the `[RI-NNNN]` prefix. */
93
+ message: string;
94
+ /** [start, end) span in the analyzed CSS input, or null when unknown. */
95
+ start: number | null;
96
+ end: number | null;
97
+ }
98
+ /** Extract the RI-NNNN code from a legacy warning string, or null. */
99
+ declare function warningCode(message: string): string | null;
100
+ /**
101
+ * Severity by code range — the same convention warnings.ts budgets by:
102
+ * RI-0xxx (fatal/bootstrap) and RI-2xxx (compile/runtime errors) are errors,
103
+ * everything else (informational 1xxx ranges) is a warning.
104
+ */
105
+ declare function severityForCode(code: string | null): DiagnosticSeverity;
106
+ /** Wrap a legacy warning string as a Diagnostic, with an optional span. */
107
+ declare function diagnosticFromWarning(message: string, span?: readonly [number, number] | null): Diagnostic;
108
+
109
+ /**
110
+ * Theme-only project analysis — the cheap front half of compileProject.
111
+ *
112
+ * Kept in a leaf module (no assembly/font machinery in the import graph) so
113
+ * IO-free consumers — the `rainbowindex/editor` entry — can turn a CSS input
114
+ * string into a ResolvedTheme without dragging Node-only code along.
115
+ * `project/pipeline.ts` re-exports this module, so existing importers are
116
+ * unaffected.
117
+ */
118
+
119
+ interface ProjectAnalysis {
120
+ directives: ParsedDirective[];
121
+ theme: ResolvedTheme;
122
+ warnings: string[];
123
+ warningSeen: Set<string>;
124
+ /**
125
+ * Structured view of `warnings` — same messages, same order
126
+ * (`diagnostics[i].message === warnings[i]`), each with the parsed code,
127
+ * range-derived severity, and a [start, end) span into the CSS input when
128
+ * the emitter knew one: directive-parse problems point at the offending
129
+ * at-rule, resolver problems at the directive whose body produced them.
130
+ */
131
+ diagnostics: Diagnostic[];
132
+ }
133
+ declare function analyzeProjectCSS(css: string): ProjectAnalysis;
134
+
135
+ /**
136
+ * Parses utility class strings into structured tokens.
137
+ *
138
+ * "hover:bg-red-500" → { variants: ["hover"], utility: "bg", value: "red-500" }
139
+ * "sm:p-4" → { variants: ["sm"], utility: "p", value: "4" }
140
+ * "text-center!" → { variants: [], utility: "text-center", value: null, important: true }
141
+ * "p-[13px]" → { variants: [], utility: "p", value: "[13px]", arbitrary: true }
142
+ * "@md:flex" → { variants: ["@md"], utility: "flex", value: null }
143
+ * "pl-physical-4" → { variants: [], utility: "pl", value: "4", physical: true }
144
+ */
145
+ interface ParsedUtility {
146
+ /** Original class string before parsing */
147
+ raw: string;
148
+ /** Variant prefixes in order, e.g. ["hover"], ["sm", "hover"] */
149
+ variants: string[];
150
+ /** The utility name (everything before the value separator), e.g. "bg", "p", "text" */
151
+ utility: string;
152
+ /** The value part after the last `-`, or null for valueless utilities like "flex" */
153
+ value: string | null;
154
+ /** Whether the value is an arbitrary bracket expression like [13px] */
155
+ arbitrary: boolean;
156
+ /** Whether !important is applied */
157
+ important: boolean;
158
+ /** Whether the -physical- infix is present */
159
+ physical: boolean;
160
+ /** Whether the utility is negative (prefixed with -) */
161
+ negative: boolean;
162
+ /** When the class is an arbitrary property like [color:red] */
163
+ arbitraryProperty: {
164
+ property: string;
165
+ value: string;
166
+ } | null;
167
+ /**
168
+ * Explicit type hint extracted from an arbitrary value, e.g. the `length`
169
+ * in `border-[length:1rem]` or `border-(color:--my-color)`. When set, it
170
+ * forces a specific dispatch path in generators — see `borderGenerator`,
171
+ * `colorGenerator`, etc. Null when no hint was provided.
172
+ */
173
+ dataType: string | null;
174
+ }
175
+ /**
176
+ * Parse a single utility class string into its structural components.
177
+ */
178
+ declare function parseUtility(raw: string): ParsedUtility;
179
+
180
+ interface CSSDeclaration {
181
+ property: string;
182
+ value: string;
183
+ }
184
+
185
+ /**
186
+ * Variant resolution — maps variant names to CSS wrappers.
187
+ *
188
+ * Handles pseudo-classes, pseudo-elements, media queries, responsive breakpoints,
189
+ * container queries, data/aria attributes, :has()/:not(), arbitrary variants,
190
+ * and custom variants.
191
+ */
192
+
193
+ type VariantKind = "pseudo-class" | "pseudo-element" | "media" | "breakpoint" | "container" | "special" | "custom" | "pattern";
194
+ interface VariantInfo {
195
+ /** The variant as typed before the `:` — for patterns, the family prefix. */
196
+ name: string;
197
+ kind: VariantKind;
198
+ /** What the variant emits — a selector suffix, an at-rule, or (for
199
+ * patterns) a description of the accepted form. */
200
+ wraps: string;
201
+ }
202
+ /**
203
+ * Enumerate every concrete variant the given theme resolves, plus the
204
+ * open-ended pattern families. Concrete entries (kind ≠ "pattern") are
205
+ * guaranteed to resolve via resolveVariant — the list mirrors its checks,
206
+ * including the CSS-length guard on breakpoint values.
207
+ */
208
+ declare function listVariants(theme: ResolvedTheme): VariantInfo[];
209
+
210
+ /**
211
+ * Class inspector — single-class validation and explanation for editor
212
+ * tooling, running the exact resolution the compile loop performs.
213
+ *
214
+ * The compiler intentionally drops unknown utilities silently (reserved
215
+ * RI-1001): the build scanner over-collects, so at build time an unresolved
216
+ * candidate is usually noise. Inside an editor the certainty is inverted — a
217
+ * token in a class attribute is meant to be a class — so the inspector
218
+ * finally gives RI-1001 a voice: `validate()` reports WHY a class produces no
219
+ * CSS, with a typo suggestion when one is close enough.
220
+ *
221
+ * An inspector instance owns the per-theme caches the compile loop rebuilds
222
+ * per pass (custom-variant map, variant memo, breakpoint weights) plus a
223
+ * resolution cache, so per-keystroke validation of the same classes is cheap.
224
+ * Create one per theme and drop it when the theme changes.
225
+ */
226
+
227
+ type ClassValidation = {
228
+ ok: true;
229
+ } | {
230
+ ok: false;
231
+ reason: "unknown-utility" | "unknown-variant" | "invalid-arbitrary";
232
+ /** The failing fragment — the variant for "unknown-variant", the
233
+ * base class (variants stripped) otherwise. */
234
+ offender: string;
235
+ /** Closest known name within typo distance, when one exists. */
236
+ suggestion?: string;
237
+ };
238
+ interface ClassExplanation {
239
+ parsed: ParsedUtility;
240
+ /** Root declarations before variant wrapping. */
241
+ declarations: CSSDeclaration[];
242
+ /** Escaped selector, including variant suffixes (`.hover\:px-2:hover`). */
243
+ selector: string;
244
+ /** The complete rule text, including wrapping at-rules. */
245
+ css: string;
246
+ /** Deterministic ordering key — lower emits earlier in generated CSS. */
247
+ sortKey: number;
248
+ }
249
+ interface ClassInspector {
250
+ readonly theme: ResolvedTheme;
251
+ /** Would this class produce CSS under the theme? Reports why not. */
252
+ validate(className: string): ClassValidation;
253
+ /** Structured breakdown + generated CSS, or null when invalid. */
254
+ explain(className: string): ClassExplanation | null;
255
+ /** Every variant the theme resolves (cached). */
256
+ variants(): readonly VariantInfo[];
257
+ }
258
+ declare function createClassInspector(theme: ResolvedTheme): ClassInspector;
259
+
260
+ /**
261
+ * Typo suggestion helpers using optimal string alignment (OSA) distance —
262
+ * Levenshtein plus adjacent transpositions, so `felx` → `flex` is distance 1.
263
+ * Shared between engine.ts and css-functions.ts.
264
+ */
265
+ /**
266
+ * Find the closest match to `input` from a list of candidates.
267
+ * Returns null if no candidate is within `maxDistance`.
268
+ */
269
+ declare function findClosest(input: string, candidates: string[], maxDistance?: number): string | null;
270
+
271
+ /**
272
+ * Class enumeration — the completion universe for editor tooling.
273
+ *
274
+ * Design: candidates are generated from a deliberately GENEROUS value-space
275
+ * table (which theme namespaces and keyword families to TRY per functional
276
+ * root), then every candidate is probed through the real utility resolver.
277
+ * The resolver is the single authority — an enumerated class is one that
278
+ * actually compiles, so the table can over-approximate freely and can never
279
+ * emit something `validate()` would reject. Coverage is enforced the other
280
+ * way by tests: every PREFIX_DISPATCH root must appear in the table (an empty
281
+ * spec marks a statics-only root), so adding a generator root without
282
+ * deciding its value space fails CI.
283
+ *
284
+ * Statics come from the merge conflict tables (STATIC_UTILITIES) plus each
285
+ * generator's own static-map keys — probed too, for the same guarantee.
286
+ */
287
+
288
+ type ValueSpaceKind = "color" | "special-color" | "spacing" | "fraction" | "text-size" | "fluid-text-size" | "font-slot" | "weight" | "rounded" | "rounded-side" | "shadow" | "z" | "ease" | "blur" | "animation" | "leading" | "tracking" | "opacity" | "duration" | "breakpoint" | "int" | "percent" | "keywords";
289
+ interface ValueSpaceSpec {
290
+ kinds: readonly ValueSpaceKind[];
291
+ /** Extra value parts to try verbatim (for "keywords" and beyond). */
292
+ keywords?: readonly string[];
293
+ }
294
+ /** Root → value spaces to try. Coverage of every PREFIX_DISPATCH root is
295
+ * enforced by __tests__/core/enumerate.test.ts. */
296
+ declare const UTILITY_VALUE_SPACES: ReadonlyMap<string, ValueSpaceSpec>;
297
+ interface EnumeratedClass {
298
+ name: string;
299
+ /** How the class was produced: a static table, a custom @utility, or the
300
+ * value-space kind that filled the functional root. */
301
+ kind: ValueSpaceKind | "static" | "custom";
302
+ /** The functional root, or null for statics/custom statics. */
303
+ root: string | null;
304
+ }
305
+ interface ClassTemplate {
306
+ root: string;
307
+ /** The open-ended space: numeric spacing scale, plain numbers, or a
308
+ * functional custom utility that accepts any suffix. */
309
+ kind: "spacing" | "number" | "custom";
310
+ example: string;
311
+ }
312
+ interface ClassEnumeration {
313
+ /** Every finite concrete class, probed valid, sorted by name. */
314
+ classes: EnumeratedClass[];
315
+ /** Families whose value space is infinite — offer as snippets. */
316
+ templates: ClassTemplate[];
317
+ }
318
+ /**
319
+ * Enumerate the finite completion universe for a theme. Every returned class
320
+ * has been resolved by the real utility resolver — `validate()` accepts each
321
+ * one by construction. Infinite families (the spacing scale, numeric values,
322
+ * functional custom utilities) come back as templates; a template is emitted
323
+ * only when at least one of its probes resolved.
324
+ */
325
+ declare function enumerateClassNames(theme: ResolvedTheme): ClassEnumeration;
326
+
327
+ /**
328
+ * Color swatches and theme-token introspection for editor tooling.
329
+ *
330
+ * Resolves a theme color (and stop) to concrete light/dark colors — the same
331
+ * OKLCH math the CSS variable emitter uses (generateStop / computeDarkStop),
332
+ * plus an sRGB hex conversion for completion-item swatches and sidebar chips.
333
+ * Pure computation, no IO.
334
+ */
335
+
336
+ /** The canonical palette stops every generative color defines. */
337
+ declare const CANONICAL_COLOR_STOPS: readonly number[];
338
+ /** Convert an OKLCH color to a #rrggbb hex string (sRGB, channel-clamped). */
339
+ declare function oklchToHex(l: number, c: number, h: number): string;
340
+ /** Best-effort hex for the CSS color texts theme definitions hold: `oklch()`
341
+ * and hex literals. Anything else (named colors, rgb(), vars) returns null —
342
+ * the raw CSS text still travels alongside. */
343
+ declare function cssColorToHex(css: string): string | null;
344
+ interface SwatchColor {
345
+ /** CSS color text (`oklch(…)`, or the definition's own value verbatim). */
346
+ css: string;
347
+ /** sRGB hex, or null when the CSS text isn't convertible. */
348
+ hex: string | null;
349
+ }
350
+ interface ColorSwatch {
351
+ light: SwatchColor;
352
+ /** Null when the theme's dark mode is off or the color has no dark form. */
353
+ dark: SwatchColor | null;
354
+ }
355
+ /**
356
+ * Resolve a theme color name (+ stop, for generative palettes) to concrete
357
+ * light/dark swatch colors — exactly the values the emitted CSS variables
358
+ * carry. Theme-defined colors always win; the fixed semantic swatches
359
+ * (paper/ink/white/black) apply only when the theme does not define the name,
360
+ * mirroring the emitter (a user `@color { white: … }` palette emits
361
+ * `--color-white-*` variables that suffixed utilities resolve against).
362
+ * Returns null for unknown names, unresolvable aliases, and keyword colors
363
+ * with no concrete value (transparent, currentColor).
364
+ */
365
+ declare function resolveColorSwatch(theme: ResolvedTheme, name: string, stop?: number): ColorSwatch | null;
366
+ interface ThemeTokens {
367
+ /** Color names with their definition kind — pair with resolveColorSwatch. */
368
+ colors: Array<{
369
+ name: string;
370
+ kind: ColorDefinition["type"];
371
+ }>;
372
+ colorStops: readonly number[];
373
+ spacingBase: string;
374
+ textSizes: Array<{
375
+ name: string;
376
+ fontSize: string;
377
+ lineHeight: string;
378
+ }>;
379
+ breakpoints: Record<string, string>;
380
+ rounded: Record<string, string>;
381
+ shadows: Record<string, string>;
382
+ weights: Record<string, number>;
383
+ easing: Record<string, string>;
384
+ blur: Record<string, string>;
385
+ z: Record<string, string>;
386
+ leading: Record<string, string>;
387
+ tracking: Record<string, string>;
388
+ opacity: Record<string, string>;
389
+ duration: Record<string, string>;
390
+ fonts: Array<{
391
+ slot: string;
392
+ family: string;
393
+ }>;
394
+ animations: string[];
395
+ }
396
+ /** One render-ready view of a theme's token namespaces for sidebar chips and
397
+ * completion detail — plain data, no theme internals to traverse. */
398
+ declare function listThemeTokens(theme: ResolvedTheme): ThemeTokens;
399
+
400
+ /**
401
+ * Editor session — the façade that ties the editor toolkit together.
402
+ *
403
+ * An editor host holds one session per workspace, calls `setCss()` whenever
404
+ * the project's CSS entry changes, and everything else per keystroke. The
405
+ * session owns the caching story: theme analysis, the class inspector, the
406
+ * enumeration, token introspection, and the merge snapshot are computed
407
+ * lazily and invalidated together when the CSS changes — callers never
408
+ * juggle per-theme cache keys themselves. Every capability is also exported
409
+ * à la carte from `rainbowindex/editor` for hosts that want finer control.
410
+ *
411
+ * Pure computation, no IO: the host reads the CSS file (see
412
+ * CSS_ENTRY_CANDIDATES / hasRIActivation for locating it) and passes text.
413
+ */
414
+
415
+ interface EditorSession {
416
+ /** The CSS input the session is currently analyzing. */
417
+ readonly css: string;
418
+ /** Swap the CSS input; all theme-derived caches invalidate together.
419
+ * A no-op when the text is unchanged. */
420
+ setCss(css: string): void;
421
+ readonly theme: ResolvedTheme;
422
+ /** Positioned diagnostics for the CSS input (see ProjectAnalysis). */
423
+ readonly diagnostics: readonly Diagnostic[];
424
+ /** Single-class validation/explanation, cached per theme. */
425
+ readonly inspector: ClassInspector;
426
+ /** The finite completion universe + templates, cached per theme. */
427
+ enumerate(): ClassEnumeration;
428
+ /** Render-ready token namespaces, cached per theme. */
429
+ tokens(): ThemeTokens;
430
+ /** The merge snapshot for this theme, cached. */
431
+ snapshot(): CompilationSnapshot;
432
+ /** analyzeMerge bound to this theme's snapshot. */
433
+ analyzeMerge(classes: readonly string[]): MergeAnalysis;
434
+ /** Position-aware class extraction for a source document. */
435
+ extractCandidates(content: string, path?: string): ClassCandidate[];
436
+ /** Light/dark swatch for a theme color (+ stop), or null. */
437
+ swatch(name: string, stop?: number): ColorSwatch | null;
438
+ }
439
+ declare function createEditorSession(options?: {
440
+ css?: string;
441
+ }): EditorSession;
442
+
443
+ /**
444
+ * `rainbowindex/editor` — the IO-free toolkit editor integrations build on.
445
+ *
446
+ * Everything exported here is pure computation: strings in, structures out.
447
+ * No filesystem, no network, no module-level mutation — the entry behaves in
448
+ * browser-based editor hosts (vscode.dev) exactly as it does in Node. File
449
+ * access stays with the editor host; this module supplies the semantics:
450
+ * what the scanner extracts (and where), what activates Rainbow Index, and
451
+ * where a project's CSS entry usually lives.
452
+ *
453
+ * Editor integrations load whatever version the workspace has installed, so
454
+ * the surface is feature-detectable: gate on `editorCapabilities` entries,
455
+ * not on `version`, when deciding what the installed copy supports.
456
+ */
457
+ /** Package version — build-time injected; "0.0.0-dev" when run from source. */
458
+ declare const version: string;
459
+ /** Editor API protocol version — bumped only on breaking changes to this entry. */
460
+ declare const EDITOR_API_VERSION = 1;
461
+ /** Feature-detection roster for this entry. */
462
+ declare const editorCapabilities: readonly string[];
463
+
464
+ export { CANONICAL_COLOR_STOPS, CLASS_HELPER_NAMES, CSS_ENTRY_CANDIDATES, type CandidateOrigin, type ClassCandidate, type ClassEnumeration, type ClassExplanation, type ClassInspector, type ClassTemplate, type ClassValidation, ColorDefinition, type ColorSwatch, CompilationSnapshot, type Diagnostic, type DiagnosticSeverity, EDITOR_API_VERSION, type EditorSession, type EnumeratedClass, MergeAnalysis, ParsedDirective, type ParsedUtility, type ProjectAnalysis, RI_IMPORT_SPECIFIERS, ResolvedTheme, type SourceExtractionInput, type SwatchColor, type ThemeTokens, UTILITY_VALUE_SPACES, VARIANT_HELPER_NAMES, type ValueSpaceKind, type ValueSpaceSpec, type VariantInfo, type VariantKind, analyzeProjectCSS, createClassInspector, createEditorSession, cssColorToHex, diagnosticFromWarning, editorCapabilities, enumerateClassNames, expandVariantGroups, extractClassCandidates, extractClasses, extractClassesFromSource, findClosest, hasRIActivation, isSourceFile, listThemeTokens, listVariants, oklchToHex, parseUtility, resolveColorSwatch, severityForCode, version, warningCode };