@bamboocss/vite 1.34.1 → 1.35.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.d.cts CHANGED
@@ -1,9 +1,8 @@
1
1
  import { Plugin } from "vite";
2
- import { Context } from "@bamboocss/core";
3
- import { Dict, ParserResultInterface, ResultItem } from "@bamboocss/types";
4
- import MagicString from "magic-string";
5
- import { SourceFile } from "ts-morph";
6
2
 
3
+ //#region src/static-session.d.ts
4
+ type DenseClassNameMode = boolean | 'stable' | 'local';
5
+ //#endregion
7
6
  //#region src/css.d.ts
8
7
  /**
9
8
  * What a project imports to get the stylesheet.
@@ -13,257 +12,21 @@ import { SourceFile } from "ts-morph";
13
12
  * bundled as javascript and injected as a script.
14
13
  */
15
14
  declare const VIRTUAL_CSS_ID = "virtual:bamboo.css";
16
- interface BambooCssPluginOptions {
17
- configPath?: string;
18
- cwd?: string;
19
- }
20
- /**
21
- * Serve bamboo's stylesheet as a virtual module, in dev and in build.
22
- *
23
- * This is the integration itself, not an optimisation: without it nothing emits css and
24
- * the generated `styled-system` runtime names classes no rule exists for.
25
- *
26
- * A virtual module rather than a file written to disk, because vite already owns the two
27
- * things a file would have to reimplement. In dev it injects css over the websocket and
28
- * replaces it in place, so an edit repaints without reloading; in build it hashes the
29
- * content into the asset graph and lets the bundler decide where it lands. Writing
30
- * `styles.css` and asking the project to import it means the build reads a file the same
31
- * process just wrote, which is a race on any watch rebuild.
32
- */
33
- declare const bamboocssCss: (options?: BambooCssPluginOptions) => Plugin;
34
- //#endregion
35
- //#region src/fold-recipe.d.ts
36
- /**
37
- * Lowering a call of an inline recipe to the class string it produces.
38
- *
39
- * The prize is not the `cva` runtime, which is small. It is the *config*: `cva({ base, variants })`
40
- * ships the whole style object to the browser purely so the runtime can hash it into a name and
41
- * pick classes off it. Those styles are already in the stylesheet. Once every call of a binding
42
- * is lowered, the binding is unreferenced and a bundler drops the config with it — measured at
43
- * 81 kB gzipped across one application's 1,297 inline recipes, against 4.5 kB for the runtime.
44
- *
45
- * Correct by construction rather than by a matching reimplementation: the class names come from
46
- * `getRecipeIdentity` and `getRecipeClassNames`, the same functions the browser runs, and the
47
- * prefixing and hashing from `classFormatter`, which is what the encoder emitted rules under.
48
- */
49
- type Dict$1 = Record<string, unknown>;
50
- /** A recipe's config, as the extractor resolved it. */
51
- interface RecipeConfig {
52
- className?: string;
53
- base?: Dict$1;
54
- variants?: Record<string, Record<string, unknown>>;
55
- defaultVariants?: Record<string, unknown>;
56
- compoundVariants?: unknown[];
57
- /** Present on a slot recipe, which resolves to one class per slot rather than a string. */
58
- slots?: unknown;
59
- }
60
- /**
61
- * A recipe the fold can lower against.
62
- *
63
- * `name` is hashed once here rather than per call site: `getRecipeIdentity` serialises the
64
- * whole config to hash it, which measured as 91% of the per-call work when it sat inside
65
- * `lowerRecipeCall`. The runtime does it once per `cva()` for the same reason.
66
- *
67
- * `box` is the *definition's* node, carried so the fold can register the module the config
68
- * came from as a watch dependency. Without it, editing a config in another module leaves
69
- * every literal folded against it stale — the stylesheet gets a new identity and the element
70
- * keeps the old class.
71
- */
72
- interface RecipeEntry {
73
- config: RecipeConfig;
74
- name: string;
75
- box: ResultItem['box'];
76
- }
77
- //#endregion
78
- //#region src/runtime-css.d.ts
79
- /**
80
- * The generated runtime's `css`, rebuilt in-process from a resolved context.
81
- *
82
- * A fold replaces a call with the string the runtime would have returned, so it has
83
- * to compute that string the same way the runtime does — not the way the stylesheet
84
- * does. The two differ in one respect that matters here: `StyleDecoder` escapes class
85
- * names for use in a CSS selector (`.c_red\.300`), while the runtime emits the raw
86
- * value that belongs in a `class` attribute (`c_red.300`). Folding the decoder's form
87
- * would put a stray backslash in the DOM.
88
- *
89
- * Matching the runtime this way makes the substitution behaviour-preserving by
90
- * construction. What still needs asserting — and is asserted in `__tests__` — is that
91
- * these class names correspond to rules the build actually emits.
92
- *
93
- * Mirrors `generateCssFn` in `@bamboocss/generator`: `css = memo((...styles) =>
94
- * cssFn(mergeCssUncached(...styles)))`, with the memo on the argument list and neither
95
- * inner cache. Unlike the generated runtime this one is built once per build and shared
96
- * across every module, so the outer cache is what carries the repeats.
97
- */
98
- interface RuntimeCss {
99
- (...styles: Dict[]): string;
100
- }
101
- declare const createRuntimeCss: (ctx: Context) => RuntimeCss;
102
- //#endregion
103
- //#region src/fold.d.ts
104
- /**
105
- * Why a call site was left alone. Surfaced through `panda`-style diagnostics so a
106
- * user can tell the difference between "this folded" and "this silently didn't".
107
- */
108
- type SkipReason = 'dynamic' | 'raw-call' | 'not-foldable' | 'recipe-call' | 'unsupported-kind' | 'not-imported' | 'no-call-expression' | 'overlapping' | 'empty' | 'unresolved-token' | 'runtime-binding' | 'fold-failed';
109
- interface FoldedCall {
110
- name: string;
111
- /**
112
- * What the call collapsed to.
113
- *
114
- * `class` is every style surface: a class string bound for a `class` attribute. `value`
115
- * is `token()`, which resolves to a CSS *value* (`var(--colors-red-300)`). The two are
116
- * not interchangeable, and a consumer that checks folded classes against the emitted
117
- * stylesheet has to skip the latter — there is no rule named after a variable reference.
118
- */
119
- kind: 'class' | 'value';
120
- /** The class string resolved outright, empty when the whole call lowered to ternaries. */
121
- className: string;
122
- /**
123
- * Every class literal the replacement emits, including both arms of each ternary — so a
124
- * consumer checking that folded classes have CSS behind them sees the branches too,
125
- * which `className` alone does not carry.
126
- */
127
- classNames: string[];
128
- /** The literal written in place of the call, for a `value` fold. */
129
- value?: string;
130
- start: number;
131
- end: number;
132
- }
133
- interface SkippedCall {
134
- name: string;
135
- reason: SkipReason;
136
- start: number;
137
- end: number;
138
- }
139
- interface FoldResult {
140
- code: string;
141
- /** Null when nothing was folded, so callers can return the original module untouched. */
142
- map: ReturnType<MagicString['generateMap']> | null;
143
- folded: FoldedCall[];
144
- skipped: SkippedCall[];
145
- /**
146
- * Other modules a folded value came from.
147
- *
148
- * The extractor resolves values across files, so `css(importedStyles, { … })` folds
149
- * to a string that depends on a file this module only imports. Without registering
150
- * that edge, editing the imported module leaves a stale literal behind in every
151
- * consumer. Bundlers need these as watch files.
152
- */
153
- dependencies: string[];
154
- }
155
- interface FoldOptions {
156
- ctx: Context;
157
- code: string;
158
- parserResult: ParserResultInterface;
159
- filePath: string;
160
- /** Reuse one runtime `css` across files in a build. */
161
- runtimeCss?: RuntimeCss;
162
- /**
163
- * Split a `css()` call that is only partly static, keeping the dynamic half at runtime.
164
- * On by default.
165
- */
166
- partial?: boolean;
167
- /**
168
- * Parse another module, for a recipe whose `cva` config lives outside this one.
169
- *
170
- * Threaded in rather than read off `ctx`, because the project belongs to the node
171
- * context and this signature takes the core one. Its absence is a supported state:
172
- * without it a cross-module recipe call is still *reported*, which is the half that
173
- * used to be missing entirely — it simply cannot be lowered.
174
- *
175
- * Pulling the module on demand is also what makes the fold order-independent. A
176
- * bundler transforms a consumer before the module it imports, so a registry built
177
- * from what has been transformed so far would fold or decline the same file
178
- * depending on discovery order.
179
- */
180
- parseModule?: (filePath: string) => ParserResultInterface | undefined;
181
- /**
182
- * Configs of modules other than this one, shared across a build.
183
- *
184
- * Owned by the caller because it has to outlive one call: the declaring module would
185
- * otherwise be re-parsed once per module that imports it, which is `consumers x module
186
- * size` on the transform path — measured at 909ms against 8.3ms for fifty consumers of a
187
- * hundred-recipe module. The caller clears an entry when the file changes, which is the
188
- * only place that knows.
189
- */
190
- recipeConfigCache?: Map<string, ForeignRecipes>;
191
- /**
192
- * Also report bamboo bindings the rewrite left behind, whatever the skip ledger says.
193
- *
194
- * The ledger holds only calls something recognised, so it answers "of the calls I looked
195
- * at, which survived" — and a guarantee built on it is worth exactly what the recogniser
196
- * is. A cross-module recipe call used to appear in neither column, so a build could report
197
- * a clean sweep while shipping hundreds of them.
198
- *
199
- * This asks what the guarantee actually claims: after the rewrite, is anything from a
200
- * bamboo module still referenced? Off by default because it costs an identifier walk, and
201
- * only `failOnUnfolded` needs an answer it can fail a build on.
202
- */
203
- reportSurvivors?: boolean;
204
- /**
205
- * The module's own AST, when the caller already holds it.
206
- *
207
- * Only `reportSurvivors` needs it, and only for the case it exists to catch: a module whose
208
- * bamboo usage produced no parser result at all has no call to reach the AST through.
209
- */
210
- sourceFile?: SourceFile;
211
- }
212
- /**
213
- * What one foreign module contributes, in a form that outlives it.
214
- *
215
- * Plain data only. Anything holding a ts-morph node would be read after the next
216
- * `addSourceFile` forgets that module's tree.
217
- */
218
- interface ForeignRecipes {
219
- configs: Map<string, RecipeEntry>;
220
- /** How that module spelled the css module, for a helper import written into a consumer. */
221
- cssSpecifier?: string;
222
- }
223
- declare const foldSource: (options: FoldOptions) => FoldResult;
224
15
  //#endregion
