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
@@ -1,4 +1,4 @@
1
- import { C as ColorDefinition, D as DarkModeConfig, j as CornerShape, A as AnimationDefinition, F as FluidConfig, b as CompilationSnapshot } from './index-DSgpB6bS.js';
1
+ import { C as ColorDefinition, D as DarkModeConfig, b as CornerShape, A as AnimationDefinition, F as FluidConfig } from './index-Czx-EUwh.js';
2
2
 
3
3
  /** Provider discriminant for a slot, derived from its faces. */
4
4
  type FontProviderKind = "google" | "system" | "local" | "manual";
@@ -73,23 +73,6 @@ declare function weightIsLoaded(weight: number, fonts: readonly FontSlot[]): boo
73
73
  * `Inter 300–900; Fira Code 400, 700`. */
74
74
  declare function describeLoadedWeights(fonts: readonly FontSlot[]): string;
75
75
 
76
- /**
77
- * Font loading system — @font directive processing, @font-face generation,
78
- * metrics-adjusted fallbacks for zero CLS.
79
- *
80
- * A slot (sans/serif/mono/custom) maps to one --font-<slot> variable and one
81
- * family name, but can own multiple faces — e.g. an upright + an italic file,
82
- * or split unicode ranges. Each FontFace emits one @font-face for local
83
- * providers; google/system/manual slots carry a single face.
84
- */
85
-
86
- interface FontOutput {
87
- imports: string[];
88
- fontFaces: string[];
89
- variables: string[];
90
- warnings: string[];
91
- }
92
-
93
76
  /**
94
77
  * Raw-extractable directive names — the single source for the DirectiveType
95
78
  * union and the name sets in directives/index.ts (which add the PostCSS-only
@@ -212,76 +195,87 @@ interface ResolvedTheme {
212
195
  readonly warnings: readonly string[];
213
196
  }
214
197
 
215
- interface CompiledRule {
216
- /** The original class name (escaped for CSS selector). */
217
- selector: string;
218
- /** Sort key for deterministic ordering. */
219
- sortKey: number;
220
- /** CSS declarations as a string block. */
221
- css: string;
222
- }
223
- interface CompilationResult {
224
- /** All compiled CSS rules. */
225
- rules: CompiledRule[];
226
- /** @keyframes blocks needed. */
227
- keyframes: string[];
228
- /** @property declarations needed. */
229
- properties: string[];
230
- /** Map of used color hue → set of used suffixes (for token pruning). */
231
- usedColorStops: Map<string, Set<number>>;
232
- /** Set of used text size names (for token pruning). */
233
- usedTextSizes: Set<string>;
234
- /** Set of used font slot names (for token pruning). */
235
- usedFonts: Set<string>;
236
- /** Set of used rounded value names (for token pruning). */
237
- /** Set of used shadow names (for token pruning). */
238
- usedShadows: Set<string>;
239
- /** Set of used animation shorthand names (for token pruning). */
240
- usedAnimations: Set<string>;
241
- /** Warnings emitted during compilation. */
242
- warnings: string[];
243
- }
244
-
245
- /**
246
- * Build a CompilationSnapshot straight from a resolved theme — no compile
247
- * pass, no module-level state. Editor tooling pairs this with
248
- * analyzeMerge()/createRi() for theme-accurate merge semantics.
249
- */
250
- declare function createThemeSnapshot(theme: ResolvedTheme): CompilationSnapshot;
251
198
  /**
252
- * Create an isolated compiler instance for SSR / concurrent-compilation
253
- * environments. Returns a `compile()` function that does NOT touch module-level
254
- * state, and a `createRi()` that produces a merge function bound to the
255
- * compilation's snapshot.
199
+ * `@import` inlining for the directive analyzer.
200
+ *
201
+ * The analyzer reads directives out of one CSS string. Until an import is
202
+ * inlined, a `@color` block living in `./tokens.css` — or in a preset shipped
203
+ * by a package — is invisible to it: only the Vite path ever saw imported
204
+ * text, because Vite resolves CSS imports before PostCSS plugins run.
256
205
  *
257
- * **Isolation scope:** Compilation context, variant map cache, and font output
258
- * cache are fully isolated per instance. Google Fonts metadata (from fonts.ts)
259
- * is intentionally shared read-only across instances — it is populated once
260
- * via atomic swap and never mutated afterward, so concurrent reads are safe.
206
+ * This module closes that gap for every other surface. It is deliberately
207
+ * IO-free: the caller supplies a resolver, so the same code serves the CLI
208
+ * (filesystem), the PostCSS plugin (filesystem), and an editor host (its own
209
+ * open-document map) without any of them dragging `node:fs` into a browser
210
+ * bundle. `resolve-import.ts` holds the Node resolver.
261
211
  *
262
- * **Font output cache lifecycle:** `fontOutputCache` is cleared at the start
263
- * of each `compile()` call, so it only caches within a single compilation pass.
264
- * If the same compiler instance is reused across compilations (the expected SSR
265
- * pattern), each compilation starts with a fresh font cache.
212
+ * What is replaced, and what is left alone:
266
213
  *
267
- * @example
268
- * ```ts
269
- * import { createCompiler } from "rainbowindex";
214
+ * - `@import "./tokens.css";` and `@import "pkg/preset.css";` — inlined.
215
+ * - `@import "rainbowindex";` — left in place at the entry, since that is what
216
+ * activates the compiler; dropped inside an imported file, so a preset that
217
+ * imports the package cannot activate it twice. `rainbowindex/tailwind.css`
218
+ * activates too, but it is a stylesheet of directives rather than a marker,
219
+ * so it is inlined like any other package preset.
220
+ * - `@import url("https://…")`, `@import "/site.css"` — left alone. Those are
221
+ * URLs for the browser to fetch, not files on disk.
222
+ * - `@import "a.css" screen;`, `… layer(x);`, `… supports(…);` — left alone
223
+ * and warned (RI-1045). Their contents apply conditionally, and directives
224
+ * have no conditional form, so silently hoisting them would be a lie.
225
+ *
226
+ * Inlining is for READING. Whether the inlined text is also emitted is the
227
+ * caller's business: the PostCSS plugin builds its output from the AST, so
228
+ * nothing is duplicated there, while the CLI and `compileProject` join the
229
+ * inlined user CSS into their output once, in import order.
230
+ *
231
+ * One thing the inliner changes rather than copies: comments inside a PACKAGE
232
+ * import are dropped, and comments in the project's own files are not. A
233
+ * package's stylesheet is consumed as CSS, and its notes are addressed to
234
+ * whoever opens that package — the Tailwind preset alone was contributing
235
+ * 4.3 KB of section headings to every unminified build. Package-ness is
236
+ * inherited down the subtree, so a package's own relative imports are stripped
237
+ * too. See `stripCSSComments` and docs/preset-protocol.md.
238
+ */
239
+ /** A file the resolver found: its identity, and its text. */
240
+ interface ImportResolution {
241
+ /**
242
+ * Identity of the resolved file — an absolute path for the Node resolver.
243
+ * Used for cycle detection and as the base for the file's own imports, so
244
+ * it must be stable: the same file has to produce the same string.
245
+ */
246
+ path: string;
247
+ content: string;
248
+ }
249
+ /**
250
+ * Turn an `@import` specifier into a file, or null when it cannot be found.
251
+ * `from` is the identity of the importing file, or undefined at the entry.
252
+ */
253
+ type ImportResolver = (specifier: string, from: string | undefined) => ImportResolution | null;
254
+ interface InlineImportsOptions {
255
+ resolve: ImportResolver;
256
+ /** Identity of the CSS being inlined, so its relative imports resolve. */
257
+ from?: string;
258
+ /** How deep the import graph may nest before RI-1043. */
259
+ maxDepth?: number;
260
+ /** Ceiling on total inlined bytes before RI-1044. */
261
+ maxBytes?: number;
262
+ }
263
+ interface InlineImportsResult {
264
+ css: string;
265
+ warnings: string[];
266
+ /**
267
+ * Every file inlined, in first-visit order. A watcher adds these to what it
268
+ * watches; without them, editing an imported token file changes nothing.
269
+ */
270
+ files: string[];
271
+ }
272
+ /**
273
+ * Replace resolvable `@import` at-rules with the text they name, recursively,
274
+ * so the directive analyzer sees one stylesheet.
270
275
  *
271
- * const compiler = createCompiler();
272
- * const result = compiler.compile(classNames, theme);
273
- * const ri = compiler.createRi();
274
- * ```
276
+ * Returns the input unchanged when there is nothing to inline, which keeps the
277
+ * analyzer's single-entry memo hitting on repeat builds.
275
278
  */
