@bamboocss/config 1.31.0 → 1.33.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.
@@ -51,14 +51,12 @@ function createMatcher(id, patterns) {
51
51
  const all = [
52
52
  "clean",
53
53
  "cwd",
54
- "eject",
55
54
  "outdir",
56
55
  "forceConsistentTypeExtension",
57
56
  "outExtension",
58
57
  "emitTokensOnly",
59
58
  "presets",
60
- "plugins",
61
- "hooks"
59
+ "plugins"
62
60
  ];
63
61
  const format = [
64
62
  "hash",
@@ -103,7 +101,7 @@ const artifactConfigDeps = {
103
101
  "types-entry": [],
104
102
  "types-gen": [],
105
103
  "types-gen-system": [],
106
- themes: ["themes"].concat(tokens),
104
+ themes: ["theme.variants"].concat(tokens),
107
105
  "static-css": [
108
106
  "staticCss",
109
107
  "patterns",
@@ -117,6 +115,7 @@ const artifactMatchers = Object.entries(artifactConfigDeps).map(([key, paths]) =
117
115
  if (!paths.length) return () => void 0;
118
116
  return createMatcher(key, paths.concat(all));
119
117
  });
118
+ Array.from(new Set([...all, ...Object.values(artifactConfigDeps).flat()]));
120
119
  //#endregion
121
120
  //#region src/diff-config.ts
122
121
  const runIfFn = (fn) => typeof fn === "function" ? fn() : fn;
@@ -27,14 +27,12 @@ function createMatcher(id, patterns) {
27
27
  const all = [
28
28
  "clean",
29
29
  "cwd",
30
- "eject",
31
30
  "outdir",
32
31
  "forceConsistentTypeExtension",
33
32
  "outExtension",
34
33
  "emitTokensOnly",
35
34
  "presets",
36
- "plugins",
37
- "hooks"
35
+ "plugins"
38
36
  ];
39
37
  const format = [
40
38
  "hash",
@@ -79,7 +77,7 @@ const artifactConfigDeps = {
79
77
  "types-entry": [],
80
78
  "types-gen": [],
81
79
  "types-gen-system": [],
82
- themes: ["themes"].concat(tokens),
80
+ themes: ["theme.variants"].concat(tokens),
83
81
  "static-css": [
84
82
  "staticCss",
85
83
  "patterns",
@@ -93,6 +91,7 @@ const artifactMatchers = Object.entries(artifactConfigDeps).map(([key, paths]) =
93
91
  if (!paths.length) return () => void 0;
94
92
  return createMatcher(key, paths.concat(all));
95
93
  });
94
+ Array.from(new Set([...all, ...Object.values(artifactConfigDeps).flat()]));
96
95
  //#endregion
97
96
  //#region src/diff-config.ts
98
97
  const runIfFn = (fn) => typeof fn === "function" ? fn() : fn;
package/dist/index.cjs CHANGED
@@ -132,14 +132,12 @@ function createMatcher(id, patterns) {
132
132
  const all = [
133
133
  "clean",
134
134
  "cwd",
135
- "eject",
136
135
  "outdir",
137
136
  "forceConsistentTypeExtension",
138
137
  "outExtension",
139
138
  "emitTokensOnly",
140
139
  "presets",
141
- "plugins",
142
- "hooks"
140
+ "plugins"
143
141
  ];
144
142
  const format = [
145
143
  "hash",
@@ -184,7 +182,7 @@ const artifactConfigDeps = {
184
182
  "types-entry": [],
185
183
  "types-gen": [],
186
184
  "types-gen-system": [],
187
- themes: ["themes"].concat(tokens),
185
+ themes: ["theme.variants"].concat(tokens),
188
186
  "static-css": [
189
187
  "staticCss",
190
188
  "patterns",
@@ -198,6 +196,7 @@ const artifactMatchers = Object.entries(artifactConfigDeps).map(([key, paths]) =
198
196
  if (!paths.length) return () => void 0;
199
197
  return createMatcher(key, paths.concat(all));
200
198
  });
199
+ Array.from(new Set([...all, ...Object.values(artifactConfigDeps).flat()]));
201
200
  //#endregion
202
201
  //#region src/diff-config.ts
203
202
  const runIfFn = (fn) => typeof fn === "function" ? fn() : fn;
@@ -652,12 +651,6 @@ function mergeScalarShorthand(key, records) {
652
651
  * Merge all configs into a single config
653
652
  */
654
653
  function mergeConfigs(configs) {
655
- const userConfig = configs.at(-1);
656
- const pluginHooks = userConfig.plugins ?? [];
657
- if (userConfig.hooks) pluginHooks.push({
658
- name: _bamboocss_shared.BAMBOO_CONFIG_NAME,
659
- hooks: userConfig.hooks
660
- });
661
654
  const reversed = Array.from(configs).reverse();
662
655
  const theme = mergeExtensions(reversed.map((config) => config.theme ?? {}));
663
656
  const themeVariants = mergeExtensions(reversed.map((config) => config.theme?.variants ?? {}));
@@ -679,8 +672,7 @@ function mergeConfigs(configs) {
679
672
  prune: mergeExtensions(reversed.map((config) => config.prune ?? {})),
680
673
  hash: mergeScalarShorthand("hash", reversed),
681
674
  prefix: mergeScalarShorthand("prefix", reversed),
682
- preflight: mergeScalarShorthand("preflight", reversed),
683
- hooks: mergeHooks(pluginHooks)
675
+ preflight: mergeScalarShorthand("preflight", reversed)
684
676
  }, ...reversed));
685
677
  /**
686
678
  * Properly merge tokens between flat/nested forms by setting the flat form as the default
@@ -875,19 +867,58 @@ const validateRecipes = (options) => {
875
867
  const REMOVED = {
876
868
  pruneUnusedTokens: (value) => value === "strict" ? `\`pruneUnusedTokens: 'strict'\` is now \`prune: { tokens: 'accounted', unresolvedPath: 'error' }\`.` : `\`pruneUnusedTokens\` is now \`prune: { tokens: '${value === false ? "off" : "reachable"}' }\`.`,
877
869
  pruneUnusedKeyframes: (value) => `\`pruneUnusedKeyframes\` is now \`prune: { keyframes: ${value === false ? "false" : "true"} }\`.`,
878
- prunePreflight: (value) => `\`prunePreflight\` is now \`prune: { preflight: ${value === false ? "false" : "true"} }\`.`,
870
+ prunePreflight: (value) => `\`prunePreflight\` is now \`preflight: { prune: ${value === false ? "false" : "true"} }\`.`,
879
871
  globalCss: () => `\`globalCss\` is now \`global: { css }\`.`,
880
872
  globalFontface: () => `\`globalFontface\` is now \`global: { fontface }\`.`,
881
873
  globalPositionTry: () => `\`globalPositionTry\` is now \`global: { positionTry }\`.`,
882
874
  globalVars: () => `\`globalVars\` is now \`global: { vars }\`.`,
883
875
  themes: () => `\`themes\` is now \`theme.variants\`. One character from \`theme\`, both spellings valid, so the typo resolved to a different feature instead of an error.`,
884
- eject: (value) => value ? `\`eject: true\` is now \`presets: []\`. \`presets\` is the complete list — an unset \`presets\` loads \`defaultPresets\`, and listing your own no longer keeps a default underneath it.` : `\`eject: false\` is the default and can be removed. \`presets\` is now the complete list.`,
885
- lightningcss: (value) => value ? `\`lightningcss: true\` is now \`plugins: [pluginLightningcss()]\` from \`@bamboocss/plugin-lightningcss\`, which you install yourself. The flag forced a static import, so every project carried the native binary whether or not it was on.` : `\`lightningcss: false\` is the default and can be removed.`
876
+ eject: (value) => value ? `\`eject: true\` is now \`presets: []\`. \`presets\` is the complete list — an unset \`presets\` loads \`defaultPresets\`, and listing your own no longer keeps a default underneath it.` : `\`eject: false\` was the default and no longer exists — delete it. \`presets\` is now the complete list.`,
877
+ hooks: () => `\`hooks\` is now a plugin: \`plugins: [{ name: 'my-app', hooks: { ... } }]\`. One mechanism had two spellings, and the nameless one left every diagnostic about a hook with nothing to print. Ordering is now just the order of the array, rather than "plugins in sequence, then the config's own last".`,
878
+ lightningcss: (value) => value ? `\`lightningcss: true\` is now \`plugins: [pluginLightningcss()]\` from \`@bamboocss/plugin-lightningcss\`, which you install yourself. The flag forced a static import, so every project carried the native binary whether or not it was on.` : `\`lightningcss: false\` was the default and no longer exists — delete it.`
886
879
  };
887
880
  /** Values that no longer exist for an option that does. Keyed by option, then by old value. */
888
881
  const RETIRED_VALUES = { validation: { none: `\`validation: 'none'\` is now \`validation: 'off'\`, matching \`prune.unresolvedPath\`.` } };
889
882
  /** Removed keys nested one level down, keyed by their parent. */
890
- const REMOVED_NESTED = { prune: { unresolved: (value) => `\`prune.unresolved\` is now \`prune.unresolvedPath\`, and the accounting pass it used to switch on is now \`prune.tokens: 'accounted'\` write \`prune: { tokens: 'accounted', unresolvedPath: '${value === "error" ? "error" : "warn"}' }\`. They are separate because \`'off'\` used to mean two things at once: no accounting, and no report.` } };
883
+ const COMPOSITION_MOVED = (old, prop) => () => `\`theme.${old}\` is now \`theme.mixins\`, applied through \`css({ mixin: '…' })\` rather than \`css({ ${prop}: '' })\`. The three keys ran through one registration and differed only in which properties the value could set an arbitrary partition that cost a bundle spanning two of them a second key and a second application.`;
884
+ const REMOVED_NESTED = {
885
+ prune: {
886
+ preflight: (value) => `\`prune.preflight\` is now \`preflight: { prune: ${value === false ? "false" : "true"} }\`. It was a second key named \`preflight\` one level away from the one that emits the reset, so a config asked for a reset in one place and reshaped it in another — and pruning a scoped reset already had to read \`preflight.scope\` to work at all.`,
887
+ unresolved: (value) => `\`prune.unresolved\` is now \`prune.unresolvedPath\`, and the accounting pass it used to switch on is now \`prune.tokens: 'accounted'\` — write \`prune: { tokens: 'accounted', unresolvedPath: '${value === "error" ? "error" : "warn"}' }\`. They are separate because \`'off'\` used to mean two things at once: no accounting, and no report.`
888
+ },
889
+ theme: {
890
+ textStyles: COMPOSITION_MOVED("textStyles", "textStyle"),
891
+ layerStyles: COMPOSITION_MOVED("layerStyles", "layerStyle"),
892
+ animationStyles: COMPOSITION_MOVED("animationStyles", "animationStyle")
893
+ }
894
+ };
895
+ /**
896
+ * Options a config still sets that no longer exist — a hard error, and not silenceable.
897
+ *
898
+ * Runs ahead of `validation` and ignores it, for the reason `assertNoRetiredSyntax` does. The
899
+ * rest of `validateConfig` reports opinions about a config that will still build; this reports a
900
+ * config that is *provably* not the one being read. An unknown key might be forward-compatible —
901
+ * a setting for a version you have not installed yet — but a key on this list is only reachable
902
+ * by a config written against a version that is behind the one running it.
903
+ *
904
+ * It used to warn, which is the wrong severity for exactly the upgrade this exists to catch. A
905
+ * warning scrolls past in CI, and a removed option is silent in every other way: the build
906
+ * reverts to the default and the assertion the user asked for stops being enforced. These
907
+ * removals ship in minor versions, so a Renovate auto-merge sails through a warning without a
908
+ * person ever reading it — the one case where nothing else can catch it.
909
+ *
910
+ * Every occurrence is collected before throwing, because the point is to fix a config once
911
+ * rather than to be told about it one key at a time. Delete this a release or two after removal,
912
+ * along with `validate-retired-syntax.ts`.
913
+ */
914
+ function assertNoRemovedOptions(config) {
915
+ const found = [];
916
+ validateRemovedOptions(config, (scope, message) => {
917
+ found.push(`- [${scope}] ${message}`);
918
+ });
919
+ if (!found.length) return;
920
+ throw new _bamboocss_shared.BambooError("CONFIG_ERROR", `${found.length} config option(s) no longer exist:\n\n${found.join("\n")}\n\nNothing walks a config for keys it does not recognise, so an option left in place here is reported nowhere else — the build reverts to the default in silence, and any assertion the option asked for stops being enforced. Make the edits above and the build proceeds. This is not governed by \`validation\`, which grades a config that still builds.\n\nThis reads the config after presets are merged, so a key you cannot find in your own file came from one of them — upgrade that preset, or drop the key with a \`config:resolved\` hook.`);
921
+ }
891
922
  function validateRemovedOptions(config, addError) {
892
923
  const dict = config;
893
924
  for (const [name, describe] of Object.entries(REMOVED)) {
@@ -1082,16 +1113,21 @@ const validateTokens = (options) => {
1082
1113
  * - Check for missing tokens references
1083
1114
  * - Check for conditions selectors (must contain '&')
1084
1115
  * - Check for breakpoints units (must be the same)
1085
- * - Check for options that have been removed, which are otherwise ignored in silence
1116
+ * - Throw on options that have been removed, which are otherwise ignored in silence
1086
1117
  * - Throw on token values still written in the retired curly reference syntax
1118
+ *
1119
+ * The two throwing checks run first and answer to nothing below them. `validation` grades
1120
+ * *opinions about a config that still builds*; those two are evidence that the config is not
1121
+ * the one being read, which is a different question and not one a severity setting should
1122
+ * decide.
1087
1123
  */
1088
1124
  const validateConfig = (config) => {
1089
1125
  assertNoRetiredSyntax(config);
1126
+ assertNoRemovedOptions(config);
1090
1127
  const warnings = /* @__PURE__ */ new Set();
1091
1128
  const addError = (scope, message) => {
1092
1129
  warnings.add(`[${scope}] ` + message);
1093
1130
  };
1094
- validateRemovedOptions(config, addError);
1095
1131
  const report = () => {
1096
1132
  if (!warnings.size) return;
1097
1133
  const errors = `⚠️ Invalid config:\n${Array.from(warnings).map((err) => "- " + err).join("\n")}\n`;
@@ -1170,15 +1206,8 @@ async function resolveConfig(result, cwd) {
1170
1206
  const listed = result.config.presets;
1171
1207
  result.config.presets = listed ? Array.from(new Set(listed.map((preset) => getBundledPreset(preset) ?? preset))) : [...defaultPresets];
1172
1208
  warnIfBaseDropped(listed, result.config.presets);
1173
- const userConfig = result.config;
1174
- const pluginHooks = userConfig.plugins ?? [];
1175
- if (userConfig.hooks) pluginHooks.push({
1176
- name: _bamboocss_shared.BAMBOO_CONFIG_NAME,
1177
- hooks: userConfig.hooks
1178
- });
1179
- const earlyHooks = mergeHooks(pluginHooks);
1180
- const mergedConfig = await getResolvedConfig(result.config, cwd, earlyHooks);
1181
- const hooks = mergedConfig.hooks ?? {};
1209
+ const hooks = mergeHooks(result.config.plugins ?? []);
1210
+ const mergedConfig = await getResolvedConfig(result.config, cwd, hooks);
1182
1211
  if (mergedConfig.logLevel) _bamboocss_logger.logger.level = mergedConfig.logLevel;
1183
1212
  if (mergedConfig.logFilter) _bamboocss_logger.logger.filter = mergedConfig.logFilter;
1184
1213
  validateConfig(mergedConfig);
package/dist/index.d.cts CHANGED
@@ -183,93 +183,6 @@ declare const defaultPresets: ({
183
183
  flexShrink: any;
184
184
  };
185
185
  };
186
- stack: {
187
- properties: {
188
- align: {
189
- type: "property";
190
- value: "alignItems";
191
- };
192
- justify: {
193
- type: "property";
194
- value: "justifyContent";
195
- };
196
- direction: {
197
- type: "property";
198
- value: "flexDirection";
199
- };
200
- gap: {
201
- type: "property";
202
- value: "gap";
203
- };
204
- };
205
- defaultValues: {
206
- direction: string;
207
- gap: string;
208
- };
209
- transform(props: {
210
- [x: string]: any;
211
- [x: number]: any;
212
- [x: string & Record<never, never>]: any;
213
- }): {
214
- display: "flex";
215
- flexDirection: any;
216
- alignItems: any;
217
- justifyContent: any;
218
- gap: any;
219
- };
220
- };
221
- vstack: {
222
- properties: {
223
- justify: {
224
- type: "property";
225
- value: "justifyContent";
226
- };
227
- gap: {
228
- type: "property";
229
- value: "gap";
230
- };
231
- };
232
- defaultValues: {
233
- gap: string;
234
- };
235
- transform(props: {
236
- [x: string]: any;
237
- [x: number]: any;
238
- [x: string & Record<never, never>]: any;
239
- }): {
240
- display: "flex";
241
- alignItems: "center";
242
- justifyContent: any;
243
- gap: any;
244
- flexDirection: "column";
245
- };
246
- };
247
- hstack: {
248
- properties: {
249
- justify: {
250
- type: "property";
251
- value: "justifyContent";
252
- };
253
- gap: {
254
- type: "property";
255
- value: "gap";
256
- };
257
- };
258
- defaultValues: {
259
- gap: string;
260
- };
261
- transform(props: {
262
- [x: string]: any;
263
- [x: number]: any;
264
- [x: string & Record<never, never>]: any;
265
- }): {
266
- display: "flex";
267
- alignItems: "center";
268
- justifyContent: any;
269
- gap: any;
270
- flexDirection: "row";
271
- };
272
- };
273
186
  spacer: {
274
187
  properties: {
275
188
  size: {
@@ -292,28 +205,11 @@ declare const defaultPresets: ({
292
205
  flex: any;
293
206
  };
294
207
  };
295
- square: {
208
+ center: {
296
209
  properties: {
297
- size: {
298
- type: "property";
299
- value: "width";
210
+ inline: {
211
+ type: "boolean";
300
212
  };
301
- };
302
- transform(props: {
303
- [x: string]: any;
304
- [x: number]: any;
305
- [x: string & Record<never, never>]: any;
306
- }): {
307
- display: "flex";
308
- alignItems: "center";
309
- justifyContent: "center";
310
- flex: "0 0 auto";
311
- width: any;
312
- height: any;
313
- };
314
- };
315
- circle: {
316
- properties: {
317
213
  size: {
318
214
  type: "property";
319
215
  value: "width";
@@ -324,29 +220,12 @@ declare const defaultPresets: ({
324
220
  [x: number]: any;
325
221
  [x: string & Record<never, never>]: any;
326
222
  }): {
327
- display: "flex";
223
+ display: "flex" | "inline-flex";
328
224
  alignItems: "center";
329
225
  justifyContent: "center";
330
- flex: "0 0 auto";
226
+ flex: "0 0 auto" | undefined;
331
227
  width: any;
332
228
  height: any;
333
- borderRadius: "9999px";
334
- };
335
- };
336
- center: {
337
- properties: {
338
- inline: {
339
- type: "boolean";
340
- };
341
- };
342
- transform(props: {
343
- [x: string]: any;
344
- [x: number]: any;
345
- [x: string & Record<never, never>]: any;
346
- }): {
347
- display: "flex" | "inline-flex";
348
- alignItems: "center";
349
- justifyContent: "center";
350
229
  };
351
230
  };
352
231
  linkOverlay: {
@@ -478,43 +357,6 @@ declare const defaultPresets: ({
478
357
  gridRowEnd: any;
479
358
  };
480
359
  };
481
- wrap: {
482
- properties: {
483
- gap: {
484
- type: "property";
485
- value: "gap";
486
- };
487
- rowGap: {
488
- type: "property";
489
- value: "gap";
490
- };
491
- columnGap: {
492
- type: "property";
493
- value: "gap";
494
- };
495
- align: {
496
- type: "property";
497
- value: "alignItems";
498
- };
499
- justify: {
500
- type: "property";
501
- value: "justifyContent";
502
- };
503
- };
504
- transform(props: {
505
- [x: string]: any;
506
- [x: number]: any;
507
- [x: string & Record<never, never>]: any;
508
- }): {
509
- display: "flex";
510
- flexWrap: "wrap";
511
- alignItems: any;
512
- justifyContent: any;
513
- gap: any;
514
- columnGap: any;
515
- rowGap: any;
516
- };
517
- };
518
360
  container: {
519
361
  transform(props: {
520
362
  [x: string]: any;
@@ -648,30 +490,6 @@ declare const defaultPresets: ({
648
490
  marginBlock: "calc(var(--bleed-y, 0) * -1)";
649
491
  };
650
492
  };
651
- cq: {
652
- properties: {
653
- name: {
654
- type: "token";
655
- value: "containerNames";
656
- property: "containerName";
657
- };
658
- type: {
659
- type: "property";
660
- value: "containerType";
661
- };
662
- };
663
- defaultValues: {
664
- type: string;
665
- };
666
- transform(props: {
667
- [x: string]: any;
668
- [x: number]: any;
669
- [x: string & Record<never, never>]: any;
670
- }): {
671
- containerType: any;
672
- containerName: any;
673
- };
674
- };
675
493
  };
676
494
  } | {
677
495
  name: string;
@@ -1936,7 +1754,7 @@ declare const defaultPresets: ({
1936
1754
  };
1937
1755
  };
1938
1756
  };
1939
- textStyles: import("@bamboocss/types").TextStyles;
1757
+ mixins: import("@bamboocss/types").Mixins;
1940
1758
  containerSizes: {
1941
1759
  xs: string;
1942
1760
  sm: string;
package/dist/index.d.mts CHANGED
@@ -183,93 +183,6 @@ declare const defaultPresets: ({
183
183
  flexShrink: any;
184
184
  };
185
185
  };
186
- stack: {
187
- properties: {
188
- align: {
189
- type: "property";
190
- value: "alignItems";
191
- };
192
- justify: {
193
- type: "property";
194
- value: "justifyContent";
195
- };
196
- direction: {
197
- type: "property";
198
- value: "flexDirection";
199
- };
200
- gap: {
201
- type: "property";
202
- value: "gap";
203
- };
204
- };
205
- defaultValues: {
206
- direction: string;
207
- gap: string;
208
- };
209
- transform(props: {
210
- [x: string]: any;
211
- [x: number]: any;
212
- [x: string & Record<never, never>]: any;
213
- }): {
214
- display: "flex";
215
- flexDirection: any;
216
- alignItems: any;
217
- justifyContent: any;
218
- gap: any;
219
- };
220
- };
221
- vstack: {
222
- properties: {
223
- justify: {
224
- type: "property";
225
- value: "justifyContent";
226
- };
227
- gap: {
228
- type: "property";
229
- value: "gap";
230
- };
231
- };
232
- defaultValues: {
233
- gap: string;
234
- };
235
- transform(props: {
236
- [x: string]: any;
237
- [x: number]: any;
238
- [x: string & Record<never, never>]: any;
239
- }): {
240
- display: "flex";
241
- alignItems: "center";
242
- justifyContent: any;
243
- gap: any;
244
- flexDirection: "column";
245
- };
246
- };
247
- hstack: {
248
- properties: {
249
- justify: {
250
- type: "property";
251
- value: "justifyContent";
252
- };
253
- gap: {
254
- type: "property";
255
- value: "gap";
256
- };
257
- };
258
- defaultValues: {
259
- gap: string;
260
- };
261
- transform(props: {
262
- [x: string]: any;
263
- [x: number]: any;
264
- [x: string & Record<never, never>]: any;
265
- }): {
266
- display: "flex";
267
- alignItems: "center";
268
- justifyContent: any;
269
- gap: any;
270
- flexDirection: "row";
271
- };
272
- };
273
186
  spacer: {
274
187
  properties: {
275
188
  size: {
@@ -292,28 +205,11 @@ declare const defaultPresets: ({
292
205
  flex: any;
293
206
  };
294
207
  };
295
- square: {
208
+ center: {
296
209
  properties: {
297
- size: {
298
- type: "property";
299
- value: "width";
210
+ inline: {
211
+ type: "boolean";
300
212
  };
301
- };
302
- transform(props: {
303
- [x: string]: any;
304
- [x: number]: any;
305
- [x: string & Record<never, never>]: any;
306
- }): {
307
- display: "flex";
308
- alignItems: "center";
309
- justifyContent: "center";
310
- flex: "0 0 auto";
311
- width: any;
312
- height: any;
313
- };
314
- };
315
- circle: {
316
- properties: {
317
213
  size: {
318
214
  type: "property";
319
215
  value: "width";
@@ -324,29 +220,12 @@ declare const defaultPresets: ({
324
220
  [x: number]: any;
325
221
  [x: string & Record<never, never>]: any;
326
222
  }): {
327
- display: "flex";
223
+ display: "flex" | "inline-flex";
328
224
  alignItems: "center";
329
225
  justifyContent: "center";
330
- flex: "0 0 auto";
226
+ flex: "0 0 auto" | undefined;
331
227
  width: any;
332
228
  height: any;
333
- borderRadius: "9999px";
334
- };
335
- };
336
- center: {
337
- properties: {
338
- inline: {
339
- type: "boolean";
340
- };
341
- };
342
- transform(props: {
343
- [x: string]: any;
344
- [x: number]: any;
345
- [x: string & Record<never, never>]: any;
346
- }): {
347
- display: "flex" | "inline-flex";
348
- alignItems: "center";
349
- justifyContent: "center";
350
229
  };
351
230
  };
352
231
  linkOverlay: {
@@ -478,43 +357,6 @@ declare const defaultPresets: ({
478
357
  gridRowEnd: any;
479
358
  };
480
359
  };
481
- wrap: {
482
- properties: {
483
- gap: {
484
- type: "property";
485
- value: "gap";
486
- };
487
- rowGap: {
488
- type: "property";
489
- value: "gap";
490
- };
491
- columnGap: {
492
- type: "property";
493
- value: "gap";
494
- };
495
- align: {
496
- type: "property";
497
- value: "alignItems";
498
- };
499
- justify: {
500
- type: "property";
501
- value: "justifyContent";
502
- };
503
- };
504
- transform(props: {
505
- [x: string]: any;
506
- [x: number]: any;
507
- [x: string & Record<never, never>]: any;
508
- }): {
509
- display: "flex";
510
- flexWrap: "wrap";
511
- alignItems: any;
512
- justifyContent: any;
513
- gap: any;
514
- columnGap: any;
515
- rowGap: any;
516
- };
517
- };
518
360
  container: {
519
361
  transform(props: {
520
362
  [x: string]: any;
@@ -648,30 +490,6 @@ declare const defaultPresets: ({
648
490
  marginBlock: "calc(var(--bleed-y, 0) * -1)";
649
491
  };
650
492
  };
651
- cq: {
652
- properties: {
653
- name: {
654
- type: "token";
655
- value: "containerNames";
656
- property: "containerName";
657
- };
658
- type: {
659
- type: "property";
660
- value: "containerType";
661
- };
662
- };
663
- defaultValues: {
664
- type: string;
665
- };
666
- transform(props: {
667
- [x: string]: any;
668
- [x: number]: any;
669
- [x: string & Record<never, never>]: any;
670
- }): {
671
- containerType: any;
672
- containerName: any;
673
- };
674
- };
675
493
  };
676
494
  } | {
677
495
  name: string;
@@ -1936,7 +1754,7 @@ declare const defaultPresets: ({
1936
1754
  };
1937
1755
  };
1938
1756
  };
1939
- textStyles: import("@bamboocss/types").TextStyles;
1757
+ mixins: import("@bamboocss/types").Mixins;
1940
1758
  containerSizes: {
1941
1759
  xs: string;
1942
1760
  sm: string;
package/dist/index.mjs CHANGED
@@ -104,14 +104,12 @@ function createMatcher(id, patterns) {
104
104
  const all = [
105
105
  "clean",
106
106
  "cwd",
107
- "eject",
108
107
  "outdir",
109
108
  "forceConsistentTypeExtension",
110
109
  "outExtension",
111
110
  "emitTokensOnly",
112
111
  "presets",
113
- "plugins",
114
- "hooks"
112
+ "plugins"
115
113
  ];
116
114
  const format = [
117
115
  "hash",
@@ -156,7 +154,7 @@ const artifactConfigDeps = {
156
154
  "types-entry": [],
157
155
  "types-gen": [],
158
156
  "types-gen-system": [],
159
- themes: ["themes"].concat(tokens),
157
+ themes: ["theme.variants"].concat(tokens),
160
158
  "static-css": [
161
159
  "staticCss",
162
160
  "patterns",
@@ -170,6 +168,7 @@ const artifactMatchers = Object.entries(artifactConfigDeps).map(([key, paths]) =
170
168
  if (!paths.length) return () => void 0;
171
169
  return createMatcher(key, paths.concat(all));
172
170
  });
171
+ Array.from(new Set([...all, ...Object.values(artifactConfigDeps).flat()]));
173
172
  //#endregion
174
173
  //#region src/diff-config.ts
175
174
  const runIfFn = (fn) => typeof fn === "function" ? fn() : fn;
@@ -624,12 +623,6 @@ function mergeScalarShorthand(key, records) {
624
623
  * Merge all configs into a single config
625
624
  */
626
625
  function mergeConfigs(configs) {
627
- const userConfig = configs.at(-1);
628
- const pluginHooks = userConfig.plugins ?? [];
629
- if (userConfig.hooks) pluginHooks.push({
630
- name: BAMBOO_CONFIG_NAME,
631
- hooks: userConfig.hooks
632
- });
633
626
  const reversed = Array.from(configs).reverse();
634
627
  const theme = mergeExtensions(reversed.map((config) => config.theme ?? {}));
635
628
  const themeVariants = mergeExtensions(reversed.map((config) => config.theme?.variants ?? {}));
@@ -651,8 +644,7 @@ function mergeConfigs(configs) {
651
644
  prune: mergeExtensions(reversed.map((config) => config.prune ?? {})),
652
645
  hash: mergeScalarShorthand("hash", reversed),
653
646
  prefix: mergeScalarShorthand("prefix", reversed),
654
- preflight: mergeScalarShorthand("preflight", reversed),
655
- hooks: mergeHooks(pluginHooks)
647
+ preflight: mergeScalarShorthand("preflight", reversed)
656
648
  }, ...reversed));
657
649
  /**
658
650
  * Properly merge tokens between flat/nested forms by setting the flat form as the default
@@ -847,19 +839,58 @@ const validateRecipes = (options) => {
847
839
  const REMOVED = {
848
840
  pruneUnusedTokens: (value) => value === "strict" ? `\`pruneUnusedTokens: 'strict'\` is now \`prune: { tokens: 'accounted', unresolvedPath: 'error' }\`.` : `\`pruneUnusedTokens\` is now \`prune: { tokens: '${value === false ? "off" : "reachable"}' }\`.`,
849
841
  pruneUnusedKeyframes: (value) => `\`pruneUnusedKeyframes\` is now \`prune: { keyframes: ${value === false ? "false" : "true"} }\`.`,
850
- prunePreflight: (value) => `\`prunePreflight\` is now \`prune: { preflight: ${value === false ? "false" : "true"} }\`.`,
842
+ prunePreflight: (value) => `\`prunePreflight\` is now \`preflight: { prune: ${value === false ? "false" : "true"} }\`.`,
851
843
  globalCss: () => `\`globalCss\` is now \`global: { css }\`.`,
852
844
  globalFontface: () => `\`globalFontface\` is now \`global: { fontface }\`.`,
853
845
  globalPositionTry: () => `\`globalPositionTry\` is now \`global: { positionTry }\`.`,
854
846
  globalVars: () => `\`globalVars\` is now \`global: { vars }\`.`,
855
847
  themes: () => `\`themes\` is now \`theme.variants\`. One character from \`theme\`, both spellings valid, so the typo resolved to a different feature instead of an error.`,
856
- eject: (value) => value ? `\`eject: true\` is now \`presets: []\`. \`presets\` is the complete list — an unset \`presets\` loads \`defaultPresets\`, and listing your own no longer keeps a default underneath it.` : `\`eject: false\` is the default and can be removed. \`presets\` is now the complete list.`,
857
- lightningcss: (value) => value ? `\`lightningcss: true\` is now \`plugins: [pluginLightningcss()]\` from \`@bamboocss/plugin-lightningcss\`, which you install yourself. The flag forced a static import, so every project carried the native binary whether or not it was on.` : `\`lightningcss: false\` is the default and can be removed.`
848
+ eject: (value) => value ? `\`eject: true\` is now \`presets: []\`. \`presets\` is the complete list — an unset \`presets\` loads \`defaultPresets\`, and listing your own no longer keeps a default underneath it.` : `\`eject: false\` was the default and no longer exists — delete it. \`presets\` is now the complete list.`,
849
+ hooks: () => `\`hooks\` is now a plugin: \`plugins: [{ name: 'my-app', hooks: { ... } }]\`. One mechanism had two spellings, and the nameless one left every diagnostic about a hook with nothing to print. Ordering is now just the order of the array, rather than "plugins in sequence, then the config's own last".`,
850
+ lightningcss: (value) => value ? `\`lightningcss: true\` is now \`plugins: [pluginLightningcss()]\` from \`@bamboocss/plugin-lightningcss\`, which you install yourself. The flag forced a static import, so every project carried the native binary whether or not it was on.` : `\`lightningcss: false\` was the default and no longer exists — delete it.`
858
851
  };
859
852
  /** Values that no longer exist for an option that does. Keyed by option, then by old value. */
860
853
  const RETIRED_VALUES = { validation: { none: `\`validation: 'none'\` is now \`validation: 'off'\`, matching \`prune.unresolvedPath\`.` } };
861
854
  /** Removed keys nested one level down, keyed by their parent. */
862
- const REMOVED_NESTED = { prune: { unresolved: (value) => `\`prune.unresolved\` is now \`prune.unresolvedPath\`, and the accounting pass it used to switch on is now \`prune.tokens: 'accounted'\` write \`prune: { tokens: 'accounted', unresolvedPath: '${value === "error" ? "error" : "warn"}' }\`. They are separate because \`'off'\` used to mean two things at once: no accounting, and no report.` } };
855
+ const COMPOSITION_MOVED = (old, prop) => () => `\`theme.${old}\` is now \`theme.mixins\`, applied through \`css({ mixin: '…' })\` rather than \`css({ ${prop}: '' })\`. The three keys ran through one registration and differed only in which properties the value could set an arbitrary partition that cost a bundle spanning two of them a second key and a second application.`;
856
+ const REMOVED_NESTED = {
857
+ prune: {
858
+ preflight: (value) => `\`prune.preflight\` is now \`preflight: { prune: ${value === false ? "false" : "true"} }\`. It was a second key named \`preflight\` one level away from the one that emits the reset, so a config asked for a reset in one place and reshaped it in another — and pruning a scoped reset already had to read \`preflight.scope\` to work at all.`,
859
+ unresolved: (value) => `\`prune.unresolved\` is now \`prune.unresolvedPath\`, and the accounting pass it used to switch on is now \`prune.tokens: 'accounted'\` — write \`prune: { tokens: 'accounted', unresolvedPath: '${value === "error" ? "error" : "warn"}' }\`. They are separate because \`'off'\` used to mean two things at once: no accounting, and no report.`
860
+ },
861
+ theme: {
862
+ textStyles: COMPOSITION_MOVED("textStyles", "textStyle"),
863
+ layerStyles: COMPOSITION_MOVED("layerStyles", "layerStyle"),
864
+ animationStyles: COMPOSITION_MOVED("animationStyles", "animationStyle")
865
+ }
866
+ };
867
+ /**
868
+ * Options a config still sets that no longer exist — a hard error, and not silenceable.
869
+ *
870
+ * Runs ahead of `validation` and ignores it, for the reason `assertNoRetiredSyntax` does. The
871
+ * rest of `validateConfig` reports opinions about a config that will still build; this reports a
872
+ * config that is *provably* not the one being read. An unknown key might be forward-compatible —
873
+ * a setting for a version you have not installed yet — but a key on this list is only reachable
874
+ * by a config written against a version that is behind the one running it.
875
+ *
876
+ * It used to warn, which is the wrong severity for exactly the upgrade this exists to catch. A
877
+ * warning scrolls past in CI, and a removed option is silent in every other way: the build
878
+ * reverts to the default and the assertion the user asked for stops being enforced. These
879
+ * removals ship in minor versions, so a Renovate auto-merge sails through a warning without a
880
+ * person ever reading it — the one case where nothing else can catch it.
881
+ *
882
+ * Every occurrence is collected before throwing, because the point is to fix a config once
883
+ * rather than to be told about it one key at a time. Delete this a release or two after removal,
884
+ * along with `validate-retired-syntax.ts`.
885
+ */
886
+ function assertNoRemovedOptions(config) {
887
+ const found = [];
888
+ validateRemovedOptions(config, (scope, message) => {
889
+ found.push(`- [${scope}] ${message}`);
890
+ });
891
+ if (!found.length) return;
892
+ throw new BambooError("CONFIG_ERROR", `${found.length} config option(s) no longer exist:\n\n${found.join("\n")}\n\nNothing walks a config for keys it does not recognise, so an option left in place here is reported nowhere else — the build reverts to the default in silence, and any assertion the option asked for stops being enforced. Make the edits above and the build proceeds. This is not governed by \`validation\`, which grades a config that still builds.\n\nThis reads the config after presets are merged, so a key you cannot find in your own file came from one of them — upgrade that preset, or drop the key with a \`config:resolved\` hook.`);
893
+ }
863
894
  function validateRemovedOptions(config, addError) {
864
895
  const dict = config;
865
896
  for (const [name, describe] of Object.entries(REMOVED)) {
@@ -1054,16 +1085,21 @@ const validateTokens = (options) => {
1054
1085
  * - Check for missing tokens references
1055
1086
  * - Check for conditions selectors (must contain '&')
1056
1087
  * - Check for breakpoints units (must be the same)
1057
- * - Check for options that have been removed, which are otherwise ignored in silence
1088
+ * - Throw on options that have been removed, which are otherwise ignored in silence
1058
1089
  * - Throw on token values still written in the retired curly reference syntax
1090
+ *
1091
+ * The two throwing checks run first and answer to nothing below them. `validation` grades
1092
+ * *opinions about a config that still builds*; those two are evidence that the config is not
1093
+ * the one being read, which is a different question and not one a severity setting should
1094
+ * decide.
1059
1095
  */
1060
1096
  const validateConfig = (config) => {
1061
1097
  assertNoRetiredSyntax(config);
1098
+ assertNoRemovedOptions(config);
1062
1099
  const warnings = /* @__PURE__ */ new Set();
1063
1100
  const addError = (scope, message) => {
1064
1101
  warnings.add(`[${scope}] ` + message);
1065
1102
  };
1066
- validateRemovedOptions(config, addError);
1067
1103
  const report = () => {
1068
1104
  if (!warnings.size) return;
1069
1105
  const errors = `⚠️ Invalid config:\n${Array.from(warnings).map((err) => "- " + err).join("\n")}\n`;
@@ -1142,15 +1178,8 @@ async function resolveConfig(result, cwd) {
1142
1178
  const listed = result.config.presets;
1143
1179
  result.config.presets = listed ? Array.from(new Set(listed.map((preset) => getBundledPreset(preset) ?? preset))) : [...defaultPresets];
1144
1180
  warnIfBaseDropped(listed, result.config.presets);
1145
- const userConfig = result.config;
1146
- const pluginHooks = userConfig.plugins ?? [];
1147
- if (userConfig.hooks) pluginHooks.push({
1148
- name: BAMBOO_CONFIG_NAME,
1149
- hooks: userConfig.hooks
1150
- });
1151
- const earlyHooks = mergeHooks(pluginHooks);
1152
- const mergedConfig = await getResolvedConfig(result.config, cwd, earlyHooks);
1153
- const hooks = mergedConfig.hooks ?? {};
1181
+ const hooks = mergeHooks(result.config.plugins ?? []);
1182
+ const mergedConfig = await getResolvedConfig(result.config, cwd, hooks);
1154
1183
  if (mergedConfig.logLevel) logger.level = mergedConfig.logLevel;
1155
1184
  if (mergedConfig.logFilter) logger.filter = mergedConfig.logFilter;
1156
1185
  validateConfig(mergedConfig);
@@ -215,12 +215,6 @@ function mergeScalarShorthand(key, records) {
215
215
  * Merge all configs into a single config
216
216
  */
217
217
  function mergeConfigs(configs) {
218
- const userConfig = configs.at(-1);
219
- const pluginHooks = userConfig.plugins ?? [];
220
- if (userConfig.hooks) pluginHooks.push({
221
- name: _bamboocss_shared.BAMBOO_CONFIG_NAME,
222
- hooks: userConfig.hooks
223
- });
224
218
  const reversed = Array.from(configs).reverse();
225
219
  const theme = mergeExtensions(reversed.map((config) => config.theme ?? {}));
226
220
  const themeVariants = mergeExtensions(reversed.map((config) => config.theme?.variants ?? {}));
@@ -242,8 +236,7 @@ function mergeConfigs(configs) {
242
236
  prune: mergeExtensions(reversed.map((config) => config.prune ?? {})),
243
237
  hash: mergeScalarShorthand("hash", reversed),
244
238
  prefix: mergeScalarShorthand("prefix", reversed),
245
- preflight: mergeScalarShorthand("preflight", reversed),
246
- hooks: mergeHooks(pluginHooks)
239
+ preflight: mergeScalarShorthand("preflight", reversed)
247
240
  }, ...reversed));
248
241
  /**
249
242
  * Properly merge tokens between flat/nested forms by setting the flat form as the default
@@ -1,4 +1,4 @@
1
- import { BAMBOO_CONFIG_NAME, assign, isObject, mergeAndConcat, mergeWith, walkObject } from "@bamboocss/shared";
1
+ import { assign, isObject, mergeAndConcat, mergeWith, walkObject } from "@bamboocss/shared";
2
2
  import { logger } from "@bamboocss/logger";
3
3
  //#region src/merge-hooks.ts
4
4
  const mergeHooks = (plugins) => {
@@ -214,12 +214,6 @@ function mergeScalarShorthand(key, records) {
214
214
  * Merge all configs into a single config
215
215
  */
216
216
  function mergeConfigs(configs) {
217
- const userConfig = configs.at(-1);
218
- const pluginHooks = userConfig.plugins ?? [];
219
- if (userConfig.hooks) pluginHooks.push({
220
- name: BAMBOO_CONFIG_NAME,
221
- hooks: userConfig.hooks
222
- });
223
217
  const reversed = Array.from(configs).reverse();
224
218
  const theme = mergeExtensions(reversed.map((config) => config.theme ?? {}));
225
219
  const themeVariants = mergeExtensions(reversed.map((config) => config.theme?.variants ?? {}));
@@ -241,8 +235,7 @@ function mergeConfigs(configs) {
241
235
  prune: mergeExtensions(reversed.map((config) => config.prune ?? {})),
242
236
  hash: mergeScalarShorthand("hash", reversed),
243
237
  prefix: mergeScalarShorthand("prefix", reversed),
244
- preflight: mergeScalarShorthand("preflight", reversed),
245
- hooks: mergeHooks(pluginHooks)
238
+ preflight: mergeScalarShorthand("preflight", reversed)
246
239
  }, ...reversed));
247
240
  /**
248
241
  * Properly merge tokens between flat/nested forms by setting the flat form as the default
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bamboocss/config",
3
- "version": "1.31.0",
3
+ "version": "1.33.0",
4
4
  "description": "Find and load bamboo config",
5
5
  "homepage": "https://bamboocss.com",
6
6
  "license": "MIT",
@@ -64,11 +64,11 @@
64
64
  "escalade": "3.2.0",
65
65
  "microdiff": "1.5.0",
66
66
  "typescript": "6.0.2",
67
- "@bamboocss/logger": "1.31.0",
68
- "@bamboocss/preset-bamboo": "1.31.0",
69
- "@bamboocss/preset-base": "1.31.0",
70
- "@bamboocss/shared": "1.31.0",
71
- "@bamboocss/types": "1.31.0"
67
+ "@bamboocss/logger": "1.33.0",
68
+ "@bamboocss/preset-bamboo": "1.33.0",
69
+ "@bamboocss/preset-base": "1.33.0",
70
+ "@bamboocss/shared": "1.33.0",
71
+ "@bamboocss/types": "1.33.0"
72
72
  },
73
73
  "devDependencies": {
74
74
  "pkg-types": "2.3.0"