225
16
  //#region src/plugin.d.ts
226
17
  interface BambooVitePluginOptions {
227
- /**
228
- * Rewrite statically-resolvable `css()` and pattern calls into literal class
229
- * strings, so they cost nothing at runtime.
230
- *
231
- * On by default, and build-only — it never runs in `vite dev`, where the parse would land
232
- * on every hot update and a dev bundle gains nothing from pre-resolved calls.
233
- *
234
- * What it buys is per-call CPU, not bytes: the runtime still ships, because dropping it
235
- * needs *every* call site in the graph to fold. Bundle size moves slightly against you —
236
- * measured at -0.8% raw and +1.0% gzipped on `sandbox/runtime-perf`, since distinct class
237
- * literals compress worse than the repeated `css({ … })` calls they replace. Set it to
238
- * `false` if that trade is the wrong way round for you, or to keep builds faster: folding
239
- * re-parses each module with `ts-morph`, roughly 0.3ms for a small component and 3ms for a
240
- * 147-line file with 24 call sites.
241
- *
242
- * @default true
243
- */
244
- transform?: boolean;
245
- /**
246
- * Split a call or element that is only partly static, so the resolvable half becomes a
247
- * literal and only the rest keeps its runtime call. On by default.
248
- *
249
- * Without it a single dynamic value declines the whole site.
250
- *
251
- * @default true
252
- */
253
- partial?: boolean;
254
18
  /** Path to `bamboo.config.ts`. Resolved the same way the CLI resolves it. */
255
19
  configPath?: string;
256
20
  cwd?: string;
257
21
  /**
258
- * Report every call site that did *not* fold, and why, per file. Useful when a call
259
- * you expected to collapse still shows up in the bundle.
22
+ * Report every call site the compiler rejected, and why, per file.
260
23
  *
261
24
  * @default false
262
25
  */
263
26
  reportSkipped?: boolean;
264
27
  /**
265
- * Print a coverage summary when the build finishes: how much folded, and what the
266
- * remainder was declined for.
28
+ * Print a coverage summary when the build finishes: how much compiled, and why any
29
+ * candidates were rejected.
267
30
  *
268
31
  * On by default. Without it there is no signal that the transform did anything, and
269
32
  * no way to tell a project where everything folds from one where nothing does.
@@ -272,38 +35,30 @@ interface BambooVitePluginOptions {
272
35
  */
273
36
  reportSummary?: boolean;
274
37
  /**
275
- * Fail the build when a `css()` or pattern call is left for the runtime.
276
- *
277
- * The fold's value is not the per-call CPU it saves — it is that a bundle where *every*
278
- * such call folded no longer imports `styled-system/css` at all, and the engine behind it
279
- * drops out. One survivor keeps the whole thing, so a coverage percentage cannot tell you
280
- * whether you got the prize. This can.
281
- *
282
- * Deliberately silent about `cva`/`sva`. A `cva(...)` definition returns a function and can
283
- * never collapse to a class string, so failing on it would make this unusable for anyone
284
- * writing recipes — and recipes keep their own much smaller runtime by design. What this
285
- * guarantees is narrower and checkable: nothing still calls `css()`.
286
- *
287
- * Named for what it checks. It was `strict`, which meant nothing in common with
288
- * `strictTokens` or a pattern's old `strict` — three unrelated options sharing a word, to
289
- * the point that comments in this repo used a bare "strict" for all three.
290
- *
291
- * @default false
38
+ * Compact atom names. `true`/`stable` is deterministic across
39
+ * client and SSR builds. `local` uses the shortest names and is safe only when one build
40
+ * produces both HTML and CSS. @default true
41
+ */
42
+ denseClassNames?: DenseClassNameMode;
43
+ /**
44
+ * Maximum complete selections compiled for one runtime `cva`/`sva` call. This bounds
45
+ * build time and memory for the exact compound-variant decision table. @default 65536
292
46
  */
293
- failOnUnfolded?: boolean;
47
+ maxRecipeStates?: number;
294
48
  }