276
- declare function createCompiler(): {
277
- /** `authored` names the classes the user wrote by hand (`@source inline`,
278
- * `@apply`, a caller-supplied list). Omit it to treat every class as
279
- * authored — correct for callers who assembled the list themselves. */
280
- compile: (classNames: Iterable<string>, theme: ResolvedTheme, authored?: ReadonlySet<string>) => CompilationResult;
281
- createRi: () => (...inputs: (string | false | null | undefined)[]) => string;
282
- /** Isolated font output cache for this compiler instance. Pass to
283
- * `assembleSections()` to avoid sharing module-level font state. */
284
- fontOutputCache: Map<string, FontOutput>;
285
- };
279
+ declare function inlineDirectiveImports(css: string, options: InlineImportsOptions): InlineImportsResult;
286
280
 
287
- export { type CompilationResult as C, type ParsedDirective as P, type ResolvedTheme as R, type CompiledRule as a, createThemeSnapshot as b, createCompiler as c, describeLoadedWeights as d, weightIsLoaded as w };
281
+ export { type ImportResolver as I, type ParsedDirective as P, type ResolvedTheme as R, type ImportResolution as a, type InlineImportsOptions as b, type InlineImportsResult as c, describeLoadedWeights as d, inlineDirectiveImports as i, weightIsLoaded as w };
@@ -0,0 +1,56 @@
1
+ import { a as CompilationSnapshot } from './context-DcBtnnan.js';
2
+
3
+ /**
4
+ * ri() — class merge function.
5
+ * Replaces both tailwind-merge and clsx.
6
+ *
7
+ * Re-exported from the package's main and browser entries as `ri()`.
8
+ * Right-to-left scan: rightmost class wins when two classes set the same CSS property.
9
+ *
10
+ * This file is the pure merge runtime. Its siblings hold the other merge
11
+ * concepts: props.ts (claim data), resolve.ts (dual-mode claim resolution),
12
+ * context.ts (compilation-context lifecycle + published state), analyze.ts
13
+ * (editor-only merge diagnostics).
14
+ *
15
+ * ## Concurrency
16
+ *
17
+ * The default `ri()` export uses module-level state published by
18
+ * `finalizeCompilationContext()`. This is safe for single-compilation
19
+ * environments (typical browser usage, single Vite build, PostCSS).
20
+ *
21
+ * In multi-tenant / SSR / concurrent-compilation environments, use
22
+ * `createRi(snapshot)` instead — it captures a frozen snapshot of the
23
+ * compilation state and uses its own independent cache:
24
+ *
25
+ * const snapshot = finalizeCompilationContext(ctx);
26
+ * const ri = createRi(snapshot);
27
+ */
28
+ /** Anything `ri()` accepts: class strings, falsy holes, and nested arrays.
29
+ * Exported because `rainbowindex/recipe` builds its own inputs from it. */
30
+ type ClassInput = string | false | null | undefined | ClassInput[];
31
+
32
+ /**
33
+ * Merge class names with conflict resolution (replaces both tailwind-merge and clsx).
34
+ * Rightmost class wins when two classes set the same CSS property.
35
+ * Falsy values are filtered.
36
+ *
37
+ * @example
38
+ * ri('p-2 bg-red-500', 'p-4') // → 'bg-red-500 p-4'
39
+ * ri('px-2 py-1', 'p-4') // → 'p-4' (shorthand wins)
40
+ * ri('flex', isActive && 'bg-blue-500') // → 'flex bg-blue-500'
41
+ * ri('text-lg text-red-500') // → 'text-lg text-red-500' (different properties)
42
+ */
43
+ declare function ri(...inputs: ClassInput[]): string;
44
+ /**
45
+ * Create an isolated ri() instance bound to a specific compilation snapshot.
46
+ * Use this in SSR or multi-compilation environments where the global ri()
47
+ * would be corrupted by concurrent compilations.
48
+ *
49
+ * @example
50
+ * const snapshot = finalizeCompilationContext(ctx);
51
+ * const ri = createRi(snapshot);
52
+ * ri('p-2 bg-red-500', 'p-4') // → 'bg-red-500 p-4'
53
+ */
54
+ declare function createRi(snapshot?: CompilationSnapshot): (...inputs: ClassInput[]) => string;
55
+
56
+ export { type ClassInput as C, createRi as c, ri as r };
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Generative color system — color domain model, OKLCH ramp generation,
3
+ * and light-dark() pairing.
4
+ *
5
+ * 2 numbers (chroma + hue) → 19-stop palette with automatic dark mode.
6
+ *
7
+ * The ramp is sampled from a fixed reference profile (`L_PROFILE` / `C_SHAPE` /
8
+ * `H_DRIFT`, captured from the reference palette): lightness is a curved,
9
+ * compressed scale (low suffix → light, high → dark), chroma is an asymmetric
10
+ * bell peaking at stop 500, and hue is near-flat. Dark mode is a simple ramp
11
+ * reversal — the dark value is the stop the ramp reaches at the mirror position
12
+ * (`1000 - suffix`), so stop 500 pivots to itself.
13
+ */
14
+ /** Per-color dark mode override strategy. */
15
+ type ColorDarkOverride = {
16
+ strategy: "mirror";
17
+ } | {
18
+ strategy: "fixed";
19
+ } | {
20
+ strategy: "shift";
21
+ chromaDelta: number;
22
+ hueDelta: number;
23
+ };
24
+ /**
25
+ * Color definition — discriminated union supporting:
26
+ * - Generative: `brand: 0.18 330;` → 19-stop palette with auto dark mode
27
+ * - Explicit: `accent: oklch(0.72 0.21 330);` → single color value
28
+ * - Pair: `surface: oklch(0.98 0.01 260) / oklch(0.15 0.01 260);` → light/dark pair
29
+ * - Alias: `theme: brand;` → references another color's palette via var()
30
+ */
31
+ type ColorDefinition = {
32
+ type: "generative";
33
+ chroma: number;
34
+ hue: number;
35
+ dark?: ColorDarkOverride;
36
+ inline?: boolean;
37
+ parabolic?: boolean;
38
+ chromaBoost?: boolean;
39
+ } | {
40
+ type: "explicit";
41
+ value: string;
42
+ } | {
43
+ type: "keyword";
44
+ value: string;
45
+ } | {
46
+ type: "pair";
47
+ light: string;
48
+ dark: string;
49
+ } | {
50
+ type: "alias";
51
+ source: string;
52
+ };
53
+ /**
54
+ * How `dark:` and `light:` decide they apply.
55
+ *
56
+ * The point of the choice is that it has to agree with when the *tokens* flip.
57
+ * Tokens use `light-dark()`, which follows `color-scheme`, which the shipped
58
+ * preflight drives from `html[data-appearance]` on top of the OS preference. A
59
+ * strategy that disagrees with that gives a build two theme switches that
60
+ * disagree, which is what this replaced.
61
+ *
62
+ * - `media` — `@media (prefers-color-scheme: dark)`. The OS preference alone.
63
+ * The historical behaviour, and the default.
64
+ * - `appearance` — matches exactly when `light-dark()` flips under the shipped
65
+ * preflight: an explicit `html[data-appearance="dark"]`, or the OS preference
66
+ * where no attribute has overridden it. Needs two rules; see `alternate` on
67
+ * {@link VariantWrapper}.
68
+ * - `selector` — a class or any selector you toggle yourself, the strategy
69
+ * Tailwind projects arrive with. The OS preference is ignored, as it is
70
+ * there.
71
+ */
72
+ type DarkVariantStrategy = {
73
+ readonly kind: "media";
74
+ } | {
75
+ readonly kind: "appearance";
76
+ } | {
77
+ readonly kind: "selector";
78
+ readonly selector: string;
79
+ };
80
+ interface DarkModeConfig {
81
+ mode: "auto" | "off";
82
+ chromaBoost: number;
83
+ hueShift: number;
84
+ variant: DarkVariantStrategy;
85
+ }
86
+
87
+ /**
88
+ * Default theme values — the static data that ships if the user writes no
89
+ * directives. Only the colour palette and the spacing base ship a value; every
90
+ * named scale starts empty and is filled by its directive.
91
+ */
92
+
93
+ interface TextSize {
94
+ fontSize: string;
95
+ lineHeight: string;
96
+ }
97
+ /** Viewport units, and the container-query units that track a container
98
+ * instead. Keep in step with `FLUID_UNITS` in directives/resolver.ts, which
99
+ * validates the `unit` a `@fluid` block asks for. */
100
+ type FluidUnit = "vw" | "vi" | "vmin" | "vmax" | "cqw" | "cqi" | "cqmin" | "cqmax";
101
+ interface FluidConfig {
102
+ min?: string;
103
+ max?: string;
104
+ unit?: FluidUnit;
105
+ multiplier?: number;
106
+ }
107
+ interface AnimationDefinition {
108
+ shorthand: string;
109
+ keyframes: string;
110
+ }
111
+ interface Theme {
112
+ spacing: {
113
+ base: string;
114
+ };
115
+ colors: Record<string, ColorDefinition>;
116
+ text: Record<string, TextSize>;
117
+ breakpoints: Record<string, string>;
118
+ shadows: Record<string, string>;
119
+ weights: Record<string, number>;
120
+ easing: Record<string, string>;
121
+ fluid: FluidConfig;
122
+ animations: Record<string, AnimationDefinition>;
123
+ blur: Record<string, string>;
124
+ }
125
+ /**
126
+ * Keyword corner-shape values. `superellipse(N)` is represented separately
127
+ * as `{ superellipse: N }` since the numeric parameter isn't a keyword.
128
+ * Single source for the type, the scale table below, and the @rounded
129
+ * modifier parser (directives/parsers.ts).
130
+ */
131
+ declare const CORNER_SHAPE_KEYWORDS: readonly ["round", "scoop", "bevel", "notch", "square", "squircle"];
132
+ type CornerShapeKeyword = (typeof CORNER_SHAPE_KEYWORDS)[number];
133
+ type CornerShape = CornerShapeKeyword | {
134
+ superellipse: number;
135
+ };
136
+ declare const defaultTheme: Theme;
137
+
138
+ export { type AnimationDefinition as A, type ColorDefinition as C, type DarkModeConfig as D, type FluidConfig as F, type TextSize as T, type Theme as a, type CornerShape as b, defaultTheme as d };
@@ -0,0 +1,104 @@
1
+ import { a as CompilationSnapshot } from './context-DcBtnnan.js';
2
+ import { R as ResolvedTheme } from './imports-C9esHd5Q.js';
3
+
4
+ /**
5
+ * Pure `@font-face` emission — no network, no cache, no `node:` anything.
6
+ *
7
+ * Split out of `index.ts` so the CSS assembly graph stays browser-safe. The
8
+ * barrel next door re-exports both halves, but it also re-exports the Google
9
+ * client, which reaches `node:crypto` and `node:fs` through its on-disk
10
+ * metadata cache. `assembly.ts` needs only the emission half, and
11
+ * `rainbowindex/editor` needs `assembly.ts`, so importing the barrel there
12
+ * would drag the whole fetch/cache machinery into a bundle meant to run in
13
+ * vscode.dev and in the playground. Everything here is strings in, strings
14
+ * out: the network resolver hands its answers to the theme long before
15
+ * anything in this file runs.
16
+ */
17
+
18
+ interface FontOutput {
19
+ imports: string[];
20
+ fontFaces: string[];
21
+ variables: string[];
22
+ warnings: string[];
23
+ }
24
+
25
+ interface CompiledRule {
26
+ /** The original class name (escaped for CSS selector). */
27
+ selector: string;
28
+ /** Sort key for deterministic ordering. */
29
+ sortKey: number;
30
+ /** CSS declarations as a string block. */
31
+ css: string;
32
+ }
33
+ interface CompilationResult {
34
+ /** All compiled CSS rules. */
35
+ rules: CompiledRule[];
36
+ /** @keyframes blocks needed. */
37
+ keyframes: string[];
38
+ /** @property declarations needed. */
39
+ properties: string[];
40
+ /** Map of used color hue → set of used suffixes (for token pruning). */
41
+ usedColorStops: Map<string, Set<number>>;
42
+ /**
43
+ * Whole `--color-<name>` token names referenced anywhere, generative stops
44
+ * included. `usedColorStops` cannot stand in for this: an explicit or pair
45
+ * entry is keyed by its undivided name, and a stop-less reference such as
46
+ * `var(--color-surface)` has no suffix for that map to record at all.
47
+ */
48
+ usedColorNames: Set<string>;
49
+ /** Set of used text size names (for token pruning). */
50
+ usedTextSizes: Set<string>;
51
+ /** Set of used font slot names (for token pruning). */
52
+ usedFonts: Set<string>;
53
+ /** Set of used rounded value names (for token pruning). */
54
+ /** Set of used shadow names (for token pruning). */
55
+ usedShadows: Set<string>;
56
+ /** Set of used animation shorthand names (for token pruning). */
57
+ usedAnimations: Set<string>;
58
+ /** Warnings emitted during compilation. */
59
+ warnings: string[];
60
+ }
61
+
62
+ /**
63
+ * Build a CompilationSnapshot straight from a resolved theme — no compile
64
+ * pass, no module-level state. Editor tooling pairs this with
65
+ * analyzeMerge()/createRi() for theme-accurate merge semantics.
66
+ */
67
+ declare function createThemeSnapshot(theme: ResolvedTheme): CompilationSnapshot;
68
+ /**
69
+ * Create an isolated compiler instance for SSR / concurrent-compilation
70
+ * environments. Returns a `compile()` function that does NOT touch module-level
71
+ * state, and a `createRi()` that produces a merge function bound to the
72
+ * compilation's snapshot.
73
+ *
74
+ * **Isolation scope:** Compilation context, variant map cache, and font output
75
+ * cache are fully isolated per instance. Google Fonts metadata (from fonts.ts)
76
+ * is intentionally shared read-only across instances — it is populated once
77
+ * via atomic swap and never mutated afterward, so concurrent reads are safe.
78
+ *
79
+ * **Font output cache lifecycle:** `fontOutputCache` is cleared at the start
80
+ * of each `compile()` call, so it only caches within a single compilation pass.
81
+ * If the same compiler instance is reused across compilations (the expected SSR
82
+ * pattern), each compilation starts with a fresh font cache.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * import { createCompiler } from "rainbowindex";
87
+ *
88
+ * const compiler = createCompiler();
89
+ * const result = compiler.compile(classNames, theme);
90
+ * const ri = compiler.createRi();
91
+ * ```
92
+ */
93
+ declare function createCompiler(): {
94
+ /** `authored` names the classes the user wrote by hand (`@source inline`,
95
+ * `@apply`, a caller-supplied list). Omit it to treat every class as
96
+ * authored — correct for callers who assembled the list themselves. */
97
+ compile: (classNames: Iterable<string>, theme: ResolvedTheme, authored?: ReadonlySet<string>) => CompilationResult;
98
+ createRi: () => (...inputs: (string | false | null | undefined)[]) => string;
99
+ /** Isolated font output cache for this compiler instance. Pass to
100
+ * `assembleSections()` to avoid sharing module-level font state. */
101
+ fontOutputCache: Map<string, FontOutput>;
102
+ };
103
+
104
+ export { type CompilationResult as C, type CompiledRule as a, createThemeSnapshot as b, createCompiler as c };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,11 @@
1
- import { R as ResolvedTheme, P as ParsedDirective } from './index-4Kyaq3IZ.js';
2
- export { C as CompilationResult, a as CompiledRule, c as createCompiler } from './index-4Kyaq3IZ.js';
1
+ export { C as CompilationResult, a as CompiledRule, c as createCompiler } from './index-DW8YSxTz.js';
3
2
  import { PluginCreator } from 'postcss';
