@bamboocss/config
Advanced tools
| //#region \0rolldown/runtime.js | ||
| var __create = Object.create; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __getProtoOf = Object.getPrototypeOf; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) { | ||
| key = keys[i]; | ||
| if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { | ||
| get: ((k) => from[k]).bind(null, key), | ||
| enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable | ||
| }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { | ||
| value: mod, | ||
| enumerable: true | ||
| }) : target, mod)); | ||
| //#endregion | ||
| let _bamboocss_shared = require("@bamboocss/shared"); | ||
| let microdiff = require("microdiff"); | ||
| microdiff = __toESM(microdiff); | ||
| //#region src/create-matcher.ts | ||
| /** | ||
| * Acts like a .gitignore matcher | ||
| * e.g a list of string to search for nested path with glob and exclusion allowed | ||
| * ["outdir", "theme.recipes", '*.css', '!aaa.*.bbb'] | ||
| */ | ||
| function createMatcher(id, patterns) { | ||
| if (!patterns?.length) return () => void 0; | ||
| const includePatterns = []; | ||
| const excludePatterns = []; | ||
| new Set(patterns).forEach((pattern) => { | ||
| const regexString = pattern.replace(/\*/g, ".*"); | ||
| if (pattern.startsWith("!")) excludePatterns.push(regexString.slice(1)); | ||
| else includePatterns.push(regexString); | ||
| }); | ||
| const include = new RegExp(includePatterns.join("|")); | ||
| const exclude = new RegExp(excludePatterns.join("|")); | ||
| return (path) => { | ||
| if (excludePatterns.length && exclude.test(path)) return; | ||
| return include.test(path) ? id : void 0; | ||
| }; | ||
| } | ||
| //#endregion | ||
| //#region src/config-deps.ts | ||
| const all = [ | ||
| "clean", | ||
| "cwd", | ||
| "eject", | ||
| "outdir", | ||
| "forceConsistentTypeExtension", | ||
| "outExtension", | ||
| "emitTokensOnly", | ||
| "presets", | ||
| "plugins", | ||
| "hooks" | ||
| ]; | ||
| const format = [ | ||
| "syntax", | ||
| "hash", | ||
| "prefix", | ||
| "separator", | ||
| "strictTokens", | ||
| "strictPropertyValues", | ||
| "shorthands" | ||
| ]; | ||
| const tokens = [ | ||
| "utilities", | ||
| "conditions", | ||
| "theme.tokens", | ||
| "theme.semanticTokens", | ||
| "theme.breakpoints", | ||
| "theme.containerNames", | ||
| "theme.containerSizes" | ||
| ]; | ||
| const jsx = [ | ||
| "jsxFramework", | ||
| "jsxFactory", | ||
| "jsxStyleProps", | ||
| "syntax" | ||
| ]; | ||
| const common = tokens.concat(jsx, format); | ||
| const artifactConfigDeps = { | ||
| helpers: ["syntax", "jsxFramework"], | ||
| keyframes: ["theme.keyframes", "layers"], | ||
| "design-tokens": ["layers", "!utilities.*.className"].concat(tokens), | ||
| types: ["!utilities.*.className"].concat(common), | ||
| "css-fn": common, | ||
| cva: ["syntax"], | ||
| sva: ["syntax"], | ||
| cx: [], | ||
| "create-recipe": [ | ||
| "separator", | ||
| "prefix", | ||
| "hash" | ||
| ], | ||
| "recipes-index": ["theme.recipes", "theme.slotRecipes"], | ||
| recipes: ["theme.recipes", "theme.slotRecipes"], | ||
| "patterns-index": ["syntax", "patterns"], | ||
| patterns: ["syntax", "patterns"], | ||
| "jsx-is-valid-prop": common, | ||
| "jsx-factory": jsx, | ||
| "jsx-helpers": jsx, | ||
| "jsx-patterns": jsx.concat("patterns"), | ||
| "jsx-patterns-index": jsx.concat("patterns"), | ||
| "jsx-create-style-context": jsx, | ||
| "css-index": ["syntax"], | ||
| "package.json": ["forceConsistentTypeExtension", "outExtension"], | ||
| "types-styles": ["shorthands"], | ||
| "types-conditions": ["conditions"], | ||
| "types-jsx": jsx, | ||
| "types-entry": [], | ||
| "types-gen": [], | ||
| "types-gen-system": [], | ||
| themes: ["themes"].concat(tokens), | ||
| "static-css": [ | ||
| "staticCss", | ||
| "patterns", | ||
| "theme.recipes", | ||
| "theme.slotRecipes" | ||
| ].concat(tokens), | ||
| styles: [], | ||
| "styles.css": [] | ||
| }; | ||
| const artifactMatchers = Object.entries(artifactConfigDeps).map(([key, paths]) => { | ||
| if (!paths.length) return () => void 0; | ||
| return createMatcher(key, paths.concat(all)); | ||
| }); | ||
| //#endregion | ||
| //#region src/diff-config.ts | ||
| const runIfFn = (fn) => typeof fn === "function" ? fn() : fn; | ||
| /** | ||
| * Check if recipes were empty before and non-empty now (or vice versa) | ||
| */ | ||
| const hasRecipeStateTransition = (prevConfig, nextConfig) => { | ||
| const prevRecipes = prevConfig.theme?.recipes ?? {}; | ||
| const prevSlotRecipes = prevConfig.theme?.slotRecipes ?? {}; | ||
| const prevHasRecipes = Object.keys(prevRecipes).length > 0 || Object.keys(prevSlotRecipes).length > 0; | ||
| const nextRecipes = nextConfig.theme?.recipes ?? {}; | ||
| const nextSlotRecipes = nextConfig.theme?.slotRecipes ?? {}; | ||
| return prevHasRecipes !== (Object.keys(nextRecipes).length > 0 || Object.keys(nextSlotRecipes).length > 0); | ||
| }; | ||
| /** | ||
| * Diff the two config objects and return the list of affected properties | ||
| */ | ||
| function diffConfigs(config, prevConfig) { | ||
| const affected = { | ||
| artifacts: /* @__PURE__ */ new Set(), | ||
| hasConfigChanged: false, | ||
| diffs: [] | ||
| }; | ||
| if (!prevConfig) { | ||
| affected.hasConfigChanged = true; | ||
| return affected; | ||
| } | ||
| const configDiff = (0, microdiff.default)(prevConfig, runIfFn(config)); | ||
| if (!configDiff.length) return affected; | ||
| affected.hasConfigChanged = true; | ||
| affected.diffs = configDiff; | ||
| configDiff.forEach((change) => { | ||
| const changePath = change.path.join("."); | ||
| artifactMatchers.forEach((matcher) => { | ||
| const id = matcher(changePath); | ||
| if (!id) return; | ||
| if (id === "recipes") { | ||
| const name = (0, _bamboocss_shared.dashCase)(change.path.slice(1, 3).join(".")); | ||
| affected.artifacts.add(name); | ||
| } | ||
| if (id === "patterns") { | ||
| const name = (0, _bamboocss_shared.dashCase)(change.path.slice(0, 2).join(".")); | ||
| affected.artifacts.add(name); | ||
| } | ||
| affected.artifacts.add(id); | ||
| }); | ||
| }); | ||
| if (affected.artifacts.has("recipes") || affected.artifacts.has("recipes-index")) { | ||
| if (hasRecipeStateTransition(prevConfig, runIfFn(config))) affected.artifacts.add("create-recipe"); | ||
| } | ||
| return affected; | ||
| } | ||
| //#endregion | ||
| Object.defineProperty(exports, "__toESM", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return __toESM; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "diffConfigs", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return diffConfigs; | ||
| } | ||
| }); |
| import { dashCase } from "@bamboocss/shared"; | ||
| import microdiff from "microdiff"; | ||
| //#region src/create-matcher.ts | ||
| /** | ||
| * Acts like a .gitignore matcher | ||
| * e.g a list of string to search for nested path with glob and exclusion allowed | ||
| * ["outdir", "theme.recipes", '*.css', '!aaa.*.bbb'] | ||
| */ | ||
| function createMatcher(id, patterns) { | ||
| if (!patterns?.length) return () => void 0; | ||
| const includePatterns = []; | ||
| const excludePatterns = []; | ||
| new Set(patterns).forEach((pattern) => { | ||
| const regexString = pattern.replace(/\*/g, ".*"); | ||
| if (pattern.startsWith("!")) excludePatterns.push(regexString.slice(1)); | ||
| else includePatterns.push(regexString); | ||
| }); | ||
| const include = new RegExp(includePatterns.join("|")); | ||
| const exclude = new RegExp(excludePatterns.join("|")); | ||
| return (path) => { | ||
| if (excludePatterns.length && exclude.test(path)) return; | ||
| return include.test(path) ? id : void 0; | ||
| }; | ||
| } | ||
| //#endregion | ||
| //#region src/config-deps.ts | ||
| const all = [ | ||
| "clean", | ||
| "cwd", | ||
| "eject", | ||
| "outdir", | ||
| "forceConsistentTypeExtension", | ||
| "outExtension", | ||
| "emitTokensOnly", | ||
| "presets", | ||
| "plugins", | ||
| "hooks" | ||
| ]; | ||
| const format = [ | ||
| "syntax", | ||
| "hash", | ||
| "prefix", | ||
| "separator", | ||
| "strictTokens", | ||
| "strictPropertyValues", | ||
| "shorthands" | ||
| ]; | ||
| const tokens = [ | ||
| "utilities", | ||
| "conditions", | ||
| "theme.tokens", | ||
| "theme.semanticTokens", | ||
| "theme.breakpoints", | ||
| "theme.containerNames", | ||
| "theme.containerSizes" | ||
| ]; | ||
| const jsx = [ | ||
| "jsxFramework", | ||
| "jsxFactory", | ||
| "jsxStyleProps", | ||
| "syntax" | ||
| ]; | ||
| const common = tokens.concat(jsx, format); | ||
| const artifactConfigDeps = { | ||
| helpers: ["syntax", "jsxFramework"], | ||
| keyframes: ["theme.keyframes", "layers"], | ||
| "design-tokens": ["layers", "!utilities.*.className"].concat(tokens), | ||
| types: ["!utilities.*.className"].concat(common), | ||
| "css-fn": common, | ||
| cva: ["syntax"], | ||
| sva: ["syntax"], | ||
| cx: [], | ||
| "create-recipe": [ | ||
| "separator", | ||
| "prefix", | ||
| "hash" | ||
| ], | ||
| "recipes-index": ["theme.recipes", "theme.slotRecipes"], | ||
| recipes: ["theme.recipes", "theme.slotRecipes"], | ||
| "patterns-index": ["syntax", "patterns"], | ||
| patterns: ["syntax", "patterns"], | ||
| "jsx-is-valid-prop": common, | ||
| "jsx-factory": jsx, | ||
| "jsx-helpers": jsx, | ||
| "jsx-patterns": jsx.concat("patterns"), | ||
| "jsx-patterns-index": jsx.concat("patterns"), | ||
| "jsx-create-style-context": jsx, | ||
| "css-index": ["syntax"], | ||
| "package.json": ["forceConsistentTypeExtension", "outExtension"], | ||
| "types-styles": ["shorthands"], | ||
| "types-conditions": ["conditions"], | ||
| "types-jsx": jsx, | ||
| "types-entry": [], | ||
| "types-gen": [], | ||
| "types-gen-system": [], | ||
| themes: ["themes"].concat(tokens), | ||
| "static-css": [ | ||
| "staticCss", | ||
| "patterns", | ||
| "theme.recipes", | ||
| "theme.slotRecipes" | ||
| ].concat(tokens), | ||
| styles: [], | ||
| "styles.css": [] | ||
| }; | ||
| const artifactMatchers = Object.entries(artifactConfigDeps).map(([key, paths]) => { | ||
| if (!paths.length) return () => void 0; | ||
| return createMatcher(key, paths.concat(all)); | ||
| }); | ||
| //#endregion | ||
| //#region src/diff-config.ts | ||
| const runIfFn = (fn) => typeof fn === "function" ? fn() : fn; | ||
| /** | ||
| * Check if recipes were empty before and non-empty now (or vice versa) | ||
| */ | ||
| const hasRecipeStateTransition = (prevConfig, nextConfig) => { | ||
| const prevRecipes = prevConfig.theme?.recipes ?? {}; | ||
| const prevSlotRecipes = prevConfig.theme?.slotRecipes ?? {}; | ||
| const prevHasRecipes = Object.keys(prevRecipes).length > 0 || Object.keys(prevSlotRecipes).length > 0; | ||
| const nextRecipes = nextConfig.theme?.recipes ?? {}; | ||
| const nextSlotRecipes = nextConfig.theme?.slotRecipes ?? {}; | ||
| return prevHasRecipes !== (Object.keys(nextRecipes).length > 0 || Object.keys(nextSlotRecipes).length > 0); | ||
| }; | ||
| /** | ||
| * Diff the two config objects and return the list of affected properties | ||
| */ | ||
| function diffConfigs(config, prevConfig) { | ||
| const affected = { | ||
| artifacts: /* @__PURE__ */ new Set(), | ||
| hasConfigChanged: false, | ||
| diffs: [] | ||
| }; | ||
| if (!prevConfig) { | ||
| affected.hasConfigChanged = true; | ||
| return affected; | ||
| } | ||
| const configDiff = microdiff(prevConfig, runIfFn(config)); | ||
| if (!configDiff.length) return affected; | ||
| affected.hasConfigChanged = true; | ||
| affected.diffs = configDiff; | ||
| configDiff.forEach((change) => { | ||
| const changePath = change.path.join("."); | ||
| artifactMatchers.forEach((matcher) => { | ||
| const id = matcher(changePath); | ||
| if (!id) return; | ||
| if (id === "recipes") { | ||
| const name = dashCase(change.path.slice(1, 3).join(".")); | ||
| affected.artifacts.add(name); | ||
| } | ||
| if (id === "patterns") { | ||
| const name = dashCase(change.path.slice(0, 2).join(".")); | ||
| affected.artifacts.add(name); | ||
| } | ||
| affected.artifacts.add(id); | ||
| }); | ||
| }); | ||
| if (affected.artifacts.has("recipes") || affected.artifacts.has("recipes-index")) { | ||
| if (hasRecipeStateTransition(prevConfig, runIfFn(config))) affected.artifacts.add("create-recipe"); | ||
| } | ||
| return affected; | ||
| } | ||
| //#endregion | ||
| export { diffConfigs as t }; |
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| const require_diff_config = require("./diff-config-Co_3mDXE.cjs"); | ||
| exports.diffConfigs = require_diff_config.diffConfigs; |
| import { Config, DiffConfigResult } from "@bamboocss/types"; | ||
| //#region src/diff-config.d.ts | ||
| type ConfigOrFn = Config | (() => Config); | ||
| /** | ||
| * Diff the two config objects and return the list of affected properties | ||
| */ | ||
| declare function diffConfigs(config: ConfigOrFn, prevConfig: Config | undefined): DiffConfigResult; | ||
| //#endregion | ||
| export { diffConfigs }; |
| import { Config, DiffConfigResult } from "@bamboocss/types"; | ||
| //#region src/diff-config.d.ts | ||
| type ConfigOrFn = Config | (() => Config); | ||
| /** | ||
| * Diff the two config objects and return the list of affected properties | ||
| */ | ||
| declare function diffConfigs(config: ConfigOrFn, prevConfig: Config | undefined): DiffConfigResult; | ||
| //#endregion | ||
| export { diffConfigs }; |
+575
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| const require_diff_config = require("./diff-config-Co_3mDXE.cjs"); | ||
| const require_resolve_ts_path_pattern = require("./resolve-ts-path-pattern.cjs"); | ||
| const require_merge_config = require("./merge-config-CcNpHJit.cjs"); | ||
| let _bamboocss_logger = require("@bamboocss/logger"); | ||
| let _bamboocss_shared = require("@bamboocss/shared"); | ||
| let bundle_n_require = require("bundle-n-require"); | ||
| let escalade_sync = require("escalade/sync"); | ||
| escalade_sync = require_diff_config.__toESM(escalade_sync); | ||
| let path = require("path"); | ||
| path = require_diff_config.__toESM(path); | ||
| let fs = require("fs"); | ||
| fs = require_diff_config.__toESM(fs); | ||
| let typescript = require("typescript"); | ||
| typescript = require_diff_config.__toESM(typescript); | ||
| let _bamboocss_preset_base = require("@bamboocss/preset-base"); | ||
| let _bamboocss_preset_bamboo = require("@bamboocss/preset-bamboo"); | ||
| //#region src/is-bamboo-config.ts | ||
| const configName = "bamboo"; | ||
| const bambooConfigFiles = new Set([ | ||
| `${configName}.config.ts`, | ||
| `${configName}.config.js`, | ||
| `${configName}.config.mts`, | ||
| `${configName}.config.mjs`, | ||
| `${configName}.config.cts`, | ||
| `${configName}.config.cjs` | ||
| ]); | ||
| const isBambooConfig = (file) => bambooConfigFiles.has(file); | ||
| //#endregion | ||
| //#region src/find-config.ts | ||
| function findConfig(options) { | ||
| const { cwd = process.cwd(), file } = options; | ||
| if (file) return (0, path.resolve)(cwd, file); | ||
| const configPath = (0, escalade_sync.default)(cwd, (_dir, paths) => paths.find(isBambooConfig)); | ||
| if (!configPath) throw new _bamboocss_shared.BambooError("CONFIG_NOT_FOUND", `Cannot find config file \`bamboo.config.{ts,js,mjs,mts}\`. Did you forget to run \`bamboo init\`?`); | ||
| return configPath; | ||
| } | ||
| //#endregion | ||
| //#region src/bundle-config.ts | ||
| async function bundle(filepath, cwd) { | ||
| const { mod, dependencies } = await (0, bundle_n_require.bundleNRequire)(filepath, { | ||
| cwd, | ||
| interopDefault: true | ||
| }); | ||
| return { | ||
| config: mod?.default ?? mod, | ||
| dependencies | ||
| }; | ||
| } | ||
| async function bundleConfig(options) { | ||
| const { cwd, file } = options; | ||
| const filePath = findConfig({ | ||
| cwd, | ||
| file | ||
| }); | ||
| _bamboocss_logger.logger.debug("config:path", filePath); | ||
| const result = await bundle(filePath, cwd); | ||
| if (typeof result.config !== "object") throw new _bamboocss_shared.BambooError("CONFIG_ERROR", `💥 Config must export or return an object.`); | ||
| result.config.outdir ??= "styled-system"; | ||
| result.config.validation ??= "warn"; | ||
| return { | ||
| ...result, | ||
| config: result.config, | ||
| path: filePath | ||
| }; | ||
| } | ||
| //#endregion | ||
| //#region src/ts-config-paths.ts | ||
| /** | ||
| * @see https://github.com/aleclarson/vite-tsconfig-paths/blob/e8f0acf7adfcfbf77edbe937f64b4e5d39557ad0/src/mappings.ts | ||
| */ | ||
| function convertTsPathsToRegexes(paths, baseUrl) { | ||
| const sortedPatterns = Object.keys(paths).sort((a, b) => getPrefixLength(b) - getPrefixLength(a)); | ||
| const resolved = []; | ||
| for (let pattern of sortedPatterns) { | ||
| const relativePaths = paths[pattern]; | ||
| pattern = escapeStringRegexp(pattern).replace(/\*/g, "(.+)"); | ||
| resolved.push({ | ||
| pattern: new RegExp("^" + pattern + "$"), | ||
| paths: relativePaths.map((relativePath) => (0, path.resolve)(baseUrl, relativePath)) | ||
| }); | ||
| } | ||
| return resolved; | ||
| } | ||
| function getPrefixLength(pattern) { | ||
| const prefixLength = pattern.indexOf("*"); | ||
| return pattern.substr(0, prefixLength).length; | ||
| } | ||
| function escapeStringRegexp(string) { | ||
| return string.replace(/[|\\{}()[\]^$+?.]/g, "\\$&").replace(/-/g, "\\x2d"); | ||
| } | ||
| //#endregion | ||
| //#region src/get-mod-deps.ts | ||
| const jsExtensions = [ | ||
| ".js", | ||
| ".cjs", | ||
| ".mjs" | ||
| ]; | ||
| const jsResolutionOrder = [ | ||
| "", | ||
| ".js", | ||
| ".cjs", | ||
| ".mjs", | ||
| ".ts", | ||
| ".cts", | ||
| ".mts", | ||
| ".jsx", | ||
| ".tsx" | ||
| ]; | ||
| const tsResolutionOrder = [ | ||
| "", | ||
| ".ts", | ||
| ".cts", | ||
| ".mts", | ||
| ".tsx", | ||
| ".js", | ||
| ".cjs", | ||
| ".mjs", | ||
| ".jsx" | ||
| ]; | ||
| function resolveWithExtension(file, extensions) { | ||
| for (const ext of extensions) { | ||
| const full = `${file}${ext}`; | ||
| if (fs.default.existsSync(full) && fs.default.statSync(full).isFile()) return full; | ||
| } | ||
| for (const ext of extensions) { | ||
| const full = `${file}/index${ext}`; | ||
| if (fs.default.existsSync(full)) return full; | ||
| } | ||
| return null; | ||
| } | ||
| const importRegex = /import[\s\S]*?['"](.{3,}?)['"]/gi; | ||
| const importFromRegex = /import[\s\S]*from[\s\S]*?['"](.{3,}?)['"]/gi; | ||
| const requireRegex = /require\(['"`](.+)['"`]\)/gi; | ||
| const exportRegex = /export[\s\S]*from[\s\S]*?['"](.{3,}?)['"]/gi; | ||
| function getDeps(opts, fromAlias) { | ||
| const { filename, seen } = opts; | ||
| const { moduleResolution: _, ...compilerOptions } = opts.compilerOptions ?? {}; | ||
| const absoluteFile = resolveWithExtension(path.default.resolve(opts.cwd, filename), jsExtensions.includes(opts.ext) ? jsResolutionOrder : tsResolutionOrder); | ||
| if (absoluteFile === null) return; | ||
| if (fromAlias) opts.foundModuleAliases.set(fromAlias, absoluteFile); | ||
| if (seen.size > 1 && seen.has(absoluteFile)) return; | ||
| seen.add(absoluteFile); | ||
| const contents = fs.default.readFileSync(absoluteFile, "utf-8"); | ||
| const fileDeps = [ | ||
| ...contents.matchAll(importRegex), | ||
| ...contents.matchAll(importFromRegex), | ||
| ...contents.matchAll(requireRegex), | ||
| ...contents.matchAll(exportRegex) | ||
| ]; | ||
| if (!fileDeps.length) return; | ||
| const nextOpts = { | ||
| cwd: path.default.dirname(absoluteFile), | ||
| ext: path.default.extname(absoluteFile), | ||
| seen, | ||
| baseUrl: opts.baseUrl, | ||
| pathMappings: opts.pathMappings, | ||
| foundModuleAliases: opts.foundModuleAliases | ||
| }; | ||
| fileDeps.forEach((match) => { | ||
| const mod = match[1]; | ||
| if (mod[0] === ".") { | ||
| getDeps(Object.assign({}, nextOpts, { filename: mod })); | ||
| return; | ||
| } | ||
| try { | ||
| const found = typescript.default.resolveModuleName(mod, absoluteFile, compilerOptions, typescript.default.sys).resolvedModule; | ||
| if (found && found.extension.endsWith("ts")) { | ||
| getDeps(Object.assign({}, nextOpts, { filename: found.resolvedFileName })); | ||
| return; | ||
| } | ||
| if (!opts.pathMappings) return; | ||
| const filename = require_resolve_ts_path_pattern.resolveTsPathPattern(opts.pathMappings, mod); | ||
| if (!filename) return; | ||
| getDeps(Object.assign({}, nextOpts, { filename }), mod); | ||
| } catch {} | ||
| }); | ||
| } | ||
| function getConfigDependencies(filePath, tsOptions = { pathMappings: [] }, compilerOptions) { | ||
| if (filePath === null) return { | ||
| deps: /* @__PURE__ */ new Set(), | ||
| aliases: /* @__PURE__ */ new Map() | ||
| }; | ||
| const foundModuleAliases = /* @__PURE__ */ new Map(); | ||
| const deps = /* @__PURE__ */ new Set(); | ||
| deps.add(filePath); | ||
| getDeps({ | ||
| filename: filePath, | ||
| ext: path.default.extname(filePath), | ||
| cwd: path.default.dirname(filePath), | ||
| seen: deps, | ||
| baseUrl: tsOptions.baseUrl, | ||
| pathMappings: tsOptions.pathMappings ?? [], | ||
| foundModuleAliases, | ||
| compilerOptions | ||
| }); | ||
| return { | ||
| deps, | ||
| aliases: foundModuleAliases | ||
| }; | ||
| } | ||
| //#endregion | ||
| //#region src/get-resolved-config.ts | ||
| const hookUtils$1 = { | ||
| omit: _bamboocss_shared.omit, | ||
| pick: _bamboocss_shared.pick, | ||
| traverse: _bamboocss_shared.traverse | ||
| }; | ||
| /** | ||
| * Recursively merge all presets into a single config (depth-first using stack) | ||
| */ | ||
| async function getResolvedConfig(config, cwd, hooks) { | ||
| const stack = [config]; | ||
| const configs = []; | ||
| while (stack.length > 0) { | ||
| const current = stack.pop(); | ||
| const subPresets = current.presets ?? []; | ||
| for (const subPreset of subPresets) { | ||
| let presetConfig; | ||
| let presetName; | ||
| if (typeof subPreset === "string") { | ||
| presetConfig = (await bundle(subPreset, cwd)).config; | ||
| presetName = subPreset; | ||
| } else { | ||
| presetConfig = await subPreset; | ||
| presetName = presetConfig.name || "unknown-preset"; | ||
| } | ||
| if (hooks?.["preset:resolved"]) { | ||
| const resolvedPreset = await hooks["preset:resolved"]({ | ||
| preset: presetConfig, | ||
| name: presetName, | ||
| utils: hookUtils$1 | ||
| }); | ||
| if (resolvedPreset !== void 0) presetConfig = resolvedPreset; | ||
| } | ||
| stack.push(presetConfig); | ||
| } | ||
| configs.unshift(current); | ||
| } | ||
| const merged = require_merge_config.mergeConfigs(configs); | ||
| merged.presets = configs.slice(0, -1); | ||
| return merged; | ||
| } | ||
| //#endregion | ||
| //#region src/bundled-preset.ts | ||
| const bundledPresets = { | ||
| "@bamboocss/preset-base": _bamboocss_preset_base.preset, | ||
| "@bamboocss/preset-bamboo": _bamboocss_preset_bamboo.preset, | ||
| "@bamboocss/dev/presets": _bamboocss_preset_bamboo.preset | ||
| }; | ||
| const bundledPresetsNames = Object.keys(bundledPresets); | ||
| const isBundledPreset = (preset) => bundledPresetsNames.includes(preset); | ||
| const getBundledPreset = (preset) => { | ||
| return typeof preset === "string" && isBundledPreset(preset) ? bundledPresets[preset] : void 0; | ||
| }; | ||
| //#endregion | ||
| //#region src/validation/validate-artifact.ts | ||
| const validateArtifactNames = (names, addError) => { | ||
| names.recipes.forEach((recipeName) => { | ||
| if (names.slotRecipes.has(recipeName)) addError("recipes", `This recipe name is already used in \`theme.slotRecipes\`: ${recipeName}`); | ||
| if (names.patterns.has(recipeName)) addError("recipes", `This recipe name is already used in \`patterns\`: \`${recipeName}\``); | ||
| }); | ||
| names.slotRecipes.forEach((recipeName) => { | ||
| if (names.patterns.has(recipeName)) addError("recipes", `This recipe name is already used in \`patterns\`: ${recipeName}`); | ||
| }); | ||
| }; | ||
| //#endregion | ||
| //#region src/validation/validate-breakpoints.ts | ||
| const validateBreakpoints = (breakpoints, addError) => { | ||
| if (!breakpoints) return; | ||
| const units = /* @__PURE__ */ new Set(); | ||
| const values = Object.values(breakpoints); | ||
| for (const value of values) { | ||
| const unit = (0, _bamboocss_shared.getUnit)(value) ?? "px"; | ||
| units.add(unit); | ||
| } | ||
| if (units.size > 1) addError("breakpoints", `All breakpoints must use the same unit: \`${values.join(", ")}\``); | ||
| }; | ||
| //#endregion | ||
| //#region src/validation/validate-condition.ts | ||
| const validateObjectCondition = (obj, addError) => { | ||
| let hasSlot = false; | ||
| for (const [key, value] of Object.entries(obj)) { | ||
| if (!key.startsWith("@") && !key.includes("&")) addError("conditions", `Selectors should contain the \`&\` character: \`${key}\``); | ||
| if (value === "@slot") { | ||
| hasSlot = true; | ||
| continue; | ||
| } | ||
| if (typeof value === "string") { | ||
| addError("conditions", `Object condition leaves must be the literal string \`'@slot'\`, got \`${JSON.stringify(value)}\` at \`${key}\``); | ||
| continue; | ||
| } | ||
| if (typeof value === "object" && value !== null) { | ||
| if (validateObjectCondition(value, addError).hasSlot) hasSlot = true; | ||
| } | ||
| } | ||
| return { hasSlot }; | ||
| }; | ||
| const validateConditions = (conditions, addError) => { | ||
| if (!conditions) return; | ||
| Object.values(conditions).forEach((condition) => { | ||
| if ((0, _bamboocss_shared.isString)(condition)) { | ||
| if (!condition.startsWith("@") && !condition.includes("&")) addError("conditions", `Selectors should contain the \`&\` character: \`${condition}\``); | ||
| return; | ||
| } | ||
| if (Array.isArray(condition)) { | ||
| condition.forEach((c) => { | ||
| if (!c.startsWith("@") && !c.includes("&")) addError("conditions", `Selectors should contain the \`&\` character: \`${c}\``); | ||
| }); | ||
| return; | ||
| } | ||
| const { hasSlot } = validateObjectCondition(condition, addError); | ||
| if (!hasSlot) addError("conditions", `Object conditions must contain at least one \`'@slot'\` marker`); | ||
| }); | ||
| }; | ||
| //#endregion | ||
| //#region src/validation/validate-patterns.ts | ||
| const validatePatterns = (patterns, names) => { | ||
| if (!patterns) return; | ||
| Object.keys(patterns).forEach((patternName) => { | ||
| names.patterns.add(patternName); | ||
| }); | ||
| }; | ||
| //#endregion | ||
| //#region src/validation/validate-recipes.ts | ||
| const validateRecipes = (options) => { | ||
| const { config: { theme }, artifacts } = options; | ||
| if (!theme) return; | ||
| if (theme.recipes) Object.keys(theme.recipes).forEach((recipeName) => { | ||
| artifacts.recipes.add(recipeName); | ||
| }); | ||
| if (theme.slotRecipes) Object.keys(theme.slotRecipes).forEach((recipeName) => { | ||
| artifacts.slotRecipes.add(recipeName); | ||
| }); | ||
| return artifacts; | ||
| }; | ||
| //#endregion | ||
| //#region src/validation/validate-token-references.ts | ||
| const validateTokenReferences = (props) => { | ||
| const { valueAtPath, refsByPath, addError, typeByPath } = props; | ||
| refsByPath.forEach((refs, path) => { | ||
| if (refs.has(path)) addError("tokens", `Self token reference: \`${path}\``); | ||
| const stack = [path]; | ||
| while (stack.length > 0) { | ||
| let currentPath = stack.pop(); | ||
| if (currentPath.includes("/")) { | ||
| const [tokenPath] = currentPath.split("/"); | ||
| currentPath = tokenPath; | ||
| } | ||
| const value = valueAtPath.get(currentPath); | ||
| if (!value) { | ||
| const configKey = typeByPath.get(path); | ||
| addError("tokens", `Missing token: \`${currentPath}\` used in \`theme.${configKey}.${path}\``); | ||
| } | ||
| if (require_merge_config.isTokenReference(value) && !refsByPath.has(value)) addError("tokens", `Unknown token reference: \`${currentPath}\` used in \`${value}\``); | ||
| const deps = refsByPath.get(currentPath); | ||
| if (!deps) continue; | ||
| for (const transitiveDep of deps) { | ||
| if (path === transitiveDep) { | ||
| addError("tokens", `Circular token reference: \`${transitiveDep}\` -> \`${currentPath}\` -> ... -> \`${path}\``); | ||
| break; | ||
| } | ||
| stack.push(transitiveDep); | ||
| } | ||
| } | ||
| }); | ||
| }; | ||
| //#endregion | ||
| //#region src/validation/validate-tokens.ts | ||
| const validateTokens = (options) => { | ||
| const { config: { theme }, tokens, addError } = options; | ||
| if (!theme) return; | ||
| const { tokenNames, semanticTokenNames, valueAtPath, refsByPath, typeByPath } = tokens; | ||
| if (theme.tokens) { | ||
| const tokenPaths = /* @__PURE__ */ new Set(); | ||
| (0, _bamboocss_shared.walkObject)(theme.tokens, (value, paths) => { | ||
| const path = paths.join("."); | ||
| tokenNames.add(path); | ||
| tokenPaths.add(path); | ||
| valueAtPath.set(path, value); | ||
| if (path.includes("DEFAULT")) valueAtPath.set(path.replace(".DEFAULT", ""), value); | ||
| }, { stop: require_merge_config.isValidToken }); | ||
| tokenPaths.forEach((path) => { | ||
| const itemValue = valueAtPath.get(path); | ||
| const formattedPath = require_merge_config.formatPath(path); | ||
| typeByPath.set(formattedPath, "tokens"); | ||
| if (!require_merge_config.isValidToken(itemValue)) { | ||
| addError("tokens", `Token must contain 'value': \`theme.tokens.${formattedPath}\``); | ||
| return; | ||
| } | ||
| if (path.includes(" ")) { | ||
| addError("tokens", `Token key must not contain spaces: \`theme.tokens.${formattedPath}\``); | ||
| return; | ||
| } | ||
| const valueStr = require_merge_config.serializeTokenValue(itemValue.value || itemValue); | ||
| if (require_merge_config.isTokenReference(valueStr)) refsByPath.set(formattedPath, /* @__PURE__ */ new Set([])); | ||
| const references = refsByPath.get(formattedPath); | ||
| if (!references) return; | ||
| require_merge_config.getReferences(valueStr).forEach((reference) => { | ||
| references.add(reference); | ||
| }); | ||
| }); | ||
| } | ||
| if (theme.semanticTokens) { | ||
| const tokenPaths = /* @__PURE__ */ new Set(); | ||
| (0, _bamboocss_shared.walkObject)(theme.semanticTokens, (value, paths) => { | ||
| const path = paths.join("."); | ||
| semanticTokenNames.add(path); | ||
| valueAtPath.set(path, value); | ||
| tokenPaths.add(path); | ||
| if (path.includes("DEFAULT")) valueAtPath.set(path.replace(".DEFAULT", ""), value); | ||
| if (!require_merge_config.isValidToken(value)) return; | ||
| (0, _bamboocss_shared.walkObject)(value, (itemValue, paths) => { | ||
| const valuePath = paths.join("."); | ||
| const formattedPath = require_merge_config.formatPath(path); | ||
| typeByPath.set(formattedPath, "semanticTokens"); | ||
| const fullPath = formattedPath + "." + paths.join("."); | ||
| if (valuePath.includes("value.value")) addError("tokens", `You used \`value\` twice resulting in an invalid token \`theme.tokens.${fullPath}\``); | ||
| const valueStr = require_merge_config.serializeTokenValue(itemValue.value || itemValue); | ||
| if (require_merge_config.isTokenReference(valueStr)) { | ||
| if (!refsByPath.has(formattedPath)) refsByPath.set(formattedPath, /* @__PURE__ */ new Set()); | ||
| const references = refsByPath.get(formattedPath); | ||
| if (!references) return; | ||
| require_merge_config.getReferences(valueStr).forEach((reference) => { | ||
| references.add(reference); | ||
| }); | ||
| } | ||
| }); | ||
| }, { stop: require_merge_config.isValidToken }); | ||
| tokenPaths.forEach((path) => { | ||
| const formattedPath = require_merge_config.formatPath(path); | ||
| const value = valueAtPath.get(path); | ||
| if (path.includes(" ")) { | ||
| addError("tokens", `Token key must not contain spaces: \`theme.tokens.${formattedPath}\``); | ||
| return; | ||
| } | ||
| if (!(0, _bamboocss_shared.isObject)(value) && !path.includes("value")) addError("tokens", `Token must contain 'value': \`theme.semanticTokens.${formattedPath}\``); | ||
| }); | ||
| } | ||
| validateTokenReferences({ | ||
| valueAtPath, | ||
| refsByPath, | ||
| addError, | ||
| typeByPath | ||
| }); | ||
| }; | ||
| //#endregion | ||
| //#region src/validate-config.ts | ||
| /** | ||
| * Validate the config | ||
| * - Check for duplicate between token & semanticTokens names | ||
| * - Check for duplicate between recipes/patterns/slots names | ||
| * - Check for token / semanticTokens paths (must end/contain 'value') | ||
| * - Check for self/circular token references | ||
| * - Check for missing tokens references | ||
| * - Check for conditions selectors (must contain '&') | ||
| * - Check for breakpoints units (must be the same) | ||
| */ | ||
| const validateConfig = (config) => { | ||
| if (config.validation === "none") return; | ||
| const warnings = /* @__PURE__ */ new Set(); | ||
| const addError = (scope, message) => { | ||
| warnings.add(`[${scope}] ` + message); | ||
| }; | ||
| validateBreakpoints(config.theme?.breakpoints, addError); | ||
| validateConditions(config.conditions, addError); | ||
| const artifacts = { | ||
| recipes: /* @__PURE__ */ new Set(), | ||
| slotRecipes: /* @__PURE__ */ new Set(), | ||
| patterns: /* @__PURE__ */ new Set() | ||
| }; | ||
| const tokens = { | ||
| tokenNames: /* @__PURE__ */ new Set(), | ||
| semanticTokenNames: /* @__PURE__ */ new Set(), | ||
| valueAtPath: /* @__PURE__ */ new Map(), | ||
| refsByPath: /* @__PURE__ */ new Map(), | ||
| typeByPath: /* @__PURE__ */ new Map() | ||
| }; | ||
| if (config.theme) { | ||
| validateTokens({ | ||
| config, | ||
| tokens, | ||
| addError | ||
| }); | ||
| validateRecipes({ | ||
| config, | ||
| tokens, | ||
| artifacts, | ||
| addError | ||
| }); | ||
| } | ||
| validatePatterns(config.patterns, artifacts); | ||
| validateArtifactNames(artifacts, addError); | ||
| if (warnings.size) { | ||
| const errors = `⚠️ Invalid config:\n${Array.from(warnings).map((err) => "- " + err).join("\n")}\n`; | ||
| if (config.validation === "error") throw new _bamboocss_shared.BambooError("CONFIG_ERROR", errors); | ||
| _bamboocss_logger.logger.warn("config", errors); | ||
| return warnings; | ||
| } | ||
| }; | ||
| //#endregion | ||
| //#region src/resolve-config.ts | ||
| const hookUtils = { | ||
| omit: _bamboocss_shared.omit, | ||
| pick: _bamboocss_shared.pick, | ||
| traverse: _bamboocss_shared.traverse | ||
| }; | ||
| /** | ||
| * Resolve the final config (including presets) | ||
| * @bamboocss/preset-base: ALWAYS included if NOT using eject: true | ||
| * @bamboocss/preset-bamboo: only included by default if no presets | ||
| */ | ||
| async function resolveConfig(result, cwd) { | ||
| const presets = /* @__PURE__ */ new Set(); | ||
| if (!result.config.eject) presets.add(_bamboocss_preset_base.preset); | ||
| if (result.config.presets) result.config.presets.forEach((preset) => { | ||
| presets.add(getBundledPreset(preset) ?? preset); | ||
| }); | ||
| else if (!result.config.eject) presets.add(_bamboocss_preset_bamboo.preset); | ||
| result.config.presets = Array.from(presets); | ||
| const userConfig = result.config; | ||
| const pluginHooks = userConfig.plugins ?? []; | ||
| if (userConfig.hooks) pluginHooks.push({ | ||
| name: _bamboocss_shared.BAMBOO_CONFIG_NAME, | ||
| hooks: userConfig.hooks | ||
| }); | ||
| const earlyHooks = require_merge_config.mergeHooks(pluginHooks); | ||
| const mergedConfig = await getResolvedConfig(result.config, cwd, earlyHooks); | ||
| const hooks = mergedConfig.hooks ?? {}; | ||
| if (mergedConfig.logLevel) _bamboocss_logger.logger.level = mergedConfig.logLevel; | ||
| validateConfig(mergedConfig); | ||
| const loadConfigResult = { | ||
| ...result, | ||
| config: mergedConfig | ||
| }; | ||
| if (hooks["config:resolved"]) { | ||
| const result = await hooks["config:resolved"]({ | ||
| config: loadConfigResult.config, | ||
| path: loadConfigResult.path, | ||
| dependencies: loadConfigResult.dependencies, | ||
| utils: hookUtils | ||
| }); | ||
| if (result) loadConfigResult.config = result; | ||
| } | ||
| const serialized = (0, _bamboocss_shared.stringifyJson)(Object.assign({}, loadConfigResult.config, { | ||
| name: _bamboocss_shared.BAMBOO_CONFIG_NAME, | ||
| presets: [] | ||
| })); | ||
| const deserialize = () => (0, _bamboocss_shared.parseJson)(serialized); | ||
| return { | ||
| ...loadConfigResult, | ||
| serialized, | ||
| deserialize, | ||
| hooks | ||
| }; | ||
| } | ||
| //#endregion | ||
| //#region src/load-config.ts | ||
| /** | ||
| * Find, load and resolve the final config (including presets) | ||
| */ | ||
| async function loadConfig(options) { | ||
| return resolveConfig(await bundleConfig(options), options.cwd); | ||
| } | ||
| //#endregion | ||
| exports.bundleConfig = bundleConfig; | ||
| exports.convertTsPathsToRegexes = convertTsPathsToRegexes; | ||
| exports.diffConfigs = require_diff_config.diffConfigs; | ||
| exports.findConfig = findConfig; | ||
| exports.getConfigDependencies = getConfigDependencies; | ||
| exports.getResolvedConfig = getResolvedConfig; | ||
| exports.loadConfig = loadConfig; | ||
| exports.mergeConfigs = require_merge_config.mergeConfigs; | ||
| exports.mergeHooks = require_merge_config.mergeHooks; | ||
| exports.resolveConfig = resolveConfig; |
| import { diffConfigs } from "./diff-config.cjs"; | ||
| import { n as convertTsPathsToRegexes, t as PathMapping } from "./ts-config-paths-wVx39QZ0.cjs"; | ||
| import { n as mergeHooks, t as mergeConfigs } from "./merge-config-DVOlBQJY.cjs"; | ||
| import { BambooHooks, Config, ConfigTsOptions, LoadConfigResult as LoadConfigResult$1 } from "@bamboocss/types"; | ||
| import { CompilerOptions, TypeAcquisition } from "typescript"; | ||
| //#region src/types.d.ts | ||
| interface ConfigFileOptions { | ||
| cwd: string; | ||
| file?: string; | ||
| } | ||
| interface BundleConfigResult<T = Config> { | ||
| config: T; | ||
| dependencies: string[]; | ||
| path: string; | ||
| } | ||
| //#endregion | ||
| //#region src/bundle-config.d.ts | ||
| declare function bundleConfig(options: ConfigFileOptions): Promise<BundleConfigResult>; | ||
| //#endregion | ||
| //#region src/find-config.d.ts | ||
| declare function findConfig(options: Partial<ConfigFileOptions>): string; | ||
| //#endregion | ||
| //#region ../../node_modules/.pnpm/pkg-types@2.3.0/node_modules/pkg-types/dist/index.d.mts | ||
| type StripEnums<T extends Record<string, any>> = { [K in keyof T]: T[K] extends boolean ? T[K] : T[K] extends string ? T[K] : T[K] extends object ? T[K] : T[K] extends Array<any> ? T[K] : T[K] extends undefined ? undefined : any }; | ||
| interface TSConfig { | ||
| compilerOptions?: StripEnums<CompilerOptions>; | ||
| exclude?: string[]; | ||
| compileOnSave?: boolean; | ||
| extends?: string | string[]; | ||
| files?: string[]; | ||
| include?: string[]; | ||
| typeAcquisition?: TypeAcquisition; | ||
| references?: { | ||
| path: string; | ||
| }[]; | ||
| } | ||
| /** | ||
| * Defines a TSConfig structure. | ||
| * @param tsconfig - The contents of `tsconfig.json` as an object. See {@link TSConfig}. | ||
| * @returns the same `tsconfig.json` object. | ||
| */ | ||
| //#endregion | ||
| //#region src/get-mod-deps.d.ts | ||
| interface GetDepsOptions { | ||
| filename: string; | ||
| ext: string; | ||
| cwd: string; | ||
| seen: Set<string>; | ||
| baseUrl: string | undefined; | ||
| pathMappings: PathMapping[]; | ||
| foundModuleAliases: Map<string, string>; | ||
| compilerOptions?: TSConfig['compilerOptions']; | ||
| } | ||
| declare function getConfigDependencies(filePath: string, tsOptions?: ConfigTsOptions, compilerOptions?: TSConfig['compilerOptions']): { | ||
| deps: Set<string>; | ||
| aliases: Map<string, string>; | ||
| }; | ||
| //#endregion | ||
| //#region src/get-resolved-config.d.ts | ||
| type Extendable<T> = T & { | ||
| extend?: T; | ||
| }; | ||
| type ExtendableConfig = Extendable<Config>; | ||
| /** | ||
| * Recursively merge all presets into a single config (depth-first using stack) | ||
| */ | ||
| declare function getResolvedConfig(config: ExtendableConfig, cwd: string, hooks?: Partial<BambooHooks>): Promise<Config>; | ||
| //#endregion | ||
| //#region src/load-config.d.ts | ||
| /** | ||
| * Find, load and resolve the final config (including presets) | ||
| */ | ||
| declare function loadConfig(options: ConfigFileOptions): Promise<LoadConfigResult>; | ||
| //#endregion | ||
| //#region src/resolve-config.d.ts | ||
| /** | ||
| * Resolve the final config (including presets) | ||
| * @bamboocss/preset-base: ALWAYS included if NOT using eject: true | ||
| * @bamboocss/preset-bamboo: only included by default if no presets | ||
| */ | ||
| declare function resolveConfig(result: BundleConfigResult, cwd: string): Promise<LoadConfigResult$1>; | ||
| //#endregion | ||
| export { type BundleConfigResult, type GetDepsOptions, bundleConfig, convertTsPathsToRegexes, diffConfigs, findConfig, getConfigDependencies, getResolvedConfig, loadConfig, mergeConfigs, mergeHooks, resolveConfig }; |
| import { diffConfigs } from "./diff-config.mjs"; | ||
| import { n as convertTsPathsToRegexes, t as PathMapping } from "./ts-config-paths-CvGId8kq.mjs"; | ||
| import { n as mergeHooks, t as mergeConfigs } from "./merge-config-oEiBYbfB.mjs"; | ||
| import { CompilerOptions, TypeAcquisition } from "typescript"; | ||
| import { BambooHooks, Config, ConfigTsOptions, LoadConfigResult as LoadConfigResult$1 } from "@bamboocss/types"; | ||
| //#region src/types.d.ts | ||
| interface ConfigFileOptions { | ||
| cwd: string; | ||
| file?: string; | ||
| } | ||
| interface BundleConfigResult<T = Config> { | ||
| config: T; | ||
| dependencies: string[]; | ||
| path: string; | ||
| } | ||
| //#endregion | ||
| //#region src/bundle-config.d.ts | ||
| declare function bundleConfig(options: ConfigFileOptions): Promise<BundleConfigResult>; | ||
| //#endregion | ||
| //#region src/find-config.d.ts | ||
| declare function findConfig(options: Partial<ConfigFileOptions>): string; | ||
| //#endregion | ||
| //#region ../../node_modules/.pnpm/pkg-types@2.3.0/node_modules/pkg-types/dist/index.d.mts | ||
| type StripEnums<T extends Record<string, any>> = { [K in keyof T]: T[K] extends boolean ? T[K] : T[K] extends string ? T[K] : T[K] extends object ? T[K] : T[K] extends Array<any> ? T[K] : T[K] extends undefined ? undefined : any }; | ||
| interface TSConfig { | ||
| compilerOptions?: StripEnums<CompilerOptions>; | ||
| exclude?: string[]; | ||
| compileOnSave?: boolean; | ||
| extends?: string | string[]; | ||
| files?: string[]; | ||
| include?: string[]; | ||
| typeAcquisition?: TypeAcquisition; | ||
| references?: { | ||
| path: string; | ||
| }[]; | ||
| } | ||
| /** | ||
| * Defines a TSConfig structure. | ||
| * @param tsconfig - The contents of `tsconfig.json` as an object. See {@link TSConfig}. | ||
| * @returns the same `tsconfig.json` object. | ||
| */ | ||
| //#endregion | ||
| //#region src/get-mod-deps.d.ts | ||
| interface GetDepsOptions { | ||
| filename: string; | ||
| ext: string; | ||
| cwd: string; | ||
| seen: Set<string>; | ||
| baseUrl: string | undefined; | ||
| pathMappings: PathMapping[]; | ||
| foundModuleAliases: Map<string, string>; | ||
| compilerOptions?: TSConfig['compilerOptions']; | ||
| } | ||
| declare function getConfigDependencies(filePath: string, tsOptions?: ConfigTsOptions, compilerOptions?: TSConfig['compilerOptions']): { | ||
| deps: Set<string>; | ||
| aliases: Map<string, string>; | ||
| }; | ||
| //#endregion | ||
| //#region src/get-resolved-config.d.ts | ||
| type Extendable<T> = T & { | ||
| extend?: T; | ||
| }; | ||
| type ExtendableConfig = Extendable<Config>; | ||
| /** | ||
| * Recursively merge all presets into a single config (depth-first using stack) | ||
| */ | ||
| declare function getResolvedConfig(config: ExtendableConfig, cwd: string, hooks?: Partial<BambooHooks>): Promise<Config>; | ||
| //#endregion | ||
| //#region src/load-config.d.ts | ||
| /** | ||
| * Find, load and resolve the final config (including presets) | ||
| */ | ||
| declare function loadConfig(options: ConfigFileOptions): Promise<LoadConfigResult>; | ||
| //#endregion | ||
| //#region src/resolve-config.d.ts | ||
| /** | ||
| * Resolve the final config (including presets) | ||
| * @bamboocss/preset-base: ALWAYS included if NOT using eject: true | ||
| * @bamboocss/preset-bamboo: only included by default if no presets | ||
| */ | ||
| declare function resolveConfig(result: BundleConfigResult, cwd: string): Promise<LoadConfigResult$1>; | ||
| //#endregion | ||
| export { type BundleConfigResult, type GetDepsOptions, bundleConfig, convertTsPathsToRegexes, diffConfigs, findConfig, getConfigDependencies, getResolvedConfig, loadConfig, mergeConfigs, mergeHooks, resolveConfig }; |
| require("./diff-config-Co_3mDXE.cjs"); | ||
| let _bamboocss_logger = require("@bamboocss/logger"); | ||
| let _bamboocss_shared = require("@bamboocss/shared"); | ||
| //#region src/merge-hooks.ts | ||
| const mergeHooks = (plugins) => { | ||
| const hooksFns = {}; | ||
| plugins.forEach(({ name, hooks }) => { | ||
| Object.entries(hooks ?? {}).forEach(([key, value]) => { | ||
| if (!hooksFns[key]) hooksFns[key] = []; | ||
| hooksFns[key].push([name, value]); | ||
| }); | ||
| }); | ||
| return Object.fromEntries(Object.entries(hooksFns).map(([key, entries]) => { | ||
| const fns = entries.map(([name, fn]) => tryCatch(name, fn)); | ||
| const reducer = key in reducers ? reducers[key] : void 0; | ||
| if (reducer) return [key, reducer(fns)]; | ||
| return [key, syncHooks.includes(key) ? callAll(...fns) : callAllAsync(...fns)]; | ||
| })); | ||
| }; | ||
| const createReducer = (reducer) => reducer; | ||
| const reducers = { | ||
| "config:resolved": createReducer((fns) => async (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.config; | ||
| let config = args.config; | ||
| for (const hookFn of fns) { | ||
| const result = await hookFn(Object.assign(args, { | ||
| config, | ||
| original | ||
| })); | ||
| if (result !== void 0) config = result; | ||
| } | ||
| return config; | ||
| }), | ||
| "parser:before": createReducer((fns) => (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.content; | ||
| let content = args.content; | ||
| for (const hookFn of fns) { | ||
| const result = hookFn(Object.assign(args, { | ||
| content, | ||
| original | ||
| })); | ||
| if (result !== void 0) content = result; | ||
| } | ||
| return content; | ||
| }), | ||
| "parser:preprocess": createReducer((fns) => (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.data; | ||
| let data = args.data; | ||
| for (const hookFn of fns) { | ||
| const result = hookFn(Object.assign(args, { | ||
| data, | ||
| original | ||
| })); | ||
| if (result !== void 0) data = result; | ||
| } | ||
| return data; | ||
| }), | ||
| "cssgen:done": createReducer((fns) => (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.content; | ||
| let content = args.content; | ||
| for (const hookFn of fns) { | ||
| const result = hookFn(Object.assign(args, { | ||
| content, | ||
| original | ||
| })); | ||
| if (result !== void 0) content = result; | ||
| } | ||
| return content; | ||
| }), | ||
| "codegen:prepare": createReducer((fns) => async (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.artifacts; | ||
| let artifacts = args.artifacts; | ||
| for (const hookFn of fns) { | ||
| const result = await hookFn(Object.assign(args, { | ||
| artifacts, | ||
| original | ||
| })); | ||
| if (result) artifacts = result; | ||
| } | ||
| return artifacts; | ||
| }), | ||
| "preset:resolved": createReducer((fns) => async (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.preset; | ||
| let preset = args.preset; | ||
| for (const hookFn of fns) { | ||
| const result = await hookFn(Object.assign(args, { | ||
| preset, | ||
| original | ||
| })); | ||
| if (result !== void 0) preset = result; | ||
| } | ||
| return preset; | ||
| }), | ||
| "css:optimize": createReducer((fns) => (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.css; | ||
| let css = args.css; | ||
| for (const hookFn of fns) { | ||
| const result = hookFn(Object.assign(args, { | ||
| css, | ||
| original | ||
| })); | ||
| if (result !== void 0) css = result; | ||
| } | ||
| return css; | ||
| }) | ||
| }; | ||
| const syncHooks = [ | ||
| "context:created", | ||
| "parser:before", | ||
| "parser:preprocess", | ||
| "parser:after", | ||
| "cssgen:done", | ||
| "css:optimize" | ||
| ]; | ||
| const callAllAsync = (...fns) => async (...a) => { | ||
| for (const fn of fns) await fn?.(...a); | ||
| }; | ||
| const callAll = (...fns) => (...a) => { | ||
| fns.forEach((fn) => fn?.(...a)); | ||
| }; | ||
| const tryCatch = (name, fn) => { | ||
| return (...args) => { | ||
| try { | ||
| return fn(...args); | ||
| } catch (e) { | ||
| _bamboocss_logger.logger.caughtError("hooks", `Error in plugin "${name}"`, e); | ||
| } | ||
| }; | ||
| }; | ||
| //#endregion | ||
| //#region src/validation/utils.ts | ||
| const REFERENCE_REGEX = /({([^}]*)})/g; | ||
| const curlyBracketRegex = /[{}]/g; | ||
| const isValidToken = (token) => (0, _bamboocss_shared.isObject)(token) && Object.hasOwnProperty.call(token, "value"); | ||
| const isTokenReference = (value) => typeof value === "string" && REFERENCE_REGEX.test(value); | ||
| const formatPath = (path) => path; | ||
| function getReferences(value) { | ||
| if (typeof value !== "string") return []; | ||
| const matches = value.match(REFERENCE_REGEX); | ||
| if (!matches) return []; | ||
| return matches.map((match) => match.replace(curlyBracketRegex, "")).map((value) => { | ||
| return value.trim().split("/")[0]; | ||
| }); | ||
| } | ||
| const serializeTokenValue = (value) => { | ||
| if ((0, _bamboocss_shared.isString)(value)) return value; | ||
| if ((0, _bamboocss_shared.isObject)(value)) return Object.values(value).map((v) => serializeTokenValue(v)).join(" "); | ||
| if (Array.isArray(value)) return value.map((v) => serializeTokenValue(v)).join(" "); | ||
| return value.toString(); | ||
| }; | ||
| //#endregion | ||
| //#region src/merge-config.ts | ||
| /** | ||
| * Collect all `extend` properties into an array (to avoid mutation) | ||
| */ | ||
| function getExtends(items) { | ||
| return items.reduce((merged, { extend }) => { | ||
| if (!extend) return merged; | ||
| return (0, _bamboocss_shared.mergeWith)(merged, extend, (originalValue, newValue) => { | ||
| if (newValue === void 0) return originalValue ?? []; | ||
| if (originalValue === void 0) return [newValue]; | ||
| if (Array.isArray(originalValue)) return [newValue, ...originalValue]; | ||
| return [newValue, originalValue]; | ||
| }); | ||
| }, {}); | ||
| } | ||
| /** | ||
| * Separate the `extend` properties from the rest of the object | ||
| */ | ||
| function mergeRecords(records) { | ||
| return { | ||
| ...records.reduce((acc, record) => (0, _bamboocss_shared.assign)(acc, record), {}), | ||
| extend: getExtends(records) | ||
| }; | ||
| } | ||
| /** | ||
| * Merge all `extend` properties into the rest of the object | ||
| */ | ||
| function mergeExtensions(records) { | ||
| const { extend = [], ...restProps } = mergeRecords(records); | ||
| return (0, _bamboocss_shared.mergeWith)(restProps, extend, (obj, extensions) => { | ||
| return (0, _bamboocss_shared.mergeAndConcat)({}, obj, ...extensions); | ||
| }); | ||
| } | ||
| const isEmptyObject = (obj) => typeof obj === "object" && Object.keys(obj).length === 0; | ||
| const compact = (obj) => { | ||
| return Object.keys(obj).reduce((acc, key) => { | ||
| if (obj[key] !== void 0 && !isEmptyObject(obj[key])) acc[key] = obj[key]; | ||
| return acc; | ||
| }, {}); | ||
| }; | ||
| const tokenKeys = [ | ||
| "description", | ||
| "extensions", | ||
| "type", | ||
| "value", | ||
| "deprecated" | ||
| ]; | ||
| /** | ||
| * Merge all configs into a single config | ||
| */ | ||
| function mergeConfigs(configs) { | ||
| const userConfig = configs.at(-1); | ||
| const pluginHooks = userConfig.plugins ?? []; | ||
| if (userConfig.hooks) pluginHooks.push({ | ||
| name: _bamboocss_shared.BAMBOO_CONFIG_NAME, | ||
| hooks: userConfig.hooks | ||
| }); | ||
| const reversed = Array.from(configs).reverse(); | ||
| const withoutEmpty = compact((0, _bamboocss_shared.assign)({ | ||
| conditions: mergeExtensions(reversed.map((config) => config.conditions ?? {})), | ||
| theme: mergeExtensions(reversed.map((config) => config.theme ?? {})), | ||
| patterns: mergeExtensions(reversed.map((config) => config.patterns ?? {})), | ||
| utilities: mergeExtensions(reversed.map((config) => config.utilities ?? {})), | ||
| globalCss: mergeExtensions(reversed.map((config) => config.globalCss ?? {})), | ||
| globalVars: mergeExtensions(reversed.map((config) => config.globalVars ?? {})), | ||
| globalFontface: mergeExtensions(reversed.map((config) => config.globalFontface ?? {})), | ||
| globalPositionTry: mergeExtensions(reversed.map((config) => config.globalPositionTry ?? {})), | ||
| staticCss: mergeExtensions(reversed.map((config) => config.staticCss ?? {})), | ||
| themes: mergeExtensions(reversed.map((config) => config.themes ?? {})), | ||
| hooks: mergeHooks(pluginHooks) | ||
| }, ...reversed)); | ||
| /** | ||
| * Properly merge tokens between flat/nested forms by setting the flat form as the default | ||
| * preset: | ||
| * ``` | ||
| * tokens: { | ||
| * black: { | ||
| * value: "black" | ||
| * } | ||
| * } | ||
| * // color: "black" | ||
| * ``` | ||
| * | ||
| * config: | ||
| * ``` | ||
| * tokens: { | ||
| * black: { | ||
| * 0: { value: "black" }, | ||
| * 10: { value: "black/10" }, | ||
| * 20: { value: "black/20" }, | ||
| * // ... | ||
| * } | ||
| * } | ||
| * | ||
| * // color: "black.20" | ||
| * ``` | ||
| */ | ||
| if (withoutEmpty.theme?.tokens) (0, _bamboocss_shared.walkObject)(withoutEmpty.theme.tokens, (args) => args, { stop(token) { | ||
| if (!isValidToken(token)) return false; | ||
| if (Object.keys(token).filter((k) => !tokenKeys.includes(k)).length > 0) { | ||
| token.DEFAULT ||= {}; | ||
| tokenKeys.forEach((key) => { | ||
| if (token[key] == null) return; | ||
| token.DEFAULT[key] ||= token[key]; | ||
| delete token[key]; | ||
| }); | ||
| } | ||
| return true; | ||
| } }); | ||
| return withoutEmpty; | ||
| } | ||
| //#endregion | ||
| Object.defineProperty(exports, "formatPath", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return formatPath; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "getReferences", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return getReferences; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "isTokenReference", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return isTokenReference; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "isValidToken", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return isValidToken; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "mergeConfigs", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return mergeConfigs; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "mergeHooks", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return mergeHooks; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "serializeTokenValue", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return serializeTokenValue; | ||
| } | ||
| }); |
| import { logger } from "@bamboocss/logger"; | ||
| import { BAMBOO_CONFIG_NAME, assign, isObject, isString, mergeAndConcat, mergeWith, walkObject } from "@bamboocss/shared"; | ||
| //#region src/merge-hooks.ts | ||
| const mergeHooks = (plugins) => { | ||
| const hooksFns = {}; | ||
| plugins.forEach(({ name, hooks }) => { | ||
| Object.entries(hooks ?? {}).forEach(([key, value]) => { | ||
| if (!hooksFns[key]) hooksFns[key] = []; | ||
| hooksFns[key].push([name, value]); | ||
| }); | ||
| }); | ||
| return Object.fromEntries(Object.entries(hooksFns).map(([key, entries]) => { | ||
| const fns = entries.map(([name, fn]) => tryCatch(name, fn)); | ||
| const reducer = key in reducers ? reducers[key] : void 0; | ||
| if (reducer) return [key, reducer(fns)]; | ||
| return [key, syncHooks.includes(key) ? callAll(...fns) : callAllAsync(...fns)]; | ||
| })); | ||
| }; | ||
| const createReducer = (reducer) => reducer; | ||
| const reducers = { | ||
| "config:resolved": createReducer((fns) => async (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.config; | ||
| let config = args.config; | ||
| for (const hookFn of fns) { | ||
| const result = await hookFn(Object.assign(args, { | ||
| config, | ||
| original | ||
| })); | ||
| if (result !== void 0) config = result; | ||
| } | ||
| return config; | ||
| }), | ||
| "parser:before": createReducer((fns) => (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.content; | ||
| let content = args.content; | ||
| for (const hookFn of fns) { | ||
| const result = hookFn(Object.assign(args, { | ||
| content, | ||
| original | ||
| })); | ||
| if (result !== void 0) content = result; | ||
| } | ||
| return content; | ||
| }), | ||
| "parser:preprocess": createReducer((fns) => (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.data; | ||
| let data = args.data; | ||
| for (const hookFn of fns) { | ||
| const result = hookFn(Object.assign(args, { | ||
| data, | ||
| original | ||
| })); | ||
| if (result !== void 0) data = result; | ||
| } | ||
| return data; | ||
| }), | ||
| "cssgen:done": createReducer((fns) => (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.content; | ||
| let content = args.content; | ||
| for (const hookFn of fns) { | ||
| const result = hookFn(Object.assign(args, { | ||
| content, | ||
| original | ||
| })); | ||
| if (result !== void 0) content = result; | ||
| } | ||
| return content; | ||
| }), | ||
| "codegen:prepare": createReducer((fns) => async (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.artifacts; | ||
| let artifacts = args.artifacts; | ||
| for (const hookFn of fns) { | ||
| const result = await hookFn(Object.assign(args, { | ||
| artifacts, | ||
| original | ||
| })); | ||
| if (result) artifacts = result; | ||
| } | ||
| return artifacts; | ||
| }), | ||
| "preset:resolved": createReducer((fns) => async (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.preset; | ||
| let preset = args.preset; | ||
| for (const hookFn of fns) { | ||
| const result = await hookFn(Object.assign(args, { | ||
| preset, | ||
| original | ||
| })); | ||
| if (result !== void 0) preset = result; | ||
| } | ||
| return preset; | ||
| }), | ||
| "css:optimize": createReducer((fns) => (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.css; | ||
| let css = args.css; | ||
| for (const hookFn of fns) { | ||
| const result = hookFn(Object.assign(args, { | ||
| css, | ||
| original | ||
| })); | ||
| if (result !== void 0) css = result; | ||
| } | ||
| return css; | ||
| }) | ||
| }; | ||
| const syncHooks = [ | ||
| "context:created", | ||
| "parser:before", | ||
| "parser:preprocess", | ||
| "parser:after", | ||
| "cssgen:done", | ||
| "css:optimize" | ||
| ]; | ||
| const callAllAsync = (...fns) => async (...a) => { | ||
| for (const fn of fns) await fn?.(...a); | ||
| }; | ||
| const callAll = (...fns) => (...a) => { | ||
| fns.forEach((fn) => fn?.(...a)); | ||
| }; | ||
| const tryCatch = (name, fn) => { | ||
| return (...args) => { | ||
| try { | ||
| return fn(...args); | ||
| } catch (e) { | ||
| logger.caughtError("hooks", `Error in plugin "${name}"`, e); | ||
| } | ||
| }; | ||
| }; | ||
| //#endregion | ||
| //#region src/validation/utils.ts | ||
| const REFERENCE_REGEX = /({([^}]*)})/g; | ||
| const curlyBracketRegex = /[{}]/g; | ||
| const isValidToken = (token) => isObject(token) && Object.hasOwnProperty.call(token, "value"); | ||
| const isTokenReference = (value) => typeof value === "string" && REFERENCE_REGEX.test(value); | ||
| const formatPath = (path) => path; | ||
| function getReferences(value) { | ||
| if (typeof value !== "string") return []; | ||
| const matches = value.match(REFERENCE_REGEX); | ||
| if (!matches) return []; | ||
| return matches.map((match) => match.replace(curlyBracketRegex, "")).map((value) => { | ||
| return value.trim().split("/")[0]; | ||
| }); | ||
| } | ||
| const serializeTokenValue = (value) => { | ||
| if (isString(value)) return value; | ||
| if (isObject(value)) return Object.values(value).map((v) => serializeTokenValue(v)).join(" "); | ||
| if (Array.isArray(value)) return value.map((v) => serializeTokenValue(v)).join(" "); | ||
| return value.toString(); | ||
| }; | ||
| //#endregion | ||
| //#region src/merge-config.ts | ||
| /** | ||
| * Collect all `extend` properties into an array (to avoid mutation) | ||
| */ | ||
| function getExtends(items) { | ||
| return items.reduce((merged, { extend }) => { | ||
| if (!extend) return merged; | ||
| return mergeWith(merged, extend, (originalValue, newValue) => { | ||
| if (newValue === void 0) return originalValue ?? []; | ||
| if (originalValue === void 0) return [newValue]; | ||
| if (Array.isArray(originalValue)) return [newValue, ...originalValue]; | ||
| return [newValue, originalValue]; | ||
| }); | ||
| }, {}); | ||
| } | ||
| /** | ||
| * Separate the `extend` properties from the rest of the object | ||
| */ | ||
| function mergeRecords(records) { | ||
| return { | ||
| ...records.reduce((acc, record) => assign(acc, record), {}), | ||
| extend: getExtends(records) | ||
| }; | ||
| } | ||
| /** | ||
| * Merge all `extend` properties into the rest of the object | ||
| */ | ||
| function mergeExtensions(records) { | ||
| const { extend = [], ...restProps } = mergeRecords(records); | ||
| return mergeWith(restProps, extend, (obj, extensions) => { | ||
| return mergeAndConcat({}, obj, ...extensions); | ||
| }); | ||
| } | ||
| const isEmptyObject = (obj) => typeof obj === "object" && Object.keys(obj).length === 0; | ||
| const compact = (obj) => { | ||
| return Object.keys(obj).reduce((acc, key) => { | ||
| if (obj[key] !== void 0 && !isEmptyObject(obj[key])) acc[key] = obj[key]; | ||
| return acc; | ||
| }, {}); | ||
| }; | ||
| const tokenKeys = [ | ||
| "description", | ||
| "extensions", | ||
| "type", | ||
| "value", | ||
| "deprecated" | ||
| ]; | ||
| /** | ||
| * Merge all configs into a single config | ||
| */ | ||
| function mergeConfigs(configs) { | ||
| const userConfig = configs.at(-1); | ||
| const pluginHooks = userConfig.plugins ?? []; | ||
| if (userConfig.hooks) pluginHooks.push({ | ||
| name: BAMBOO_CONFIG_NAME, | ||
| hooks: userConfig.hooks | ||
| }); | ||
| const reversed = Array.from(configs).reverse(); | ||
| const withoutEmpty = compact(assign({ | ||
| conditions: mergeExtensions(reversed.map((config) => config.conditions ?? {})), | ||
| theme: mergeExtensions(reversed.map((config) => config.theme ?? {})), | ||
| patterns: mergeExtensions(reversed.map((config) => config.patterns ?? {})), | ||
| utilities: mergeExtensions(reversed.map((config) => config.utilities ?? {})), | ||
| globalCss: mergeExtensions(reversed.map((config) => config.globalCss ?? {})), | ||
| globalVars: mergeExtensions(reversed.map((config) => config.globalVars ?? {})), | ||
| globalFontface: mergeExtensions(reversed.map((config) => config.globalFontface ?? {})), | ||
| globalPositionTry: mergeExtensions(reversed.map((config) => config.globalPositionTry ?? {})), | ||
| staticCss: mergeExtensions(reversed.map((config) => config.staticCss ?? {})), | ||
| themes: mergeExtensions(reversed.map((config) => config.themes ?? {})), | ||
| hooks: mergeHooks(pluginHooks) | ||
| }, ...reversed)); | ||
| /** | ||
| * Properly merge tokens between flat/nested forms by setting the flat form as the default | ||
| * preset: | ||
| * ``` | ||
| * tokens: { | ||
| * black: { | ||
| * value: "black" | ||
| * } | ||
| * } | ||
| * // color: "black" | ||
| * ``` | ||
| * | ||
| * config: | ||
| * ``` | ||
| * tokens: { | ||
| * black: { | ||
| * 0: { value: "black" }, | ||
| * 10: { value: "black/10" }, | ||
| * 20: { value: "black/20" }, | ||
| * // ... | ||
| * } | ||
| * } | ||
| * | ||
| * // color: "black.20" | ||
| * ``` | ||
| */ | ||
| if (withoutEmpty.theme?.tokens) walkObject(withoutEmpty.theme.tokens, (args) => args, { stop(token) { | ||
| if (!isValidToken(token)) return false; | ||
| if (Object.keys(token).filter((k) => !tokenKeys.includes(k)).length > 0) { | ||
| token.DEFAULT ||= {}; | ||
| tokenKeys.forEach((key) => { | ||
| if (token[key] == null) return; | ||
| token.DEFAULT[key] ||= token[key]; | ||
| delete token[key]; | ||
| }); | ||
| } | ||
| return true; | ||
| } }); | ||
| return withoutEmpty; | ||
| } | ||
| //#endregion | ||
| export { isValidToken as a, isTokenReference as i, formatPath as n, serializeTokenValue as o, getReferences as r, mergeHooks as s, mergeConfigs as t }; |
| import { BambooPlugin, Config } from "@bamboocss/types"; | ||
| //#region src/merge-hooks.d.ts | ||
| declare const mergeHooks: (plugins: BambooPlugin[]) => BambooHooks; | ||
| //#endregion | ||
| //#region src/merge-config.d.ts | ||
| type Extendable<T> = T & { | ||
| extend?: T; | ||
| }; | ||
| type ExtendableConfig = Extendable<Config>; | ||
| /** | ||
| * Merge all configs into a single config | ||
| */ | ||
| declare function mergeConfigs(configs: ExtendableConfig[]): any; | ||
| //#endregion | ||
| export { mergeHooks as n, mergeConfigs as t }; |
| import { BambooPlugin, Config } from "@bamboocss/types"; | ||
| //#region src/merge-hooks.d.ts | ||
| declare const mergeHooks: (plugins: BambooPlugin[]) => BambooHooks; | ||
| //#endregion | ||
| //#region src/merge-config.d.ts | ||
| type Extendable<T> = T & { | ||
| extend?: T; | ||
| }; | ||
| type ExtendableConfig = Extendable<Config>; | ||
| /** | ||
| * Merge all configs into a single config | ||
| */ | ||
| declare function mergeConfigs(configs: ExtendableConfig[]): any; | ||
| //#endregion | ||
| export { mergeHooks as n, mergeConfigs as t }; |
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| const require_merge_config = require("./merge-config-CcNpHJit.cjs"); | ||
| exports.mergeConfigs = require_merge_config.mergeConfigs; | ||
| exports.mergeHooks = require_merge_config.mergeHooks; |
| import { n as mergeHooks, t as mergeConfigs } from "./merge-config-DVOlBQJY.cjs"; | ||
| export { mergeConfigs, mergeHooks }; |
| import { n as mergeHooks, t as mergeConfigs } from "./merge-config-oEiBYbfB.mjs"; | ||
| export { mergeConfigs, mergeHooks }; |
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| require("./diff-config-Co_3mDXE.cjs"); | ||
| let path = require("path"); | ||
| //#region src/resolve-ts-path-pattern.ts | ||
| /** | ||
| * @see https://github.com/aleclarson/vite-tsconfig-paths/blob/e8f0acf7adfcfbf77edbe937f64b4e5d39557ad0/src/index.ts#LL231C57-L231C57 | ||
| */ | ||
| const resolveTsPathPattern = (pathMappings, moduleSpecifier) => { | ||
| for (const mapping of pathMappings) { | ||
| const match = moduleSpecifier.match(mapping.pattern); | ||
| if (!match) continue; | ||
| for (const pathTemplate of mapping.paths) { | ||
| let starCount = 0; | ||
| return pathTemplate.replace(/\*/g, () => { | ||
| return match[Math.min(++starCount, match.length - 1)]; | ||
| }).split(path.sep).join(path.posix.sep); | ||
| } | ||
| } | ||
| }; | ||
| //#endregion | ||
| exports.resolveTsPathPattern = resolveTsPathPattern; |
| import { t as PathMapping } from "./ts-config-paths-wVx39QZ0.cjs"; | ||
| //#region src/resolve-ts-path-pattern.d.ts | ||
| /** | ||
| * @see https://github.com/aleclarson/vite-tsconfig-paths/blob/e8f0acf7adfcfbf77edbe937f64b4e5d39557ad0/src/index.ts#LL231C57-L231C57 | ||
| */ | ||
| declare const resolveTsPathPattern: (pathMappings: PathMapping[], moduleSpecifier: string) => string | undefined; | ||
| //#endregion | ||
| export { resolveTsPathPattern }; |
| import { t as PathMapping } from "./ts-config-paths-CvGId8kq.mjs"; | ||
| //#region src/resolve-ts-path-pattern.d.ts | ||
| /** | ||
| * @see https://github.com/aleclarson/vite-tsconfig-paths/blob/e8f0acf7adfcfbf77edbe937f64b4e5d39557ad0/src/index.ts#LL231C57-L231C57 | ||
| */ | ||
| declare const resolveTsPathPattern: (pathMappings: PathMapping[], moduleSpecifier: string) => string | undefined; | ||
| //#endregion | ||
| export { resolveTsPathPattern }; |
| //#region src/ts-config-paths.d.ts | ||
| interface PathMapping { | ||
| pattern: RegExp; | ||
| paths: string[]; | ||
| } | ||
| /** | ||
| * @see https://github.com/aleclarson/vite-tsconfig-paths/blob/e8f0acf7adfcfbf77edbe937f64b4e5d39557ad0/src/mappings.ts | ||
| */ | ||
| declare function convertTsPathsToRegexes(paths: Record<string, string[]>, baseUrl: string): PathMapping[]; | ||
| //#endregion | ||
| export { convertTsPathsToRegexes as n, PathMapping as t }; |
| //#region src/ts-config-paths.d.ts | ||
| interface PathMapping { | ||
| pattern: RegExp; | ||
| paths: string[]; | ||
| } | ||
| /** | ||
| * @see https://github.com/aleclarson/vite-tsconfig-paths/blob/e8f0acf7adfcfbf77edbe937f64b4e5d39557ad0/src/mappings.ts | ||
| */ | ||
| declare function convertTsPathsToRegexes(paths: Record<string, string[]>, baseUrl: string): PathMapping[]; | ||
| //#endregion | ||
| export { convertTsPathsToRegexes as n, PathMapping as t }; |
@@ -1,6 +0,2 @@ | ||
| import { | ||
| diffConfigs | ||
| } from "./chunk-6TQW6KOI.mjs"; | ||
| export { | ||
| diffConfigs | ||
| }; | ||
| import { t as diffConfigs } from "./diff-config-KDQWMnQN.mjs"; | ||
| export { diffConfigs }; |
+520
-589
@@ -1,630 +0,561 @@ | ||
| import { | ||
| diffConfigs | ||
| } from "./chunk-6TQW6KOI.mjs"; | ||
| import { | ||
| SEP, | ||
| formatPath, | ||
| getReferences, | ||
| isTokenReference, | ||
| isValidToken, | ||
| mergeConfigs, | ||
| mergeHooks, | ||
| serializeTokenValue | ||
| } from "./chunk-RIBK22OM.mjs"; | ||
| import { | ||
| resolveTsPathPattern | ||
| } from "./chunk-RPIVZP2I.mjs"; | ||
| // src/bundle-config.ts | ||
| import { t as diffConfigs } from "./diff-config-KDQWMnQN.mjs"; | ||
| import { resolveTsPathPattern } from "./resolve-ts-path-pattern.mjs"; | ||
| import { a as isValidToken, i as isTokenReference, n as formatPath, o as serializeTokenValue, r as getReferences, s as mergeHooks, t as mergeConfigs } from "./merge-config-DI__LOWx.mjs"; | ||
| import { logger } from "@bamboocss/logger"; | ||
| import { BambooError as BambooError2 } from "@bamboocss/shared"; | ||
| import { BAMBOO_CONFIG_NAME, BambooError, getUnit, isObject, isString, omit, parseJson, pick, stringifyJson, traverse, walkObject } from "@bamboocss/shared"; | ||
| import { bundleNRequire } from "bundle-n-require"; | ||
| // src/find-config.ts | ||
| import { BambooError } from "@bamboocss/shared"; | ||
| import findUp from "escalade/sync"; | ||
| import { resolve } from "path"; | ||
| // src/is-bamboo-config.ts | ||
| var configName = "bamboo"; | ||
| var bambooConfigFiles = /* @__PURE__ */ new Set([ | ||
| `${configName}.config.ts`, | ||
| `${configName}.config.js`, | ||
| `${configName}.config.mts`, | ||
| `${configName}.config.mjs`, | ||
| `${configName}.config.cts`, | ||
| `${configName}.config.cjs` | ||
| import path, { resolve } from "path"; | ||
| import fs from "fs"; | ||
| import ts from "typescript"; | ||
| import { preset as presetBase } from "@bamboocss/preset-base"; | ||
| import { preset as presetBamboo } from "@bamboocss/preset-bamboo"; | ||
| //#region src/is-bamboo-config.ts | ||
| const configName = "bamboo"; | ||
| const bambooConfigFiles = new Set([ | ||
| `${configName}.config.ts`, | ||
| `${configName}.config.js`, | ||
| `${configName}.config.mts`, | ||
| `${configName}.config.mjs`, | ||
| `${configName}.config.cts`, | ||
| `${configName}.config.cjs` | ||
| ]); | ||
| var isBambooConfig = (file) => bambooConfigFiles.has(file); | ||
| // src/find-config.ts | ||
| const isBambooConfig = (file) => bambooConfigFiles.has(file); | ||
| //#endregion | ||
| //#region src/find-config.ts | ||
| function findConfig(options) { | ||
| const { cwd = process.cwd(), file } = options; | ||
| if (file) { | ||
| return resolve(cwd, file); | ||
| } | ||
| const configPath = findUp(cwd, (_dir, paths) => paths.find(isBambooConfig)); | ||
| if (!configPath) { | ||
| throw new BambooError( | ||
| "CONFIG_NOT_FOUND", | ||
| `Cannot find config file \`bamboo.config.{ts,js,mjs,mts}\`. Did you forget to run \`bamboo init\`?` | ||
| ); | ||
| } | ||
| return configPath; | ||
| const { cwd = process.cwd(), file } = options; | ||
| if (file) return resolve(cwd, file); | ||
| const configPath = findUp(cwd, (_dir, paths) => paths.find(isBambooConfig)); | ||
| if (!configPath) throw new BambooError("CONFIG_NOT_FOUND", `Cannot find config file \`bamboo.config.{ts,js,mjs,mts}\`. Did you forget to run \`bamboo init\`?`); | ||
| return configPath; | ||
| } | ||
| // src/bundle-config.ts | ||
| //#endregion | ||
| //#region src/bundle-config.ts | ||
| async function bundle(filepath, cwd) { | ||
| const { mod, dependencies } = await bundleNRequire(filepath, { | ||
| cwd, | ||
| interopDefault: true | ||
| }); | ||
| const config = mod?.default ?? mod; | ||
| return { | ||
| config, | ||
| dependencies | ||
| }; | ||
| const { mod, dependencies } = await bundleNRequire(filepath, { | ||
| cwd, | ||
| interopDefault: true | ||
| }); | ||
| return { | ||
| config: mod?.default ?? mod, | ||
| dependencies | ||
| }; | ||
| } | ||
| async function bundleConfig(options) { | ||
| const { cwd, file } = options; | ||
| const filePath = findConfig({ cwd, file }); | ||
| logger.debug("config:path", filePath); | ||
| const result = await bundle(filePath, cwd); | ||
| if (typeof result.config !== "object") { | ||
| throw new BambooError2("CONFIG_ERROR", `\u{1F4A5} Config must export or return an object.`); | ||
| } | ||
| result.config.outdir ??= "styled-system"; | ||
| result.config.validation ??= "warn"; | ||
| return { | ||
| ...result, | ||
| config: result.config, | ||
| path: filePath | ||
| }; | ||
| const { cwd, file } = options; | ||
| const filePath = findConfig({ | ||
| cwd, | ||
| file | ||
| }); | ||
| logger.debug("config:path", filePath); | ||
| const result = await bundle(filePath, cwd); | ||
| if (typeof result.config !== "object") throw new BambooError("CONFIG_ERROR", `💥 Config must export or return an object.`); | ||
| result.config.outdir ??= "styled-system"; | ||
| result.config.validation ??= "warn"; | ||
| return { | ||
| ...result, | ||
| config: result.config, | ||
| path: filePath | ||
| }; | ||
| } | ||
| // src/get-mod-deps.ts | ||
| import fs from "fs"; | ||
| import path from "path"; | ||
| import ts from "typescript"; | ||
| // src/ts-config-paths.ts | ||
| import { resolve as resolve2 } from "path"; | ||
| //#endregion | ||
| //#region src/ts-config-paths.ts | ||
| /** | ||
| * @see https://github.com/aleclarson/vite-tsconfig-paths/blob/e8f0acf7adfcfbf77edbe937f64b4e5d39557ad0/src/mappings.ts | ||
| */ | ||
| function convertTsPathsToRegexes(paths, baseUrl) { | ||
| const sortedPatterns = Object.keys(paths).sort((a, b) => getPrefixLength(b) - getPrefixLength(a)); | ||
| const resolved = []; | ||
| for (let pattern of sortedPatterns) { | ||
| const relativePaths = paths[pattern]; | ||
| pattern = escapeStringRegexp(pattern).replace(/\*/g, "(.+)"); | ||
| resolved.push({ | ||
| pattern: new RegExp("^" + pattern + "$"), | ||
| paths: relativePaths.map((relativePath) => resolve2(baseUrl, relativePath)) | ||
| }); | ||
| } | ||
| return resolved; | ||
| const sortedPatterns = Object.keys(paths).sort((a, b) => getPrefixLength(b) - getPrefixLength(a)); | ||
| const resolved = []; | ||
| for (let pattern of sortedPatterns) { | ||
| const relativePaths = paths[pattern]; | ||
| pattern = escapeStringRegexp(pattern).replace(/\*/g, "(.+)"); | ||
| resolved.push({ | ||
| pattern: new RegExp("^" + pattern + "$"), | ||
| paths: relativePaths.map((relativePath) => resolve(baseUrl, relativePath)) | ||
| }); | ||
| } | ||
| return resolved; | ||
| } | ||
| function getPrefixLength(pattern) { | ||
| const prefixLength = pattern.indexOf("*"); | ||
| return pattern.substr(0, prefixLength).length; | ||
| const prefixLength = pattern.indexOf("*"); | ||
| return pattern.substr(0, prefixLength).length; | ||
| } | ||
| function escapeStringRegexp(string) { | ||
| return string.replace(/[|\\{}()[\]^$+?.]/g, "\\$&").replace(/-/g, "\\x2d"); | ||
| return string.replace(/[|\\{}()[\]^$+?.]/g, "\\$&").replace(/-/g, "\\x2d"); | ||
| } | ||
| // src/get-mod-deps.ts | ||
| var jsExtensions = [".js", ".cjs", ".mjs"]; | ||
| var jsResolutionOrder = ["", ".js", ".cjs", ".mjs", ".ts", ".cts", ".mts", ".jsx", ".tsx"]; | ||
| var tsResolutionOrder = ["", ".ts", ".cts", ".mts", ".tsx", ".js", ".cjs", ".mjs", ".jsx"]; | ||
| //#endregion | ||
| //#region src/get-mod-deps.ts | ||
| const jsExtensions = [ | ||
| ".js", | ||
| ".cjs", | ||
| ".mjs" | ||
| ]; | ||
| const jsResolutionOrder = [ | ||
| "", | ||
| ".js", | ||
| ".cjs", | ||
| ".mjs", | ||
| ".ts", | ||
| ".cts", | ||
| ".mts", | ||
| ".jsx", | ||
| ".tsx" | ||
| ]; | ||
| const tsResolutionOrder = [ | ||
| "", | ||
| ".ts", | ||
| ".cts", | ||
| ".mts", | ||
| ".tsx", | ||
| ".js", | ||
| ".cjs", | ||
| ".mjs", | ||
| ".jsx" | ||
| ]; | ||
| function resolveWithExtension(file, extensions) { | ||
| for (const ext of extensions) { | ||
| const full = `${file}${ext}`; | ||
| if (fs.existsSync(full) && fs.statSync(full).isFile()) { | ||
| return full; | ||
| } | ||
| } | ||
| for (const ext of extensions) { | ||
| const full = `${file}/index${ext}`; | ||
| if (fs.existsSync(full)) { | ||
| return full; | ||
| } | ||
| } | ||
| return null; | ||
| for (const ext of extensions) { | ||
| const full = `${file}${ext}`; | ||
| if (fs.existsSync(full) && fs.statSync(full).isFile()) return full; | ||
| } | ||
| for (const ext of extensions) { | ||
| const full = `${file}/index${ext}`; | ||
| if (fs.existsSync(full)) return full; | ||
| } | ||
| return null; | ||
| } | ||
| var importRegex = /import[\s\S]*?['"](.{3,}?)['"]/gi; | ||
| var importFromRegex = /import[\s\S]*from[\s\S]*?['"](.{3,}?)['"]/gi; | ||
| var requireRegex = /require\(['"`](.+)['"`]\)/gi; | ||
| var exportRegex = /export[\s\S]*from[\s\S]*?['"](.{3,}?)['"]/gi; | ||
| const importRegex = /import[\s\S]*?['"](.{3,}?)['"]/gi; | ||
| const importFromRegex = /import[\s\S]*from[\s\S]*?['"](.{3,}?)['"]/gi; | ||
| const requireRegex = /require\(['"`](.+)['"`]\)/gi; | ||
| const exportRegex = /export[\s\S]*from[\s\S]*?['"](.{3,}?)['"]/gi; | ||
| function getDeps(opts, fromAlias) { | ||
| const { filename, seen } = opts; | ||
| const { moduleResolution: _, ...compilerOptions } = opts.compilerOptions ?? {}; | ||
| const absoluteFile = resolveWithExtension( | ||
| path.resolve(opts.cwd, filename), | ||
| jsExtensions.includes(opts.ext) ? jsResolutionOrder : tsResolutionOrder | ||
| ); | ||
| if (absoluteFile === null) return; | ||
| if (fromAlias) { | ||
| opts.foundModuleAliases.set(fromAlias, absoluteFile); | ||
| } | ||
| if (seen.size > 1 && seen.has(absoluteFile)) return; | ||
| seen.add(absoluteFile); | ||
| const contents = fs.readFileSync(absoluteFile, "utf-8"); | ||
| const fileDeps = [ | ||
| ...contents.matchAll(importRegex), | ||
| ...contents.matchAll(importFromRegex), | ||
| ...contents.matchAll(requireRegex), | ||
| ...contents.matchAll(exportRegex) | ||
| ]; | ||
| if (!fileDeps.length) return; | ||
| const nextOpts = { | ||
| // Resolve new base for new imports/requires | ||
| cwd: path.dirname(absoluteFile), | ||
| ext: path.extname(absoluteFile), | ||
| seen, | ||
| baseUrl: opts.baseUrl, | ||
| pathMappings: opts.pathMappings, | ||
| foundModuleAliases: opts.foundModuleAliases | ||
| }; | ||
| fileDeps.forEach((match) => { | ||
| const mod = match[1]; | ||
| if (mod[0] === ".") { | ||
| getDeps(Object.assign({}, nextOpts, { filename: mod })); | ||
| return; | ||
| } | ||
| try { | ||
| const found = ts.resolveModuleName(mod, absoluteFile, compilerOptions, ts.sys).resolvedModule; | ||
| if (found && found.extension.endsWith("ts")) { | ||
| getDeps(Object.assign({}, nextOpts, { filename: found.resolvedFileName })); | ||
| return; | ||
| } | ||
| if (!opts.pathMappings) return; | ||
| const filename2 = resolveTsPathPattern(opts.pathMappings, mod); | ||
| if (!filename2) return; | ||
| getDeps(Object.assign({}, nextOpts, { filename: filename2 }), mod); | ||
| } catch { | ||
| } | ||
| }); | ||
| const { filename, seen } = opts; | ||
| const { moduleResolution: _, ...compilerOptions } = opts.compilerOptions ?? {}; | ||
| const absoluteFile = resolveWithExtension(path.resolve(opts.cwd, filename), jsExtensions.includes(opts.ext) ? jsResolutionOrder : tsResolutionOrder); | ||
| if (absoluteFile === null) return; | ||
| if (fromAlias) opts.foundModuleAliases.set(fromAlias, absoluteFile); | ||
| if (seen.size > 1 && seen.has(absoluteFile)) return; | ||
| seen.add(absoluteFile); | ||
| const contents = fs.readFileSync(absoluteFile, "utf-8"); | ||
| const fileDeps = [ | ||
| ...contents.matchAll(importRegex), | ||
| ...contents.matchAll(importFromRegex), | ||
| ...contents.matchAll(requireRegex), | ||
| ...contents.matchAll(exportRegex) | ||
| ]; | ||
| if (!fileDeps.length) return; | ||
| const nextOpts = { | ||
| cwd: path.dirname(absoluteFile), | ||
| ext: path.extname(absoluteFile), | ||
| seen, | ||
| baseUrl: opts.baseUrl, | ||
| pathMappings: opts.pathMappings, | ||
| foundModuleAliases: opts.foundModuleAliases | ||
| }; | ||
| fileDeps.forEach((match) => { | ||
| const mod = match[1]; | ||
| if (mod[0] === ".") { | ||
| getDeps(Object.assign({}, nextOpts, { filename: mod })); | ||
| return; | ||
| } | ||
| try { | ||
| const found = ts.resolveModuleName(mod, absoluteFile, compilerOptions, ts.sys).resolvedModule; | ||
| if (found && found.extension.endsWith("ts")) { | ||
| getDeps(Object.assign({}, nextOpts, { filename: found.resolvedFileName })); | ||
| return; | ||
| } | ||
| if (!opts.pathMappings) return; | ||
| const filename = resolveTsPathPattern(opts.pathMappings, mod); | ||
| if (!filename) return; | ||
| getDeps(Object.assign({}, nextOpts, { filename }), mod); | ||
| } catch {} | ||
| }); | ||
| } | ||
| function getConfigDependencies(filePath, tsOptions = { pathMappings: [] }, compilerOptions) { | ||
| if (filePath === null) return { deps: /* @__PURE__ */ new Set(), aliases: /* @__PURE__ */ new Map() }; | ||
| const foundModuleAliases = /* @__PURE__ */ new Map(); | ||
| const deps = /* @__PURE__ */ new Set(); | ||
| deps.add(filePath); | ||
| getDeps({ | ||
| filename: filePath, | ||
| ext: path.extname(filePath), | ||
| cwd: path.dirname(filePath), | ||
| seen: deps, | ||
| baseUrl: tsOptions.baseUrl, | ||
| pathMappings: tsOptions.pathMappings ?? [], | ||
| foundModuleAliases, | ||
| compilerOptions | ||
| }); | ||
| return { deps, aliases: foundModuleAliases }; | ||
| if (filePath === null) return { | ||
| deps: /* @__PURE__ */ new Set(), | ||
| aliases: /* @__PURE__ */ new Map() | ||
| }; | ||
| const foundModuleAliases = /* @__PURE__ */ new Map(); | ||
| const deps = /* @__PURE__ */ new Set(); | ||
| deps.add(filePath); | ||
| getDeps({ | ||
| filename: filePath, | ||
| ext: path.extname(filePath), | ||
| cwd: path.dirname(filePath), | ||
| seen: deps, | ||
| baseUrl: tsOptions.baseUrl, | ||
| pathMappings: tsOptions.pathMappings ?? [], | ||
| foundModuleAliases, | ||
| compilerOptions | ||
| }); | ||
| return { | ||
| deps, | ||
| aliases: foundModuleAliases | ||
| }; | ||
| } | ||
| // src/get-resolved-config.ts | ||
| import { omit, pick, traverse } from "@bamboocss/shared"; | ||
| var hookUtils = { | ||
| omit, | ||
| pick, | ||
| traverse | ||
| //#endregion | ||
| //#region src/get-resolved-config.ts | ||
| const hookUtils$1 = { | ||
| omit, | ||
| pick, | ||
| traverse | ||
| }; | ||
| /** | ||
| * Recursively merge all presets into a single config (depth-first using stack) | ||
| */ | ||
| async function getResolvedConfig(config, cwd, hooks) { | ||
| const stack = [config]; | ||
| const configs = []; | ||
| while (stack.length > 0) { | ||
| const current = stack.pop(); | ||
| const subPresets = current.presets ?? []; | ||
| for (const subPreset of subPresets) { | ||
| let presetConfig; | ||
| let presetName; | ||
| if (typeof subPreset === "string") { | ||
| const presetModule = await bundle(subPreset, cwd); | ||
| presetConfig = presetModule.config; | ||
| presetName = subPreset; | ||
| } else { | ||
| presetConfig = await subPreset; | ||
| presetName = presetConfig.name || "unknown-preset"; | ||
| } | ||
| if (hooks?.["preset:resolved"]) { | ||
| const resolvedPreset = await hooks["preset:resolved"]({ | ||
| preset: presetConfig, | ||
| name: presetName, | ||
| utils: hookUtils | ||
| }); | ||
| if (resolvedPreset !== void 0) { | ||
| presetConfig = resolvedPreset; | ||
| } | ||
| } | ||
| stack.push(presetConfig); | ||
| } | ||
| configs.unshift(current); | ||
| } | ||
| const merged = mergeConfigs(configs); | ||
| merged.presets = configs.slice(0, -1); | ||
| return merged; | ||
| const stack = [config]; | ||
| const configs = []; | ||
| while (stack.length > 0) { | ||
| const current = stack.pop(); | ||
| const subPresets = current.presets ?? []; | ||
| for (const subPreset of subPresets) { | ||
| let presetConfig; | ||
| let presetName; | ||
| if (typeof subPreset === "string") { | ||
| presetConfig = (await bundle(subPreset, cwd)).config; | ||
| presetName = subPreset; | ||
| } else { | ||
| presetConfig = await subPreset; | ||
| presetName = presetConfig.name || "unknown-preset"; | ||
| } | ||
| if (hooks?.["preset:resolved"]) { | ||
| const resolvedPreset = await hooks["preset:resolved"]({ | ||
| preset: presetConfig, | ||
| name: presetName, | ||
| utils: hookUtils$1 | ||
| }); | ||
| if (resolvedPreset !== void 0) presetConfig = resolvedPreset; | ||
| } | ||
| stack.push(presetConfig); | ||
| } | ||
| configs.unshift(current); | ||
| } | ||
| const merged = mergeConfigs(configs); | ||
| merged.presets = configs.slice(0, -1); | ||
| return merged; | ||
| } | ||
| // src/resolve-config.ts | ||
| import { logger as logger3 } from "@bamboocss/logger"; | ||
| import { BAMBOO_CONFIG_NAME, omit as omit2, parseJson, pick as pick2, stringifyJson, traverse as traverse2 } from "@bamboocss/shared"; | ||
| // src/bundled-preset.ts | ||
| import { preset as presetBase } from "@bamboocss/preset-base"; | ||
| import { preset as presetBamboo } from "@bamboocss/preset-bamboo"; | ||
| var bundledPresets = { | ||
| "@bamboocss/preset-base": presetBase, | ||
| "@bamboocss/preset-bamboo": presetBamboo, | ||
| "@bamboocss/dev/presets": presetBamboo | ||
| //#endregion | ||
| //#region src/bundled-preset.ts | ||
| const bundledPresets = { | ||
| "@bamboocss/preset-base": presetBase, | ||
| "@bamboocss/preset-bamboo": presetBamboo, | ||
| "@bamboocss/dev/presets": presetBamboo | ||
| }; | ||
| var bundledPresetsNames = Object.keys(bundledPresets); | ||
| var isBundledPreset = (preset) => bundledPresetsNames.includes(preset); | ||
| var getBundledPreset = (preset) => { | ||
| return typeof preset === "string" && isBundledPreset(preset) ? bundledPresets[preset] : void 0; | ||
| const bundledPresetsNames = Object.keys(bundledPresets); | ||
| const isBundledPreset = (preset) => bundledPresetsNames.includes(preset); | ||
| const getBundledPreset = (preset) => { | ||
| return typeof preset === "string" && isBundledPreset(preset) ? bundledPresets[preset] : void 0; | ||
| }; | ||
| // src/validate-config.ts | ||
| import { logger as logger2 } from "@bamboocss/logger"; | ||
| import { BambooError as BambooError3 } from "@bamboocss/shared"; | ||
| // src/validation/validate-artifact.ts | ||
| var validateArtifactNames = (names, addError) => { | ||
| names.recipes.forEach((recipeName) => { | ||
| if (names.slotRecipes.has(recipeName)) { | ||
| addError("recipes", `This recipe name is already used in \`theme.slotRecipes\`: ${recipeName}`); | ||
| } | ||
| if (names.patterns.has(recipeName)) { | ||
| addError("recipes", `This recipe name is already used in \`patterns\`: \`${recipeName}\``); | ||
| } | ||
| }); | ||
| names.slotRecipes.forEach((recipeName) => { | ||
| if (names.patterns.has(recipeName)) { | ||
| addError("recipes", `This recipe name is already used in \`patterns\`: ${recipeName}`); | ||
| } | ||
| }); | ||
| //#endregion | ||
| //#region src/validation/validate-artifact.ts | ||
| const validateArtifactNames = (names, addError) => { | ||
| names.recipes.forEach((recipeName) => { | ||
| if (names.slotRecipes.has(recipeName)) addError("recipes", `This recipe name is already used in \`theme.slotRecipes\`: ${recipeName}`); | ||
| if (names.patterns.has(recipeName)) addError("recipes", `This recipe name is already used in \`patterns\`: \`${recipeName}\``); | ||
| }); | ||
| names.slotRecipes.forEach((recipeName) => { | ||
| if (names.patterns.has(recipeName)) addError("recipes", `This recipe name is already used in \`patterns\`: ${recipeName}`); | ||
| }); | ||
| }; | ||
| // src/validation/validate-breakpoints.ts | ||
| import { getUnit } from "@bamboocss/shared"; | ||
| var validateBreakpoints = (breakpoints, addError) => { | ||
| if (!breakpoints) return; | ||
| const units = /* @__PURE__ */ new Set(); | ||
| const values = Object.values(breakpoints); | ||
| for (const value of values) { | ||
| const unit = getUnit(value) ?? "px"; | ||
| units.add(unit); | ||
| } | ||
| if (units.size > 1) { | ||
| addError("breakpoints", `All breakpoints must use the same unit: \`${values.join(", ")}\``); | ||
| } | ||
| //#endregion | ||
| //#region src/validation/validate-breakpoints.ts | ||
| const validateBreakpoints = (breakpoints, addError) => { | ||
| if (!breakpoints) return; | ||
| const units = /* @__PURE__ */ new Set(); | ||
| const values = Object.values(breakpoints); | ||
| for (const value of values) { | ||
| const unit = getUnit(value) ?? "px"; | ||
| units.add(unit); | ||
| } | ||
| if (units.size > 1) addError("breakpoints", `All breakpoints must use the same unit: \`${values.join(", ")}\``); | ||
| }; | ||
| // src/validation/validate-condition.ts | ||
| import { isString } from "@bamboocss/shared"; | ||
| var validateObjectCondition = (obj, addError) => { | ||
| let hasSlot = false; | ||
| for (const [key, value] of Object.entries(obj)) { | ||
| if (!key.startsWith("@") && !key.includes("&")) { | ||
| addError("conditions", `Selectors should contain the \`&\` character: \`${key}\``); | ||
| } | ||
| if (value === "@slot") { | ||
| hasSlot = true; | ||
| continue; | ||
| } | ||
| if (typeof value === "string") { | ||
| addError( | ||
| "conditions", | ||
| `Object condition leaves must be the literal string \`'@slot'\`, got \`${JSON.stringify(value)}\` at \`${key}\`` | ||
| ); | ||
| continue; | ||
| } | ||
| if (typeof value === "object" && value !== null) { | ||
| const nested = validateObjectCondition(value, addError); | ||
| if (nested.hasSlot) hasSlot = true; | ||
| } | ||
| } | ||
| return { hasSlot }; | ||
| //#endregion | ||
| //#region src/validation/validate-condition.ts | ||
| const validateObjectCondition = (obj, addError) => { | ||
| let hasSlot = false; | ||
| for (const [key, value] of Object.entries(obj)) { | ||
| if (!key.startsWith("@") && !key.includes("&")) addError("conditions", `Selectors should contain the \`&\` character: \`${key}\``); | ||
| if (value === "@slot") { | ||
| hasSlot = true; | ||
| continue; | ||
| } | ||
| if (typeof value === "string") { | ||
| addError("conditions", `Object condition leaves must be the literal string \`'@slot'\`, got \`${JSON.stringify(value)}\` at \`${key}\``); | ||
| continue; | ||
| } | ||
| if (typeof value === "object" && value !== null) { | ||
| if (validateObjectCondition(value, addError).hasSlot) hasSlot = true; | ||
| } | ||
| } | ||
| return { hasSlot }; | ||
| }; | ||
| var validateConditions = (conditions, addError) => { | ||
| if (!conditions) return; | ||
| Object.values(conditions).forEach((condition) => { | ||
| if (isString(condition)) { | ||
| if (!condition.startsWith("@") && !condition.includes("&")) { | ||
| addError("conditions", `Selectors should contain the \`&\` character: \`${condition}\``); | ||
| } | ||
| return; | ||
| } | ||
| if (Array.isArray(condition)) { | ||
| condition.forEach((c) => { | ||
| if (!c.startsWith("@") && !c.includes("&")) { | ||
| addError("conditions", `Selectors should contain the \`&\` character: \`${c}\``); | ||
| } | ||
| }); | ||
| return; | ||
| } | ||
| const { hasSlot } = validateObjectCondition(condition, addError); | ||
| if (!hasSlot) { | ||
| addError("conditions", `Object conditions must contain at least one \`'@slot'\` marker`); | ||
| } | ||
| }); | ||
| const validateConditions = (conditions, addError) => { | ||
| if (!conditions) return; | ||
| Object.values(conditions).forEach((condition) => { | ||
| if (isString(condition)) { | ||
| if (!condition.startsWith("@") && !condition.includes("&")) addError("conditions", `Selectors should contain the \`&\` character: \`${condition}\``); | ||
| return; | ||
| } | ||
| if (Array.isArray(condition)) { | ||
| condition.forEach((c) => { | ||
| if (!c.startsWith("@") && !c.includes("&")) addError("conditions", `Selectors should contain the \`&\` character: \`${c}\``); | ||
| }); | ||
| return; | ||
| } | ||
| const { hasSlot } = validateObjectCondition(condition, addError); | ||
| if (!hasSlot) addError("conditions", `Object conditions must contain at least one \`'@slot'\` marker`); | ||
| }); | ||
| }; | ||
| // src/validation/validate-patterns.ts | ||
| var validatePatterns = (patterns, names) => { | ||
| if (!patterns) return; | ||
| Object.keys(patterns).forEach((patternName) => { | ||
| names.patterns.add(patternName); | ||
| }); | ||
| //#endregion | ||
| //#region src/validation/validate-patterns.ts | ||
| const validatePatterns = (patterns, names) => { | ||
| if (!patterns) return; | ||
| Object.keys(patterns).forEach((patternName) => { | ||
| names.patterns.add(patternName); | ||
| }); | ||
| }; | ||
| // src/validation/validate-recipes.ts | ||
| var validateRecipes = (options) => { | ||
| const { | ||
| config: { theme }, | ||
| artifacts | ||
| } = options; | ||
| if (!theme) return; | ||
| if (theme.recipes) { | ||
| Object.keys(theme.recipes).forEach((recipeName) => { | ||
| artifacts.recipes.add(recipeName); | ||
| }); | ||
| } | ||
| if (theme.slotRecipes) { | ||
| Object.keys(theme.slotRecipes).forEach((recipeName) => { | ||
| artifacts.slotRecipes.add(recipeName); | ||
| }); | ||
| } | ||
| return artifacts; | ||
| //#endregion | ||
| //#region src/validation/validate-recipes.ts | ||
| const validateRecipes = (options) => { | ||
| const { config: { theme }, artifacts } = options; | ||
| if (!theme) return; | ||
| if (theme.recipes) Object.keys(theme.recipes).forEach((recipeName) => { | ||
| artifacts.recipes.add(recipeName); | ||
| }); | ||
| if (theme.slotRecipes) Object.keys(theme.slotRecipes).forEach((recipeName) => { | ||
| artifacts.slotRecipes.add(recipeName); | ||
| }); | ||
| return artifacts; | ||
| }; | ||
| // src/validation/validate-tokens.ts | ||
| import { isObject, walkObject } from "@bamboocss/shared"; | ||
| // src/validation/validate-token-references.ts | ||
| var validateTokenReferences = (props) => { | ||
| const { valueAtPath, refsByPath, addError, typeByPath } = props; | ||
| refsByPath.forEach((refs, path2) => { | ||
| if (refs.has(path2)) { | ||
| addError("tokens", `Self token reference: \`${path2}\``); | ||
| } | ||
| const stack = [path2]; | ||
| while (stack.length > 0) { | ||
| let currentPath = stack.pop(); | ||
| if (currentPath.includes("/")) { | ||
| const [tokenPath] = currentPath.split("/"); | ||
| currentPath = tokenPath; | ||
| } | ||
| const value = valueAtPath.get(currentPath); | ||
| if (!value) { | ||
| const configKey = typeByPath.get(path2); | ||
| addError("tokens", `Missing token: \`${currentPath}\` used in \`theme.${configKey}.${path2}\``); | ||
| } | ||
| if (isTokenReference(value) && !refsByPath.has(value)) { | ||
| addError("tokens", `Unknown token reference: \`${currentPath}\` used in \`${value}\``); | ||
| } | ||
| const deps = refsByPath.get(currentPath); | ||
| if (!deps) continue; | ||
| for (const transitiveDep of deps) { | ||
| if (path2 === transitiveDep) { | ||
| addError( | ||
| "tokens", | ||
| `Circular token reference: \`${transitiveDep}\` -> \`${currentPath}\` -> ... -> \`${path2}\`` | ||
| ); | ||
| break; | ||
| } | ||
| stack.push(transitiveDep); | ||
| } | ||
| } | ||
| }); | ||
| //#endregion | ||
| //#region src/validation/validate-token-references.ts | ||
| const validateTokenReferences = (props) => { | ||
| const { valueAtPath, refsByPath, addError, typeByPath } = props; | ||
| refsByPath.forEach((refs, path) => { | ||
| if (refs.has(path)) addError("tokens", `Self token reference: \`${path}\``); | ||
| const stack = [path]; | ||
| while (stack.length > 0) { | ||
| let currentPath = stack.pop(); | ||
| if (currentPath.includes("/")) { | ||
| const [tokenPath] = currentPath.split("/"); | ||
| currentPath = tokenPath; | ||
| } | ||
| const value = valueAtPath.get(currentPath); | ||
| if (!value) { | ||
| const configKey = typeByPath.get(path); | ||
| addError("tokens", `Missing token: \`${currentPath}\` used in \`theme.${configKey}.${path}\``); | ||
| } | ||
| if (isTokenReference(value) && !refsByPath.has(value)) addError("tokens", `Unknown token reference: \`${currentPath}\` used in \`${value}\``); | ||
| const deps = refsByPath.get(currentPath); | ||
| if (!deps) continue; | ||
| for (const transitiveDep of deps) { | ||
| if (path === transitiveDep) { | ||
| addError("tokens", `Circular token reference: \`${transitiveDep}\` -> \`${currentPath}\` -> ... -> \`${path}\``); | ||
| break; | ||
| } | ||
| stack.push(transitiveDep); | ||
| } | ||
| } | ||
| }); | ||
| }; | ||
| // src/validation/validate-tokens.ts | ||
| var validateTokens = (options) => { | ||
| const { | ||
| config: { theme }, | ||
| tokens, | ||
| addError | ||
| } = options; | ||
| if (!theme) return; | ||
| const { tokenNames, semanticTokenNames, valueAtPath, refsByPath, typeByPath } = tokens; | ||
| if (theme.tokens) { | ||
| const tokenPaths = /* @__PURE__ */ new Set(); | ||
| walkObject( | ||
| theme.tokens, | ||
| (value, paths) => { | ||
| const path2 = paths.join(SEP); | ||
| tokenNames.add(path2); | ||
| tokenPaths.add(path2); | ||
| valueAtPath.set(path2, value); | ||
| if (path2.includes("DEFAULT")) { | ||
| valueAtPath.set(path2.replace(SEP + "DEFAULT", ""), value); | ||
| } | ||
| }, | ||
| { | ||
| stop: isValidToken | ||
| } | ||
| ); | ||
| tokenPaths.forEach((path2) => { | ||
| const itemValue = valueAtPath.get(path2); | ||
| const formattedPath = formatPath(path2); | ||
| typeByPath.set(formattedPath, "tokens"); | ||
| if (!isValidToken(itemValue)) { | ||
| addError("tokens", `Token must contain 'value': \`theme.tokens.${formattedPath}\``); | ||
| return; | ||
| } | ||
| if (path2.includes(" ")) { | ||
| addError("tokens", `Token key must not contain spaces: \`theme.tokens.${formattedPath}\``); | ||
| return; | ||
| } | ||
| const valueStr = serializeTokenValue(itemValue.value || itemValue); | ||
| if (isTokenReference(valueStr)) { | ||
| refsByPath.set(formattedPath, /* @__PURE__ */ new Set([])); | ||
| } | ||
| const references = refsByPath.get(formattedPath); | ||
| if (!references) return; | ||
| getReferences(valueStr).forEach((reference) => { | ||
| references.add(reference); | ||
| }); | ||
| }); | ||
| } | ||
| if (theme.semanticTokens) { | ||
| const tokenPaths = /* @__PURE__ */ new Set(); | ||
| walkObject( | ||
| theme.semanticTokens, | ||
| (value, paths) => { | ||
| const path2 = paths.join(SEP); | ||
| semanticTokenNames.add(path2); | ||
| valueAtPath.set(path2, value); | ||
| tokenPaths.add(path2); | ||
| if (path2.includes("DEFAULT")) { | ||
| valueAtPath.set(path2.replace(SEP + "DEFAULT", ""), value); | ||
| } | ||
| if (!isValidToken(value)) return; | ||
| walkObject(value, (itemValue, paths2) => { | ||
| const valuePath = paths2.join(SEP); | ||
| const formattedPath = formatPath(path2); | ||
| typeByPath.set(formattedPath, "semanticTokens"); | ||
| const fullPath = formattedPath + "." + paths2.join(SEP); | ||
| if (valuePath.includes("value" + SEP + "value")) { | ||
| addError("tokens", `You used \`value\` twice resulting in an invalid token \`theme.tokens.${fullPath}\``); | ||
| } | ||
| const valueStr = serializeTokenValue(itemValue.value || itemValue); | ||
| if (isTokenReference(valueStr)) { | ||
| if (!refsByPath.has(formattedPath)) { | ||
| refsByPath.set(formattedPath, /* @__PURE__ */ new Set()); | ||
| } | ||
| const references = refsByPath.get(formattedPath); | ||
| if (!references) return; | ||
| getReferences(valueStr).forEach((reference) => { | ||
| references.add(reference); | ||
| }); | ||
| } | ||
| }); | ||
| }, | ||
| { | ||
| stop: isValidToken | ||
| } | ||
| ); | ||
| tokenPaths.forEach((path2) => { | ||
| const formattedPath = formatPath(path2); | ||
| const value = valueAtPath.get(path2); | ||
| if (path2.includes(" ")) { | ||
| addError("tokens", `Token key must not contain spaces: \`theme.tokens.${formattedPath}\``); | ||
| return; | ||
| } | ||
| if (!isObject(value) && !path2.includes("value")) { | ||
| addError("tokens", `Token must contain 'value': \`theme.semanticTokens.${formattedPath}\``); | ||
| } | ||
| }); | ||
| } | ||
| validateTokenReferences({ valueAtPath, refsByPath, addError, typeByPath }); | ||
| //#endregion | ||
| //#region src/validation/validate-tokens.ts | ||
| const validateTokens = (options) => { | ||
| const { config: { theme }, tokens, addError } = options; | ||
| if (!theme) return; | ||
| const { tokenNames, semanticTokenNames, valueAtPath, refsByPath, typeByPath } = tokens; | ||
| if (theme.tokens) { | ||
| const tokenPaths = /* @__PURE__ */ new Set(); | ||
| walkObject(theme.tokens, (value, paths) => { | ||
| const path = paths.join("."); | ||
| tokenNames.add(path); | ||
| tokenPaths.add(path); | ||
| valueAtPath.set(path, value); | ||
| if (path.includes("DEFAULT")) valueAtPath.set(path.replace(".DEFAULT", ""), value); | ||
| }, { stop: isValidToken }); | ||
| tokenPaths.forEach((path) => { | ||
| const itemValue = valueAtPath.get(path); | ||
| const formattedPath = formatPath(path); | ||
| typeByPath.set(formattedPath, "tokens"); | ||
| if (!isValidToken(itemValue)) { | ||
| addError("tokens", `Token must contain 'value': \`theme.tokens.${formattedPath}\``); | ||
| return; | ||
| } | ||
| if (path.includes(" ")) { | ||
| addError("tokens", `Token key must not contain spaces: \`theme.tokens.${formattedPath}\``); | ||
| return; | ||
| } | ||
| const valueStr = serializeTokenValue(itemValue.value || itemValue); | ||
| if (isTokenReference(valueStr)) refsByPath.set(formattedPath, /* @__PURE__ */ new Set([])); | ||
| const references = refsByPath.get(formattedPath); | ||
| if (!references) return; | ||
| getReferences(valueStr).forEach((reference) => { | ||
| references.add(reference); | ||
| }); | ||
| }); | ||
| } | ||
| if (theme.semanticTokens) { | ||
| const tokenPaths = /* @__PURE__ */ new Set(); | ||
| walkObject(theme.semanticTokens, (value, paths) => { | ||
| const path = paths.join("."); | ||
| semanticTokenNames.add(path); | ||
| valueAtPath.set(path, value); | ||
| tokenPaths.add(path); | ||
| if (path.includes("DEFAULT")) valueAtPath.set(path.replace(".DEFAULT", ""), value); | ||
| if (!isValidToken(value)) return; | ||
| walkObject(value, (itemValue, paths) => { | ||
| const valuePath = paths.join("."); | ||
| const formattedPath = formatPath(path); | ||
| typeByPath.set(formattedPath, "semanticTokens"); | ||
| const fullPath = formattedPath + "." + paths.join("."); | ||
| if (valuePath.includes("value.value")) addError("tokens", `You used \`value\` twice resulting in an invalid token \`theme.tokens.${fullPath}\``); | ||
| const valueStr = serializeTokenValue(itemValue.value || itemValue); | ||
| if (isTokenReference(valueStr)) { | ||
| if (!refsByPath.has(formattedPath)) refsByPath.set(formattedPath, /* @__PURE__ */ new Set()); | ||
| const references = refsByPath.get(formattedPath); | ||
| if (!references) return; | ||
| getReferences(valueStr).forEach((reference) => { | ||
| references.add(reference); | ||
| }); | ||
| } | ||
| }); | ||
| }, { stop: isValidToken }); | ||
| tokenPaths.forEach((path) => { | ||
| const formattedPath = formatPath(path); | ||
| const value = valueAtPath.get(path); | ||
| if (path.includes(" ")) { | ||
| addError("tokens", `Token key must not contain spaces: \`theme.tokens.${formattedPath}\``); | ||
| return; | ||
| } | ||
| if (!isObject(value) && !path.includes("value")) addError("tokens", `Token must contain 'value': \`theme.semanticTokens.${formattedPath}\``); | ||
| }); | ||
| } | ||
| validateTokenReferences({ | ||
| valueAtPath, | ||
| refsByPath, | ||
| addError, | ||
| typeByPath | ||
| }); | ||
| }; | ||
| // src/validate-config.ts | ||
| var validateConfig = (config) => { | ||
| if (config.validation === "none") return; | ||
| const warnings = /* @__PURE__ */ new Set(); | ||
| const addError = (scope, message) => { | ||
| warnings.add(`[${scope}] ` + message); | ||
| }; | ||
| validateBreakpoints(config.theme?.breakpoints, addError); | ||
| validateConditions(config.conditions, addError); | ||
| const artifacts = { | ||
| recipes: /* @__PURE__ */ new Set(), | ||
| slotRecipes: /* @__PURE__ */ new Set(), | ||
| patterns: /* @__PURE__ */ new Set() | ||
| }; | ||
| const tokens = { | ||
| tokenNames: /* @__PURE__ */ new Set(), | ||
| semanticTokenNames: /* @__PURE__ */ new Set(), | ||
| valueAtPath: /* @__PURE__ */ new Map(), | ||
| refsByPath: /* @__PURE__ */ new Map(), | ||
| typeByPath: /* @__PURE__ */ new Map() | ||
| }; | ||
| if (config.theme) { | ||
| validateTokens({ config, tokens, addError }); | ||
| validateRecipes({ config, tokens, artifacts, addError }); | ||
| } | ||
| validatePatterns(config.patterns, artifacts); | ||
| validateArtifactNames(artifacts, addError); | ||
| if (warnings.size) { | ||
| const errors = `\u26A0\uFE0F Invalid config: | ||
| ${Array.from(warnings).map((err) => "- " + err).join("\n")} | ||
| `; | ||
| if (config.validation === "error") { | ||
| throw new BambooError3("CONFIG_ERROR", errors); | ||
| } | ||
| logger2.warn("config", errors); | ||
| return warnings; | ||
| } | ||
| //#endregion | ||
| //#region src/validate-config.ts | ||
| /** | ||
| * Validate the config | ||
| * - Check for duplicate between token & semanticTokens names | ||
| * - Check for duplicate between recipes/patterns/slots names | ||
| * - Check for token / semanticTokens paths (must end/contain 'value') | ||
| * - Check for self/circular token references | ||
| * - Check for missing tokens references | ||
| * - Check for conditions selectors (must contain '&') | ||
| * - Check for breakpoints units (must be the same) | ||
| */ | ||
| const validateConfig = (config) => { | ||
| if (config.validation === "none") return; | ||
| const warnings = /* @__PURE__ */ new Set(); | ||
| const addError = (scope, message) => { | ||
| warnings.add(`[${scope}] ` + message); | ||
| }; | ||
| validateBreakpoints(config.theme?.breakpoints, addError); | ||
| validateConditions(config.conditions, addError); | ||
| const artifacts = { | ||
| recipes: /* @__PURE__ */ new Set(), | ||
| slotRecipes: /* @__PURE__ */ new Set(), | ||
| patterns: /* @__PURE__ */ new Set() | ||
| }; | ||
| const tokens = { | ||
| tokenNames: /* @__PURE__ */ new Set(), | ||
| semanticTokenNames: /* @__PURE__ */ new Set(), | ||
| valueAtPath: /* @__PURE__ */ new Map(), | ||
| refsByPath: /* @__PURE__ */ new Map(), | ||
| typeByPath: /* @__PURE__ */ new Map() | ||
| }; | ||
| if (config.theme) { | ||
| validateTokens({ | ||
| config, | ||
| tokens, | ||
| addError | ||
| }); | ||
| validateRecipes({ | ||
| config, | ||
| tokens, | ||
| artifacts, | ||
| addError | ||
| }); | ||
| } | ||
| validatePatterns(config.patterns, artifacts); | ||
| validateArtifactNames(artifacts, addError); | ||
| if (warnings.size) { | ||
| const errors = `⚠️ Invalid config:\n${Array.from(warnings).map((err) => "- " + err).join("\n")}\n`; | ||
| if (config.validation === "error") throw new BambooError("CONFIG_ERROR", errors); | ||
| logger.warn("config", errors); | ||
| return warnings; | ||
| } | ||
| }; | ||
| // src/resolve-config.ts | ||
| var hookUtils2 = { | ||
| omit: omit2, | ||
| pick: pick2, | ||
| traverse: traverse2 | ||
| //#endregion | ||
| //#region src/resolve-config.ts | ||
| const hookUtils = { | ||
| omit, | ||
| pick, | ||
| traverse | ||
| }; | ||
| /** | ||
| * Resolve the final config (including presets) | ||
| * @bamboocss/preset-base: ALWAYS included if NOT using eject: true | ||
| * @bamboocss/preset-bamboo: only included by default if no presets | ||
| */ | ||
| async function resolveConfig(result, cwd) { | ||
| const presets = /* @__PURE__ */ new Set(); | ||
| if (!result.config.eject) { | ||
| presets.add(presetBase); | ||
| } | ||
| if (result.config.presets) { | ||
| result.config.presets.forEach((preset) => { | ||
| presets.add(getBundledPreset(preset) ?? preset); | ||
| }); | ||
| } else if (!result.config.eject) { | ||
| presets.add(presetBamboo); | ||
| } | ||
| result.config.presets = Array.from(presets); | ||
| const userConfig = result.config; | ||
| const pluginHooks = userConfig.plugins ?? []; | ||
| if (userConfig.hooks) { | ||
| pluginHooks.push({ name: BAMBOO_CONFIG_NAME, hooks: userConfig.hooks }); | ||
| } | ||
| const earlyHooks = mergeHooks(pluginHooks); | ||
| const mergedConfig = await getResolvedConfig(result.config, cwd, earlyHooks); | ||
| const hooks = mergedConfig.hooks ?? {}; | ||
| if (mergedConfig.logLevel) { | ||
| logger3.level = mergedConfig.logLevel; | ||
| } | ||
| validateConfig(mergedConfig); | ||
| const loadConfigResult = { | ||
| ...result, | ||
| config: mergedConfig | ||
| }; | ||
| if (hooks["config:resolved"]) { | ||
| const result2 = await hooks["config:resolved"]({ | ||
| config: loadConfigResult.config, | ||
| path: loadConfigResult.path, | ||
| dependencies: loadConfigResult.dependencies, | ||
| utils: hookUtils2 | ||
| }); | ||
| if (result2) { | ||
| loadConfigResult.config = result2; | ||
| } | ||
| } | ||
| const serialized = stringifyJson( | ||
| Object.assign({}, loadConfigResult.config, { name: BAMBOO_CONFIG_NAME, presets: [] }) | ||
| ); | ||
| const deserialize = () => parseJson(serialized); | ||
| return { ...loadConfigResult, serialized, deserialize, hooks }; | ||
| const presets = /* @__PURE__ */ new Set(); | ||
| if (!result.config.eject) presets.add(presetBase); | ||
| if (result.config.presets) result.config.presets.forEach((preset) => { | ||
| presets.add(getBundledPreset(preset) ?? preset); | ||
| }); | ||
| else if (!result.config.eject) presets.add(presetBamboo); | ||
| result.config.presets = Array.from(presets); | ||
| const userConfig = result.config; | ||
| const pluginHooks = userConfig.plugins ?? []; | ||
| if (userConfig.hooks) pluginHooks.push({ | ||
| name: BAMBOO_CONFIG_NAME, | ||
| hooks: userConfig.hooks | ||
| }); | ||
| const earlyHooks = mergeHooks(pluginHooks); | ||
| const mergedConfig = await getResolvedConfig(result.config, cwd, earlyHooks); | ||
| const hooks = mergedConfig.hooks ?? {}; | ||
| if (mergedConfig.logLevel) logger.level = mergedConfig.logLevel; | ||
| validateConfig(mergedConfig); | ||
| const loadConfigResult = { | ||
| ...result, | ||
| config: mergedConfig | ||
| }; | ||
| if (hooks["config:resolved"]) { | ||
| const result = await hooks["config:resolved"]({ | ||
| config: loadConfigResult.config, | ||
| path: loadConfigResult.path, | ||
| dependencies: loadConfigResult.dependencies, | ||
| utils: hookUtils | ||
| }); | ||
| if (result) loadConfigResult.config = result; | ||
| } | ||
| const serialized = stringifyJson(Object.assign({}, loadConfigResult.config, { | ||
| name: BAMBOO_CONFIG_NAME, | ||
| presets: [] | ||
| })); | ||
| const deserialize = () => parseJson(serialized); | ||
| return { | ||
| ...loadConfigResult, | ||
| serialized, | ||
| deserialize, | ||
| hooks | ||
| }; | ||
| } | ||
| // src/load-config.ts | ||
| //#endregion | ||
| //#region src/load-config.ts | ||
| /** | ||
| * Find, load and resolve the final config (including presets) | ||
| */ | ||
| async function loadConfig(options) { | ||
| const result = await bundleConfig(options); | ||
| return resolveConfig(result, options.cwd); | ||
| return resolveConfig(await bundleConfig(options), options.cwd); | ||
| } | ||
| export { | ||
| bundleConfig, | ||
| convertTsPathsToRegexes, | ||
| diffConfigs, | ||
| findConfig, | ||
| getConfigDependencies, | ||
| getResolvedConfig, | ||
| loadConfig, | ||
| mergeConfigs, | ||
| mergeHooks, | ||
| resolveConfig | ||
| }; | ||
| //#endregion | ||
| export { bundleConfig, convertTsPathsToRegexes, diffConfigs, findConfig, getConfigDependencies, getResolvedConfig, loadConfig, mergeConfigs, mergeHooks, resolveConfig }; |
@@ -1,8 +0,2 @@ | ||
| import { | ||
| mergeConfigs, | ||
| mergeHooks | ||
| } from "./chunk-RIBK22OM.mjs"; | ||
| export { | ||
| mergeConfigs, | ||
| mergeHooks | ||
| }; | ||
| import { s as mergeHooks, t as mergeConfigs } from "./merge-config-DI__LOWx.mjs"; | ||
| export { mergeConfigs, mergeHooks }; |
@@ -1,6 +0,19 @@ | ||
| import { | ||
| resolveTsPathPattern | ||
| } from "./chunk-RPIVZP2I.mjs"; | ||
| export { | ||
| resolveTsPathPattern | ||
| import { posix, sep } from "path"; | ||
| //#region src/resolve-ts-path-pattern.ts | ||
| /** | ||
| * @see https://github.com/aleclarson/vite-tsconfig-paths/blob/e8f0acf7adfcfbf77edbe937f64b4e5d39557ad0/src/index.ts#LL231C57-L231C57 | ||
| */ | ||
| const resolveTsPathPattern = (pathMappings, moduleSpecifier) => { | ||
| for (const mapping of pathMappings) { | ||
| const match = moduleSpecifier.match(mapping.pattern); | ||
| if (!match) continue; | ||
| for (const pathTemplate of mapping.paths) { | ||
| let starCount = 0; | ||
| return pathTemplate.replace(/\*/g, () => { | ||
| return match[Math.min(++starCount, match.length - 1)]; | ||
| }).split(sep).join(posix.sep); | ||
| } | ||
| } | ||
| }; | ||
| //#endregion | ||
| export { resolveTsPathPattern }; |
+19
-19
| { | ||
| "name": "@bamboocss/config", | ||
| "version": "1.11.1", | ||
| "version": "1.11.2", | ||
| "description": "Find and load bamboo config", | ||
@@ -10,3 +10,3 @@ "homepage": "https://bamboo-css.com", | ||
| "type": "git", | ||
| "url": "git+https://github.com/chakra-ui/bamboo.git", | ||
| "url": "git+https://github.com/bamboocss/bamboo.git", | ||
| "directory": "packages/config" | ||
@@ -18,10 +18,10 @@ }, | ||
| "sideEffects": false, | ||
| "main": "dist/index.js", | ||
| "main": "dist/index.cjs", | ||
| "module": "dist/index.mjs", | ||
| "types": "dist/index.d.ts", | ||
| "types": "dist/index.d.cts", | ||
| "exports": { | ||
| ".": { | ||
| "source": "./src/index.ts", | ||
| "types": "./dist/index.d.ts", | ||
| "require": "./dist/index.js", | ||
| "types": "./dist/index.d.cts", | ||
| "require": "./dist/index.cjs", | ||
| "import": { | ||
@@ -34,4 +34,4 @@ "types": "./dist/index.d.mts", | ||
| "source": "./src/merge-config.ts", | ||
| "types": "./dist/merge-config.d.ts", | ||
| "require": "./dist/merge-config.js", | ||
| "types": "./dist/merge-config.d.cts", | ||
| "require": "./dist/merge-config.cjs", | ||
| "import": { | ||
@@ -44,4 +44,4 @@ "types": "./dist/merge-config.d.mts", | ||
| "source": "./src/diff-config.ts", | ||
| "types": "./dist/diff-config.d.ts", | ||
| "require": "./dist/diff-config.js", | ||
| "types": "./dist/diff-config.d.cts", | ||
| "require": "./dist/diff-config.cjs", | ||
| "import": { | ||
@@ -54,4 +54,4 @@ "types": "./dist/diff-config.d.mts", | ||
| "source": "./src/resolve-ts-path-pattern.ts", | ||
| "types": "./dist/resolve-ts-path-pattern.d.ts", | ||
| "require": "./dist/resolve-ts-path-pattern.js", | ||
| "types": "./dist/resolve-ts-path-pattern.d.cts", | ||
| "require": "./dist/resolve-ts-path-pattern.cjs", | ||
| "import": { | ||
@@ -72,7 +72,7 @@ "types": "./dist/resolve-ts-path-pattern.d.mts", | ||
| "typescript": "6.0.2", | ||
| "@bamboocss/logger": "1.11.1", | ||
| "@bamboocss/preset-base": "1.11.1", | ||
| "@bamboocss/preset-bamboo": "1.11.1", | ||
| "@bamboocss/shared": "1.11.1", | ||
| "@bamboocss/types": "1.11.1" | ||
| "@bamboocss/logger": "1.11.2", | ||
| "@bamboocss/preset-base": "1.11.2", | ||
| "@bamboocss/preset-bamboo": "1.11.2", | ||
| "@bamboocss/shared": "1.11.2", | ||
| "@bamboocss/types": "1.11.2" | ||
| }, | ||
@@ -83,6 +83,6 @@ "devDependencies": { | ||
| "scripts": { | ||
| "build": "tsup --tsconfig tsconfig.build.json --dts", | ||
| "build-fast": "tsup --no-dts", | ||
| "build": "tsdown --tsconfig tsconfig.build.json --dts", | ||
| "build-fast": "tsdown --dts=false", | ||
| "dev": "pnpm build-fast --watch" | ||
| } | ||
| } |
| // src/diff-config.ts | ||
| import { dashCase } from "@bamboocss/shared"; | ||
| import microdiff from "microdiff"; | ||
| // src/create-matcher.ts | ||
| function createMatcher(id, patterns) { | ||
| if (!patterns?.length) return () => void 0; | ||
| const includePatterns = []; | ||
| const excludePatterns = []; | ||
| const deduped = new Set(patterns); | ||
| deduped.forEach((pattern) => { | ||
| const regexString = pattern.replace(/\*/g, ".*"); | ||
| if (pattern.startsWith("!")) { | ||
| excludePatterns.push(regexString.slice(1)); | ||
| } else { | ||
| includePatterns.push(regexString); | ||
| } | ||
| }); | ||
| const include = new RegExp(includePatterns.join("|")); | ||
| const exclude = new RegExp(excludePatterns.join("|")); | ||
| return (path) => { | ||
| if (excludePatterns.length && exclude.test(path)) return; | ||
| return include.test(path) ? id : void 0; | ||
| }; | ||
| } | ||
| // src/config-deps.ts | ||
| var all = [ | ||
| "clean", | ||
| "cwd", | ||
| "eject", | ||
| "outdir", | ||
| "forceConsistentTypeExtension", | ||
| "outExtension", | ||
| "emitTokensOnly", | ||
| "presets", | ||
| "plugins", | ||
| "hooks" | ||
| ]; | ||
| var format = [ | ||
| "syntax", | ||
| "hash", | ||
| "prefix", | ||
| "separator", | ||
| "strictTokens", | ||
| "strictPropertyValues", | ||
| "shorthands" | ||
| ]; | ||
| var tokens = [ | ||
| "utilities", | ||
| "conditions", | ||
| "theme.tokens", | ||
| "theme.semanticTokens", | ||
| "theme.breakpoints", | ||
| "theme.containerNames", | ||
| "theme.containerSizes" | ||
| ]; | ||
| var jsx = ["jsxFramework", "jsxFactory", "jsxStyleProps", "syntax"]; | ||
| var common = tokens.concat(jsx, format); | ||
| var artifactConfigDeps = { | ||
| helpers: ["syntax", "jsxFramework"], | ||
| keyframes: ["theme.keyframes", "layers"], | ||
| "design-tokens": ["layers", "!utilities.*.className"].concat(tokens), | ||
| types: ["!utilities.*.className"].concat(common), | ||
| "css-fn": common, | ||
| cva: ["syntax"], | ||
| sva: ["syntax"], | ||
| cx: [], | ||
| "create-recipe": ["separator", "prefix", "hash"], | ||
| "recipes-index": ["theme.recipes", "theme.slotRecipes"], | ||
| recipes: ["theme.recipes", "theme.slotRecipes"], | ||
| "patterns-index": ["syntax", "patterns"], | ||
| patterns: ["syntax", "patterns"], | ||
| "jsx-is-valid-prop": common, | ||
| "jsx-factory": jsx, | ||
| "jsx-helpers": jsx, | ||
| "jsx-patterns": jsx.concat("patterns"), | ||
| "jsx-patterns-index": jsx.concat("patterns"), | ||
| "jsx-create-style-context": jsx, | ||
| "css-index": ["syntax"], | ||
| "package.json": ["forceConsistentTypeExtension", "outExtension"], | ||
| "types-styles": ["shorthands"], | ||
| "types-conditions": ["conditions"], | ||
| "types-jsx": jsx, | ||
| "types-entry": [], | ||
| "types-gen": [], | ||
| "types-gen-system": [], | ||
| themes: ["themes"].concat(tokens), | ||
| // staticCss depends on tokens (for wildcards) and recipes (for recipe rules) | ||
| "static-css": ["staticCss", "patterns", "theme.recipes", "theme.slotRecipes"].concat(tokens), | ||
| // Split CSS artifacts (generated via cssgen --splitting) | ||
| styles: [], | ||
| "styles.css": [] | ||
| }; | ||
| var artifactMatchers = Object.entries(artifactConfigDeps).map(([key, paths]) => { | ||
| if (!paths.length) return () => void 0; | ||
| return createMatcher(key, paths.concat(all)); | ||
| }); | ||
| // src/diff-config.ts | ||
| var runIfFn = (fn) => typeof fn === "function" ? fn() : fn; | ||
| var hasRecipeStateTransition = (prevConfig, nextConfig) => { | ||
| const prevRecipes = prevConfig.theme?.recipes ?? {}; | ||
| const prevSlotRecipes = prevConfig.theme?.slotRecipes ?? {}; | ||
| const prevHasRecipes = Object.keys(prevRecipes).length > 0 || Object.keys(prevSlotRecipes).length > 0; | ||
| const nextRecipes = nextConfig.theme?.recipes ?? {}; | ||
| const nextSlotRecipes = nextConfig.theme?.slotRecipes ?? {}; | ||
| const nextHasRecipes = Object.keys(nextRecipes).length > 0 || Object.keys(nextSlotRecipes).length > 0; | ||
| return prevHasRecipes !== nextHasRecipes; | ||
| }; | ||
| function diffConfigs(config, prevConfig) { | ||
| const affected = { | ||
| artifacts: /* @__PURE__ */ new Set(), | ||
| hasConfigChanged: false, | ||
| diffs: [] | ||
| }; | ||
| if (!prevConfig) { | ||
| affected.hasConfigChanged = true; | ||
| return affected; | ||
| } | ||
| const configDiff = microdiff(prevConfig, runIfFn(config)); | ||
| if (!configDiff.length) { | ||
| return affected; | ||
| } | ||
| affected.hasConfigChanged = true; | ||
| affected.diffs = configDiff; | ||
| configDiff.forEach((change) => { | ||
| const changePath = change.path.join("."); | ||
| artifactMatchers.forEach((matcher) => { | ||
| const id = matcher(changePath); | ||
| if (!id) return; | ||
| if (id === "recipes") { | ||
| const name = dashCase(change.path.slice(1, 3).join(".")); | ||
| affected.artifacts.add(name); | ||
| } | ||
| if (id === "patterns") { | ||
| const name = dashCase(change.path.slice(0, 2).join(".")); | ||
| affected.artifacts.add(name); | ||
| } | ||
| affected.artifacts.add(id); | ||
| }); | ||
| }); | ||
| if (affected.artifacts.has("recipes") || affected.artifacts.has("recipes-index")) { | ||
| const nextConfig = runIfFn(config); | ||
| if (hasRecipeStateTransition(prevConfig, nextConfig)) { | ||
| affected.artifacts.add("create-recipe"); | ||
| } | ||
| } | ||
| return affected; | ||
| } | ||
| export { | ||
| diffConfigs | ||
| }; |
| // src/merge-config.ts | ||
| import { BAMBOO_CONFIG_NAME, assign, mergeWith, mergeAndConcat, walkObject } from "@bamboocss/shared"; | ||
| // src/merge-hooks.ts | ||
| import { logger } from "@bamboocss/logger"; | ||
| var mergeHooks = (plugins) => { | ||
| const hooksFns = {}; | ||
| plugins.forEach(({ name, hooks }) => { | ||
| Object.entries(hooks ?? {}).forEach(([key, value]) => { | ||
| if (!hooksFns[key]) { | ||
| hooksFns[key] = []; | ||
| } | ||
| hooksFns[key].push([name, value]); | ||
| }); | ||
| }); | ||
| const mergedHooks = Object.fromEntries( | ||
| Object.entries(hooksFns).map(([key, entries]) => { | ||
| const fns = entries.map(([name, fn]) => tryCatch(name, fn)); | ||
| const reducer = key in reducers ? reducers[key] : void 0; | ||
| if (reducer) { | ||
| return [key, reducer(fns)]; | ||
| } | ||
| return [key, syncHooks.includes(key) ? callAll(...fns) : callAllAsync(...fns)]; | ||
| }) | ||
| ); | ||
| return mergedHooks; | ||
| }; | ||
| var createReducer = (reducer) => reducer; | ||
| var reducers = { | ||
| "config:resolved": createReducer((fns) => async (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.config; | ||
| let config = args.config; | ||
| for (const hookFn of fns) { | ||
| const result = await hookFn(Object.assign(args, { config, original })); | ||
| if (result !== void 0) { | ||
| config = result; | ||
| } | ||
| } | ||
| return config; | ||
| }), | ||
| "parser:before": createReducer((fns) => (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.content; | ||
| let content = args.content; | ||
| for (const hookFn of fns) { | ||
| const result = hookFn(Object.assign(args, { content, original })); | ||
| if (result !== void 0) { | ||
| content = result; | ||
| } | ||
| } | ||
| return content; | ||
| }), | ||
| "parser:preprocess": createReducer((fns) => (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.data; | ||
| let data = args.data; | ||
| for (const hookFn of fns) { | ||
| const result = hookFn(Object.assign(args, { data, original })); | ||
| if (result !== void 0) { | ||
| data = result; | ||
| } | ||
| } | ||
| return data; | ||
| }), | ||
| "cssgen:done": createReducer((fns) => (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.content; | ||
| let content = args.content; | ||
| for (const hookFn of fns) { | ||
| const result = hookFn(Object.assign(args, { content, original })); | ||
| if (result !== void 0) { | ||
| content = result; | ||
| } | ||
| } | ||
| return content; | ||
| }), | ||
| "codegen:prepare": createReducer((fns) => async (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.artifacts; | ||
| let artifacts = args.artifacts; | ||
| for (const hookFn of fns) { | ||
| const result = await hookFn(Object.assign(args, { artifacts, original })); | ||
| if (result) { | ||
| artifacts = result; | ||
| } | ||
| } | ||
| return artifacts; | ||
| }), | ||
| "preset:resolved": createReducer((fns) => async (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.preset; | ||
| let preset = args.preset; | ||
| for (const hookFn of fns) { | ||
| const result = await hookFn(Object.assign(args, { preset, original })); | ||
| if (result !== void 0) { | ||
| preset = result; | ||
| } | ||
| } | ||
| return preset; | ||
| }), | ||
| "css:optimize": createReducer((fns) => (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.css; | ||
| let css = args.css; | ||
| for (const hookFn of fns) { | ||
| const result = hookFn(Object.assign(args, { css, original })); | ||
| if (result !== void 0) { | ||
| css = result; | ||
| } | ||
| } | ||
| return css; | ||
| }) | ||
| }; | ||
| var syncHooks = [ | ||
| "context:created", | ||
| "parser:before", | ||
| "parser:preprocess", | ||
| "parser:after", | ||
| "cssgen:done", | ||
| "css:optimize" | ||
| ]; | ||
| var callAllAsync = (...fns) => async (...a) => { | ||
| for (const fn of fns) { | ||
| await fn?.(...a); | ||
| } | ||
| }; | ||
| var callAll = (...fns) => (...a) => { | ||
| fns.forEach((fn) => fn?.(...a)); | ||
| }; | ||
| var tryCatch = (name, fn) => { | ||
| return (...args) => { | ||
| try { | ||
| return fn(...args); | ||
| } catch (e) { | ||
| logger.caughtError("hooks", `Error in plugin "${name}"`, e); | ||
| } | ||
| }; | ||
| }; | ||
| // src/validation/utils.ts | ||
| import { isObject, isString } from "@bamboocss/shared"; | ||
| var REFERENCE_REGEX = /({([^}]*)})/g; | ||
| var curlyBracketRegex = /[{}]/g; | ||
| var isValidToken = (token) => isObject(token) && Object.hasOwnProperty.call(token, "value"); | ||
| var isTokenReference = (value) => typeof value === "string" && REFERENCE_REGEX.test(value); | ||
| var formatPath = (path) => path; | ||
| var SEP = "."; | ||
| function getReferences(value) { | ||
| if (typeof value !== "string") return []; | ||
| const matches = value.match(REFERENCE_REGEX); | ||
| if (!matches) return []; | ||
| return matches.map((match) => match.replace(curlyBracketRegex, "")).map((value2) => { | ||
| return value2.trim().split("/")[0]; | ||
| }); | ||
| } | ||
| var serializeTokenValue = (value) => { | ||
| if (isString(value)) { | ||
| return value; | ||
| } | ||
| if (isObject(value)) { | ||
| return Object.values(value).map((v) => serializeTokenValue(v)).join(" "); | ||
| } | ||
| if (Array.isArray(value)) { | ||
| return value.map((v) => serializeTokenValue(v)).join(" "); | ||
| } | ||
| return value.toString(); | ||
| }; | ||
| // src/merge-config.ts | ||
| function getExtends(items) { | ||
| return items.reduce((merged, { extend }) => { | ||
| if (!extend) return merged; | ||
| return mergeWith(merged, extend, (originalValue, newValue) => { | ||
| if (newValue === void 0) { | ||
| return originalValue ?? []; | ||
| } | ||
| if (originalValue === void 0) { | ||
| return [newValue]; | ||
| } | ||
| if (Array.isArray(originalValue)) { | ||
| return [newValue, ...originalValue]; | ||
| } | ||
| return [newValue, originalValue]; | ||
| }); | ||
| }, {}); | ||
| } | ||
| function mergeRecords(records) { | ||
| return { | ||
| ...records.reduce((acc, record) => assign(acc, record), {}), | ||
| extend: getExtends(records) | ||
| }; | ||
| } | ||
| function mergeExtensions(records) { | ||
| const { extend = [], ...restProps } = mergeRecords(records); | ||
| return mergeWith(restProps, extend, (obj, extensions) => { | ||
| return mergeAndConcat({}, obj, ...extensions); | ||
| }); | ||
| } | ||
| var isEmptyObject = (obj) => typeof obj === "object" && Object.keys(obj).length === 0; | ||
| var compact = (obj) => { | ||
| return Object.keys(obj).reduce((acc, key) => { | ||
| if (obj[key] !== void 0 && !isEmptyObject(obj[key])) { | ||
| acc[key] = obj[key]; | ||
| } | ||
| return acc; | ||
| }, {}); | ||
| }; | ||
| var tokenKeys = ["description", "extensions", "type", "value", "deprecated"]; | ||
| function mergeConfigs(configs) { | ||
| const userConfig = configs.at(-1); | ||
| const pluginHooks = userConfig.plugins ?? []; | ||
| if (userConfig.hooks) { | ||
| pluginHooks.push({ name: BAMBOO_CONFIG_NAME, hooks: userConfig.hooks }); | ||
| } | ||
| const reversed = Array.from(configs).reverse(); | ||
| const mergedResult = assign( | ||
| { | ||
| conditions: mergeExtensions(reversed.map((config) => config.conditions ?? {})), | ||
| theme: mergeExtensions(reversed.map((config) => config.theme ?? {})), | ||
| patterns: mergeExtensions(reversed.map((config) => config.patterns ?? {})), | ||
| utilities: mergeExtensions(reversed.map((config) => config.utilities ?? {})), | ||
| globalCss: mergeExtensions(reversed.map((config) => config.globalCss ?? {})), | ||
| globalVars: mergeExtensions(reversed.map((config) => config.globalVars ?? {})), | ||
| globalFontface: mergeExtensions(reversed.map((config) => config.globalFontface ?? {})), | ||
| globalPositionTry: mergeExtensions(reversed.map((config) => config.globalPositionTry ?? {})), | ||
| staticCss: mergeExtensions(reversed.map((config) => config.staticCss ?? {})), | ||
| themes: mergeExtensions(reversed.map((config) => config.themes ?? {})), | ||
| hooks: mergeHooks(pluginHooks) | ||
| }, | ||
| ...reversed | ||
| ); | ||
| const withoutEmpty = compact(mergedResult); | ||
| if (withoutEmpty.theme?.tokens) { | ||
| walkObject(withoutEmpty.theme.tokens, (args) => args, { | ||
| stop(token) { | ||
| if (!isValidToken(token)) return false; | ||
| const keys = Object.keys(token); | ||
| const nestedKeys = keys.filter((k) => !tokenKeys.includes(k)); | ||
| const nested = nestedKeys.length > 0; | ||
| if (nested) { | ||
| token.DEFAULT ||= {}; | ||
| tokenKeys.forEach((key) => { | ||
| if (token[key] == null) return; | ||
| token.DEFAULT[key] ||= token[key]; | ||
| delete token[key]; | ||
| }); | ||
| } | ||
| return true; | ||
| } | ||
| }); | ||
| } | ||
| return withoutEmpty; | ||
| } | ||
| export { | ||
| mergeHooks, | ||
| isValidToken, | ||
| isTokenReference, | ||
| formatPath, | ||
| SEP, | ||
| getReferences, | ||
| serializeTokenValue, | ||
| mergeConfigs | ||
| }; |
| // src/resolve-ts-path-pattern.ts | ||
| import { posix, sep } from "path"; | ||
| var resolveTsPathPattern = (pathMappings, moduleSpecifier) => { | ||
| for (const mapping of pathMappings) { | ||
| const match = moduleSpecifier.match(mapping.pattern); | ||
| if (!match) { | ||
| continue; | ||
| } | ||
| for (const pathTemplate of mapping.paths) { | ||
| let starCount = 0; | ||
| const mappedId = pathTemplate.replace(/\*/g, () => { | ||
| const matchIndex = Math.min(++starCount, match.length - 1); | ||
| return match[matchIndex]; | ||
| }); | ||
| return mappedId.split(sep).join(posix.sep); | ||
| } | ||
| } | ||
| }; | ||
| export { | ||
| resolveTsPathPattern | ||
| }; |
| "use strict"; | ||
| var __create = Object.create; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __getProtoOf = Object.getPrototypeOf; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __export = (target, all2) => { | ||
| for (var name in all2) | ||
| __defProp(target, name, { get: all2[name], enumerable: true }); | ||
| }; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
| // If the importer is in node compatibility mode or this is not an ESM | ||
| // file that has been converted to a CommonJS file using a Babel- | ||
| // compatible transform (i.e. "__esModule" has not been set), then set | ||
| // "default" to the CommonJS "module.exports" for node compatibility. | ||
| isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
| mod | ||
| )); | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| // src/diff-config.ts | ||
| var diff_config_exports = {}; | ||
| __export(diff_config_exports, { | ||
| diffConfigs: () => diffConfigs | ||
| }); | ||
| module.exports = __toCommonJS(diff_config_exports); | ||
| var import_shared = require("@bamboocss/shared"); | ||
| var import_microdiff = __toESM(require("microdiff")); | ||
| // src/create-matcher.ts | ||
| function createMatcher(id, patterns) { | ||
| if (!patterns?.length) return () => void 0; | ||
| const includePatterns = []; | ||
| const excludePatterns = []; | ||
| const deduped = new Set(patterns); | ||
| deduped.forEach((pattern) => { | ||
| const regexString = pattern.replace(/\*/g, ".*"); | ||
| if (pattern.startsWith("!")) { | ||
| excludePatterns.push(regexString.slice(1)); | ||
| } else { | ||
| includePatterns.push(regexString); | ||
| } | ||
| }); | ||
| const include = new RegExp(includePatterns.join("|")); | ||
| const exclude = new RegExp(excludePatterns.join("|")); | ||
| return (path) => { | ||
| if (excludePatterns.length && exclude.test(path)) return; | ||
| return include.test(path) ? id : void 0; | ||
| }; | ||
| } | ||
| // src/config-deps.ts | ||
| var all = [ | ||
| "clean", | ||
| "cwd", | ||
| "eject", | ||
| "outdir", | ||
| "forceConsistentTypeExtension", | ||
| "outExtension", | ||
| "emitTokensOnly", | ||
| "presets", | ||
| "plugins", | ||
| "hooks" | ||
| ]; | ||
| var format = [ | ||
| "syntax", | ||
| "hash", | ||
| "prefix", | ||
| "separator", | ||
| "strictTokens", | ||
| "strictPropertyValues", | ||
| "shorthands" | ||
| ]; | ||
| var tokens = [ | ||
| "utilities", | ||
| "conditions", | ||
| "theme.tokens", | ||
| "theme.semanticTokens", | ||
| "theme.breakpoints", | ||
| "theme.containerNames", | ||
| "theme.containerSizes" | ||
| ]; | ||
| var jsx = ["jsxFramework", "jsxFactory", "jsxStyleProps", "syntax"]; | ||
| var common = tokens.concat(jsx, format); | ||
| var artifactConfigDeps = { | ||
| helpers: ["syntax", "jsxFramework"], | ||
| keyframes: ["theme.keyframes", "layers"], | ||
| "design-tokens": ["layers", "!utilities.*.className"].concat(tokens), | ||
| types: ["!utilities.*.className"].concat(common), | ||
| "css-fn": common, | ||
| cva: ["syntax"], | ||
| sva: ["syntax"], | ||
| cx: [], | ||
| "create-recipe": ["separator", "prefix", "hash"], | ||
| "recipes-index": ["theme.recipes", "theme.slotRecipes"], | ||
| recipes: ["theme.recipes", "theme.slotRecipes"], | ||
| "patterns-index": ["syntax", "patterns"], | ||
| patterns: ["syntax", "patterns"], | ||
| "jsx-is-valid-prop": common, | ||
| "jsx-factory": jsx, | ||
| "jsx-helpers": jsx, | ||
| "jsx-patterns": jsx.concat("patterns"), | ||
| "jsx-patterns-index": jsx.concat("patterns"), | ||
| "jsx-create-style-context": jsx, | ||
| "css-index": ["syntax"], | ||
| "package.json": ["forceConsistentTypeExtension", "outExtension"], | ||
| "types-styles": ["shorthands"], | ||
| "types-conditions": ["conditions"], | ||
| "types-jsx": jsx, | ||
| "types-entry": [], | ||
| "types-gen": [], | ||
| "types-gen-system": [], | ||
| themes: ["themes"].concat(tokens), | ||
| // staticCss depends on tokens (for wildcards) and recipes (for recipe rules) | ||
| "static-css": ["staticCss", "patterns", "theme.recipes", "theme.slotRecipes"].concat(tokens), | ||
| // Split CSS artifacts (generated via cssgen --splitting) | ||
| styles: [], | ||
| "styles.css": [] | ||
| }; | ||
| var artifactMatchers = Object.entries(artifactConfigDeps).map(([key, paths]) => { | ||
| if (!paths.length) return () => void 0; | ||
| return createMatcher(key, paths.concat(all)); | ||
| }); | ||
| // src/diff-config.ts | ||
| var runIfFn = (fn) => typeof fn === "function" ? fn() : fn; | ||
| var hasRecipeStateTransition = (prevConfig, nextConfig) => { | ||
| const prevRecipes = prevConfig.theme?.recipes ?? {}; | ||
| const prevSlotRecipes = prevConfig.theme?.slotRecipes ?? {}; | ||
| const prevHasRecipes = Object.keys(prevRecipes).length > 0 || Object.keys(prevSlotRecipes).length > 0; | ||
| const nextRecipes = nextConfig.theme?.recipes ?? {}; | ||
| const nextSlotRecipes = nextConfig.theme?.slotRecipes ?? {}; | ||
| const nextHasRecipes = Object.keys(nextRecipes).length > 0 || Object.keys(nextSlotRecipes).length > 0; | ||
| return prevHasRecipes !== nextHasRecipes; | ||
| }; | ||
| function diffConfigs(config, prevConfig) { | ||
| const affected = { | ||
| artifacts: /* @__PURE__ */ new Set(), | ||
| hasConfigChanged: false, | ||
| diffs: [] | ||
| }; | ||
| if (!prevConfig) { | ||
| affected.hasConfigChanged = true; | ||
| return affected; | ||
| } | ||
| const configDiff = (0, import_microdiff.default)(prevConfig, runIfFn(config)); | ||
| if (!configDiff.length) { | ||
| return affected; | ||
| } | ||
| affected.hasConfigChanged = true; | ||
| affected.diffs = configDiff; | ||
| configDiff.forEach((change) => { | ||
| const changePath = change.path.join("."); | ||
| artifactMatchers.forEach((matcher) => { | ||
| const id = matcher(changePath); | ||
| if (!id) return; | ||
| if (id === "recipes") { | ||
| const name = (0, import_shared.dashCase)(change.path.slice(1, 3).join(".")); | ||
| affected.artifacts.add(name); | ||
| } | ||
| if (id === "patterns") { | ||
| const name = (0, import_shared.dashCase)(change.path.slice(0, 2).join(".")); | ||
| affected.artifacts.add(name); | ||
| } | ||
| affected.artifacts.add(id); | ||
| }); | ||
| }); | ||
| if (affected.artifacts.has("recipes") || affected.artifacts.has("recipes-index")) { | ||
| const nextConfig = runIfFn(config); | ||
| if (hasRecipeStateTransition(prevConfig, nextConfig)) { | ||
| affected.artifacts.add("create-recipe"); | ||
| } | ||
| } | ||
| return affected; | ||
| } | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| diffConfigs | ||
| }); |
-1086
| "use strict"; | ||
| var __create = Object.create; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __getProtoOf = Object.getPrototypeOf; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __export = (target, all2) => { | ||
| for (var name in all2) | ||
| __defProp(target, name, { get: all2[name], enumerable: true }); | ||
| }; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
| // If the importer is in node compatibility mode or this is not an ESM | ||
| // file that has been converted to a CommonJS file using a Babel- | ||
| // compatible transform (i.e. "__esModule" has not been set), then set | ||
| // "default" to the CommonJS "module.exports" for node compatibility. | ||
| isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
| mod | ||
| )); | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| // src/index.ts | ||
| var index_exports = {}; | ||
| __export(index_exports, { | ||
| bundleConfig: () => bundleConfig, | ||
| convertTsPathsToRegexes: () => convertTsPathsToRegexes, | ||
| diffConfigs: () => diffConfigs, | ||
| findConfig: () => findConfig, | ||
| getConfigDependencies: () => getConfigDependencies, | ||
| getResolvedConfig: () => getResolvedConfig, | ||
| loadConfig: () => loadConfig, | ||
| mergeConfigs: () => mergeConfigs, | ||
| mergeHooks: () => mergeHooks, | ||
| resolveConfig: () => resolveConfig | ||
| }); | ||
| module.exports = __toCommonJS(index_exports); | ||
| // src/bundle-config.ts | ||
| var import_logger = require("@bamboocss/logger"); | ||
| var import_shared2 = require("@bamboocss/shared"); | ||
| var import_bundle_n_require = require("bundle-n-require"); | ||
| // src/find-config.ts | ||
| var import_shared = require("@bamboocss/shared"); | ||
| var import_sync = __toESM(require("escalade/sync")); | ||
| var import_path = require("path"); | ||
| // src/is-bamboo-config.ts | ||
| var configName = "bamboo"; | ||
| var bambooConfigFiles = /* @__PURE__ */ new Set([ | ||
| `${configName}.config.ts`, | ||
| `${configName}.config.js`, | ||
| `${configName}.config.mts`, | ||
| `${configName}.config.mjs`, | ||
| `${configName}.config.cts`, | ||
| `${configName}.config.cjs` | ||
| ]); | ||
| var isBambooConfig = (file) => bambooConfigFiles.has(file); | ||
| // src/find-config.ts | ||
| function findConfig(options) { | ||
| const { cwd = process.cwd(), file } = options; | ||
| if (file) { | ||
| return (0, import_path.resolve)(cwd, file); | ||
| } | ||
| const configPath = (0, import_sync.default)(cwd, (_dir, paths) => paths.find(isBambooConfig)); | ||
| if (!configPath) { | ||
| throw new import_shared.BambooError( | ||
| "CONFIG_NOT_FOUND", | ||
| `Cannot find config file \`bamboo.config.{ts,js,mjs,mts}\`. Did you forget to run \`bamboo init\`?` | ||
| ); | ||
| } | ||
| return configPath; | ||
| } | ||
| // src/bundle-config.ts | ||
| async function bundle(filepath, cwd) { | ||
| const { mod, dependencies } = await (0, import_bundle_n_require.bundleNRequire)(filepath, { | ||
| cwd, | ||
| interopDefault: true | ||
| }); | ||
| const config = mod?.default ?? mod; | ||
| return { | ||
| config, | ||
| dependencies | ||
| }; | ||
| } | ||
| async function bundleConfig(options) { | ||
| const { cwd, file } = options; | ||
| const filePath = findConfig({ cwd, file }); | ||
| import_logger.logger.debug("config:path", filePath); | ||
| const result = await bundle(filePath, cwd); | ||
| if (typeof result.config !== "object") { | ||
| throw new import_shared2.BambooError("CONFIG_ERROR", `\u{1F4A5} Config must export or return an object.`); | ||
| } | ||
| result.config.outdir ??= "styled-system"; | ||
| result.config.validation ??= "warn"; | ||
| return { | ||
| ...result, | ||
| config: result.config, | ||
| path: filePath | ||
| }; | ||
| } | ||
| // src/diff-config.ts | ||
| var import_shared3 = require("@bamboocss/shared"); | ||
| var import_microdiff = __toESM(require("microdiff")); | ||
| // src/create-matcher.ts | ||
| function createMatcher(id, patterns) { | ||
| if (!patterns?.length) return () => void 0; | ||
| const includePatterns = []; | ||
| const excludePatterns = []; | ||
| const deduped = new Set(patterns); | ||
| deduped.forEach((pattern) => { | ||
| const regexString = pattern.replace(/\*/g, ".*"); | ||
| if (pattern.startsWith("!")) { | ||
| excludePatterns.push(regexString.slice(1)); | ||
| } else { | ||
| includePatterns.push(regexString); | ||
| } | ||
| }); | ||
| const include = new RegExp(includePatterns.join("|")); | ||
| const exclude = new RegExp(excludePatterns.join("|")); | ||
| return (path2) => { | ||
| if (excludePatterns.length && exclude.test(path2)) return; | ||
| return include.test(path2) ? id : void 0; | ||
| }; | ||
| } | ||
| // src/config-deps.ts | ||
| var all = [ | ||
| "clean", | ||
| "cwd", | ||
| "eject", | ||
| "outdir", | ||
| "forceConsistentTypeExtension", | ||
| "outExtension", | ||
| "emitTokensOnly", | ||
| "presets", | ||
| "plugins", | ||
| "hooks" | ||
| ]; | ||
| var format = [ | ||
| "syntax", | ||
| "hash", | ||
| "prefix", | ||
| "separator", | ||
| "strictTokens", | ||
| "strictPropertyValues", | ||
| "shorthands" | ||
| ]; | ||
| var tokens = [ | ||
| "utilities", | ||
| "conditions", | ||
| "theme.tokens", | ||
| "theme.semanticTokens", | ||
| "theme.breakpoints", | ||
| "theme.containerNames", | ||
| "theme.containerSizes" | ||
| ]; | ||
| var jsx = ["jsxFramework", "jsxFactory", "jsxStyleProps", "syntax"]; | ||
| var common = tokens.concat(jsx, format); | ||
| var artifactConfigDeps = { | ||
| helpers: ["syntax", "jsxFramework"], | ||
| keyframes: ["theme.keyframes", "layers"], | ||
| "design-tokens": ["layers", "!utilities.*.className"].concat(tokens), | ||
| types: ["!utilities.*.className"].concat(common), | ||
| "css-fn": common, | ||
| cva: ["syntax"], | ||
| sva: ["syntax"], | ||
| cx: [], | ||
| "create-recipe": ["separator", "prefix", "hash"], | ||
| "recipes-index": ["theme.recipes", "theme.slotRecipes"], | ||
| recipes: ["theme.recipes", "theme.slotRecipes"], | ||
| "patterns-index": ["syntax", "patterns"], | ||
| patterns: ["syntax", "patterns"], | ||
| "jsx-is-valid-prop": common, | ||
| "jsx-factory": jsx, | ||
| "jsx-helpers": jsx, | ||
| "jsx-patterns": jsx.concat("patterns"), | ||
| "jsx-patterns-index": jsx.concat("patterns"), | ||
| "jsx-create-style-context": jsx, | ||
| "css-index": ["syntax"], | ||
| "package.json": ["forceConsistentTypeExtension", "outExtension"], | ||
| "types-styles": ["shorthands"], | ||
| "types-conditions": ["conditions"], | ||
| "types-jsx": jsx, | ||
| "types-entry": [], | ||
| "types-gen": [], | ||
| "types-gen-system": [], | ||
| themes: ["themes"].concat(tokens), | ||
| // staticCss depends on tokens (for wildcards) and recipes (for recipe rules) | ||
| "static-css": ["staticCss", "patterns", "theme.recipes", "theme.slotRecipes"].concat(tokens), | ||
| // Split CSS artifacts (generated via cssgen --splitting) | ||
| styles: [], | ||
| "styles.css": [] | ||
| }; | ||
| var artifactMatchers = Object.entries(artifactConfigDeps).map(([key, paths]) => { | ||
| if (!paths.length) return () => void 0; | ||
| return createMatcher(key, paths.concat(all)); | ||
| }); | ||
| // src/diff-config.ts | ||
| var runIfFn = (fn) => typeof fn === "function" ? fn() : fn; | ||
| var hasRecipeStateTransition = (prevConfig, nextConfig) => { | ||
| const prevRecipes = prevConfig.theme?.recipes ?? {}; | ||
| const prevSlotRecipes = prevConfig.theme?.slotRecipes ?? {}; | ||
| const prevHasRecipes = Object.keys(prevRecipes).length > 0 || Object.keys(prevSlotRecipes).length > 0; | ||
| const nextRecipes = nextConfig.theme?.recipes ?? {}; | ||
| const nextSlotRecipes = nextConfig.theme?.slotRecipes ?? {}; | ||
| const nextHasRecipes = Object.keys(nextRecipes).length > 0 || Object.keys(nextSlotRecipes).length > 0; | ||
| return prevHasRecipes !== nextHasRecipes; | ||
| }; | ||
| function diffConfigs(config, prevConfig) { | ||
| const affected = { | ||
| artifacts: /* @__PURE__ */ new Set(), | ||
| hasConfigChanged: false, | ||
| diffs: [] | ||
| }; | ||
| if (!prevConfig) { | ||
| affected.hasConfigChanged = true; | ||
| return affected; | ||
| } | ||
| const configDiff = (0, import_microdiff.default)(prevConfig, runIfFn(config)); | ||
| if (!configDiff.length) { | ||
| return affected; | ||
| } | ||
| affected.hasConfigChanged = true; | ||
| affected.diffs = configDiff; | ||
| configDiff.forEach((change) => { | ||
| const changePath = change.path.join("."); | ||
| artifactMatchers.forEach((matcher) => { | ||
| const id = matcher(changePath); | ||
| if (!id) return; | ||
| if (id === "recipes") { | ||
| const name = (0, import_shared3.dashCase)(change.path.slice(1, 3).join(".")); | ||
| affected.artifacts.add(name); | ||
| } | ||
| if (id === "patterns") { | ||
| const name = (0, import_shared3.dashCase)(change.path.slice(0, 2).join(".")); | ||
| affected.artifacts.add(name); | ||
| } | ||
| affected.artifacts.add(id); | ||
| }); | ||
| }); | ||
| if (affected.artifacts.has("recipes") || affected.artifacts.has("recipes-index")) { | ||
| const nextConfig = runIfFn(config); | ||
| if (hasRecipeStateTransition(prevConfig, nextConfig)) { | ||
| affected.artifacts.add("create-recipe"); | ||
| } | ||
| } | ||
| return affected; | ||
| } | ||
| // src/get-mod-deps.ts | ||
| var import_fs = __toESM(require("fs")); | ||
| var import_path4 = __toESM(require("path")); | ||
| var import_typescript = __toESM(require("typescript")); | ||
| // src/resolve-ts-path-pattern.ts | ||
| var import_path2 = require("path"); | ||
| var resolveTsPathPattern = (pathMappings, moduleSpecifier) => { | ||
| for (const mapping of pathMappings) { | ||
| const match = moduleSpecifier.match(mapping.pattern); | ||
| if (!match) { | ||
| continue; | ||
| } | ||
| for (const pathTemplate of mapping.paths) { | ||
| let starCount = 0; | ||
| const mappedId = pathTemplate.replace(/\*/g, () => { | ||
| const matchIndex = Math.min(++starCount, match.length - 1); | ||
| return match[matchIndex]; | ||
| }); | ||
| return mappedId.split(import_path2.sep).join(import_path2.posix.sep); | ||
| } | ||
| } | ||
| }; | ||
| // src/ts-config-paths.ts | ||
| var import_path3 = require("path"); | ||
| function convertTsPathsToRegexes(paths, baseUrl) { | ||
| const sortedPatterns = Object.keys(paths).sort((a, b) => getPrefixLength(b) - getPrefixLength(a)); | ||
| const resolved = []; | ||
| for (let pattern of sortedPatterns) { | ||
| const relativePaths = paths[pattern]; | ||
| pattern = escapeStringRegexp(pattern).replace(/\*/g, "(.+)"); | ||
| resolved.push({ | ||
| pattern: new RegExp("^" + pattern + "$"), | ||
| paths: relativePaths.map((relativePath) => (0, import_path3.resolve)(baseUrl, relativePath)) | ||
| }); | ||
| } | ||
| return resolved; | ||
| } | ||
| function getPrefixLength(pattern) { | ||
| const prefixLength = pattern.indexOf("*"); | ||
| return pattern.substr(0, prefixLength).length; | ||
| } | ||
| function escapeStringRegexp(string) { | ||
| return string.replace(/[|\\{}()[\]^$+?.]/g, "\\$&").replace(/-/g, "\\x2d"); | ||
| } | ||
| // src/get-mod-deps.ts | ||
| var jsExtensions = [".js", ".cjs", ".mjs"]; | ||
| var jsResolutionOrder = ["", ".js", ".cjs", ".mjs", ".ts", ".cts", ".mts", ".jsx", ".tsx"]; | ||
| var tsResolutionOrder = ["", ".ts", ".cts", ".mts", ".tsx", ".js", ".cjs", ".mjs", ".jsx"]; | ||
| function resolveWithExtension(file, extensions) { | ||
| for (const ext of extensions) { | ||
| const full = `${file}${ext}`; | ||
| if (import_fs.default.existsSync(full) && import_fs.default.statSync(full).isFile()) { | ||
| return full; | ||
| } | ||
| } | ||
| for (const ext of extensions) { | ||
| const full = `${file}/index${ext}`; | ||
| if (import_fs.default.existsSync(full)) { | ||
| return full; | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
| var importRegex = /import[\s\S]*?['"](.{3,}?)['"]/gi; | ||
| var importFromRegex = /import[\s\S]*from[\s\S]*?['"](.{3,}?)['"]/gi; | ||
| var requireRegex = /require\(['"`](.+)['"`]\)/gi; | ||
| var exportRegex = /export[\s\S]*from[\s\S]*?['"](.{3,}?)['"]/gi; | ||
| function getDeps(opts, fromAlias) { | ||
| const { filename, seen } = opts; | ||
| const { moduleResolution: _, ...compilerOptions } = opts.compilerOptions ?? {}; | ||
| const absoluteFile = resolveWithExtension( | ||
| import_path4.default.resolve(opts.cwd, filename), | ||
| jsExtensions.includes(opts.ext) ? jsResolutionOrder : tsResolutionOrder | ||
| ); | ||
| if (absoluteFile === null) return; | ||
| if (fromAlias) { | ||
| opts.foundModuleAliases.set(fromAlias, absoluteFile); | ||
| } | ||
| if (seen.size > 1 && seen.has(absoluteFile)) return; | ||
| seen.add(absoluteFile); | ||
| const contents = import_fs.default.readFileSync(absoluteFile, "utf-8"); | ||
| const fileDeps = [ | ||
| ...contents.matchAll(importRegex), | ||
| ...contents.matchAll(importFromRegex), | ||
| ...contents.matchAll(requireRegex), | ||
| ...contents.matchAll(exportRegex) | ||
| ]; | ||
| if (!fileDeps.length) return; | ||
| const nextOpts = { | ||
| // Resolve new base for new imports/requires | ||
| cwd: import_path4.default.dirname(absoluteFile), | ||
| ext: import_path4.default.extname(absoluteFile), | ||
| seen, | ||
| baseUrl: opts.baseUrl, | ||
| pathMappings: opts.pathMappings, | ||
| foundModuleAliases: opts.foundModuleAliases | ||
| }; | ||
| fileDeps.forEach((match) => { | ||
| const mod = match[1]; | ||
| if (mod[0] === ".") { | ||
| getDeps(Object.assign({}, nextOpts, { filename: mod })); | ||
| return; | ||
| } | ||
| try { | ||
| const found = import_typescript.default.resolveModuleName(mod, absoluteFile, compilerOptions, import_typescript.default.sys).resolvedModule; | ||
| if (found && found.extension.endsWith("ts")) { | ||
| getDeps(Object.assign({}, nextOpts, { filename: found.resolvedFileName })); | ||
| return; | ||
| } | ||
| if (!opts.pathMappings) return; | ||
| const filename2 = resolveTsPathPattern(opts.pathMappings, mod); | ||
| if (!filename2) return; | ||
| getDeps(Object.assign({}, nextOpts, { filename: filename2 }), mod); | ||
| } catch { | ||
| } | ||
| }); | ||
| } | ||
| function getConfigDependencies(filePath, tsOptions = { pathMappings: [] }, compilerOptions) { | ||
| if (filePath === null) return { deps: /* @__PURE__ */ new Set(), aliases: /* @__PURE__ */ new Map() }; | ||
| const foundModuleAliases = /* @__PURE__ */ new Map(); | ||
| const deps = /* @__PURE__ */ new Set(); | ||
| deps.add(filePath); | ||
| getDeps({ | ||
| filename: filePath, | ||
| ext: import_path4.default.extname(filePath), | ||
| cwd: import_path4.default.dirname(filePath), | ||
| seen: deps, | ||
| baseUrl: tsOptions.baseUrl, | ||
| pathMappings: tsOptions.pathMappings ?? [], | ||
| foundModuleAliases, | ||
| compilerOptions | ||
| }); | ||
| return { deps, aliases: foundModuleAliases }; | ||
| } | ||
| // src/get-resolved-config.ts | ||
| var import_shared6 = require("@bamboocss/shared"); | ||
| // src/merge-config.ts | ||
| var import_shared5 = require("@bamboocss/shared"); | ||
| // src/merge-hooks.ts | ||
| var import_logger2 = require("@bamboocss/logger"); | ||
| var mergeHooks = (plugins) => { | ||
| const hooksFns = {}; | ||
| plugins.forEach(({ name, hooks }) => { | ||
| Object.entries(hooks ?? {}).forEach(([key, value]) => { | ||
| if (!hooksFns[key]) { | ||
| hooksFns[key] = []; | ||
| } | ||
| hooksFns[key].push([name, value]); | ||
| }); | ||
| }); | ||
| const mergedHooks = Object.fromEntries( | ||
| Object.entries(hooksFns).map(([key, entries]) => { | ||
| const fns = entries.map(([name, fn]) => tryCatch(name, fn)); | ||
| const reducer = key in reducers ? reducers[key] : void 0; | ||
| if (reducer) { | ||
| return [key, reducer(fns)]; | ||
| } | ||
| return [key, syncHooks.includes(key) ? callAll(...fns) : callAllAsync(...fns)]; | ||
| }) | ||
| ); | ||
| return mergedHooks; | ||
| }; | ||
| var createReducer = (reducer) => reducer; | ||
| var reducers = { | ||
| "config:resolved": createReducer((fns) => async (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.config; | ||
| let config = args.config; | ||
| for (const hookFn of fns) { | ||
| const result = await hookFn(Object.assign(args, { config, original })); | ||
| if (result !== void 0) { | ||
| config = result; | ||
| } | ||
| } | ||
| return config; | ||
| }), | ||
| "parser:before": createReducer((fns) => (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.content; | ||
| let content = args.content; | ||
| for (const hookFn of fns) { | ||
| const result = hookFn(Object.assign(args, { content, original })); | ||
| if (result !== void 0) { | ||
| content = result; | ||
| } | ||
| } | ||
| return content; | ||
| }), | ||
| "parser:preprocess": createReducer((fns) => (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.data; | ||
| let data = args.data; | ||
| for (const hookFn of fns) { | ||
| const result = hookFn(Object.assign(args, { data, original })); | ||
| if (result !== void 0) { | ||
| data = result; | ||
| } | ||
| } | ||
| return data; | ||
| }), | ||
| "cssgen:done": createReducer((fns) => (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.content; | ||
| let content = args.content; | ||
| for (const hookFn of fns) { | ||
| const result = hookFn(Object.assign(args, { content, original })); | ||
| if (result !== void 0) { | ||
| content = result; | ||
| } | ||
| } | ||
| return content; | ||
| }), | ||
| "codegen:prepare": createReducer((fns) => async (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.artifacts; | ||
| let artifacts = args.artifacts; | ||
| for (const hookFn of fns) { | ||
| const result = await hookFn(Object.assign(args, { artifacts, original })); | ||
| if (result) { | ||
| artifacts = result; | ||
| } | ||
| } | ||
| return artifacts; | ||
| }), | ||
| "preset:resolved": createReducer((fns) => async (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.preset; | ||
| let preset = args.preset; | ||
| for (const hookFn of fns) { | ||
| const result = await hookFn(Object.assign(args, { preset, original })); | ||
| if (result !== void 0) { | ||
| preset = result; | ||
| } | ||
| } | ||
| return preset; | ||
| }), | ||
| "css:optimize": createReducer((fns) => (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.css; | ||
| let css = args.css; | ||
| for (const hookFn of fns) { | ||
| const result = hookFn(Object.assign(args, { css, original })); | ||
| if (result !== void 0) { | ||
| css = result; | ||
| } | ||
| } | ||
| return css; | ||
| }) | ||
| }; | ||
| var syncHooks = [ | ||
| "context:created", | ||
| "parser:before", | ||
| "parser:preprocess", | ||
| "parser:after", | ||
| "cssgen:done", | ||
| "css:optimize" | ||
| ]; | ||
| var callAllAsync = (...fns) => async (...a) => { | ||
| for (const fn of fns) { | ||
| await fn?.(...a); | ||
| } | ||
| }; | ||
| var callAll = (...fns) => (...a) => { | ||
| fns.forEach((fn) => fn?.(...a)); | ||
| }; | ||
| var tryCatch = (name, fn) => { | ||
| return (...args) => { | ||
| try { | ||
| return fn(...args); | ||
| } catch (e) { | ||
| import_logger2.logger.caughtError("hooks", `Error in plugin "${name}"`, e); | ||
| } | ||
| }; | ||
| }; | ||
| // src/validation/utils.ts | ||
| var import_shared4 = require("@bamboocss/shared"); | ||
| var REFERENCE_REGEX = /({([^}]*)})/g; | ||
| var curlyBracketRegex = /[{}]/g; | ||
| var isValidToken = (token) => (0, import_shared4.isObject)(token) && Object.hasOwnProperty.call(token, "value"); | ||
| var isTokenReference = (value) => typeof value === "string" && REFERENCE_REGEX.test(value); | ||
| var formatPath = (path2) => path2; | ||
| var SEP = "."; | ||
| function getReferences(value) { | ||
| if (typeof value !== "string") return []; | ||
| const matches = value.match(REFERENCE_REGEX); | ||
| if (!matches) return []; | ||
| return matches.map((match) => match.replace(curlyBracketRegex, "")).map((value2) => { | ||
| return value2.trim().split("/")[0]; | ||
| }); | ||
| } | ||
| var serializeTokenValue = (value) => { | ||
| if ((0, import_shared4.isString)(value)) { | ||
| return value; | ||
| } | ||
| if ((0, import_shared4.isObject)(value)) { | ||
| return Object.values(value).map((v) => serializeTokenValue(v)).join(" "); | ||
| } | ||
| if (Array.isArray(value)) { | ||
| return value.map((v) => serializeTokenValue(v)).join(" "); | ||
| } | ||
| return value.toString(); | ||
| }; | ||
| // src/merge-config.ts | ||
| function getExtends(items) { | ||
| return items.reduce((merged, { extend }) => { | ||
| if (!extend) return merged; | ||
| return (0, import_shared5.mergeWith)(merged, extend, (originalValue, newValue) => { | ||
| if (newValue === void 0) { | ||
| return originalValue ?? []; | ||
| } | ||
| if (originalValue === void 0) { | ||
| return [newValue]; | ||
| } | ||
| if (Array.isArray(originalValue)) { | ||
| return [newValue, ...originalValue]; | ||
| } | ||
| return [newValue, originalValue]; | ||
| }); | ||
| }, {}); | ||
| } | ||
| function mergeRecords(records) { | ||
| return { | ||
| ...records.reduce((acc, record) => (0, import_shared5.assign)(acc, record), {}), | ||
| extend: getExtends(records) | ||
| }; | ||
| } | ||
| function mergeExtensions(records) { | ||
| const { extend = [], ...restProps } = mergeRecords(records); | ||
| return (0, import_shared5.mergeWith)(restProps, extend, (obj, extensions) => { | ||
| return (0, import_shared5.mergeAndConcat)({}, obj, ...extensions); | ||
| }); | ||
| } | ||
| var isEmptyObject = (obj) => typeof obj === "object" && Object.keys(obj).length === 0; | ||
| var compact = (obj) => { | ||
| return Object.keys(obj).reduce((acc, key) => { | ||
| if (obj[key] !== void 0 && !isEmptyObject(obj[key])) { | ||
| acc[key] = obj[key]; | ||
| } | ||
| return acc; | ||
| }, {}); | ||
| }; | ||
| var tokenKeys = ["description", "extensions", "type", "value", "deprecated"]; | ||
| function mergeConfigs(configs) { | ||
| const userConfig = configs.at(-1); | ||
| const pluginHooks = userConfig.plugins ?? []; | ||
| if (userConfig.hooks) { | ||
| pluginHooks.push({ name: import_shared5.BAMBOO_CONFIG_NAME, hooks: userConfig.hooks }); | ||
| } | ||
| const reversed = Array.from(configs).reverse(); | ||
| const mergedResult = (0, import_shared5.assign)( | ||
| { | ||
| conditions: mergeExtensions(reversed.map((config) => config.conditions ?? {})), | ||
| theme: mergeExtensions(reversed.map((config) => config.theme ?? {})), | ||
| patterns: mergeExtensions(reversed.map((config) => config.patterns ?? {})), | ||
| utilities: mergeExtensions(reversed.map((config) => config.utilities ?? {})), | ||
| globalCss: mergeExtensions(reversed.map((config) => config.globalCss ?? {})), | ||
| globalVars: mergeExtensions(reversed.map((config) => config.globalVars ?? {})), | ||
| globalFontface: mergeExtensions(reversed.map((config) => config.globalFontface ?? {})), | ||
| globalPositionTry: mergeExtensions(reversed.map((config) => config.globalPositionTry ?? {})), | ||
| staticCss: mergeExtensions(reversed.map((config) => config.staticCss ?? {})), | ||
| themes: mergeExtensions(reversed.map((config) => config.themes ?? {})), | ||
| hooks: mergeHooks(pluginHooks) | ||
| }, | ||
| ...reversed | ||
| ); | ||
| const withoutEmpty = compact(mergedResult); | ||
| if (withoutEmpty.theme?.tokens) { | ||
| (0, import_shared5.walkObject)(withoutEmpty.theme.tokens, (args) => args, { | ||
| stop(token) { | ||
| if (!isValidToken(token)) return false; | ||
| const keys = Object.keys(token); | ||
| const nestedKeys = keys.filter((k) => !tokenKeys.includes(k)); | ||
| const nested = nestedKeys.length > 0; | ||
| if (nested) { | ||
| token.DEFAULT ||= {}; | ||
| tokenKeys.forEach((key) => { | ||
| if (token[key] == null) return; | ||
| token.DEFAULT[key] ||= token[key]; | ||
| delete token[key]; | ||
| }); | ||
| } | ||
| return true; | ||
| } | ||
| }); | ||
| } | ||
| return withoutEmpty; | ||
| } | ||
| // src/get-resolved-config.ts | ||
| var hookUtils = { | ||
| omit: import_shared6.omit, | ||
| pick: import_shared6.pick, | ||
| traverse: import_shared6.traverse | ||
| }; | ||
| async function getResolvedConfig(config, cwd, hooks) { | ||
| const stack = [config]; | ||
| const configs = []; | ||
| while (stack.length > 0) { | ||
| const current = stack.pop(); | ||
| const subPresets = current.presets ?? []; | ||
| for (const subPreset of subPresets) { | ||
| let presetConfig; | ||
| let presetName; | ||
| if (typeof subPreset === "string") { | ||
| const presetModule = await bundle(subPreset, cwd); | ||
| presetConfig = presetModule.config; | ||
| presetName = subPreset; | ||
| } else { | ||
| presetConfig = await subPreset; | ||
| presetName = presetConfig.name || "unknown-preset"; | ||
| } | ||
| if (hooks?.["preset:resolved"]) { | ||
| const resolvedPreset = await hooks["preset:resolved"]({ | ||
| preset: presetConfig, | ||
| name: presetName, | ||
| utils: hookUtils | ||
| }); | ||
| if (resolvedPreset !== void 0) { | ||
| presetConfig = resolvedPreset; | ||
| } | ||
| } | ||
| stack.push(presetConfig); | ||
| } | ||
| configs.unshift(current); | ||
| } | ||
| const merged = mergeConfigs(configs); | ||
| merged.presets = configs.slice(0, -1); | ||
| return merged; | ||
| } | ||
| // src/resolve-config.ts | ||
| var import_logger4 = require("@bamboocss/logger"); | ||
| var import_shared11 = require("@bamboocss/shared"); | ||
| // src/bundled-preset.ts | ||
| var import_preset_base = require("@bamboocss/preset-base"); | ||
| var import_preset_bamboo = require("@bamboocss/preset-bamboo"); | ||
| var bundledPresets = { | ||
| "@bamboocss/preset-base": import_preset_base.preset, | ||
| "@bamboocss/preset-bamboo": import_preset_bamboo.preset, | ||
| "@bamboocss/dev/presets": import_preset_bamboo.preset | ||
| }; | ||
| var bundledPresetsNames = Object.keys(bundledPresets); | ||
| var isBundledPreset = (preset) => bundledPresetsNames.includes(preset); | ||
| var getBundledPreset = (preset) => { | ||
| return typeof preset === "string" && isBundledPreset(preset) ? bundledPresets[preset] : void 0; | ||
| }; | ||
| // src/validate-config.ts | ||
| var import_logger3 = require("@bamboocss/logger"); | ||
| var import_shared10 = require("@bamboocss/shared"); | ||
| // src/validation/validate-artifact.ts | ||
| var validateArtifactNames = (names, addError) => { | ||
| names.recipes.forEach((recipeName) => { | ||
| if (names.slotRecipes.has(recipeName)) { | ||
| addError("recipes", `This recipe name is already used in \`theme.slotRecipes\`: ${recipeName}`); | ||
| } | ||
| if (names.patterns.has(recipeName)) { | ||
| addError("recipes", `This recipe name is already used in \`patterns\`: \`${recipeName}\``); | ||
| } | ||
| }); | ||
| names.slotRecipes.forEach((recipeName) => { | ||
| if (names.patterns.has(recipeName)) { | ||
| addError("recipes", `This recipe name is already used in \`patterns\`: ${recipeName}`); | ||
| } | ||
| }); | ||
| }; | ||
| // src/validation/validate-breakpoints.ts | ||
| var import_shared7 = require("@bamboocss/shared"); | ||
| var validateBreakpoints = (breakpoints, addError) => { | ||
| if (!breakpoints) return; | ||
| const units = /* @__PURE__ */ new Set(); | ||
| const values = Object.values(breakpoints); | ||
| for (const value of values) { | ||
| const unit = (0, import_shared7.getUnit)(value) ?? "px"; | ||
| units.add(unit); | ||
| } | ||
| if (units.size > 1) { | ||
| addError("breakpoints", `All breakpoints must use the same unit: \`${values.join(", ")}\``); | ||
| } | ||
| }; | ||
| // src/validation/validate-condition.ts | ||
| var import_shared8 = require("@bamboocss/shared"); | ||
| var validateObjectCondition = (obj, addError) => { | ||
| let hasSlot = false; | ||
| for (const [key, value] of Object.entries(obj)) { | ||
| if (!key.startsWith("@") && !key.includes("&")) { | ||
| addError("conditions", `Selectors should contain the \`&\` character: \`${key}\``); | ||
| } | ||
| if (value === "@slot") { | ||
| hasSlot = true; | ||
| continue; | ||
| } | ||
| if (typeof value === "string") { | ||
| addError( | ||
| "conditions", | ||
| `Object condition leaves must be the literal string \`'@slot'\`, got \`${JSON.stringify(value)}\` at \`${key}\`` | ||
| ); | ||
| continue; | ||
| } | ||
| if (typeof value === "object" && value !== null) { | ||
| const nested = validateObjectCondition(value, addError); | ||
| if (nested.hasSlot) hasSlot = true; | ||
| } | ||
| } | ||
| return { hasSlot }; | ||
| }; | ||
| var validateConditions = (conditions, addError) => { | ||
| if (!conditions) return; | ||
| Object.values(conditions).forEach((condition) => { | ||
| if ((0, import_shared8.isString)(condition)) { | ||
| if (!condition.startsWith("@") && !condition.includes("&")) { | ||
| addError("conditions", `Selectors should contain the \`&\` character: \`${condition}\``); | ||
| } | ||
| return; | ||
| } | ||
| if (Array.isArray(condition)) { | ||
| condition.forEach((c) => { | ||
| if (!c.startsWith("@") && !c.includes("&")) { | ||
| addError("conditions", `Selectors should contain the \`&\` character: \`${c}\``); | ||
| } | ||
| }); | ||
| return; | ||
| } | ||
| const { hasSlot } = validateObjectCondition(condition, addError); | ||
| if (!hasSlot) { | ||
| addError("conditions", `Object conditions must contain at least one \`'@slot'\` marker`); | ||
| } | ||
| }); | ||
| }; | ||
| // src/validation/validate-patterns.ts | ||
| var validatePatterns = (patterns, names) => { | ||
| if (!patterns) return; | ||
| Object.keys(patterns).forEach((patternName) => { | ||
| names.patterns.add(patternName); | ||
| }); | ||
| }; | ||
| // src/validation/validate-recipes.ts | ||
| var validateRecipes = (options) => { | ||
| const { | ||
| config: { theme }, | ||
| artifacts | ||
| } = options; | ||
| if (!theme) return; | ||
| if (theme.recipes) { | ||
| Object.keys(theme.recipes).forEach((recipeName) => { | ||
| artifacts.recipes.add(recipeName); | ||
| }); | ||
| } | ||
| if (theme.slotRecipes) { | ||
| Object.keys(theme.slotRecipes).forEach((recipeName) => { | ||
| artifacts.slotRecipes.add(recipeName); | ||
| }); | ||
| } | ||
| return artifacts; | ||
| }; | ||
| // src/validation/validate-tokens.ts | ||
| var import_shared9 = require("@bamboocss/shared"); | ||
| // src/validation/validate-token-references.ts | ||
| var validateTokenReferences = (props) => { | ||
| const { valueAtPath, refsByPath, addError, typeByPath } = props; | ||
| refsByPath.forEach((refs, path2) => { | ||
| if (refs.has(path2)) { | ||
| addError("tokens", `Self token reference: \`${path2}\``); | ||
| } | ||
| const stack = [path2]; | ||
| while (stack.length > 0) { | ||
| let currentPath = stack.pop(); | ||
| if (currentPath.includes("/")) { | ||
| const [tokenPath] = currentPath.split("/"); | ||
| currentPath = tokenPath; | ||
| } | ||
| const value = valueAtPath.get(currentPath); | ||
| if (!value) { | ||
| const configKey = typeByPath.get(path2); | ||
| addError("tokens", `Missing token: \`${currentPath}\` used in \`theme.${configKey}.${path2}\``); | ||
| } | ||
| if (isTokenReference(value) && !refsByPath.has(value)) { | ||
| addError("tokens", `Unknown token reference: \`${currentPath}\` used in \`${value}\``); | ||
| } | ||
| const deps = refsByPath.get(currentPath); | ||
| if (!deps) continue; | ||
| for (const transitiveDep of deps) { | ||
| if (path2 === transitiveDep) { | ||
| addError( | ||
| "tokens", | ||
| `Circular token reference: \`${transitiveDep}\` -> \`${currentPath}\` -> ... -> \`${path2}\`` | ||
| ); | ||
| break; | ||
| } | ||
| stack.push(transitiveDep); | ||
| } | ||
| } | ||
| }); | ||
| }; | ||
| // src/validation/validate-tokens.ts | ||
| var validateTokens = (options) => { | ||
| const { | ||
| config: { theme }, | ||
| tokens: tokens2, | ||
| addError | ||
| } = options; | ||
| if (!theme) return; | ||
| const { tokenNames, semanticTokenNames, valueAtPath, refsByPath, typeByPath } = tokens2; | ||
| if (theme.tokens) { | ||
| const tokenPaths = /* @__PURE__ */ new Set(); | ||
| (0, import_shared9.walkObject)( | ||
| theme.tokens, | ||
| (value, paths) => { | ||
| const path2 = paths.join(SEP); | ||
| tokenNames.add(path2); | ||
| tokenPaths.add(path2); | ||
| valueAtPath.set(path2, value); | ||
| if (path2.includes("DEFAULT")) { | ||
| valueAtPath.set(path2.replace(SEP + "DEFAULT", ""), value); | ||
| } | ||
| }, | ||
| { | ||
| stop: isValidToken | ||
| } | ||
| ); | ||
| tokenPaths.forEach((path2) => { | ||
| const itemValue = valueAtPath.get(path2); | ||
| const formattedPath = formatPath(path2); | ||
| typeByPath.set(formattedPath, "tokens"); | ||
| if (!isValidToken(itemValue)) { | ||
| addError("tokens", `Token must contain 'value': \`theme.tokens.${formattedPath}\``); | ||
| return; | ||
| } | ||
| if (path2.includes(" ")) { | ||
| addError("tokens", `Token key must not contain spaces: \`theme.tokens.${formattedPath}\``); | ||
| return; | ||
| } | ||
| const valueStr = serializeTokenValue(itemValue.value || itemValue); | ||
| if (isTokenReference(valueStr)) { | ||
| refsByPath.set(formattedPath, /* @__PURE__ */ new Set([])); | ||
| } | ||
| const references = refsByPath.get(formattedPath); | ||
| if (!references) return; | ||
| getReferences(valueStr).forEach((reference) => { | ||
| references.add(reference); | ||
| }); | ||
| }); | ||
| } | ||
| if (theme.semanticTokens) { | ||
| const tokenPaths = /* @__PURE__ */ new Set(); | ||
| (0, import_shared9.walkObject)( | ||
| theme.semanticTokens, | ||
| (value, paths) => { | ||
| const path2 = paths.join(SEP); | ||
| semanticTokenNames.add(path2); | ||
| valueAtPath.set(path2, value); | ||
| tokenPaths.add(path2); | ||
| if (path2.includes("DEFAULT")) { | ||
| valueAtPath.set(path2.replace(SEP + "DEFAULT", ""), value); | ||
| } | ||
| if (!isValidToken(value)) return; | ||
| (0, import_shared9.walkObject)(value, (itemValue, paths2) => { | ||
| const valuePath = paths2.join(SEP); | ||
| const formattedPath = formatPath(path2); | ||
| typeByPath.set(formattedPath, "semanticTokens"); | ||
| const fullPath = formattedPath + "." + paths2.join(SEP); | ||
| if (valuePath.includes("value" + SEP + "value")) { | ||
| addError("tokens", `You used \`value\` twice resulting in an invalid token \`theme.tokens.${fullPath}\``); | ||
| } | ||
| const valueStr = serializeTokenValue(itemValue.value || itemValue); | ||
| if (isTokenReference(valueStr)) { | ||
| if (!refsByPath.has(formattedPath)) { | ||
| refsByPath.set(formattedPath, /* @__PURE__ */ new Set()); | ||
| } | ||
| const references = refsByPath.get(formattedPath); | ||
| if (!references) return; | ||
| getReferences(valueStr).forEach((reference) => { | ||
| references.add(reference); | ||
| }); | ||
| } | ||
| }); | ||
| }, | ||
| { | ||
| stop: isValidToken | ||
| } | ||
| ); | ||
| tokenPaths.forEach((path2) => { | ||
| const formattedPath = formatPath(path2); | ||
| const value = valueAtPath.get(path2); | ||
| if (path2.includes(" ")) { | ||
| addError("tokens", `Token key must not contain spaces: \`theme.tokens.${formattedPath}\``); | ||
| return; | ||
| } | ||
| if (!(0, import_shared9.isObject)(value) && !path2.includes("value")) { | ||
| addError("tokens", `Token must contain 'value': \`theme.semanticTokens.${formattedPath}\``); | ||
| } | ||
| }); | ||
| } | ||
| validateTokenReferences({ valueAtPath, refsByPath, addError, typeByPath }); | ||
| }; | ||
| // src/validate-config.ts | ||
| var validateConfig = (config) => { | ||
| if (config.validation === "none") return; | ||
| const warnings = /* @__PURE__ */ new Set(); | ||
| const addError = (scope, message) => { | ||
| warnings.add(`[${scope}] ` + message); | ||
| }; | ||
| validateBreakpoints(config.theme?.breakpoints, addError); | ||
| validateConditions(config.conditions, addError); | ||
| const artifacts = { | ||
| recipes: /* @__PURE__ */ new Set(), | ||
| slotRecipes: /* @__PURE__ */ new Set(), | ||
| patterns: /* @__PURE__ */ new Set() | ||
| }; | ||
| const tokens2 = { | ||
| tokenNames: /* @__PURE__ */ new Set(), | ||
| semanticTokenNames: /* @__PURE__ */ new Set(), | ||
| valueAtPath: /* @__PURE__ */ new Map(), | ||
| refsByPath: /* @__PURE__ */ new Map(), | ||
| typeByPath: /* @__PURE__ */ new Map() | ||
| }; | ||
| if (config.theme) { | ||
| validateTokens({ config, tokens: tokens2, addError }); | ||
| validateRecipes({ config, tokens: tokens2, artifacts, addError }); | ||
| } | ||
| validatePatterns(config.patterns, artifacts); | ||
| validateArtifactNames(artifacts, addError); | ||
| if (warnings.size) { | ||
| const errors = `\u26A0\uFE0F Invalid config: | ||
| ${Array.from(warnings).map((err) => "- " + err).join("\n")} | ||
| `; | ||
| if (config.validation === "error") { | ||
| throw new import_shared10.BambooError("CONFIG_ERROR", errors); | ||
| } | ||
| import_logger3.logger.warn("config", errors); | ||
| return warnings; | ||
| } | ||
| }; | ||
| // src/resolve-config.ts | ||
| var hookUtils2 = { | ||
| omit: import_shared11.omit, | ||
| pick: import_shared11.pick, | ||
| traverse: import_shared11.traverse | ||
| }; | ||
| async function resolveConfig(result, cwd) { | ||
| const presets = /* @__PURE__ */ new Set(); | ||
| if (!result.config.eject) { | ||
| presets.add(import_preset_base.preset); | ||
| } | ||
| if (result.config.presets) { | ||
| result.config.presets.forEach((preset) => { | ||
| presets.add(getBundledPreset(preset) ?? preset); | ||
| }); | ||
| } else if (!result.config.eject) { | ||
| presets.add(import_preset_bamboo.preset); | ||
| } | ||
| result.config.presets = Array.from(presets); | ||
| const userConfig = result.config; | ||
| const pluginHooks = userConfig.plugins ?? []; | ||
| if (userConfig.hooks) { | ||
| pluginHooks.push({ name: import_shared11.BAMBOO_CONFIG_NAME, hooks: userConfig.hooks }); | ||
| } | ||
| const earlyHooks = mergeHooks(pluginHooks); | ||
| const mergedConfig = await getResolvedConfig(result.config, cwd, earlyHooks); | ||
| const hooks = mergedConfig.hooks ?? {}; | ||
| if (mergedConfig.logLevel) { | ||
| import_logger4.logger.level = mergedConfig.logLevel; | ||
| } | ||
| validateConfig(mergedConfig); | ||
| const loadConfigResult = { | ||
| ...result, | ||
| config: mergedConfig | ||
| }; | ||
| if (hooks["config:resolved"]) { | ||
| const result2 = await hooks["config:resolved"]({ | ||
| config: loadConfigResult.config, | ||
| path: loadConfigResult.path, | ||
| dependencies: loadConfigResult.dependencies, | ||
| utils: hookUtils2 | ||
| }); | ||
| if (result2) { | ||
| loadConfigResult.config = result2; | ||
| } | ||
| } | ||
| const serialized = (0, import_shared11.stringifyJson)( | ||
| Object.assign({}, loadConfigResult.config, { name: import_shared11.BAMBOO_CONFIG_NAME, presets: [] }) | ||
| ); | ||
| const deserialize = () => (0, import_shared11.parseJson)(serialized); | ||
| return { ...loadConfigResult, serialized, deserialize, hooks }; | ||
| } | ||
| // src/load-config.ts | ||
| async function loadConfig(options) { | ||
| const result = await bundleConfig(options); | ||
| return resolveConfig(result, options.cwd); | ||
| } | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| bundleConfig, | ||
| convertTsPathsToRegexes, | ||
| diffConfigs, | ||
| findConfig, | ||
| getConfigDependencies, | ||
| getResolvedConfig, | ||
| loadConfig, | ||
| mergeConfigs, | ||
| mergeHooks, | ||
| resolveConfig | ||
| }); |
| "use strict"; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __export = (target, all) => { | ||
| for (var name in all) | ||
| __defProp(target, name, { get: all[name], enumerable: true }); | ||
| }; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| // src/merge-config.ts | ||
| var merge_config_exports = {}; | ||
| __export(merge_config_exports, { | ||
| mergeConfigs: () => mergeConfigs, | ||
| mergeHooks: () => mergeHooks | ||
| }); | ||
| module.exports = __toCommonJS(merge_config_exports); | ||
| var import_shared2 = require("@bamboocss/shared"); | ||
| // src/merge-hooks.ts | ||
| var import_logger = require("@bamboocss/logger"); | ||
| var mergeHooks = (plugins) => { | ||
| const hooksFns = {}; | ||
| plugins.forEach(({ name, hooks }) => { | ||
| Object.entries(hooks ?? {}).forEach(([key, value]) => { | ||
| if (!hooksFns[key]) { | ||
| hooksFns[key] = []; | ||
| } | ||
| hooksFns[key].push([name, value]); | ||
| }); | ||
| }); | ||
| const mergedHooks = Object.fromEntries( | ||
| Object.entries(hooksFns).map(([key, entries]) => { | ||
| const fns = entries.map(([name, fn]) => tryCatch(name, fn)); | ||
| const reducer = key in reducers ? reducers[key] : void 0; | ||
| if (reducer) { | ||
| return [key, reducer(fns)]; | ||
| } | ||
| return [key, syncHooks.includes(key) ? callAll(...fns) : callAllAsync(...fns)]; | ||
| }) | ||
| ); | ||
| return mergedHooks; | ||
| }; | ||
| var createReducer = (reducer) => reducer; | ||
| var reducers = { | ||
| "config:resolved": createReducer((fns) => async (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.config; | ||
| let config = args.config; | ||
| for (const hookFn of fns) { | ||
| const result = await hookFn(Object.assign(args, { config, original })); | ||
| if (result !== void 0) { | ||
| config = result; | ||
| } | ||
| } | ||
| return config; | ||
| }), | ||
| "parser:before": createReducer((fns) => (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.content; | ||
| let content = args.content; | ||
| for (const hookFn of fns) { | ||
| const result = hookFn(Object.assign(args, { content, original })); | ||
| if (result !== void 0) { | ||
| content = result; | ||
| } | ||
| } | ||
| return content; | ||
| }), | ||
| "parser:preprocess": createReducer((fns) => (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.data; | ||
| let data = args.data; | ||
| for (const hookFn of fns) { | ||
| const result = hookFn(Object.assign(args, { data, original })); | ||
| if (result !== void 0) { | ||
| data = result; | ||
| } | ||
| } | ||
| return data; | ||
| }), | ||
| "cssgen:done": createReducer((fns) => (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.content; | ||
| let content = args.content; | ||
| for (const hookFn of fns) { | ||
| const result = hookFn(Object.assign(args, { content, original })); | ||
| if (result !== void 0) { | ||
| content = result; | ||
| } | ||
| } | ||
| return content; | ||
| }), | ||
| "codegen:prepare": createReducer((fns) => async (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.artifacts; | ||
| let artifacts = args.artifacts; | ||
| for (const hookFn of fns) { | ||
| const result = await hookFn(Object.assign(args, { artifacts, original })); | ||
| if (result) { | ||
| artifacts = result; | ||
| } | ||
| } | ||
| return artifacts; | ||
| }), | ||
| "preset:resolved": createReducer((fns) => async (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.preset; | ||
| let preset = args.preset; | ||
| for (const hookFn of fns) { | ||
| const result = await hookFn(Object.assign(args, { preset, original })); | ||
| if (result !== void 0) { | ||
| preset = result; | ||
| } | ||
| } | ||
| return preset; | ||
| }), | ||
| "css:optimize": createReducer((fns) => (_args) => { | ||
| const args = Object.assign({}, _args); | ||
| const original = _args.css; | ||
| let css = args.css; | ||
| for (const hookFn of fns) { | ||
| const result = hookFn(Object.assign(args, { css, original })); | ||
| if (result !== void 0) { | ||
| css = result; | ||
| } | ||
| } | ||
| return css; | ||
| }) | ||
| }; | ||
| var syncHooks = [ | ||
| "context:created", | ||
| "parser:before", | ||
| "parser:preprocess", | ||
| "parser:after", | ||
| "cssgen:done", | ||
| "css:optimize" | ||
| ]; | ||
| var callAllAsync = (...fns) => async (...a) => { | ||
| for (const fn of fns) { | ||
| await fn?.(...a); | ||
| } | ||
| }; | ||
| var callAll = (...fns) => (...a) => { | ||
| fns.forEach((fn) => fn?.(...a)); | ||
| }; | ||
| var tryCatch = (name, fn) => { | ||
| return (...args) => { | ||
| try { | ||
| return fn(...args); | ||
| } catch (e) { | ||
| import_logger.logger.caughtError("hooks", `Error in plugin "${name}"`, e); | ||
| } | ||
| }; | ||
| }; | ||
| // src/validation/utils.ts | ||
| var import_shared = require("@bamboocss/shared"); | ||
| var isValidToken = (token) => (0, import_shared.isObject)(token) && Object.hasOwnProperty.call(token, "value"); | ||
| // src/merge-config.ts | ||
| function getExtends(items) { | ||
| return items.reduce((merged, { extend }) => { | ||
| if (!extend) return merged; | ||
| return (0, import_shared2.mergeWith)(merged, extend, (originalValue, newValue) => { | ||
| if (newValue === void 0) { | ||
| return originalValue ?? []; | ||
| } | ||
| if (originalValue === void 0) { | ||
| return [newValue]; | ||
| } | ||
| if (Array.isArray(originalValue)) { | ||
| return [newValue, ...originalValue]; | ||
| } | ||
| return [newValue, originalValue]; | ||
| }); | ||
| }, {}); | ||
| } | ||
| function mergeRecords(records) { | ||
| return { | ||
| ...records.reduce((acc, record) => (0, import_shared2.assign)(acc, record), {}), | ||
| extend: getExtends(records) | ||
| }; | ||
| } | ||
| function mergeExtensions(records) { | ||
| const { extend = [], ...restProps } = mergeRecords(records); | ||
| return (0, import_shared2.mergeWith)(restProps, extend, (obj, extensions) => { | ||
| return (0, import_shared2.mergeAndConcat)({}, obj, ...extensions); | ||
| }); | ||
| } | ||
| var isEmptyObject = (obj) => typeof obj === "object" && Object.keys(obj).length === 0; | ||
| var compact = (obj) => { | ||
| return Object.keys(obj).reduce((acc, key) => { | ||
| if (obj[key] !== void 0 && !isEmptyObject(obj[key])) { | ||
| acc[key] = obj[key]; | ||
| } | ||
| return acc; | ||
| }, {}); | ||
| }; | ||
| var tokenKeys = ["description", "extensions", "type", "value", "deprecated"]; | ||
| function mergeConfigs(configs) { | ||
| const userConfig = configs.at(-1); | ||
| const pluginHooks = userConfig.plugins ?? []; | ||
| if (userConfig.hooks) { | ||
| pluginHooks.push({ name: import_shared2.BAMBOO_CONFIG_NAME, hooks: userConfig.hooks }); | ||
| } | ||
| const reversed = Array.from(configs).reverse(); | ||
| const mergedResult = (0, import_shared2.assign)( | ||
| { | ||
| conditions: mergeExtensions(reversed.map((config) => config.conditions ?? {})), | ||
| theme: mergeExtensions(reversed.map((config) => config.theme ?? {})), | ||
| patterns: mergeExtensions(reversed.map((config) => config.patterns ?? {})), | ||
| utilities: mergeExtensions(reversed.map((config) => config.utilities ?? {})), | ||
| globalCss: mergeExtensions(reversed.map((config) => config.globalCss ?? {})), | ||
| globalVars: mergeExtensions(reversed.map((config) => config.globalVars ?? {})), | ||
| globalFontface: mergeExtensions(reversed.map((config) => config.globalFontface ?? {})), | ||
| globalPositionTry: mergeExtensions(reversed.map((config) => config.globalPositionTry ?? {})), | ||
| staticCss: mergeExtensions(reversed.map((config) => config.staticCss ?? {})), | ||
| themes: mergeExtensions(reversed.map((config) => config.themes ?? {})), | ||
| hooks: mergeHooks(pluginHooks) | ||
| }, | ||
| ...reversed | ||
| ); | ||
| const withoutEmpty = compact(mergedResult); | ||
| if (withoutEmpty.theme?.tokens) { | ||
| (0, import_shared2.walkObject)(withoutEmpty.theme.tokens, (args) => args, { | ||
| stop(token) { | ||
| if (!isValidToken(token)) return false; | ||
| const keys = Object.keys(token); | ||
| const nestedKeys = keys.filter((k) => !tokenKeys.includes(k)); | ||
| const nested = nestedKeys.length > 0; | ||
| if (nested) { | ||
| token.DEFAULT ||= {}; | ||
| tokenKeys.forEach((key) => { | ||
| if (token[key] == null) return; | ||
| token.DEFAULT[key] ||= token[key]; | ||
| delete token[key]; | ||
| }); | ||
| } | ||
| return true; | ||
| } | ||
| }); | ||
| } | ||
| return withoutEmpty; | ||
| } | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| mergeConfigs, | ||
| mergeHooks | ||
| }); |
| "use strict"; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __export = (target, all) => { | ||
| for (var name in all) | ||
| __defProp(target, name, { get: all[name], enumerable: true }); | ||
| }; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| // src/resolve-ts-path-pattern.ts | ||
| var resolve_ts_path_pattern_exports = {}; | ||
| __export(resolve_ts_path_pattern_exports, { | ||
| resolveTsPathPattern: () => resolveTsPathPattern | ||
| }); | ||
| module.exports = __toCommonJS(resolve_ts_path_pattern_exports); | ||
| var import_path = require("path"); | ||
| var resolveTsPathPattern = (pathMappings, moduleSpecifier) => { | ||
| for (const mapping of pathMappings) { | ||
| const match = moduleSpecifier.match(mapping.pattern); | ||
| if (!match) { | ||
| continue; | ||
| } | ||
| for (const pathTemplate of mapping.paths) { | ||
| let starCount = 0; | ||
| const mappedId = pathTemplate.replace(/\*/g, () => { | ||
| const matchIndex = Math.min(++starCount, match.length - 1); | ||
| return match[matchIndex]; | ||
| }); | ||
| return mappedId.split(import_path.sep).join(import_path.posix.sep); | ||
| } | ||
| } | ||
| }; | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| resolveTsPathPattern | ||
| }); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
26
100%83068
-8.21%2129
-17.96%4
33.33%1
Infinity%+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
Updated
Updated
Updated