295
49
  /**
296
50
  * Vite integration for Bamboo CSS.
297
51
  *
298
52
  * Two plugins, because they do unrelated jobs on different schedules. The first emits the
299
53
  * stylesheet as a virtual module and runs in dev and build alike — that is the integration,
300
- * and nothing styles without it. The second is the optional build-time fold.
54
+ * and nothing styles without it. The second compiles every Bamboo source call in both dev
55
+ * and build; there is no runtime styling fallback.
301
56
  *
302
- * The fold runs with `enforce: 'pre'` so it sees module source as close as possible to what
57
+ * The compiler runs with `enforce: 'pre'` so it sees module source as close as possible to what
303
58
  * the CSS extractor reads off disk. A plugin that rewrites style calls before bamboo
304
59
  * sees them would otherwise make the two disagree, and a folded class could end up
305
60
  * with no matching rule.
306
61
  */
307
62
  declare const bamboocss: (options?: BambooVitePluginOptions) => Plugin[];
308
63
  //#endregion
309
- export { type BambooCssPluginOptions, type BambooVitePluginOptions, type FoldOptions, type FoldResult, type FoldedCall, type RuntimeCss, type SkipReason, type SkippedCall, VIRTUAL_CSS_ID, bamboocss, bamboocss as default, bamboocssCss, createRuntimeCss, foldSource };
64
+ export { type BambooVitePluginOptions, VIRTUAL_CSS_ID, bamboocss, bamboocss as default };
package/dist/index.d.mts CHANGED
@@ -1,9 +1,8 @@
1
- import MagicString from "magic-string";
2
- import { Node, SourceFile } from "ts-morph";
3
- import { Context } from "@bamboocss/core";
4
1
  import { Plugin } from "vite";