4
- export { C as ColorDefinition, a as CompilationContext, b as CompilationSnapshot, F as FluidConfig, T as TextSize, c as Theme, d as createCompilationContext, e as defaultTheme, f as finalizeCompilationContext, r as registerColorNames, g as registerCustomFontFamilies, h as registerCustomTextSizes, i as registerCustomUtility } from './index-DSgpB6bS.js';
5
- export { c as createRi, r as ri, s as safelist } from './safelist-CGCtF-Fr.js';
3
+ export { C as CompilationContext, a as CompilationSnapshot, S as SerializedSnapshot, c as createCompilationContext, f as finalizeCompilationContext, h as hydrateSnapshot, p as publishSnapshot, r as registerColorNames, b as registerCustomFontFamilies, d as registerCustomTextSizes, e as registerCustomUtility, s as serializeSnapshot } from './context-DcBtnnan.js';
4
+ export { c as createRi, r as ri } from './index-CNqdL5U0.js';
5
+ import { R as ResolvedTheme, P as ParsedDirective, I as ImportResolver } from './imports-C9esHd5Q.js';
6
+ export { a as ImportResolution, b as InlineImportsOptions, c as InlineImportsResult, i as inlineDirectiveImports } from './imports-C9esHd5Q.js';
7
+ export { s as safelist } from './safelist-CH3_PywB.js';
8
+ export { C as ColorDefinition, F as FluidConfig, T as TextSize, a as Theme, d as defaultTheme } from './index-Czx-EUwh.js';
6
9
 
