@bamboocss/config 1.30.1 → 1.31.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.cjs CHANGED
@@ -28,14 +28,14 @@ let escalade_sync = require("escalade/sync");
28
28
  escalade_sync = __toESM(escalade_sync);
29
29
  let path = require("path");
30
30
  path = __toESM(path);
31
+ let _bamboocss_preset_base = require("@bamboocss/preset-base");
32
+ let _bamboocss_preset_bamboo = require("@bamboocss/preset-bamboo");
31
33
  let microdiff = require("microdiff");
32
34
  microdiff = __toESM(microdiff);
33
35
  let fs = require("fs");
34
36
  fs = __toESM(fs);
35
37
  let typescript = require("typescript");
36
38
  typescript = __toESM(typescript);
37
- let _bamboocss_preset_base = require("@bamboocss/preset-base");
38
- let _bamboocss_preset_bamboo = require("@bamboocss/preset-bamboo");
39
39
  //#region src/is-bamboo-config.ts
40
40
  const configName = "bamboo";
41
41
  const bambooConfigFiles = new Set([
@@ -86,6 +86,25 @@ async function bundleConfig(options) {
86
86
  };
87
87
  }
88
88
  //#endregion
89
+ //#region src/bundled-preset.ts
90
+ const bundledPresets = {
91
+ "@bamboocss/preset-base": _bamboocss_preset_base.preset,
92
+ "@bamboocss/preset-bamboo": _bamboocss_preset_bamboo.preset,
93
+ "@bamboocss/dev/presets": _bamboocss_preset_bamboo.preset
94
+ };
95
+ const bundledPresetsNames = Object.keys(bundledPresets);
96
+ const isBundledPreset = (preset) => bundledPresetsNames.includes(preset);
97
+ const getBundledPreset = (preset) => {
98
+ return typeof preset === "string" && isBundledPreset(preset) ? bundledPresets[preset] : void 0;
99
+ };
100
+ /**
101
+ * What `presets` loads when a config does not list any.
102
+ *
103
+ * Exported so a config that adds a preset can keep them without restating them:
104
+ * `presets: [...defaultPresets, myPreset]`. Spread it — the array is shared.
105
+ */
106
+ const defaultPresets = [_bamboocss_preset_base.preset, _bamboocss_preset_bamboo.preset];
107
+ //#endregion
89
108
  //#region src/create-matcher.ts
90
109
  /**
91
110
  * Acts like a .gitignore matcher
@@ -505,18 +524,35 @@ const tryCatch = (name, fn) => {
505
524
  };
506
525
  //#endregion
507
526
  //#region src/validation/utils.ts
508
- const REFERENCE_REGEX = /({([^}]*)})/g;
509
- const curlyBracketRegex = /[{}]/g;
527
+ /**
528
+ * A reference to another token: `token(colors.red.300)`.
529
+ *
530
+ * Deliberately a copy of the regex in `@bamboocss/token-dictionary`, which this package does not
531
+ * depend on. The two must agree: validation is what reports a missing or circular reference, so a
532
+ * spelling only the dictionary understands is one this never checks — which is silence, not an
533
+ * error, and exactly what a spelling change here is most likely to cause.
534
+ */
535
+ const REFERENCE_REGEX = /token\(([^(),]+)\)/g;
510
536
  const isValidToken = (token) => (0, _bamboocss_shared.isObject)(token) && Object.hasOwnProperty.call(token, "value");
511
- const isTokenReference = (value) => typeof value === "string" && REFERENCE_REGEX.test(value);
537
+ const isTokenReference = (value) => typeof value === "string" && getReferences(value).length > 0;
538
+ /**
539
+ * The retired curly reference — `{colors.red.300}`, or `{$spacing-2}` under a custom
540
+ * `formatTokenName`. A copy of the regex in `@bamboocss/token-dictionary`, which this package
541
+ * does not depend on.
542
+ *
543
+ * Reported here as well as there because a *token* value carrying one is the worse case: the
544
+ * text is emitted into the stylesheet rather than dropped, and validation is the only thing that
545
+ * can name which token it came from.
546
+ */
547
+ const CURLY_REFERENCE = /\{[^{}\s:;"']+\}/;
548
+ const findCurlyReference = (value) => value.includes("{") ? CURLY_REFERENCE.exec(value)?.[0] ?? void 0 : void 0;
549
+ /** The retired `token(path, fallback)` form. See `findCurlyReference` for why these fail. */
550
+ const FALLBACK_REFERENCE = /token\([^(),]+,[^()]*\)/;
551
+ const findFallbackReference = (value) => value.includes("token(") ? FALLBACK_REFERENCE.exec(value)?.[0] ?? void 0 : void 0;
512
552
  const formatPath = (path) => path;
513
553
  function getReferences(value) {
514
554
  if (typeof value !== "string") return [];
515
- const matches = value.match(REFERENCE_REGEX);
516
- if (!matches) return [];
517
- return matches.map((match) => match.replace(curlyBracketRegex, "")).map((value) => {
518
- return value.trim().split("/")[0];
519
- });
555
+ return [...value.matchAll(REFERENCE_REGEX)].map((match) => match[1].trim().split("/")[0]).filter(Boolean);
520
556
  }
521
557
  const serializeTokenValue = (value) => {
522
558
  if ((0, _bamboocss_shared.isString)(value)) return value;
@@ -573,6 +609,46 @@ const tokenKeys = [
573
609
  "deprecated"
574
610
  ];
575
611
  /**
612
+ * Options whose scalar form is shorthand for setting every member of their object form.
613
+ *
614
+ * `hash: true` says both `cssVar` and `className`; `prefix: 'bb'` says both; `preflight: true`
615
+ * says "on, with the defaults". Expanding them is what lets the object forms compose: a preset
616
+ * that sets `prefix.className` and an app that sets `prefix.cssVar` should end up with both,
617
+ * and before this the app's object replaced the preset's wholesale — silently, since the two
618
+ * name different members. `hash`'s members are optional, so writing the partial form that
619
+ * triggered it is the natural thing to do.
620
+ *
621
+ * `preflight: false` has no object form — there is no member meaning "off" — so it stays a
622
+ * scalar and wins outright when it is the value the winning config states.
623
+ */
624
+ const SCALAR_SHORTHANDS = {
625
+ hash: (value) => typeof value === "boolean" ? {
626
+ cssVar: value,
627
+ className: value
628
+ } : value,
629
+ prefix: (value) => typeof value === "string" ? {
630
+ cssVar: value,
631
+ className: value
632
+ } : value,
633
+ preflight: (value) => value === true ? {} : value
634
+ };
635
+ /**
636
+ * Merge one of those, winner-first per member.
637
+ *
638
+ * `records` arrives in precedence order — the user's config, then each preset — which is the
639
+ * order `assign` wants, since it only fills keys the target does not already have.
640
+ */
641
+ function mergeScalarShorthand(key, records) {
642
+ const normalize = SCALAR_SHORTHANDS[key];
643
+ const values = records.map((record) => record[key]).filter((value) => value !== void 0);
644
+ if (!values.length) return void 0;
645
+ if (values[0] === false) return false;
646
+ const objects = values.map(normalize).filter((value) => value !== null && typeof value === "object");
647
+ if (!objects.length) return values[0];
648
+ const merged = objects.reduce((acc, object) => (0, _bamboocss_shared.assign)(acc, object), {});
649
+ return isEmptyObject(merged) ? values[0] : merged;
650
+ }
651
+ /**
576
652
  * Merge all configs into a single config
577
653
  */
578
654
  function mergeConfigs(configs) {
@@ -583,17 +659,27 @@ function mergeConfigs(configs) {
583
659
  hooks: userConfig.hooks
584
660
  });
585
661
  const reversed = Array.from(configs).reverse();
662
+ const theme = mergeExtensions(reversed.map((config) => config.theme ?? {}));
663
+ const themeVariants = mergeExtensions(reversed.map((config) => config.theme?.variants ?? {}));
664
+ if (isEmptyObject(themeVariants)) delete theme.variants;
665
+ else theme.variants = themeVariants;
666
+ const global = compact({
667
+ css: mergeExtensions(reversed.map((config) => config.global?.css ?? {})),
668
+ vars: mergeExtensions(reversed.map((config) => config.global?.vars ?? {})),
669
+ fontface: mergeExtensions(reversed.map((config) => config.global?.fontface ?? {})),
670
+ positionTry: mergeExtensions(reversed.map((config) => config.global?.positionTry ?? {}))
671
+ });
586
672
  const withoutEmpty = compact((0, _bamboocss_shared.assign)({
587
673
  conditions: mergeExtensions(reversed.map((config) => config.conditions ?? {})),
588
- theme: mergeExtensions(reversed.map((config) => config.theme ?? {})),
674
+ theme,
589
675
  patterns: mergeExtensions(reversed.map((config) => config.patterns ?? {})),
590
676
  utilities: mergeExtensions(reversed.map((config) => config.utilities ?? {})),
591
- globalCss: mergeExtensions(reversed.map((config) => config.globalCss ?? {})),
592
- globalVars: mergeExtensions(reversed.map((config) => config.globalVars ?? {})),
593
- globalFontface: mergeExtensions(reversed.map((config) => config.globalFontface ?? {})),
594
- globalPositionTry: mergeExtensions(reversed.map((config) => config.globalPositionTry ?? {})),
677
+ global,
595
678
  staticCss: mergeExtensions(reversed.map((config) => config.staticCss ?? {})),
596
- themes: mergeExtensions(reversed.map((config) => config.themes ?? {})),
679
+ prune: mergeExtensions(reversed.map((config) => config.prune ?? {})),
680
+ hash: mergeScalarShorthand("hash", reversed),
681
+ prefix: mergeScalarShorthand("prefix", reversed),
682
+ preflight: mergeScalarShorthand("preflight", reversed),
597
683
  hooks: mergeHooks(pluginHooks)
598
684
  }, ...reversed));
599
685
  /**
@@ -679,18 +765,6 @@ async function getResolvedConfig(config, cwd, hooks) {
679
765
  return merged;
680
766
  }
681
767
  //#endregion
682
- //#region src/bundled-preset.ts
683
- const bundledPresets = {
684
- "@bamboocss/preset-base": _bamboocss_preset_base.preset,
685
- "@bamboocss/preset-bamboo": _bamboocss_preset_bamboo.preset,
686
- "@bamboocss/dev/presets": _bamboocss_preset_bamboo.preset
687
- };
688
- const bundledPresetsNames = Object.keys(bundledPresets);
689
- const isBundledPreset = (preset) => bundledPresetsNames.includes(preset);
690
- const getBundledPreset = (preset) => {
691
- return typeof preset === "string" && isBundledPreset(preset) ? bundledPresets[preset] : void 0;
692
- };
693
- //#endregion
694
768
  //#region src/validation/validate-artifact.ts
695
769
  const validateArtifactNames = (names, addError) => {
696
770
  names.recipes.forEach((recipeName) => {
@@ -785,6 +859,109 @@ const validateRecipes = (options) => {
785
859
  return artifacts;
786
860
  };
787
861
  //#endregion
862
+ //#region src/validation/validate-removed.ts
863
+ /**
864
+ * Config options that no longer exist, and what replaced them.
865
+ *
866
+ * An unknown key is otherwise *silently ignored* — nothing walks the config for keys it does not
867
+ * recognise. So removing an option without this leaves the worst possible upgrade: the build
868
+ * reverts to the default and says nothing, and an assertion the user asked for simply stops being
869
+ * enforced. That is exactly the shape a renamed prune flag would have taken.
870
+ *
871
+ * Keyed by the removed name so the message can say what to write instead, rather than reporting a
872
+ * bare "unknown option". Entries can be dropped a release or two after removal, once nobody is
873
+ * upgrading across them.
874
+ */
875
+ const REMOVED = {
876
+ pruneUnusedTokens: (value) => value === "strict" ? `\`pruneUnusedTokens: 'strict'\` is now \`prune: { tokens: 'accounted', unresolvedPath: 'error' }\`.` : `\`pruneUnusedTokens\` is now \`prune: { tokens: '${value === false ? "off" : "reachable"}' }\`.`,
877
+ pruneUnusedKeyframes: (value) => `\`pruneUnusedKeyframes\` is now \`prune: { keyframes: ${value === false ? "false" : "true"} }\`.`,
878
+ prunePreflight: (value) => `\`prunePreflight\` is now \`prune: { preflight: ${value === false ? "false" : "true"} }\`.`,
879
+ globalCss: () => `\`globalCss\` is now \`global: { css }\`.`,
880
+ globalFontface: () => `\`globalFontface\` is now \`global: { fontface }\`.`,
881
+ globalPositionTry: () => `\`globalPositionTry\` is now \`global: { positionTry }\`.`,
882
+ globalVars: () => `\`globalVars\` is now \`global: { vars }\`.`,
883
+ 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.`
886
+ };
887
+ /** Values that no longer exist for an option that does. Keyed by option, then by old value. */
888
+ const RETIRED_VALUES = { validation: { none: `\`validation: 'none'\` is now \`validation: 'off'\`, matching \`prune.unresolvedPath\`.` } };
889
+ /** 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.` } };
891
+ function validateRemovedOptions(config, addError) {
892
+ const dict = config;
893
+ for (const [name, describe] of Object.entries(REMOVED)) {
894
+ if (!Object.hasOwn(config, name)) continue;
895
+ addError("config", describe(dict[name]));
896
+ }
897
+ for (const [parent, removed] of Object.entries(REMOVED_NESTED)) {
898
+ const value = dict[parent];
899
+ if (value == null || typeof value !== "object") continue;
900
+ for (const [name, describe] of Object.entries(removed)) {
901
+ if (!Object.hasOwn(value, name)) continue;
902
+ addError("config", describe(value[name]));
903
+ }
904
+ }
905
+ for (const [name, retired] of Object.entries(RETIRED_VALUES)) {
906
+ const value = dict[name];
907
+ if (typeof value !== "string") continue;
908
+ const message = retired[value];
909
+ if (message) addError("config", message);
910
+ }
911
+ if (typeof dict.prune?.tokens === "boolean") addError("config", `\`prune.tokens\` takes a strategy now, not a boolean — write \`'${dict.prune.tokens ? "reachable" : "off"}'\`. \`'accounted'\` is the new one: keeps computed from the token paths in your source rather than from what the css reaches.`);
912
+ for (const [name, pattern] of Object.entries(config.patterns ?? {})) {
913
+ const dictPattern = pattern;
914
+ if (!dictPattern) continue;
915
+ if (Object.hasOwn(dictPattern, "strict")) addError("patterns", `\`${name}.strict\` is now \`${name}.cssProps: '${dictPattern.strict ? "none" : "all"}'\`.`);
916
+ if (Object.hasOwn(dictPattern, "blocklist")) addError("patterns", `\`${name}.blocklist\` is now \`${name}.cssProps: { except: [...] }\`, which is no longer experimental and no longer silently dropped when the pattern also set \`strict\`.`);
917
+ }
918
+ }
919
+ //#endregion
920
+ //#region src/validation/validate-retired-syntax.ts
921
+ /**
922
+ * Token values still written in a retired reference syntax.
923
+ *
924
+ * A hard error, and one that runs ahead of `validation` rather than under it. The rest of
925
+ * `validateConfig` reports opinions about a config that will still build; this reports a spelling
926
+ * that no longer means anything, whose output is broken either way — in a token value the text is
927
+ * emitted into the stylesheet as-is, and nothing downstream reports it. `validation: 'off'` is an
928
+ * opt-out of opinions, not of that.
929
+ *
930
+ * Safe to throw on because the spelling was never available for anything else: until it was
931
+ * removed, `{…}` in a value was consumed unconditionally — braces stripped, unresolved paths
932
+ * emitted bare — so no literal `{a.b}` could have survived to mean itself.
933
+ *
934
+ * Every occurrence is collected before throwing, because the point is to fix a config once rather
935
+ * than to be told about it one token at a time. Delete this a release or two after removal, along
936
+ * with `validate-removed.ts`.
937
+ */
938
+ function assertNoRetiredSyntax(config) {
939
+ const found = [];
940
+ const collect = (source, label) => {
941
+ if (!source) return;
942
+ (0, _bamboocss_shared.walkObject)(source, (token, path) => {
943
+ if (!isValidToken(token)) return;
944
+ const value = serializeTokenValue(token.value ?? token);
945
+ const at = `${label}.${formatPath(path.join("."))}`;
946
+ const curly = findCurlyReference(value);
947
+ if (curly) found.push(`- \`${at}\`: \`${curly}\` → \`token(${curly.slice(1, -1)})\``);
948
+ const fallback = findFallbackReference(value);
949
+ if (fallback) {
950
+ const path = fallback.slice(6, fallback.lastIndexOf(",")).trim();
951
+ found.push(`- \`${at}\`: \`${fallback}\` → \`token(${path})\``);
952
+ }
953
+ }, { stop: isValidToken });
954
+ };
955
+ collect(config.theme?.tokens, "theme.tokens");
956
+ collect(config.theme?.semanticTokens, "theme.semanticTokens");
957
+ for (const [name, variant] of Object.entries(config.theme?.variants ?? {})) {
958
+ collect(variant?.tokens, `theme.variants.${name}.tokens`);
959
+ collect(variant?.semanticTokens, `theme.variants.${name}.semanticTokens`);
960
+ }
961
+ if (!found.length) return;
962
+ throw new _bamboocss_shared.BambooError("CONFIG_ERROR", `${found.length} token value(s) use a retired reference syntax:\n\n${found.join("\n")}\n\n\`{colors.red.300}\` and \`token(colors.red.300, fallback)\` were both removed so a token is referenced one way. Neither is ignored quietly — the text is emitted into the stylesheet as-is.`);
963
+ }
964
+ //#endregion
788
965
  //#region src/validation/validate-token-references.ts
789
966
  const validateTokenReferences = (props) => {
790
967
  const { valueAtPath, refsByPath, addError, typeByPath } = props;
@@ -905,13 +1082,24 @@ const validateTokens = (options) => {
905
1082
  * - Check for missing tokens references
906
1083
  * - Check for conditions selectors (must contain '&')
907
1084
  * - Check for breakpoints units (must be the same)
1085
+ * - Check for options that have been removed, which are otherwise ignored in silence
1086
+ * - Throw on token values still written in the retired curly reference syntax
908
1087
  */
909
1088
  const validateConfig = (config) => {
910
- if (config.validation === "none") return;
1089
+ assertNoRetiredSyntax(config);
911
1090
  const warnings = /* @__PURE__ */ new Set();
912
1091
  const addError = (scope, message) => {
913
1092
  warnings.add(`[${scope}] ` + message);
914
1093
  };
1094
+ validateRemovedOptions(config, addError);
1095
+ const report = () => {
1096
+ if (!warnings.size) return;
1097
+ const errors = `⚠️ Invalid config:\n${Array.from(warnings).map((err) => "- " + err).join("\n")}\n`;
1098
+ if (config.validation === "error") throw new _bamboocss_shared.BambooError("CONFIG_ERROR", errors);
1099
+ _bamboocss_logger.logger.warn("config", errors);
1100
+ return warnings;
1101
+ };
1102
+ if (config.validation === "off") return report();
915
1103
  validateBreakpoints(config.theme?.breakpoints, addError);
916
1104
  validateConditions(config.conditions, addError);
917
1105
  const artifacts = {
@@ -941,12 +1129,7 @@ const validateConfig = (config) => {
941
1129
  }
942
1130
  validatePatterns(config.patterns, artifacts);
943
1131
  validateArtifactNames(artifacts, addError);
944
- if (warnings.size) {
945
- const errors = `⚠️ Invalid config:\n${Array.from(warnings).map((err) => "- " + err).join("\n")}\n`;
946
- if (config.validation === "error") throw new _bamboocss_shared.BambooError("CONFIG_ERROR", errors);
947
- _bamboocss_logger.logger.warn("config", errors);
948
- return warnings;
949
- }
1132
+ return report();
950
1133
  };
951
1134
  //#endregion
952
1135
  //#region src/resolve-config.ts
@@ -956,18 +1139,37 @@ const hookUtils = {
956
1139
  traverse: _bamboocss_shared.traverse
957
1140
  };
958
1141
  /**
959
- * Resolve the final config (including presets)
960
- * @bamboocss/preset-base: ALWAYS included if NOT using eject: true
961
- * @bamboocss/preset-bamboo: only included by default if no presets
1142
+ * The one way this rename can break a config without saying so.
1143
+ *
1144
+ * `presets` still exists and still takes a list, so nothing in `validate-removed` notices
1145
+ * that its meaning changed. A config that listed `[myPreset]` used to get `preset-base`
1146
+ * underneath it and now does not — and what `preset-base` carries is the utility table, so
1147
+ * the failure is every class name silently changing (`c_red_300` becomes `color_red_300`)
1148
+ * rather than an error. That is the shape this codebase treats as the worst upgrade there
1149
+ * is, so it gets a message.
1150
+ *
1151
+ * Skipped for an empty list, which is a deliberate eject and the replacement for
1152
+ * `eject: true`. Drop this a release or two after the rename.
1153
+ */
1154
+ function warnIfBaseDropped(listed, resolved) {
1155
+ if (!listed?.length) return;
1156
+ if (resolved.some((preset) => preset?.name === "@bamboocss/preset-base")) return;
1157
+ _bamboocss_logger.logger.warn("config", "`presets` is now the complete list, and this one does not include `@bamboocss/preset-base` — so its utilities, conditions and patterns are not loaded, and generated class names change. Listing a preset used to keep `preset-base` underneath it.\n\n import { defaultPresets } from '@bamboocss/dev/presets'\n presets: [...defaultPresets, yourPreset]\n\nIf dropping it is deliberate, this is the intended behaviour and the warning goes away once `preset-base` is listed explicitly.");
1158
+ }
1159
+ /**
1160
+ * Resolve the final config (including presets).
1161
+ *
1162
+ * `presets` is authoritative: what the config lists is what is loaded, and an unset
1163
+ * `presets` loads `defaultPresets`. There is no implicit preset a listed one sits on top
1164
+ * of — `eject` used to control that, badly. Under it, listing any preset kept
1165
+ * `@bamboocss/preset-base` and silently dropped `@bamboocss/preset-bamboo`, so `presets`
1166
+ * was neither additive nor replacing, and `presets: []` meant "base only" rather than
1167
+ * "none". Both of those had to be discovered by reading this function.
962
1168
  */
963
1169
  async function resolveConfig(result, cwd) {
964
- const presets = /* @__PURE__ */ new Set();
965
- if (!result.config.eject) presets.add(_bamboocss_preset_base.preset);
966
- if (result.config.presets) result.config.presets.forEach((preset) => {
967
- presets.add(getBundledPreset(preset) ?? preset);
968
- });
969
- else if (!result.config.eject) presets.add(_bamboocss_preset_bamboo.preset);
970
- result.config.presets = Array.from(presets);
1170
+ const listed = result.config.presets;
1171
+ result.config.presets = listed ? Array.from(new Set(listed.map((preset) => getBundledPreset(preset) ?? preset))) : [...defaultPresets];
1172
+ warnIfBaseDropped(listed, result.config.presets);
971
1173
  const userConfig = result.config;
972
1174
  const pluginHooks = userConfig.plugins ?? [];
973
1175
  if (userConfig.hooks) pluginHooks.push({
@@ -978,6 +1180,7 @@ async function resolveConfig(result, cwd) {
978
1180
  const mergedConfig = await getResolvedConfig(result.config, cwd, earlyHooks);
979
1181
  const hooks = mergedConfig.hooks ?? {};
980
1182
  if (mergedConfig.logLevel) _bamboocss_logger.logger.level = mergedConfig.logLevel;
1183
+ if (mergedConfig.logFilter) _bamboocss_logger.logger.filter = mergedConfig.logFilter;
981
1184
  validateConfig(mergedConfig);
982
1185
  const loadConfigResult = {
983
1186
  ...result,
@@ -1015,6 +1218,7 @@ async function loadConfig(options) {
1015
1218
  //#endregion
1016
1219
  exports.bundleConfig = bundleConfig;
1017
1220
  exports.convertTsPathsToRegexes = convertTsPathsToRegexes;
1221
+ exports.defaultPresets = defaultPresets;
1018
1222
  exports.diffConfigs = diffConfigs;
1019
1223
  exports.findConfig = findConfig;
1020
1224
  exports.getConfigDependencies = getConfigDependencies;
@@ -1022,4 +1226,6 @@ exports.getResolvedConfig = getResolvedConfig;
1022
1226
  exports.loadConfig = loadConfig;
1023
1227
  exports.mergeConfigs = mergeConfigs;
1024
1228
  exports.mergeHooks = mergeHooks;
1229
+ exports.presetBamboo = _bamboocss_preset_bamboo.preset;
1230
+ exports.presetBase = _bamboocss_preset_base.preset;
1025
1231
  exports.resolveConfig = resolveConfig;