5
- import { Dict, ParserResultInterface, ResultItem } from "@bamboocss/types";
6
2
 
3
+ //#region src/static-session.d.ts
4
+ type DenseClassNameMode = boolean | 'stable' | 'local';
5
+ //#endregion
7
6
  //#region src/css.d.ts
8
7
  /**
9
8
  * What a project imports to get the stylesheet.
@@ -13,257 +12,21 @@ import { Dict, ParserResultInterface, ResultItem } from "@bamboocss/types";
13
12
  * bundled as javascript and injected as a script.
14
13
  */
15
14
  declare const VIRTUAL_CSS_ID = "virtual:bamboo.css";
16
- interface BambooCssPluginOptions {
17
- configPath?: string;
18
- cwd?: string;
19
- }
20
- /**
21
- * Serve bamboo's stylesheet as a virtual module, in dev and in build.
22
- *
23
- * This is the integration itself, not an optimisation: without it nothing emits css and
24
- * the generated `styled-system` runtime names classes no rule exists for.
25
- *
26
- * A virtual module rather than a file written to disk, because vite already owns the two
27
- * things a file would have to reimplement. In dev it injects css over the websocket and
28
- * replaces it in place, so an edit repaints without reloading; in build it hashes the
29
- * content into the asset graph and lets the bundler decide where it lands. Writing
30
- * `styles.css` and asking the project to import it means the build reads a file the same
31
- * process just wrote, which is a race on any watch rebuild.
32
- */
33
- declare const bamboocssCss: (options?: BambooCssPluginOptions) => Plugin;
34
- //#endregion
35
- //#region src/fold-recipe.d.ts
36
- /**
37
- * Lowering a call of an inline recipe to the class string it produces.
38
- *
39
- * The prize is not the `cva` runtime, which is small. It is the *config*: `cva({ base, variants })`
40
- * ships the whole style object to the browser purely so the runtime can hash it into a name and
41
- * pick classes off it. Those styles are already in the stylesheet. Once every call of a binding
42
- * is lowered, the binding is unreferenced and a bundler drops the config with it — measured at
43
- * 81 kB gzipped across one application's 1,297 inline recipes, against 4.5 kB for the runtime.
44
- *
45
- * Correct by construction rather than by a matching reimplementation: the class names come from
46
- * `getRecipeIdentity` and `getRecipeClassNames`, the same functions the browser runs, and the
47
- * prefixing and hashing from `classFormatter`, which is what the encoder emitted rules under.
48
- */
49
- type Dict$1 = Record<string, unknown>;
50
- /** A recipe's config, as the extractor resolved it. */
51
- interface RecipeConfig {
52
- className?: string;
53
- base?: Dict$1;
54
- variants?: Record<string, Record<string, unknown>>;
55
- defaultVariants?: Record<string, unknown>;
56
- compoundVariants?: unknown[];
57
- /** Present on a slot recipe, which resolves to one class per slot rather than a string. */
58
- slots?: unknown;
59
- }
60
- /**
61
- * A recipe the fold can lower against.
62
- *
63
- * `name` is hashed once here rather than per call site: `getRecipeIdentity` serialises the
64
- * whole config to hash it, which measured as 91% of the per-call work when it sat inside
65
- * `lowerRecipeCall`. The runtime does it once per `cva()` for the same reason.
66
- *
67
- * `box` is the *definition's* node, carried so the fold can register the module the config
68
- * came from as a watch dependency. Without it, editing a config in another module leaves
69
- * every literal folded against it stale — the stylesheet gets a new identity and the element
70
- * keeps the old class.
71
- */
72
- interface RecipeEntry {
73
- config: RecipeConfig;
74
- name: string;
75
- box: ResultItem['box'];
76
- }
77
- //#endregion
78
- //#region src/runtime-css.d.ts
79
- /**
80
- * The generated runtime's `css`, rebuilt in-process from a resolved context.
81
- *
82
- * A fold replaces a call with the string the runtime would have returned, so it has
83
- * to compute that string the same way the runtime does — not the way the stylesheet
84
- * does. The two differ in one respect that matters here: `StyleDecoder` escapes class
85
- * names for use in a CSS selector (`.c_red\.300`), while the runtime emits the raw
86
- * value that belongs in a `class` attribute (`c_red.300`). Folding the decoder's form
87
- * would put a stray backslash in the DOM.
88
- *
89
- * Matching the runtime this way makes the substitution behaviour-preserving by
90
- * construction. What still needs asserting — and is asserted in `__tests__` — is that
91
- * these class names correspond to rules the build actually emits.
92
- *
93
- * Mirrors `generateCssFn` in `@bamboocss/generator`: `css = memo((...styles) =>
94
- * cssFn(mergeCssUncached(...styles)))`, with the memo on the argument list and neither
95
- * inner cache. Unlike the generated runtime this one is built once per build and shared
96
- * across every module, so the outer cache is what carries the repeats.
97
- */
98
- interface RuntimeCss {
99
- (...styles: Dict[]): string;
100
- }
101
- declare const createRuntimeCss: (ctx: Context) => RuntimeCss;
102
- //#endregion
103
- //#region src/fold.d.ts
104
- /**
105
- * Why a call site was left alone. Surfaced through `panda`-style diagnostics so a
106
- * user can tell the difference between "this folded" and "this silently didn't".
107
- */
108
- type SkipReason = 'dynamic' | 'raw-call' | 'not-foldable' | 'recipe-call' | 'unsupported-kind' | 'not-imported' | 'no-call-expression' | 'overlapping' | 'empty' | 'unresolved-token' | 'runtime-binding' | 'fold-failed';
109
- interface FoldedCall {
110
- name: string;
111
- /**
112
- * What the call collapsed to.
113
- *
114
- * `class` is every style surface: a class string bound for a `class` attribute. `value`
115
- * is `token()`, which resolves to a CSS *value* (`var(--colors-red-300)`). The two are
116
- * not interchangeable, and a consumer that checks folded classes against the emitted
117
- * stylesheet has to skip the latter — there is no rule named after a variable reference.
118
- */
119
- kind: 'class' | 'value';
120
- /** The class string resolved outright, empty when the whole call lowered to ternaries. */
121
- className: string;
122
- /**
123
- * Every class literal the replacement emits, including both arms of each ternary — so a
124
- * consumer checking that folded classes have CSS behind them sees the branches too,
125
- * which `className` alone does not carry.
126
- */
127
- classNames: string[];
128
- /** The literal written in place of the call, for a `value` fold. */
129
- value?: string;
130
- start: number;
131
- end: number;
132
- }
133
- interface SkippedCall {
134
- name: string;
135
- reason: SkipReason;
136
- start: number;
137
- end: number;
138
- }
139
- interface FoldResult {
140
- code: string;
141
- /** Null when nothing was folded, so callers can return the original module untouched. */
142
- map: ReturnType<MagicString['generateMap']> | null;
143
- folded: FoldedCall[];
144
- skipped: SkippedCall[];
145
- /**
146
- * Other modules a folded value came from.
147
- *
148
- * The extractor resolves values across files, so `css(importedStyles, { … })` folds
149
- * to a string that depends on a file this module only imports. Without registering
150
- * that edge, editing the imported module leaves a stale literal behind in every
151
- * consumer. Bundlers need these as watch files.
152
- */
153
- dependencies: string[];
154
- }
155
- interface FoldOptions {
156
- ctx: Context;
157
- code: string;
158
- parserResult: ParserResultInterface;
159
- filePath: string;
160
- /** Reuse one runtime `css` across files in a build. */
161
- runtimeCss?: RuntimeCss;
162
- /**
163
- * Split a `css()` call that is only partly static, keeping the dynamic half at runtime.
164
- * On by default.
165
- */
166
- partial?: boolean;
167
- /**
168
- * Parse another module, for a recipe whose `cva` config lives outside this one.
169
- *
170
- * Threaded in rather than read off `ctx`, because the project belongs to the node
171
- * context and this signature takes the core one. Its absence is a supported state:
172
- * without it a cross-module recipe call is still *reported*, which is the half that
173
- * used to be missing entirely — it simply cannot be lowered.
174
- *
175
- * Pulling the module on demand is also what makes the fold order-independent. A
176
- * bundler transforms a consumer before the module it imports, so a registry built
177
- * from what has been transformed so far would fold or decline the same file
178
- * depending on discovery order.
179
- */
180
- parseModule?: (filePath: string) => ParserResultInterface | undefined;
181
- /**
182
- * Configs of modules other than this one, shared across a build.
183
- *
184
- * Owned by the caller because it has to outlive one call: the declaring module would
185
- * otherwise be re-parsed once per module that imports it, which is `consumers x module
186
- * size` on the transform path — measured at 909ms against 8.3ms for fifty consumers of a
187
- * hundred-recipe module. The caller clears an entry when the file changes, which is the
188
- * only place that knows.
189
- */
190
- recipeConfigCache?: Map<string, ForeignRecipes>;
191
- /**
192
- * Also report bamboo bindings the rewrite left behind, whatever the skip ledger says.
193
- *
194
- * The ledger holds only calls something recognised, so it answers "of the calls I looked
195
- * at, which survived" — and a guarantee built on it is worth exactly what the recogniser
196
- * is. A cross-module recipe call used to appear in neither column, so a build could report
197
- * a clean sweep while shipping hundreds of them.
198
- *
199
- * This asks what the guarantee actually claims: after the rewrite, is anything from a
200
- * bamboo module still referenced? Off by default because it costs an identifier walk, and
201
- * only `failOnUnfolded` needs an answer it can fail a build on.
202
- */
203
- reportSurvivors?: boolean;
204
- /**
205
- * The module's own AST, when the caller already holds it.
206
- *
207
- * Only `reportSurvivors` needs it, and only for the case it exists to catch: a module whose
208
- * bamboo usage produced no parser result at all has no call to reach the AST through.
209
- */
210
- sourceFile?: SourceFile;
211
- }
212
- /**
213
- * What one foreign module contributes, in a form that outlives it.
214
- *
215
- * Plain data only. Anything holding a ts-morph node would be read after the next
216
- * `addSourceFile` forgets that module's tree.
217
- */
218
- interface ForeignRecipes {
219
- configs: Map<string, RecipeEntry>;
220
- /** How that module spelled the css module, for a helper import written into a consumer. */
221
- cssSpecifier?: string;
222
- }
223
- declare const foldSource: (options: FoldOptions) => FoldResult;
224
15
  //#endregion