7
10
  interface RainbowIndexOptions {
8
11
  sources?: string[];
@@ -36,9 +39,47 @@ interface CompileProjectOptions {
36
39
  classNames?: Iterable<string>;
37
40
  resolveFonts?: FontResolver;
38
41
  processCssFunctions?: boolean;
42
+ /** Path of the CSS entry — the base for relative `@import` specifiers. */
43
+ cssPath?: string;
44
+ /**
45
+ * How `@import` specifiers become files, so directives in imported files
46
+ * are read. Defaults to the filesystem once `cssPath` says where the entry
47
+ * lives; with neither, imports pass through untouched as they always have.
48
+ * Pass `null` to keep that behavior even when `cssPath` is set.
49
+ */
50
+ resolveImport?: ImportResolver | null;
39
51
  }
40
52
  /** compileProject returns the pipeline result unmodified — one shape, two names. */
41
53
  type CompileProjectResult = FinalizeProjectResult;
42
54
  declare function compileProject(options: CompileProjectOptions): Promise<CompileProjectResult>;
43
55
 
44
- export { type CompileProjectOptions, type CompileProjectResult, type RainbowIndexOptions, compileProject, rainbowindex as default };
56
+ /**
57
+ * Node resolver for `@import` inlining — the only IO half of the feature.
58
+ *
59
+ * Kept apart from `imports.ts` so the inliner itself stays importable from the
60
+ * editor entry and from browser bundles. Nothing here is reachable from those:
61
+ * only the CLI, the PostCSS plugin, and `compileProject` construct a resolver.
62
+ *
63
+ * Two specifier shapes resolve:
64
+ *
65
+ * - `./tokens.css`, `../shared/theme.css` — relative to the importing file, or
66
+ * to `cwd` for the entry when it has no path of its own.
67
+ * - `pkg/preset.css` — through `require.resolve`, so a package's `exports` map
68
+ * decides, exactly as it would for JavaScript. That is what makes
69
+ * `@import "rainbowindex/tailwind.css"` work without knowing where the
70
+ * package lives.
71
+ *
72
+ * Everything else — remote URLs, site-root paths — is filtered out by the
73
+ * inliner before it ever calls this.
74
+ */
75
+
76
+ /**
77
+ * Build a resolver rooted at `cwd`. Failures — missing file, unreadable file,
78
+ * an oversized one, a bare specifier no package provides — all return null, and
79
+ * the inliner turns that into one RI-1041 naming the specifier.
80
+ */
81
+ declare function createNodeImportResolver(options: {
82
+ cwd: string;
83
+ }): ImportResolver;
84
+
85
+ export { type CompileProjectOptions, type CompileProjectResult, ImportResolver, type RainbowIndexOptions, compileProject, createNodeImportResolver, rainbowindex as default };
package/dist/index.mjs CHANGED
@@ -3,32 +3,50 @@ import {
3
3
  } from "./chunk-PD4ZXGJ6.mjs";
4
4
  import {
5
5
  postcss_default
6
- } from "./chunk-3LWJTLOJ.mjs";
6
+ } from "./chunk-RC6DDE4L.mjs";
7
7
  import {
8
8
  finalizeProjectCompilation,
9
9
  resolveGoogleFonts
10
- } from "./chunk-WK6S4HTC.mjs";
10
+ } from "./chunk-2T7V5XLK.mjs";
11
+ import {
12
+ createNodeImportResolver
13
+ } from "./chunk-W756NVYI.mjs";
11
14
  import {
12
15
  analyzeProjectCSSMemo,
13
16
  createCompiler,
14
17
  extractClassesFromSource,
18
+ inlineDirectiveImports,
15
19
  pushWarningsDeduped
16
- } from "./chunk-KSNYSR3C.mjs";
20
+ } from "./chunk-FJOZJIKB.mjs";
21
+ import {
22
+ defaultTheme
23
+ } from "./chunk-L56IRO7A.mjs";
17
24
  import {
18
25
  createCompilationContext,
19
26
  createRi,
20
- defaultTheme,
21
27
  finalizeCompilationContext,
28
+ hydrateSnapshot,
29
+ publishSnapshot,
22
30
  registerColorNames,
23
31
  registerCustomFontFamilies,
24
32
  registerCustomTextSizes,
25
33
  registerCustomUtility,
26
- ri
27
- } from "./chunk-6U4IOFOS.mjs";
34
+ ri,
35
+ serializeSnapshot
36
+ } from "./chunk-XQGSG2HK.mjs";
28
37
 