225
16
  //#region src/plugin.d.ts
226
17
  interface BambooVitePluginOptions {
227
- /**
228
- * Rewrite statically-resolvable `css()` and pattern calls into literal class
229
- * strings, so they cost nothing at runtime.
230
- *
231
- * On by default, and build-only — it never runs in `vite dev`, where the parse would land
232
- * on every hot update and a dev bundle gains nothing from pre-resolved calls.
233
- *
234
- * What it buys is per-call CPU, not bytes: the runtime still ships, because dropping it
235
- * needs *every* call site in the graph to fold. Bundle size moves slightly against you —
236
- * measured at -0.8% raw and +1.0% gzipped on `sandbox/runtime-perf`, since distinct class
237
- * literals compress worse than the repeated `css({ … })` calls they replace. Set it to
238
- * `false` if that trade is the wrong way round for you, or to keep builds faster: folding
239
- * re-parses each module with `ts-morph`, roughly 0.3ms for a small component and 3ms for a
240
- * 147-line file with 24 call sites.
241
- *
242
- * @default true
243
- */
244
- transform?: boolean;
245
- /**
246
- * Split a call or element that is only partly static, so the resolvable half becomes a
247
- * literal and only the rest keeps its runtime call. On by default.
248
- *
249
- * Without it a single dynamic value declines the whole site.
250
- *
251
- * @default true
252
- */
253
- partial?: boolean;
254
18
  /** Path to `bamboo.config.ts`. Resolved the same way the CLI resolves it. */
255
19
  configPath?: string;
256
20
  cwd?: string;
257
21
  /**
258
- * Report every call site that did *not* fold, and why, per file. Useful when a call
259
- * you expected to collapse still shows up in the bundle.
22
+ * Report every call site the compiler rejected, and why, per file.
260
23
  *
261
24
  * @default false
262
25
  */
263
26
  reportSkipped?: boolean;
264
27
  /**
265
- * Print a coverage summary when the build finishes: how much folded, and what the
266
- * remainder was declined for.
28
+ * Print a coverage summary when the build finishes: how much compiled, and why any
29
+ * candidates were rejected.
267
30
  *
268
31
  * On by default. Without it there is no signal that the transform did anything, and
269
32
  * no way to tell a project where everything folds from one where nothing does.
@@ -272,38 +35,30 @@ interface BambooVitePluginOptions {
272
35
  */
273
36
  reportSummary?: boolean;
274
37
  /**
275
- * Fail the build when a `css()` or pattern call is left for the runtime.
276
- *
277
- * The fold's value is not the per-call CPU it saves — it is that a bundle where *every*
278
- * such call folded no longer imports `styled-system/css` at all, and the engine behind it
279
- * drops out. One survivor keeps the whole thing, so a coverage percentage cannot tell you
280
- * whether you got the prize. This can.
281
- *
282
- * Deliberately silent about `cva`/`sva`. A `cva(...)` definition returns a function and can
283
- * never collapse to a class string, so failing on it would make this unusable for anyone
284
- * writing recipes — and recipes keep their own much smaller runtime by design. What this
285
- * guarantees is narrower and checkable: nothing still calls `css()`.
286
- *
287
- * Named for what it checks. It was `strict`, which meant nothing in common with
288
- * `strictTokens` or a pattern's old `strict` — three unrelated options sharing a word, to
289
- * the point that comments in this repo used a bare "strict" for all three.
290
- *
291
- * @default false
38
+ * Compact atom names. `true`/`stable` is deterministic across
39
+ * client and SSR builds. `local` uses the shortest names and is safe only when one build
40
+ * produces both HTML and CSS. @default true
41
+ */
42
+ denseClassNames?: DenseClassNameMode;
43
+ /**
44
+ * Maximum complete selections compiled for one runtime `cva`/`sva` call. This bounds
45
+ * build time and memory for the exact compound-variant decision table. @default 65536
292
46
  */
293
- failOnUnfolded?: boolean;
47
+ maxRecipeStates?: number;
294
48
  }
295
49
  /**
296
50
  * Vite integration for Bamboo CSS.
297
51
  *
298
52
  * Two plugins, because they do unrelated jobs on different schedules. The first emits the
299
53
  * stylesheet as a virtual module and runs in dev and build alike — that is the integration,
300
- * and nothing styles without it. The second is the optional build-time fold.
54
+ * and nothing styles without it. The second compiles every Bamboo source call in both dev
55
+ * and build; there is no runtime styling fallback.
301
56
  *
302
- * The fold runs with `enforce: 'pre'` so it sees module source as close as possible to what
57
+ * The compiler runs with `enforce: 'pre'` so it sees module source as close as possible to what
303
58
  * the CSS extractor reads off disk. A plugin that rewrites style calls before bamboo
304
59
  * sees them would otherwise make the two disagree, and a folded class could end up
305
60
  * with no matching rule.
306
61
  */
307
62
  declare const bamboocss: (options?: BambooVitePluginOptions) => Plugin[];
308
63
  //#endregion
309
- export { type BambooCssPluginOptions, type BambooVitePluginOptions, type FoldOptions, type FoldResult, type FoldedCall, type RuntimeCss, type SkipReason, type SkippedCall, VIRTUAL_CSS_ID, bamboocss, bamboocss as default, bamboocssCss, createRuntimeCss, foldSource };
64
+ export { type BambooVitePluginOptions, VIRTUAL_CSS_ID, bamboocss, bamboocss as default };