29
38
  // src/project/index.ts
39
+ import { dirname } from "path";
30
40
  async function compileProject(options) {
31
- const analysis = analyzeProjectCSSMemo(options.css);
41
+ const resolveImport = options.resolveImport === void 0 ? options.cssPath === void 0 ? null : createNodeImportResolver({ cwd: dirname(options.cssPath) }) : options.resolveImport;
42
+ const inlined = resolveImport === null ? { css: options.css, warnings: [] } : inlineDirectiveImports(options.css, { resolve: resolveImport, from: options.cssPath });
43
+ const analysis = analyzeProjectCSSMemo(inlined.css);
44
+ pushWarningsDeduped(
45
+ analysis.warnings,
46
+ inlined.warnings,
47
+ analysis.warningSeen,
48
+ analysis.suppressed
49
+ );
32
50
  const classNames = /* @__PURE__ */ new Set();
33
51
  if (options.classNames) {
34
52
  for (const cls of options.classNames) {
@@ -51,7 +69,8 @@ async function compileProject(options) {
51
69
  );
52
70
  }
53
71
  return finalizeProjectCompilation({
54
- css: options.css,
72
+ css: inlined.css,
73
+ cssPath: options.cssPath,
55
74
  classNames,
56
75
  authoredClassNames: authored,
57
76
  analysis,
@@ -65,14 +84,19 @@ export {
65
84
  compileProject,
66
85
  createCompilationContext,
67
86
  createCompiler,
87
+ createNodeImportResolver,
68
88
  createRi,
69
89
  postcss_default as default,
70
90
  defaultTheme,
71
91
  finalizeCompilationContext,
92
+ hydrateSnapshot,
93
+ inlineDirectiveImports,
94
+ publishSnapshot,
72
95
  registerColorNames,
73
96
  registerCustomFontFamilies,
74
97
  registerCustomTextSizes,
75
98
  registerCustomUtility,
76
99
  ri,
77
- safelist
100
+ safelist,
101
+ serializeSnapshot
78
102
  };