@tenphi/tasty 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +117 -28
- package/dist/chunks/cacheKey.js +16 -8
- package/dist/chunks/cacheKey.js.map +1 -1
- package/dist/chunks/renderChunk.js +31 -32
- package/dist/chunks/renderChunk.js.map +1 -1
- package/dist/config.d.ts +14 -2
- package/dist/config.js +11 -4
- package/dist/config.js.map +1 -1
- package/dist/core/index.d.ts +6 -4
- package/dist/core/index.js +5 -4
- package/dist/debug.d.ts +26 -141
- package/dist/debug.js +356 -635
- package/dist/debug.js.map +1 -1
- package/dist/hooks/useStyles.js +4 -3
- package/dist/hooks/useStyles.js.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.js +5 -4
- package/dist/parser/classify.js +2 -1
- package/dist/parser/classify.js.map +1 -1
- package/dist/parser/parser.js +1 -1
- package/dist/pipeline/index.d.ts +1 -1
- package/dist/pipeline/index.js +24 -14
- package/dist/pipeline/index.js.map +1 -1
- package/dist/pipeline/materialize.js +328 -79
- package/dist/pipeline/materialize.js.map +1 -1
- package/dist/pipeline/parseStateKey.d.ts +1 -1
- package/dist/pipeline/parseStateKey.js +2 -6
- package/dist/pipeline/parseStateKey.js.map +1 -1
- package/dist/plugins/okhsl-plugin.js +2 -275
- package/dist/plugins/okhsl-plugin.js.map +1 -1
- package/dist/plugins/types.d.ts +1 -1
- package/dist/properties/index.js +2 -15
- package/dist/properties/index.js.map +1 -1
- package/dist/ssr/format-property.js +9 -7
- package/dist/ssr/format-property.js.map +1 -1
- package/dist/states/index.js +10 -257
- package/dist/states/index.js.map +1 -1
- package/dist/styles/color.js +9 -5
- package/dist/styles/color.js.map +1 -1
- package/dist/styles/createStyle.js +24 -21
- package/dist/styles/createStyle.js.map +1 -1
- package/dist/styles/index.js +1 -1
- package/dist/styles/predefined.js +1 -1
- package/dist/styles/predefined.js.map +1 -1
- package/dist/styles/types.d.ts +1 -1
- package/dist/tasty.d.ts +6 -6
- package/dist/tasty.js +24 -11
- package/dist/tasty.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/utils/cache-wrapper.js +4 -8
- package/dist/utils/cache-wrapper.js.map +1 -1
- package/dist/utils/color-math.d.ts +46 -0
- package/dist/utils/color-math.js +749 -0
- package/dist/utils/color-math.js.map +1 -0
- package/dist/utils/color-space.d.ts +5 -0
- package/dist/utils/color-space.js +229 -0
- package/dist/utils/color-space.js.map +1 -0
- package/dist/utils/colors.js +3 -1
- package/dist/utils/colors.js.map +1 -1
- package/dist/utils/has-keys.js +13 -0
- package/dist/utils/has-keys.js.map +1 -0
- package/dist/utils/mod-attrs.js +2 -2
- package/dist/utils/mod-attrs.js.map +1 -1
- package/dist/utils/process-tokens.d.ts +3 -13
- package/dist/utils/process-tokens.js +18 -98
- package/dist/utils/process-tokens.js.map +1 -1
- package/dist/utils/styles.d.ts +2 -78
- package/dist/utils/styles.js +28 -535
- package/dist/utils/styles.js.map +1 -1
- package/dist/zero/babel.d.ts +8 -0
- package/dist/zero/babel.js +18 -3
- package/dist/zero/babel.js.map +1 -1
- package/dist/zero/next.js +9 -1
- package/dist/zero/next.js.map +1 -1
- package/docs/PIPELINE.md +519 -0
- package/docs/README.md +30 -0
- package/docs/adoption.md +10 -2
- package/docs/comparison.md +11 -6
- package/docs/configuration.md +26 -3
- package/docs/debug.md +152 -339
- package/docs/dsl.md +3 -1
- package/docs/getting-started.md +21 -7
- package/docs/injector.md +2 -2
- package/docs/runtime.md +59 -9
- package/docs/ssr.md +2 -2
- package/docs/styles.md +1 -1
- package/docs/tasty-static.md +19 -9
- package/package.json +4 -3
- package/dist/utils/hsl-to-rgb.js +0 -38
- package/dist/utils/hsl-to-rgb.js.map +0 -1
- package/dist/utils/okhsl-to-rgb.js +0 -296
- package/dist/utils/okhsl-to-rgb.js.map +0 -1
package/dist/utils/styles.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styles.js","names":[],"sources":["../../src/utils/styles.ts"],"sourcesContent":["import { StyleParser } from '../parser/parser';\nimport { okhslFunc } from '../plugins/okhsl-plugin';\nimport { createStateParserContext, parseAdvancedState } from '../states';\nimport type { Styles } from '../styles/types';\n\nimport { cacheWrapper } from './cache-wrapper';\nimport { camelToKebab } from './case-converter';\nimport { hslToRgb } from './hsl-to-rgb';\nimport { okhslToRgb } from './okhsl-to-rgb';\n\nimport type { ProcessedStyle, StyleDetails } from '../parser/types';\nimport type {\n AtRuleContext,\n ParsedAdvancedState,\n StateParserContext,\n} from '../states';\n\nexport type StyleValue<T = string> = T | boolean | number | null | undefined;\n\n/**\n * Normalize a color token value.\n * - Boolean `true` is converted to `'transparent'`\n * - Boolean `false` returns `null` (signals the token should be skipped)\n * - Other values are returned as-is\n *\n * @param value - The raw token value\n * @returns Normalized value or null if the token should be skipped\n */\nexport function normalizeColorTokenValue<T>(\n value: T | boolean,\n): T | 'transparent' | null {\n if (value === true) {\n return 'transparent';\n }\n if (value === false) {\n return null;\n }\n return value as T;\n}\n\nexport type StyleValueStateMap<T = string> = Record<\n string,\n StyleValue<T> | '@inherit'\n>;\n\n/**\n * Combined type for style values that can be either a direct value or a state map.\n * Use this for component props that accept style values.\n */\nexport type StylePropValue<T = string> = StyleValue<T> | StyleValueStateMap<T>;\n\nexport type ComputeModel = string | number;\n\nexport type CSSMap = { $?: string | string[] } & Record<\n string,\n string | string[]\n>;\n\nexport type StyleHandlerResult = CSSMap | CSSMap[] | void;\n\nexport type RawStyleHandler = (value: StyleValueStateMap) => StyleHandlerResult;\n\nexport type StyleHandler = RawStyleHandler & {\n __lookupStyles: string[];\n};\n\n/**\n * Handler definition forms for configure() and plugins.\n * - Function only: lookup styles inferred from key name\n * - Single property tuple: ['styleName', handler]\n * - Multi-property tuple: [['style1', 'style2'], handler]\n */\nexport type StyleHandlerDefinition =\n | RawStyleHandler\n | [string, RawStyleHandler]\n | [string[], RawStyleHandler];\n\nexport interface StyleStateData {\n model?: ComputeModel;\n tokens?: string[];\n value: StyleValue | StyleValueStateMap | StyleStateData;\n /** The list of mods to apply */\n mods: string[];\n /** The list of **not** mods to apply (e.g. `:not(:hover)`) */\n notMods: string[];\n /** Advanced states (media queries, container queries, etc.) */\n advancedStates?: ParsedAdvancedState[];\n /** At-rule context for CSS generation */\n atRuleContext?: AtRuleContext;\n /** Own mods for sub-element states (from @own()) - applied to sub-element selector */\n ownMods?: string[];\n /** Negated own mods for sub-element states */\n negatedOwnMods?: string[];\n}\n\nexport interface ParsedColor {\n color?: string;\n name?: string;\n opacity?: number;\n}\n\nexport type StyleStateDataList = StyleStateData[];\n\nexport type StyleStateDataListMap = Record<string, StyleStateDataList>;\n\nexport type StyleMap = Record<string, StyleValue | StyleValueStateMap>;\n\nexport type StyleStateMap = Record<string, StyleStateData>;\n\nconst devMode = process.env.NODE_ENV !== 'production';\n\n// Precompiled regex patterns for parseColor optimization\n// Match var(--name-color...) and extract the name, regardless of fallbacks\nconst COLOR_VAR_PATTERN = /var\\(--([a-z0-9-]+)-color/;\nconst COLOR_VAR_RGB_PATTERN = /var\\(--([a-z0-9-]+)-color-rgb/;\nconst RGB_ALPHA_PATTERN = /\\/\\s*([0-9.]+)\\)/;\nconst SIMPLE_COLOR_PATTERNS = [\n /^#[0-9a-fA-F]{3,8}$/, // Hex colors: #fff, #ffffff, #ffff, #ffffffff\n /^rgb\\(/, // RGB/RGBA functions\n /^hsl\\(/, // HSL/HSLA functions\n /^lch\\(/, // LCH color functions\n /^oklch\\(/, // OKLCH color functions\n /^okhsl\\(/, // OKHSL color functions\n /^var\\(--[a-z0-9-]+-color/, // CSS custom properties for colors\n /^currentColor$/, // CSS currentColor keyword\n /^transparent$/, // CSS transparent keyword\n];\n\n// Rate limiting for dev warnings to avoid spam\nlet colorWarningCount = 0;\nconst MAX_COLOR_WARNINGS = 10;\n\nexport const CUSTOM_UNITS = {\n r: '6px',\n cr: '10px',\n bw: '1px',\n ow: '3px',\n x: '8px',\n fs: 'var(--font-size)',\n lh: 'var(--line-height)',\n sf: function sf(num: number) {\n return `minmax(0, ${num}fr)`;\n },\n};\n\nexport const DIRECTIONS = ['top', 'right', 'bottom', 'left'];\n\n// Lazy-initialized to break the circular dependency:\n// parser.ts → classify.ts → utils/styles.ts → parser.ts\nlet __tastyParser: StyleParser | null = null;\n\nfunction getOrCreateParser(): StyleParser {\n if (!__tastyParser) {\n __tastyParser = new StyleParser({ units: CUSTOM_UNITS });\n __tastyParser.setFuncs(__tastyFuncs);\n }\n return __tastyParser;\n}\n\n// Registry for user-provided custom functions that the parser can call.\n// It is updated through the `customFunc` helper exported below.\n// okhsl is registered as a built-in function so it works regardless of\n// tree-shaking or module initialization order.\nconst __tastyFuncs: Record<string, (groups: StyleDetails[]) => string> = {\n okhsl: okhslFunc,\n};\n\nexport function customFunc(\n name: string,\n fn: (groups: StyleDetails[]) => string,\n) {\n __tastyFuncs[name] = fn;\n getOrCreateParser().setFuncs(__tastyFuncs);\n}\n\n/**\n * Get the global StyleParser instance.\n * Used by configure() to apply parser configuration.\n */\nexport function getGlobalParser(): StyleParser {\n return getOrCreateParser();\n}\n\n/**\n * Get the current custom functions registry.\n * Used by configure() to merge with new functions.\n */\nexport function getGlobalFuncs(): Record<\n string,\n (groups: StyleDetails[]) => string\n> {\n return __tastyFuncs;\n}\n\n// ============================================================================\n// Global Predefined Tokens\n// ============================================================================\n\n/**\n * Storage for predefined tokens that are replaced during style parsing.\n * Keys are token names (with $ or # prefix), values are pre-processed CSS values.\n */\nlet __globalPredefinedTokens: Record<string, string> | null = null;\n\n/**\n * Set global predefined tokens.\n * Called from configure() after processing token values.\n * Merges with existing tokens (new tokens override existing ones with same key).\n * Keys are normalized to lowercase (parser lowercases input before classification).\n * @internal\n */\nexport function setGlobalPredefinedTokens(\n tokens: Record<string, string>,\n): void {\n // Normalize keys to lowercase for case-insensitive matching\n const normalizedTokens: Record<string, string> = {};\n for (const [key, value] of Object.entries(tokens)) {\n const lowerKey = key.toLowerCase();\n const lowerValue = value.toLowerCase();\n\n // Warn if trying to use bare #current to define other color tokens\n // #current represents currentcolor which cannot be used as a base for recursive token resolution\n // Note: #current.5 (with opacity) is allowed since it resolves to a concrete color-mix value\n if (lowerKey.startsWith('#') && lowerValue === '#current') {\n console.warn(\n `Tasty: Using #current to define color token \"${key}\" is not supported. ` +\n `The #current token represents currentcolor which cannot be used as a base for other tokens.`,\n );\n continue; // Skip this token\n }\n\n normalizedTokens[lowerKey] = value;\n }\n // Merge with existing tokens (consistent with how states, units, funcs are handled)\n __globalPredefinedTokens = __globalPredefinedTokens\n ? { ...__globalPredefinedTokens, ...normalizedTokens }\n : normalizedTokens;\n // Clear parser cache since token values affect parsing\n getOrCreateParser().clearCache();\n}\n\n/**\n * Get the current global predefined tokens.\n * Returns null if no tokens are configured.\n */\nexport function getGlobalPredefinedTokens(): Record<string, string> | null {\n return __globalPredefinedTokens;\n}\n\n/**\n * Reset global predefined tokens.\n * Used for testing.\n * @internal\n */\nexport function resetGlobalPredefinedTokens(): void {\n __globalPredefinedTokens = null;\n // Clear parser cache since token availability affects parsing\n getOrCreateParser().clearCache();\n}\n\n/**\n *\n * @param {String} value\n * @param {Number} mode\n * @returns {Object<String,String|Array>}\n */\nexport function parseStyle(value: StyleValue): ProcessedStyle {\n let str: string;\n\n if (typeof value === 'string') {\n str = value;\n } else if (typeof value === 'number') {\n str = String(value);\n } else {\n // boolean, null, undefined, objects etc. → empty string\n str = '';\n }\n\n return getOrCreateParser().process(str);\n}\n\n/**\n * Parse color. Find it value, name and opacity.\n * Optimized to avoid heavy parseStyle calls for simple color patterns.\n */\nexport function parseColor(val: string, ignoreError = false): ParsedColor {\n // Early return for non-strings or empty values\n if (typeof val !== 'string') {\n val = String(val ?? '');\n }\n\n val = val.trim();\n if (!val) return {};\n\n // Fast path: Check if it's a simple color pattern that doesn't need full parsing\n const isSimpleColor = SIMPLE_COLOR_PATTERNS.some((pattern) =>\n pattern.test(val),\n );\n\n let firstColor: string;\n if (isSimpleColor) {\n // For simple colors, use the value directly without parsing\n firstColor = val;\n } else {\n const processed = parseStyle(val);\n const extractedColor = processed.groups.find((g) => g.colors.length)\n ?.colors[0];\n\n if (!extractedColor) {\n // Rate-limited warning to avoid spam\n if (!ignoreError && devMode && colorWarningCount < MAX_COLOR_WARNINGS) {\n console.warn('CubeUIKit: unable to parse color:', val);\n colorWarningCount++;\n if (colorWarningCount === MAX_COLOR_WARNINGS) {\n console.warn(\n 'CubeUIKit: color parsing warnings will be suppressed from now on',\n );\n }\n }\n return {};\n }\n\n firstColor = extractedColor;\n }\n\n // Extract color name (if present) from variable pattern using precompiled regex\n let nameMatch = firstColor.match(COLOR_VAR_PATTERN);\n if (!nameMatch) {\n nameMatch = firstColor.match(COLOR_VAR_RGB_PATTERN);\n }\n\n let opacity: number | undefined;\n if (\n firstColor.startsWith('rgb') ||\n firstColor.startsWith('hsl') ||\n firstColor.startsWith('lch') ||\n firstColor.startsWith('oklch') ||\n firstColor.startsWith('okhsl')\n ) {\n const alphaMatch = firstColor.match(RGB_ALPHA_PATTERN);\n if (alphaMatch) {\n const v = parseFloat(alphaMatch[1]);\n if (!isNaN(v)) opacity = v * 100;\n }\n }\n\n return {\n color: firstColor,\n name: nameMatch ? nameMatch[1] : undefined,\n opacity,\n };\n}\n\n/**\n * CSS named color keywords → hex values.\n * Lazy-initialized on first use to avoid up-front cost.\n */\nlet _namedColorHex: Map<string, string> | null = null;\n\nfunction getNamedColorHex(): Map<string, string> {\n if (_namedColorHex) return _namedColorHex;\n _namedColorHex = new Map([\n ['aliceblue', '#f0f8ff'],\n ['antiquewhite', '#faebd7'],\n ['aqua', '#00ffff'],\n ['aquamarine', '#7fffd4'],\n ['azure', '#f0ffff'],\n ['beige', '#f5f5dc'],\n ['bisque', '#ffe4c4'],\n ['black', '#000000'],\n ['blanchedalmond', '#ffebcd'],\n ['blue', '#0000ff'],\n ['blueviolet', '#8a2be2'],\n ['brown', '#a52a2a'],\n ['burlywood', '#deb887'],\n ['cadetblue', '#5f9ea0'],\n ['chartreuse', '#7fff00'],\n ['chocolate', '#d2691e'],\n ['coral', '#ff7f50'],\n ['cornflowerblue', '#6495ed'],\n ['cornsilk', '#fff8dc'],\n ['crimson', '#dc143c'],\n ['cyan', '#00ffff'],\n ['darkblue', '#00008b'],\n ['darkcyan', '#008b8b'],\n ['darkgoldenrod', '#b8860b'],\n ['darkgray', '#a9a9a9'],\n ['darkgreen', '#006400'],\n ['darkgrey', '#a9a9a9'],\n ['darkkhaki', '#bdb76b'],\n ['darkmagenta', '#8b008b'],\n ['darkolivegreen', '#556b2f'],\n ['darkorange', '#ff8c00'],\n ['darkorchid', '#9932cc'],\n ['darkred', '#8b0000'],\n ['darksalmon', '#e9967a'],\n ['darkseagreen', '#8fbc8f'],\n ['darkslateblue', '#483d8b'],\n ['darkslategray', '#2f4f4f'],\n ['darkslategrey', '#2f4f4f'],\n ['darkturquoise', '#00ced1'],\n ['darkviolet', '#9400d3'],\n ['deeppink', '#ff1493'],\n ['deepskyblue', '#00bfff'],\n ['dimgray', '#696969'],\n ['dimgrey', '#696969'],\n ['dodgerblue', '#1e90ff'],\n ['firebrick', '#b22222'],\n ['floralwhite', '#fffaf0'],\n ['forestgreen', '#228b22'],\n ['fuchsia', '#ff00ff'],\n ['gainsboro', '#dcdcdc'],\n ['ghostwhite', '#f8f8ff'],\n ['gold', '#ffd700'],\n ['goldenrod', '#daa520'],\n ['gray', '#808080'],\n ['green', '#008000'],\n ['greenyellow', '#adff2f'],\n ['grey', '#808080'],\n ['honeydew', '#f0fff0'],\n ['hotpink', '#ff69b4'],\n ['indianred', '#cd5c5c'],\n ['indigo', '#4b0082'],\n ['ivory', '#fffff0'],\n ['khaki', '#f0e68c'],\n ['lavender', '#e6e6fa'],\n ['lavenderblush', '#fff0f5'],\n ['lawngreen', '#7cfc00'],\n ['lemonchiffon', '#fffacd'],\n ['lightblue', '#add8e6'],\n ['lightcoral', '#f08080'],\n ['lightcyan', '#e0ffff'],\n ['lightgoldenrodyellow', '#fafad2'],\n ['lightgray', '#d3d3d3'],\n ['lightgreen', '#90ee90'],\n ['lightgrey', '#d3d3d3'],\n ['lightpink', '#ffb6c1'],\n ['lightsalmon', '#ffa07a'],\n ['lightseagreen', '#20b2aa'],\n ['lightskyblue', '#87cefa'],\n ['lightslategray', '#778899'],\n ['lightslategrey', '#778899'],\n ['lightsteelblue', '#b0c4de'],\n ['lightyellow', '#ffffe0'],\n ['lime', '#00ff00'],\n ['limegreen', '#32cd32'],\n ['linen', '#faf0e6'],\n ['magenta', '#ff00ff'],\n ['maroon', '#800000'],\n ['mediumaquamarine', '#66cdaa'],\n ['mediumblue', '#0000cd'],\n ['mediumorchid', '#ba55d3'],\n ['mediumpurple', '#9370db'],\n ['mediumseagreen', '#3cb371'],\n ['mediumslateblue', '#7b68ee'],\n ['mediumspringgreen', '#00fa9a'],\n ['mediumturquoise', '#48d1cc'],\n ['mediumvioletred', '#c71585'],\n ['midnightblue', '#191970'],\n ['mintcream', '#f5fffa'],\n ['mistyrose', '#ffe4e1'],\n ['moccasin', '#ffe4b5'],\n ['navajowhite', '#ffdead'],\n ['navy', '#000080'],\n ['oldlace', '#fdf5e6'],\n ['olive', '#808000'],\n ['olivedrab', '#6b8e23'],\n ['orange', '#ffa500'],\n ['orangered', '#ff4500'],\n ['orchid', '#da70d6'],\n ['palegoldenrod', '#eee8aa'],\n ['palegreen', '#98fb98'],\n ['paleturquoise', '#afeeee'],\n ['palevioletred', '#db7093'],\n ['papayawhip', '#ffefd5'],\n ['peachpuff', '#ffdab9'],\n ['peru', '#cd853f'],\n ['pink', '#ffc0cb'],\n ['plum', '#dda0dd'],\n ['powderblue', '#b0e0e6'],\n ['purple', '#800080'],\n ['rebeccapurple', '#663399'],\n ['red', '#ff0000'],\n ['rosybrown', '#bc8f8f'],\n ['royalblue', '#4169e1'],\n ['saddlebrown', '#8b4513'],\n ['salmon', '#fa8072'],\n ['sandybrown', '#f4a460'],\n ['seagreen', '#2e8b57'],\n ['seashell', '#fff5ee'],\n ['sienna', '#a0522d'],\n ['silver', '#c0c0c0'],\n ['skyblue', '#87ceeb'],\n ['slateblue', '#6a5acd'],\n ['slategray', '#708090'],\n ['slategrey', '#708090'],\n ['snow', '#fffafa'],\n ['springgreen', '#00ff7f'],\n ['steelblue', '#4682b4'],\n ['tan', '#d2b48c'],\n ['teal', '#008080'],\n ['thistle', '#d8bfd8'],\n ['tomato', '#ff6347'],\n ['turquoise', '#40e0d0'],\n ['violet', '#ee82ee'],\n ['wheat', '#f5deb3'],\n ['white', '#ffffff'],\n ['whitesmoke', '#f5f5f5'],\n ['yellow', '#ffff00'],\n ['yellowgreen', '#9acd32'],\n ]);\n return _namedColorHex;\n}\n\nexport function strToRgb(\n color: string,\n _ignoreAlpha = false,\n): string | null | undefined {\n if (!color) return undefined;\n\n if (color.startsWith('rgb')) return color;\n\n if (color.startsWith('#')) return hexToRgb(color);\n\n if (color.startsWith('okhsl(')) return okhslToRgb(color);\n\n if (color.startsWith('hsl')) return hslToRgb(color);\n\n // Named CSS colors\n const namedHex = getNamedColorHex().get(color.toLowerCase());\n if (namedHex) return hexToRgb(namedHex);\n\n return null;\n}\n\n/**\n * Extract RGB values from an rgb()/rgba() string.\n * Supports all modern CSS syntax variations:\n * - Comma-separated: rgb(255, 128, 0)\n * - Space-separated: rgb(255 128 0)\n * - Fractional: rgb(128.5, 64.3, 32.1)\n * - Percentages: rgb(50%, 25%, 75%)\n * - Slash alpha notation: rgb(255 128 0 / 0.5)\n *\n * Returns array of RGB values (0-255 range), converting percentages as needed.\n */\nexport function getRgbValuesFromRgbaString(str: string): number[] {\n // Extract content inside rgb()/rgba()\n const match = str.match(/rgba?\\(([^)]+)\\)/i);\n if (!match) return [];\n\n const inner = match[1].trim();\n // Split by slash first (for alpha), then handle color components\n const [colorPart] = inner.split('/');\n // Split by comma or whitespace\n const parts = colorPart\n .trim()\n .split(/[,\\s]+/)\n .filter(Boolean);\n\n return parts.slice(0, 3).map((part) => {\n part = part.trim();\n if (part.endsWith('%')) {\n // Convert percentage to 0-255 range\n return (parseFloat(part) / 100) * 255;\n }\n return parseFloat(part);\n });\n}\n\nexport function hexToRgb(hex: string): string | null {\n const matched = hex\n .replace(\n /^#?([a-f\\d])([a-f\\d])([a-f\\d])$/i,\n (_m: string, r: string, g: string, b: string) =>\n '#' + r + r + g + g + b + b,\n )\n .substring(1)\n .match(/.{2}/g);\n\n if (!matched) return null;\n\n const rgba = matched.map(\n (x: string, i: number) => parseInt(x, 16) * (i === 3 ? 1 / 255 : 1),\n );\n\n if (rgba.some((v) => Number.isNaN(v))) {\n return null;\n }\n\n if (rgba.length >= 3) {\n return `rgb(${rgba.slice(0, 3).join(' ')}${rgba.length > 3 ? ` / ${rgba[3]}` : ''})`;\n }\n\n return null;\n}\n\nexport function filterMods(mods: string[], allowedMods: string[]): string[] {\n return mods.filter((mod) => allowedMods.includes(mod));\n}\n\nexport function extendStyles(\n defaultStyles?: Record<string, unknown> | null,\n newStyles?: Record<string, unknown> | null,\n): Record<string, unknown> {\n let styles: Record<string, unknown> = {};\n\n if (!defaultStyles) {\n if (!newStyles) {\n return styles;\n }\n } else {\n styles = Object.assign({}, defaultStyles);\n }\n\n if (newStyles) {\n Object.keys(newStyles).forEach((key) => {\n if (newStyles[key] != null) {\n styles[key] = newStyles[key];\n }\n });\n }\n\n return styles;\n}\n\n/**\n * Split properties into style and non-style properties.\n * @param props - Component prop map.\n * @param [styleList] - List of all style properties.\n * @param [defaultStyles] - Default style map of the component.\n * @param [propMap] - Props to style alias map.\n * @param [ignoreList] - A list of properties to ignore.\n */\nexport function extractStyles(\n props: Record<string, unknown>,\n styleList: readonly string[] = [],\n defaultStyles?: Styles,\n propMap?: Record<string, string>,\n ignoreList: readonly string[] = [],\n): Styles {\n const styles: Styles = {\n ...defaultStyles,\n ...(ignoreList.includes('styles')\n ? undefined\n : props.styles && typeof props.styles === 'object'\n ? (props.styles as Styles)\n : undefined),\n };\n\n Object.keys(props).forEach((prop) => {\n const propName = propMap ? propMap[prop] || prop : prop;\n const value = props[prop];\n\n if (ignoreList && ignoreList.includes(prop)) {\n // do nothing\n } else if (styleList.includes(propName)) {\n styles[propName] = value as Styles[keyof Styles];\n }\n }, {});\n\n return styles;\n}\n\n// Enhanced regex that includes advanced state patterns\n// Matches: operators, parentheses, @media(...), @(...), @root(...), @own(...), @starting, @predefined,\n// value mods, boolean mods, pseudo-classes, classes, attribute selectors\nconst STATES_REGEXP =\n /([&|!^])|([()])|(@media:[a-z]+)|(@media\\([^)]+\\))|(@root\\([^)]+\\))|(@own\\([^)]+\\))|(@\\([^)]+\\))|(@starting)|(@[A-Za-z][A-Za-z0-9-]*)|([a-z][a-z0-9-]+=(?:\"[^\"]*\"|'[^']*'|[^\\s&|!^()]+))|([a-z][a-z0-9-]+)|(:[a-z][a-z0-9-]+\\([^)]+\\)|:[a-z][a-z0-9-]+)|(\\.[a-z][a-z0-9-]+)|(\\[[^\\]]+])/gi;\n\n/**\n * Check if a token is an advanced state (starts with @)\n */\nexport function isAdvancedStateToken(token: string): boolean {\n return token.startsWith('@') || token.startsWith('!@');\n}\nexport const STATE_OPERATORS = {\n NOT: '!',\n AND: '&',\n OR: '|',\n XOR: '^',\n};\n\nexport const STATE_OPERATOR_LIST = ['!', '&', '|', '^'];\n\n/**\n * Convert state notation tokens to a compute model (string, or nested [op, lhs, rhs]).\n */\nfunction convertTokensToComputeUnits(tokens: unknown[]): unknown {\n if (tokens.length === 1) {\n return tokens[0];\n }\n\n const hasLength = (x: unknown): x is string | unknown[] =>\n typeof x === 'string' || Array.isArray(x);\n\n STATE_OPERATOR_LIST.forEach((operator) => {\n let i;\n\n while ((i = tokens.indexOf(operator)) !== -1) {\n const token = tokens[i];\n\n if (token === '!') {\n const next = tokens[i + 1];\n if (next !== undefined && hasLength(next) && next.length !== 1) {\n tokens.splice(i, 2, ['!', next]);\n } else {\n tokens.splice(i, 1);\n }\n } else {\n const prev = tokens[i - 1];\n const next = tokens[i + 1];\n if (\n prev !== undefined &&\n next !== undefined &&\n hasLength(prev) &&\n hasLength(next) &&\n prev.length !== 1 &&\n next.length !== 1\n ) {\n tokens.splice(i - 1, 3, [token, prev, next]);\n } else {\n tokens.splice(i, 1);\n }\n }\n }\n });\n\n return tokens.length === 1 ? tokens[0] : tokens;\n}\n\n/**\n * Replace commas with | only outside of parentheses.\n * This preserves commas in advanced states like @(card, w < 600px)\n */\nfunction replaceCommasOutsideParens(str: string): string {\n let result = '';\n let depth = 0;\n\n for (const char of str) {\n if (char === '(') {\n depth++;\n result += char;\n } else if (char === ')') {\n depth--;\n result += char;\n } else if (char === ',' && depth === 0) {\n // Only replace commas at the top level (outside parentheses)\n result += '|';\n } else {\n result += char;\n }\n }\n\n return result;\n}\n\n/**\n * Parse state notation and return tokens, modifiers and compute model.\n */\nfunction parseStateNotationInner(\n notation: string,\n value: StyleValue | StyleValueStateMap | StyleStateData,\n): StyleStateData {\n const tokens = replaceCommasOutsideParens(notation).match(STATES_REGEXP);\n\n if (!tokens || !tokens.length) {\n return {\n model: undefined,\n mods: [],\n notMods: [],\n tokens: [],\n value,\n };\n } else if (tokens.length === 1) {\n return {\n model: tokens[0],\n mods: tokens.slice(0),\n notMods: [],\n tokens,\n value,\n };\n }\n\n const mods: string[] = [];\n\n const operations: unknown[][] = [[]];\n let list = operations[0];\n let position = 0;\n let operation: unknown[];\n\n tokens.forEach((token) => {\n switch (token) {\n case '(':\n operation = [];\n position++;\n list = operations[position] = operation;\n break;\n case ')':\n position--;\n operations[position].push(\n convertTokensToComputeUnits(list as unknown[]),\n );\n list = operations[position];\n break;\n default:\n if (token.length > 1) {\n if (!mods.includes(token)) {\n mods.push(token);\n }\n }\n list.push(token);\n }\n });\n\n while (position) {\n position--;\n operations[position].push(convertTokensToComputeUnits(list as unknown[]));\n list = operations[position];\n }\n\n return {\n tokens,\n mods,\n notMods: [],\n model: convertTokensToComputeUnits(operations[0] as unknown[]) as\n | ComputeModel\n | undefined,\n value,\n };\n}\n\nexport const parseStateNotation = cacheWrapper(parseStateNotationInner);\n\n/**\n * Build an AtRuleContext from parsed advanced states\n */\nexport function buildAtRuleContext(\n advancedStates: ParsedAdvancedState[],\n negatedStates: Set<string>,\n): AtRuleContext | undefined {\n if (advancedStates.length === 0) return undefined;\n\n const ctx: AtRuleContext = {};\n\n for (const state of advancedStates) {\n const isNegated = negatedStates.has(state.raw);\n\n switch (state.type) {\n case 'media': {\n if (!ctx.media) ctx.media = [];\n let mediaCondition = '';\n\n if (state.mediaType) {\n // @media:print, @media:screen, etc.\n mediaCondition = state.mediaType;\n } else if (state.condition) {\n // @media(width < 920px)\n mediaCondition = `(${state.condition})`;\n }\n\n if (mediaCondition) {\n if (isNegated) {\n ctx.media.push(`not ${mediaCondition}`);\n } else {\n ctx.media.push(mediaCondition);\n }\n }\n break;\n }\n\n case 'container': {\n if (!ctx.container) ctx.container = [];\n let condition = state.condition;\n if (isNegated) {\n condition = `not (${condition})`;\n }\n ctx.container.push({\n name: state.containerName,\n condition,\n });\n break;\n }\n\n case 'root': {\n if (!ctx.rootStates) ctx.rootStates = [];\n // Parse the condition to generate the proper selector\n const rootSelector = buildRootSelector(state.condition, isNegated);\n ctx.rootStates.push(rootSelector);\n break;\n }\n\n case 'starting': {\n if (!isNegated) {\n ctx.startingStyle = true;\n }\n break;\n }\n\n // 'own' and 'predefined' are handled differently (selector-based, not at-rule)\n // 'modifier' is a regular state\n }\n }\n\n // Return undefined if no at-rules were added\n if (\n !ctx.media?.length &&\n !ctx.container?.length &&\n !ctx.rootStates?.length &&\n !ctx.startingStyle\n ) {\n return undefined;\n }\n\n return ctx;\n}\n\n/**\n * Build a root state selector from a condition\n */\nfunction buildRootSelector(condition: string, isNegated: boolean): string {\n // Handle different condition formats:\n // - theme=dark -> [data-theme=\"dark\"]\n // - .className -> .className\n // - [attr] -> [attr]\n // - booleanMod -> [data-boolean-mod]\n\n let selector: string;\n\n if (condition.startsWith('.')) {\n // Class selector\n selector = condition;\n } else if (condition.startsWith('[')) {\n // Attribute selector\n selector = condition;\n } else if (condition.includes('=')) {\n // Value mod: theme=dark -> [data-theme=\"dark\"]\n const [key, value] = condition.split('=');\n selector = `[data-${camelToKebab(key.trim())}=\"${value.trim()}\"]`;\n } else {\n // Boolean mod: camelCase -> [data-camel-case]\n selector = `[data-${camelToKebab(condition)}]`;\n }\n\n if (isNegated) {\n return `:not(${selector})`;\n }\n return selector;\n}\n\n/**\n * Parse state notation and return tokens, modifiers and compute model.\n * Enhanced to detect and extract advanced states.\n */\nexport function styleStateMapToStyleStateDataList(\n styleStateMap: StyleStateMap | StyleValue | StyleValueStateMap,\n parserContext?: StateParserContext,\n): { states: StyleStateDataList; mods: string[]; hasAdvancedStates: boolean } {\n if (typeof styleStateMap !== 'object' || !styleStateMap) {\n return {\n states: [\n {\n model: undefined,\n mods: [],\n notMods: [],\n value: styleStateMap,\n },\n ],\n mods: [],\n hasAdvancedStates: false,\n };\n }\n\n const stateDataList: StyleStateDataList = [];\n let hasAdvancedStates = false;\n\n Object.keys(styleStateMap).forEach((stateNotation) => {\n const state = parseStateNotation(\n stateNotation,\n styleStateMap[stateNotation],\n );\n\n // Check if this state contains any advanced states\n const advancedStates: ParsedAdvancedState[] = [];\n const negatedAdvancedStates = new Set<string>();\n const regularMods: string[] = [];\n const ownMods: string[] = [];\n const negatedOwnMods: string[] = [];\n\n // Scan tokens for advanced states\n if (state.tokens) {\n let isNegated = false;\n for (const token of state.tokens) {\n if (token === '!') {\n isNegated = true;\n continue;\n }\n\n if (isAdvancedStateToken(token)) {\n hasAdvancedStates = true;\n const ctx = parserContext || createStateParserContext(undefined);\n const parsed = parseAdvancedState(token, ctx);\n advancedStates.push(parsed);\n\n // Handle @own states specially - extract condition as ownMod\n if (parsed.type === 'own' && parsed.condition) {\n if (isNegated) {\n negatedOwnMods.push(parsed.condition);\n } else {\n ownMods.push(parsed.condition);\n }\n } else if (isNegated) {\n negatedAdvancedStates.add(token);\n }\n isNegated = false;\n } else if (\n token.length > 1 &&\n !['&', '|', '^', '(', ')'].includes(token)\n ) {\n regularMods.push(token);\n isNegated = false;\n } else {\n isNegated = false;\n }\n }\n }\n\n // If there are advanced states, build the atRuleContext\n if (advancedStates.length > 0) {\n state.advancedStates = advancedStates;\n state.atRuleContext = buildAtRuleContext(\n advancedStates,\n negatedAdvancedStates,\n );\n // Filter mods to only include regular mods (not advanced states)\n state.mods = regularMods;\n }\n\n // Store own mods for sub-element selector generation\n if (ownMods.length > 0) {\n state.ownMods = ownMods;\n }\n if (negatedOwnMods.length > 0) {\n state.negatedOwnMods = negatedOwnMods;\n }\n\n stateDataList.push(state);\n });\n\n stateDataList.reverse();\n\n let initialState;\n\n const allMods: string[] = stateDataList.reduce((all: string[], state) => {\n if (!state.mods.length && !state.advancedStates?.length) {\n initialState = state;\n } else {\n state.mods.forEach((mod) => {\n if (!all.includes(mod)) {\n all.push(mod);\n }\n });\n }\n\n return all;\n }, []);\n\n if (!initialState) {\n stateDataList.push({\n mods: [],\n notMods: allMods,\n value: true,\n });\n }\n\n return { states: stateDataList, mods: allMods, hasAdvancedStates };\n}\n\nexport const COMPUTE_FUNC_MAP: Record<\n string,\n (a: unknown, b?: unknown) => unknown\n> = {\n '!': (a: unknown) => !a,\n '^': (a: unknown, b?: unknown) => (a && !b) || (!a && b),\n '|': (a: unknown, b?: unknown) => a || b,\n '&': (a: unknown, b?: unknown) => a && b,\n};\n\n/**\n * Compute a result based on a model and incoming map.\n */\nexport function computeState(\n computeModel: ComputeModel,\n valueMap:\n | (number | boolean)[]\n | Record<string, boolean>\n | ((...args: unknown[]) => unknown),\n) {\n if (!computeModel) return true;\n\n const map = valueMap as Record<string | number, unknown>;\n\n if (!Array.isArray(computeModel)) {\n if (typeof valueMap === 'function') {\n return !!valueMap(computeModel);\n } else {\n return !!map[computeModel];\n }\n }\n\n const func = COMPUTE_FUNC_MAP[computeModel[0]];\n\n if (!func) {\n console.warn(\n 'CubeUIKit: unexpected compute method in the model',\n computeModel,\n );\n // return false;\n }\n\n let a: unknown = computeModel[1];\n\n if (typeof a === 'object') {\n a = !!computeState(a as unknown as ComputeModel, valueMap);\n } else if (typeof valueMap === 'function') {\n a = !!valueMap(a);\n } else {\n a = !!map[a as string | number];\n }\n\n if (computeModel.length === 2) {\n return func(a);\n }\n\n let b: unknown = computeModel[2];\n\n if (typeof b === 'object') {\n b = !!computeState(b as unknown as ComputeModel, valueMap);\n } else if (typeof valueMap === 'function') {\n b = !!valueMap(b);\n } else {\n b = !!map[b as string | number];\n }\n\n return !!func(a, b);\n}\n\nconst _innerCache = new WeakMap();\n\nexport function stringifyStyles(styles: unknown): string {\n if (styles == null || typeof styles !== 'object') return '';\n const obj = styles as Record<string, unknown>;\n const keys = Object.keys(obj).sort();\n const parts: string[] = [];\n for (const k of keys) {\n const v = obj[k];\n if (v === undefined || typeof v === 'function' || typeof v === 'symbol')\n continue;\n\n const c0 = k.charCodeAt(0);\n const needsInnerSort =\n ((c0 >= 65 && c0 <= 90) || c0 === 38) &&\n v &&\n typeof v === 'object' &&\n !Array.isArray(v);\n\n let sv: string;\n if (needsInnerSort) {\n sv = _innerCache.get(v);\n if (sv === undefined) {\n const innerObj = v as Record<string, unknown>;\n const innerKeys = Object.keys(innerObj).sort();\n const innerParts: string[] = [];\n for (const ik of innerKeys) {\n const ivs = JSON.stringify(innerObj[ik]);\n if (ivs !== undefined)\n innerParts.push(JSON.stringify(ik) + ':' + ivs);\n }\n sv = '{' + innerParts.join(',') + '}';\n _innerCache.set(v, sv);\n }\n } else {\n sv = JSON.stringify(v);\n }\n parts.push(JSON.stringify(k) + ':' + sv);\n }\n return '{' + parts.join(',') + '}';\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"styles.js","names":[],"sources":["../../src/utils/styles.ts"],"sourcesContent":["import { StyleParser } from '../parser/parser';\nimport { okhslFunc } from '../plugins/okhsl-plugin';\n\nimport type { ProcessedStyle, StyleDetails } from '../parser/types';\n\nimport { getNamedColorHex } from './color-math';\n\nexport {\n getNamedColorHex,\n getRgbValuesFromRgbaString,\n hexToRgb,\n strToRgb,\n} from './color-math';\n\nexport type StyleValue<T = string> = T | boolean | number | null | undefined;\n\n/**\n * Normalize a color token value.\n * - Boolean `true` is converted to `'transparent'`\n * - Boolean `false` returns `null` (signals the token should be skipped)\n * - Other values are returned as-is\n *\n * @param value - The raw token value\n * @returns Normalized value or null if the token should be skipped\n */\nexport function normalizeColorTokenValue<T>(\n value: T | boolean,\n): T | 'transparent' | null {\n if (value === true) {\n return 'transparent';\n }\n if (value === false) {\n return null;\n }\n return value as T;\n}\n\nexport type StyleValueStateMap<T = string> = Record<\n string,\n StyleValue<T> | '@inherit'\n>;\n\n/**\n * Combined type for style values that can be either a direct value or a state map.\n * Use this for component props that accept style values.\n */\nexport type StylePropValue<T = string> = StyleValue<T> | StyleValueStateMap<T>;\n\nexport type CSSMap = { $?: string | string[] } & Record<\n string,\n string | string[]\n>;\n\nexport type StyleHandlerResult = CSSMap | CSSMap[] | void;\n\nexport type RawStyleHandler = (value: StyleValueStateMap) => StyleHandlerResult;\n\nexport type StyleHandler = RawStyleHandler & {\n __lookupStyles: string[];\n};\n\n/**\n * Handler definition forms for configure() and plugins.\n * - Function only: lookup styles inferred from key name\n * - Single property tuple: ['styleName', handler]\n * - Multi-property tuple: [['style1', 'style2'], handler]\n */\nexport type StyleHandlerDefinition =\n | RawStyleHandler\n | [string, RawStyleHandler]\n | [string[], RawStyleHandler];\n\nexport interface ParsedColor {\n color?: string;\n name?: string;\n opacity?: number;\n}\n\nexport type StyleMap = Record<string, StyleValue | StyleValueStateMap>;\n\nconst devMode = process.env.NODE_ENV !== 'production';\n\n// Precompiled regex patterns for parseColor optimization\n// Match var(--name-color...) and extract the name, regardless of fallbacks\nconst COLOR_VAR_PATTERN = /var\\(--([a-z0-9-]+)-color/;\nconst COLOR_VAR_COMPONENTS_PATTERN =\n /var\\(--([a-z0-9-]+)-color-(?:rgb|hsl|oklch)/;\nconst RGB_ALPHA_PATTERN = /\\/\\s*([0-9.]+)\\)/;\nconst RE_HEX_COLOR = /^#[0-9a-fA-F]{3,8}$/;\nconst RE_VAR_COLOR = /^var\\(--[a-z0-9-]+-color/;\n\nfunction isSimpleColorFast(val: string): boolean {\n const c0 = val.charCodeAt(0);\n\n switch (c0) {\n case 35: // '#'\n return RE_HEX_COLOR.test(val);\n case 114: // 'r'\n return val.charCodeAt(1) === 103 && val.charCodeAt(2) === 98; // 'rgb'\n case 104: // 'h'\n return val.charCodeAt(1) === 115 && val.charCodeAt(2) === 108; // 'hsl'\n case 108: // 'l'\n return val.charCodeAt(1) === 99 && val.charCodeAt(2) === 104; // 'lch'\n case 111: // 'o'\n return val.startsWith('oklch(') || val.startsWith('okhsl(');\n case 118: // 'v'\n return RE_VAR_COLOR.test(val);\n case 99: // 'c'\n return val === 'currentColor' || val === 'currentcolor';\n case 116: // 't'\n return val === 'transparent';\n default:\n return getNamedColorHex().has(val.toLowerCase());\n }\n}\n\n// Rate limiting for dev warnings to avoid spam\nlet colorWarningCount = 0;\nconst MAX_COLOR_WARNINGS = 10;\n\nexport const CUSTOM_UNITS = {\n r: '6px',\n cr: '10px',\n bw: '1px',\n ow: '3px',\n x: '8px',\n fs: 'var(--font-size)',\n lh: 'var(--line-height)',\n sf: function sf(num: number) {\n return `minmax(0, ${num}fr)`;\n },\n};\n\nexport const DIRECTIONS = ['top', 'right', 'bottom', 'left'];\n\n// Lazy-initialized to break the circular dependency:\n// parser.ts → classify.ts → utils/styles.ts → parser.ts\nlet __tastyParser: StyleParser | null = null;\n\nfunction getOrCreateParser(): StyleParser {\n if (!__tastyParser) {\n __tastyParser = new StyleParser({ units: CUSTOM_UNITS });\n __tastyParser.setFuncs(__tastyFuncs);\n }\n return __tastyParser;\n}\n\n// Registry for user-provided custom functions that the parser can call.\n// It is updated through the `customFunc` helper exported below.\n// okhsl is registered as a built-in function so it works regardless of\n// tree-shaking or module initialization order.\nconst __tastyFuncs: Record<string, (groups: StyleDetails[]) => string> = {\n okhsl: okhslFunc,\n};\n\nexport function customFunc(\n name: string,\n fn: (groups: StyleDetails[]) => string,\n) {\n __tastyFuncs[name] = fn;\n getOrCreateParser().setFuncs(__tastyFuncs);\n}\n\n/**\n * Get the global StyleParser instance.\n * Used by configure() to apply parser configuration.\n */\nexport function getGlobalParser(): StyleParser {\n return getOrCreateParser();\n}\n\n/**\n * Get the current custom functions registry.\n * Used by configure() to merge with new functions.\n */\nexport function getGlobalFuncs(): Record<\n string,\n (groups: StyleDetails[]) => string\n> {\n return __tastyFuncs;\n}\n\n// ============================================================================\n// Global Predefined Tokens\n// ============================================================================\n\n/**\n * Storage for predefined tokens that are replaced during style parsing.\n * Keys are token names (with $ or # prefix), values are pre-processed CSS values.\n */\nlet __globalPredefinedTokens: Record<string, string> | null = null;\n\n/**\n * Set global predefined tokens.\n * Called from configure() after processing token values.\n * Merges with existing tokens (new tokens override existing ones with same key).\n * Keys are normalized to lowercase (parser lowercases input before classification).\n * @internal\n */\nexport function setGlobalPredefinedTokens(\n tokens: Record<string, string>,\n): void {\n // Normalize keys to lowercase for case-insensitive matching\n const normalizedTokens: Record<string, string> = {};\n for (const [key, value] of Object.entries(tokens)) {\n const lowerKey = key.toLowerCase();\n const lowerValue = value.toLowerCase();\n\n // Warn if trying to use bare #current to define other color tokens\n // #current represents currentcolor which cannot be used as a base for recursive token resolution\n // Note: #current.5 (with opacity) is allowed since it resolves to a concrete color-mix value\n if (lowerKey.startsWith('#') && lowerValue === '#current') {\n console.warn(\n `Tasty: Using #current to define color token \"${key}\" is not supported. ` +\n `The #current token represents currentcolor which cannot be used as a base for other tokens.`,\n );\n continue; // Skip this token\n }\n\n normalizedTokens[lowerKey] = value;\n }\n // Merge with existing tokens (consistent with how states, units, funcs are handled)\n __globalPredefinedTokens = __globalPredefinedTokens\n ? { ...__globalPredefinedTokens, ...normalizedTokens }\n : normalizedTokens;\n // Clear parser cache since token values affect parsing\n getOrCreateParser().clearCache();\n}\n\n/**\n * Get the current global predefined tokens.\n * Returns null if no tokens are configured.\n */\nexport function getGlobalPredefinedTokens(): Record<string, string> | null {\n return __globalPredefinedTokens;\n}\n\n/**\n * Reset global predefined tokens.\n * Used for testing.\n * @internal\n */\nexport function resetGlobalPredefinedTokens(): void {\n __globalPredefinedTokens = null;\n // Clear parser cache since token availability affects parsing\n getOrCreateParser().clearCache();\n}\n\n/**\n *\n * @param {String} value\n * @param {Number} mode\n * @returns {Object<String,String|Array>}\n */\nexport function parseStyle(value: StyleValue): ProcessedStyle {\n let str: string;\n\n if (typeof value === 'string') {\n str = value;\n } else if (typeof value === 'number') {\n str = String(value);\n } else {\n // boolean, null, undefined, objects etc. → empty string\n str = '';\n }\n\n return getOrCreateParser().process(str);\n}\n\n/**\n * Parse color. Find it value, name and opacity.\n * Optimized to avoid heavy parseStyle calls for simple color patterns.\n */\nexport function parseColor(val: string, ignoreError = false): ParsedColor {\n // Early return for non-strings or empty values\n if (typeof val !== 'string') {\n val = String(val ?? '');\n }\n\n val = val.trim();\n if (!val) return {};\n\n // Fast path: Check if it's a simple color pattern that doesn't need full parsing\n const isSimpleColor = isSimpleColorFast(val);\n\n let firstColor: string;\n if (isSimpleColor) {\n // For simple colors, use the value directly without parsing\n firstColor = val;\n } else {\n const processed = parseStyle(val);\n const extractedColor = processed.groups.find((g) => g.colors.length)\n ?.colors[0];\n\n if (!extractedColor) {\n // Rate-limited warning to avoid spam\n if (!ignoreError && devMode && colorWarningCount < MAX_COLOR_WARNINGS) {\n console.warn('Tasty: unable to parse color:', val);\n colorWarningCount++;\n if (colorWarningCount === MAX_COLOR_WARNINGS) {\n console.warn(\n 'Tasty: color parsing warnings will be suppressed from now on',\n );\n }\n }\n return {};\n }\n\n firstColor = extractedColor;\n }\n\n // Extract color name (if present) from variable pattern using precompiled regex\n let nameMatch = firstColor.match(COLOR_VAR_PATTERN);\n if (!nameMatch) {\n nameMatch = firstColor.match(COLOR_VAR_COMPONENTS_PATTERN);\n }\n\n let opacity: number | undefined;\n if (\n firstColor.startsWith('rgb') ||\n firstColor.startsWith('hsl') ||\n firstColor.startsWith('lch') ||\n firstColor.startsWith('oklch') ||\n firstColor.startsWith('okhsl')\n ) {\n const alphaMatch = firstColor.match(RGB_ALPHA_PATTERN);\n if (alphaMatch) {\n const v = parseFloat(alphaMatch[1]);\n if (!isNaN(v)) opacity = v * 100;\n }\n }\n\n return {\n color: firstColor,\n name: nameMatch ? nameMatch[1] : undefined,\n opacity,\n };\n}\n\nexport function filterMods(mods: string[], allowedMods: string[]): string[] {\n return mods.filter((mod) => allowedMods.includes(mod));\n}\n\n// ============================================================================\n// Style Stringification\n// ============================================================================\n\nconst _innerCache = new WeakMap();\nconst _topLevelCache = new WeakMap<object, string>();\n\nexport function stringifyStyles(styles: unknown): string {\n if (styles == null || typeof styles !== 'object') return '';\n\n const cached = _topLevelCache.get(styles as object);\n if (cached !== undefined) return cached;\n\n const obj = styles as Record<string, unknown>;\n const keys = Object.keys(obj).sort();\n const parts: string[] = [];\n for (const k of keys) {\n const v = obj[k];\n if (v === undefined || typeof v === 'function' || typeof v === 'symbol')\n continue;\n\n const c0 = k.charCodeAt(0);\n const needsInnerSort =\n ((c0 >= 65 && c0 <= 90) || c0 === 38) &&\n v &&\n typeof v === 'object' &&\n !Array.isArray(v);\n\n let sv: string;\n if (needsInnerSort) {\n sv = _innerCache.get(v);\n if (sv === undefined) {\n const innerObj = v as Record<string, unknown>;\n const innerKeys = Object.keys(innerObj).sort();\n const innerParts: string[] = [];\n for (const ik of innerKeys) {\n const ivs = JSON.stringify(innerObj[ik]);\n if (ivs !== undefined)\n innerParts.push(JSON.stringify(ik) + ':' + ivs);\n }\n sv = '{' + innerParts.join(',') + '}';\n _innerCache.set(v, sv);\n }\n } else {\n sv = JSON.stringify(v);\n }\n parts.push(JSON.stringify(k) + ':' + sv);\n }\n const result = '{' + parts.join(',') + '}';\n _topLevelCache.set(styles as object, result);\n return result;\n}\n"],"mappings":"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"}
|
package/dist/zero/babel.d.ts
CHANGED
|
@@ -140,6 +140,14 @@ interface TastyZeroBabelOptions {
|
|
|
140
140
|
* Paths must be absolute (resolved by the Next.js wrapper).
|
|
141
141
|
*/
|
|
142
142
|
configDeps?: string[];
|
|
143
|
+
/**
|
|
144
|
+
* Automatically replace `@tenphi/tasty/static` imports with an import
|
|
145
|
+
* of the generated CSS file. This eliminates the need for users to
|
|
146
|
+
* manually import the CSS in their app entry point.
|
|
147
|
+
*
|
|
148
|
+
* @default true
|
|
149
|
+
*/
|
|
150
|
+
injectImport?: boolean;
|
|
143
151
|
}
|
|
144
152
|
declare const _default: (api: object, options: TastyZeroBabelOptions | null | undefined, dirname: string) => _babel_core0.PluginObj<PluginPass>;
|
|
145
153
|
//#endregion
|
package/dist/zero/babel.js
CHANGED
|
@@ -54,6 +54,13 @@ function clearRequireCacheTree(filePath) {
|
|
|
54
54
|
var babel_default = declare((api, options) => {
|
|
55
55
|
api.assertVersion(7);
|
|
56
56
|
const outputPath = options.output || "tasty.css";
|
|
57
|
+
const resolvedOutputPath = path.resolve(outputPath);
|
|
58
|
+
const injectImport = options.injectImport ?? true;
|
|
59
|
+
if (injectImport) {
|
|
60
|
+
const dir = path.dirname(resolvedOutputPath);
|
|
61
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
62
|
+
if (!fs.existsSync(resolvedOutputPath)) fs.writeFileSync(resolvedOutputPath, "/* Generated by @tenphi/tasty/zero - DO NOT EDIT */\n");
|
|
63
|
+
}
|
|
57
64
|
const configDeps = [...options.configFile ? [options.configFile] : [], ...options.configDeps || []];
|
|
58
65
|
if (configDeps.length > 0) {
|
|
59
66
|
api.cache.using(() => configDeps.map(mtime).join(","));
|
|
@@ -83,9 +90,17 @@ var babel_default = declare((api, options) => {
|
|
|
83
90
|
if (devMode && this.filename) this.sourceFile = this.filename.split("/").pop() || this.filename;
|
|
84
91
|
},
|
|
85
92
|
visitor: {
|
|
86
|
-
ImportDeclaration(
|
|
87
|
-
const source =
|
|
88
|
-
if (source === "@tenphi/tasty/static" || source.endsWith("/tasty/static"))
|
|
93
|
+
ImportDeclaration(nodePath, state) {
|
|
94
|
+
const source = nodePath.node.source.value;
|
|
95
|
+
if (source === "@tenphi/tasty/static" || source.endsWith("/tasty/static")) if (injectImport) {
|
|
96
|
+
let importPath = resolvedOutputPath;
|
|
97
|
+
if (state.filename) {
|
|
98
|
+
const sourceDir = path.dirname(state.filename);
|
|
99
|
+
importPath = path.relative(sourceDir, resolvedOutputPath);
|
|
100
|
+
if (!importPath.startsWith(".")) importPath = "./" + importPath;
|
|
101
|
+
}
|
|
102
|
+
nodePath.replaceWith(t.importDeclaration([], t.stringLiteral(importPath)));
|
|
103
|
+
} else nodePath.remove();
|
|
89
104
|
},
|
|
90
105
|
CallExpression(path, state) {
|
|
91
106
|
const callee = path.node.callee;
|
package/dist/zero/babel.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"babel.js","names":[],"sources":["../../src/zero/babel.ts"],"sourcesContent":["/**\n * Babel plugin for zero-runtime tasty static site generation.\n *\n * Transforms:\n * - `tastyStatic(styles)` → StaticStyle object { className, styles, toString() }\n * - `tastyStatic(base, styles)` → StaticStyle object with merged styles\n * - `tastyStatic(selector, styles)` → removed entirely\n *\n * Usage:\n * ```javascript\n * // babel.config.js\n * module.exports = {\n * plugins: [\n * ['@tenphi/tasty/babel-plugin', { output: 'public/tasty.css' }]\n * ]\n * };\n * ```\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nimport { declare } from '@babel/helper-plugin-utils';\nimport * as t from '@babel/types';\nimport { createJiti } from 'jiti';\n\nimport { configure, getGlobalConfigTokens } from '../config';\nimport type { RecipeStyles, Styles, ConfigTokens } from '../styles/types';\nimport { mergeStyles } from '../utils/merge-styles';\nimport { resolveRecipes } from '../utils/resolve-recipes';\nimport type { StyleHandlerDefinition } from '../utils/styles';\n\nimport { CSSWriter } from './css-writer';\nimport {\n extractKeyframesFromStyles,\n extractPropertiesFromStyles,\n extractStylesForSelector,\n extractStylesWithChunks,\n} from './extractor';\n\nimport type { NodePath, PluginPass } from '@babel/core';\nimport type { KeyframesSteps } from '../injector/types';\nimport type { StyleDetails, UnitHandler } from '../parser/types';\nimport type { TastyPlugin } from '../plugins/types';\n\n/**\n * Build-time configuration for zero-runtime mode.\n * Subset of TastyConfig that applies at build time.\n */\nexport interface TastyZeroConfig {\n /**\n * Global predefined states for advanced state mapping.\n * Example: { '@mobile': '@media(w < 768px)', '@dark': '@root(theme=dark)' }\n */\n states?: Record<string, string>;\n /**\n * Enable development mode features: source comments in generated CSS.\n * Default: false\n */\n devMode?: boolean;\n /**\n * Parser LRU cache size (default: 1000).\n * Larger values improve performance for builds with many unique style values.\n */\n parserCacheSize?: number;\n /**\n * Custom units for the style parser (merged with built-in units).\n * Units transform numeric values like `2x` → `calc(2 * var(--gap))`.\n * @example { em: 'em', vw: 'vw', custom: (n) => `${n * 10}px` }\n */\n units?: Record<string, string | UnitHandler>;\n /**\n * Custom functions for the style parser (merged with existing).\n * Functions process parsed style groups and return CSS values.\n * @example { myFunc: (groups) => groups.map(g => g.output).join(' ') }\n */\n funcs?: Record<string, (groups: StyleDetails[]) => string>;\n /**\n * Plugins that extend tasty with custom functions, units, states, and handlers.\n * Plugins are processed in order, with later plugins overriding earlier ones.\n * @example\n * ```ts\n * import { okhslPlugin } from '@tenphi/tasty';\n *\n * // babel.config.js\n * module.exports = {\n * plugins: [\n * ['@tenphi/tasty/babel-plugin', {\n * config: { plugins: [okhslPlugin()] }\n * }]\n * ]\n * };\n * ```\n */\n plugins?: TastyPlugin[];\n /**\n * Global keyframes definitions for static extraction.\n * Keys are animation names, values are keyframes step definitions.\n * @example { fadeIn: { from: { opacity: 0 }, to: { opacity: 1 } } }\n */\n keyframes?: Record<string, KeyframesSteps>;\n /**\n * Custom style handlers that transform style properties into CSS declarations.\n * Handlers replace built-in handlers for the same style name.\n * @example\n * ```ts\n * handlers: {\n * fill: ({ fill }) => fill ? { 'background-color': fill } : undefined,\n * elevation: ({ elevation }) => ({\n * 'box-shadow': `0 ${elevation}px ${elevation * 2}px rgba(0,0,0,0.1)`,\n * }),\n * }\n * ```\n */\n handlers?: Record<string, StyleHandlerDefinition>;\n /**\n * Design tokens injected as CSS custom properties on `:root`.\n * Values are parsed through the Tasty DSL. Supports state maps.\n * @example { '$gap': '4px', '#primary': { '': '#purple', '@dark': '#light-purple' } }\n */\n tokens?: ConfigTokens;\n /**\n * Predefined tokens replaced during style parsing (parse-time substitution).\n * Use `$name` for custom properties and `#name` for color tokens.\n * @example { $spacing: '2x', '#accent': '#purple' }\n */\n replaceTokens?: Record<`$${string}` | `#${string}`, string | number>;\n /**\n * Predefined style recipes -- named style bundles that can be applied via `recipe` style property.\n * Recipe values are flat tasty styles (no sub-element keys).\n * @example\n * ```ts\n * recipes: {\n * card: { padding: '4x', fill: '#surface', radius: '1r', border: true },\n * elevated: { shadow: '2x 2x 4x #shadow' },\n * }\n * ```\n */\n recipes?: Record<string, RecipeStyles>;\n /**\n * Automatically infer and register CSS @property declarations from values.\n * @default true\n */\n autoPropertyTypes?: boolean;\n}\n\nexport interface TastyZeroBabelOptions {\n /** Output path for generated CSS (default: 'tasty.css') */\n output?: string;\n /**\n * Tasty configuration for build-time processing.\n * Can be a static object or a factory function that returns fresh config.\n * A factory is called on each plugin invocation, enabling hot reload\n * of config values that depend on external files (e.g. theme tokens).\n */\n config?: TastyZeroConfig | (() => TastyZeroConfig);\n /**\n * Absolute path to a TypeScript/JavaScript module that default-exports\n * a `TastyZeroConfig` object. The module is loaded via jiti on each\n * plugin invocation, enabling hot reload when the file changes.\n *\n * This option is JSON-serializable and is the primary way Turbopack\n * passes config to the Babel plugin (since Turbopack loader options\n * must be plain primitives/objects/arrays).\n *\n * When both `config` and `configFile` are set, `config` takes precedence.\n *\n * @example '/absolute/path/to/tasty-zero.config.ts'\n */\n configFile?: string;\n /**\n * Absolute file paths whose content affects the generated CSS.\n * When any of these files change, babel-loader invalidates its cache\n * and re-runs the plugin with fresh config values.\n *\n * Typically includes theme files that define Glaze palettes or token values.\n * Paths must be absolute (resolved by the Next.js wrapper).\n */\n configDeps?: string[];\n}\n\n/**\n * Registry to track StaticStyle objects by their variable names.\n * Used to resolve base styles when extending.\n */\ntype StaticStyleRegistry = Record<\n string,\n {\n styles: Styles;\n className: string;\n }\n>;\n\ninterface PluginState extends PluginPass {\n staticStyleRegistry: StaticStyleRegistry;\n /** Current source file path (for devMode source comments) */\n sourceFile?: string;\n}\n\nfunction mtime(filePath: string): number | null {\n try {\n return fs.statSync(filePath).mtimeMs;\n } catch {\n return null;\n }\n}\n\nfunction clearRequireCacheTree(filePath: string): void {\n let resolved: string;\n\n try {\n resolved = require.resolve(filePath);\n } catch {\n return;\n }\n\n const mod = require.cache[resolved];\n\n if (!mod) return;\n\n const dir = resolved.substring(0, resolved.lastIndexOf('/'));\n\n if (mod.children) {\n for (const child of mod.children) {\n if (child.id.startsWith(dir) && !child.id.includes('node_modules')) {\n clearRequireCacheTree(child.id);\n }\n }\n }\n\n delete require.cache[resolved];\n}\n\n// @ts-expect-error PluginState vs PluginPass type mismatch in @babel/helper-plugin-utils\nexport default declare<TastyZeroBabelOptions>((api, options) => {\n api.assertVersion(7);\n\n const outputPath = options.output || 'tasty.css';\n const configDeps = [\n ...(options.configFile ? [options.configFile] : []),\n ...(options.configDeps || []),\n ];\n\n // Register external dependencies for babel-loader cache invalidation.\n // When any configDeps file changes, babel-loader discards the cached\n // transform result and re-runs the plugin, picking up fresh config.\n if (configDeps.length > 0) {\n api.cache.using(() => configDeps.map(mtime).join(','));\n\n for (const dep of configDeps) {\n try {\n (\n api as unknown as { addExternalDependency(path: string): void }\n ).addExternalDependency(dep);\n } catch {\n // addExternalDependency may not be available in all environments\n }\n }\n } else {\n api.cache.forever();\n }\n\n // When configDeps are set, clear the require cache so we get fresh values.\n if (configDeps.length > 0) {\n for (const dep of configDeps) {\n clearRequireCacheTree(dep);\n }\n }\n\n const configOption = options.config;\n let config: TastyZeroConfig;\n\n if (configOption) {\n config = typeof configOption === 'function' ? configOption() : configOption;\n } else if (options.configFile) {\n const jiti = createJiti(path.dirname(options.configFile), {\n moduleCache: false,\n });\n\n config = jiti(options.configFile) as TastyZeroConfig;\n } else {\n config = {};\n }\n\n const devMode = config.devMode ?? false;\n\n configure(config);\n\n const cssWriter = new CSSWriter(outputPath, { devMode });\n\n // Emit configured tokens as :root CSS custom properties\n const tokenStyles = getGlobalConfigTokens();\n if (tokenStyles && Object.keys(tokenStyles).length > 0) {\n const result = extractStylesForSelector(':root', tokenStyles);\n if (result.css) {\n cssWriter.add(':root:tokens', result.css);\n }\n }\n\n // Global registry for cross-file references (same build)\n const globalRegistry: StaticStyleRegistry = {};\n\n return {\n name: 'tasty-zero',\n\n pre(this: PluginState) {\n // Initialize per-file registry\n this.staticStyleRegistry = {};\n // Extract source filename for devMode comments\n if (devMode && this.filename) {\n // Get relative path or just filename\n this.sourceFile = this.filename.split('/').pop() || this.filename;\n }\n },\n\n visitor: {\n // Remove import statements for tasty/static\n ImportDeclaration(path: NodePath<t.ImportDeclaration>) {\n const source = path.node.source.value;\n\n if (\n source === '@tenphi/tasty/static' ||\n source.endsWith('/tasty/static')\n ) {\n path.remove();\n }\n },\n\n // Transform tastyStatic() calls\n CallExpression(path: NodePath<t.CallExpression>, state: PluginState) {\n const callee = path.node.callee;\n\n // Match tastyStatic(...) calls\n if (!t.isIdentifier(callee, { name: 'tastyStatic' })) {\n return;\n }\n\n const args = path.node.arguments;\n\n if (args.length === 0) {\n throw path.buildCodeFrameError(\n 'tastyStatic() requires at least one argument',\n );\n }\n\n const firstArg = args[0];\n\n if (t.isStringLiteral(firstArg)) {\n // Selector mode: tastyStatic(selector, styles)\n handleSelectorMode(\n path,\n args,\n cssWriter,\n state.sourceFile,\n config.keyframes,\n config.autoPropertyTypes,\n );\n } else if (t.isObjectExpression(firstArg)) {\n // Styles mode: tastyStatic(styles)\n handleStylesMode(\n path,\n args,\n cssWriter,\n state,\n globalRegistry,\n config.keyframes,\n config.autoPropertyTypes,\n );\n } else if (t.isIdentifier(firstArg)) {\n // Extension mode: tastyStatic(base, styles)\n handleExtensionMode(\n path,\n args,\n cssWriter,\n state,\n globalRegistry,\n config.keyframes,\n config.autoPropertyTypes,\n );\n } else {\n throw path.buildCodeFrameError(\n 'tastyStatic() first argument must be an object (styles), ' +\n 'identifier (base StaticStyle), or string (selector)',\n );\n }\n },\n\n // Track variable declarations to register StaticStyle objects\n VariableDeclarator(\n path: NodePath<t.VariableDeclarator>,\n state: PluginState,\n ) {\n const init = path.node.init;\n const id = path.node.id;\n\n // Check if this is a StaticStyle object (has className and styles properties)\n if (\n t.isIdentifier(id) &&\n t.isObjectExpression(init) &&\n isStaticStyleObject(init)\n ) {\n const variableName = id.name;\n const styles = extractStylesFromStaticStyleObject(init, path);\n const className = extractClassNameFromStaticStyleObject(init);\n\n if (styles && className) {\n state.staticStyleRegistry[variableName] = { styles, className };\n globalRegistry[variableName] = { styles, className };\n }\n }\n },\n },\n\n post() {\n // Write all collected CSS at the end of the build\n if (cssWriter.size > 0) {\n cssWriter.write();\n }\n },\n };\n});\n\n/**\n * Check if an object expression looks like a StaticStyle object\n */\nfunction isStaticStyleObject(node: t.ObjectExpression): boolean {\n const hasClassName = node.properties.some(\n (p) =>\n t.isObjectProperty(p) && t.isIdentifier(p.key, { name: 'className' }),\n );\n const hasStyles = node.properties.some(\n (p) => t.isObjectProperty(p) && t.isIdentifier(p.key, { name: 'styles' }),\n );\n return hasClassName && hasStyles;\n}\n\n/**\n * Extract styles object from a StaticStyle object expression\n */\nfunction extractStylesFromStaticStyleObject(\n node: t.ObjectExpression,\n path: NodePath,\n): Styles | null {\n for (const prop of node.properties) {\n if (\n t.isObjectProperty(prop) &&\n t.isIdentifier(prop.key, { name: 'styles' }) &&\n t.isObjectExpression(prop.value)\n ) {\n return evaluateObjectExpression(prop.value, path) as Styles;\n }\n }\n return null;\n}\n\n/**\n * Extract className from a StaticStyle object expression\n */\nfunction extractClassNameFromStaticStyleObject(\n node: t.ObjectExpression,\n): string | null {\n for (const prop of node.properties) {\n if (\n t.isObjectProperty(prop) &&\n t.isIdentifier(prop.key, { name: 'className' }) &&\n t.isStringLiteral(prop.value)\n ) {\n return prop.value.value;\n }\n }\n return null;\n}\n\n/**\n * Handle tastyStatic(styles) - returns StaticStyle object\n */\nfunction handleStylesMode(\n path: NodePath<t.CallExpression>,\n args: t.CallExpression['arguments'],\n cssWriter: CSSWriter,\n state: PluginState,\n globalRegistry: StaticStyleRegistry,\n globalKeyframes?: Record<string, KeyframesSteps>,\n autoPropertyTypes?: boolean,\n): void {\n const stylesArg = args[0];\n\n if (!t.isObjectExpression(stylesArg)) {\n throw path.buildCodeFrameError(\n 'tastyStatic(styles) argument must be a static object literal',\n );\n }\n\n // Evaluate styles object at build time\n const rawStyles = evaluateObjectExpression(stylesArg, path) as Styles;\n\n // Resolve recipes before extraction\n const styles = resolveRecipes(rawStyles);\n\n // Extract keyframes (deduplicated by content)\n const { keyframes, nameMap } = extractKeyframesFromStyles(\n styles,\n globalKeyframes,\n );\n\n // Add keyframes CSS\n for (const kf of keyframes) {\n cssWriter.add(kf.css, kf.css, state.sourceFile);\n }\n\n // Extract and add auto-inferred @property rules\n const properties = extractPropertiesFromStyles(styles, { autoPropertyTypes });\n for (const prop of properties) {\n cssWriter.add(prop.css, prop.css, state.sourceFile);\n }\n\n // Extract styles with chunking\n const chunks = extractStylesWithChunks(styles);\n\n // Add CSS to writer, replacing animation names if needed\n for (const chunk of chunks) {\n const css =\n nameMap.size > 0\n ? replaceAnimationNamesInCSS(chunk.css, nameMap)\n : chunk.css;\n cssWriter.add(chunk.className, css, state.sourceFile);\n }\n\n // Generate className\n const className =\n chunks.length > 0 ? chunks.map((c) => c.className).join(' ') : '';\n\n // Replace call with StaticStyle object\n const staticStyleObject = createStaticStyleAST(className, styles);\n path.replaceWith(staticStyleObject);\n\n // Register if this is being assigned to a variable\n registerIfVariableDeclaration(path, className, styles, state, globalRegistry);\n}\n\n/**\n * Handle tastyStatic(base, styles) - extends base with additional styles\n */\nfunction handleExtensionMode(\n path: NodePath<t.CallExpression>,\n args: t.CallExpression['arguments'],\n cssWriter: CSSWriter,\n state: PluginState,\n globalRegistry: StaticStyleRegistry,\n globalKeyframes?: Record<string, KeyframesSteps>,\n autoPropertyTypes?: boolean,\n): void {\n if (args.length < 2) {\n throw path.buildCodeFrameError(\n 'tastyStatic(base, styles) requires two arguments',\n );\n }\n\n const baseArg = args[0];\n const stylesArg = args[1];\n\n if (!t.isIdentifier(baseArg)) {\n throw path.buildCodeFrameError(\n 'tastyStatic(base, styles) first argument must be an identifier',\n );\n }\n\n if (!t.isObjectExpression(stylesArg)) {\n throw path.buildCodeFrameError(\n 'tastyStatic(base, styles) second argument must be a static object literal',\n );\n }\n\n const baseName = baseArg.name;\n\n // Look up base styles in registry\n const baseEntry =\n state.staticStyleRegistry[baseName] || globalRegistry[baseName];\n\n if (!baseEntry) {\n throw path.buildCodeFrameError(\n `Cannot find base StaticStyle '${baseName}'. ` +\n 'Make sure it is defined before being extended.',\n );\n }\n\n // Evaluate override styles\n const overrideStyles = evaluateObjectExpression(stylesArg, path) as Styles;\n\n // Merge styles using mergeStyles, then resolve recipes\n const mergedStyles = resolveRecipes(\n mergeStyles(baseEntry.styles, overrideStyles),\n );\n\n // Extract keyframes (deduplicated by content)\n const { keyframes, nameMap } = extractKeyframesFromStyles(\n mergedStyles,\n globalKeyframes,\n );\n\n // Add keyframes CSS\n for (const kf of keyframes) {\n cssWriter.add(kf.css, kf.css, state.sourceFile);\n }\n\n // Extract and add auto-inferred @property rules\n const properties = extractPropertiesFromStyles(mergedStyles, {\n autoPropertyTypes,\n });\n for (const prop of properties) {\n cssWriter.add(prop.css, prop.css, state.sourceFile);\n }\n\n // Extract styles with chunking\n const chunks = extractStylesWithChunks(mergedStyles);\n\n // Add CSS to writer, replacing animation names if needed\n for (const chunk of chunks) {\n const css =\n nameMap.size > 0\n ? replaceAnimationNamesInCSS(chunk.css, nameMap)\n : chunk.css;\n cssWriter.add(chunk.className, css, state.sourceFile);\n }\n\n // Generate className\n const className =\n chunks.length > 0 ? chunks.map((c) => c.className).join(' ') : '';\n\n // Replace call with StaticStyle object\n const staticStyleObject = createStaticStyleAST(className, mergedStyles);\n path.replaceWith(staticStyleObject);\n\n // Register if this is being assigned to a variable\n registerIfVariableDeclaration(\n path,\n className,\n mergedStyles,\n state,\n globalRegistry,\n );\n}\n\n/**\n * Handle tastyStatic(selector, styles) - removes the call entirely\n */\nfunction handleSelectorMode(\n path: NodePath<t.CallExpression>,\n args: t.CallExpression['arguments'],\n cssWriter: CSSWriter,\n sourceFile?: string,\n globalKeyframes?: Record<string, KeyframesSteps>,\n autoPropertyTypes?: boolean,\n): void {\n if (args.length < 2) {\n throw path.buildCodeFrameError(\n 'tastyStatic(selector, styles) requires two arguments',\n );\n }\n\n const selectorArg = args[0];\n const stylesArg = args[1];\n\n if (!t.isStringLiteral(selectorArg)) {\n throw path.buildCodeFrameError(\n 'tastyStatic(selector, styles) first argument must be a string literal',\n );\n }\n\n if (!t.isObjectExpression(stylesArg)) {\n throw path.buildCodeFrameError(\n 'tastyStatic(selector, styles) second argument must be a static object literal',\n );\n }\n\n const selector = selectorArg.value;\n const rawStyles = evaluateObjectExpression(stylesArg, path) as Styles;\n\n // Resolve recipes before extraction\n const styles = resolveRecipes(rawStyles);\n\n // Extract keyframes (deduplicated by content)\n const { keyframes, nameMap } = extractKeyframesFromStyles(\n styles,\n globalKeyframes,\n );\n\n // Add keyframes CSS\n for (const kf of keyframes) {\n cssWriter.add(kf.css, kf.css, sourceFile);\n }\n\n // Extract and add auto-inferred @property rules\n const properties = extractPropertiesFromStyles(styles, { autoPropertyTypes });\n for (const prop of properties) {\n cssWriter.add(prop.css, prop.css, sourceFile);\n }\n\n // Extract styles for selector\n const result = extractStylesForSelector(selector, styles);\n\n // Replace animation names if needed and add CSS\n const css =\n nameMap.size > 0\n ? replaceAnimationNamesInCSS(result.css, nameMap)\n : result.css;\n cssWriter.add(selector, css, sourceFile);\n\n // Remove the entire statement\n const parent = path.parentPath;\n if (parent && t.isExpressionStatement(parent.node)) {\n parent.remove();\n } else {\n // If used in an expression context (which would be incorrect usage),\n // replace with undefined\n path.replaceWith(t.identifier('undefined'));\n }\n}\n\n/**\n * Create a StaticStyle object AST node\n */\nfunction createStaticStyleAST(\n className: string,\n styles: Styles,\n): t.ObjectExpression {\n return t.objectExpression([\n t.objectProperty(t.identifier('className'), t.stringLiteral(className)),\n t.objectProperty(t.identifier('styles'), valueToAST(styles)),\n t.objectMethod(\n 'method',\n t.identifier('toString'),\n [],\n t.blockStatement([\n t.returnStatement(\n t.memberExpression(t.thisExpression(), t.identifier('className')),\n ),\n ]),\n ),\n ]);\n}\n\n/**\n * Register a StaticStyle in the registry if it's being assigned to a variable\n */\nfunction registerIfVariableDeclaration(\n path: NodePath,\n className: string,\n styles: Styles,\n state: PluginState,\n globalRegistry: StaticStyleRegistry,\n): void {\n const parent = path.parentPath;\n if (parent && t.isVariableDeclarator(parent.node)) {\n const id = parent.node.id;\n if (t.isIdentifier(id)) {\n const variableName = id.name;\n state.staticStyleRegistry[variableName] = { styles, className };\n globalRegistry[variableName] = { styles, className };\n }\n }\n}\n\n/**\n * Convert a JavaScript value to an AST node\n */\nfunction valueToAST(value: unknown): t.Expression {\n if (value === null) {\n return t.nullLiteral();\n }\n if (value === undefined) {\n return t.identifier('undefined');\n }\n if (typeof value === 'string') {\n return t.stringLiteral(value);\n }\n if (typeof value === 'number') {\n return t.numericLiteral(value);\n }\n if (typeof value === 'boolean') {\n return t.booleanLiteral(value);\n }\n if (Array.isArray(value)) {\n return t.arrayExpression(value.map(valueToAST));\n }\n if (typeof value === 'object') {\n const properties = Object.entries(value).map(([key, val]) =>\n t.objectProperty(\n /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key)\n ? t.identifier(key)\n : t.stringLiteral(key),\n valueToAST(val),\n ),\n );\n return t.objectExpression(properties);\n }\n // Fallback for unsupported types\n return t.identifier('undefined');\n}\n\n/**\n * Evaluate an ObjectExpression to a plain JavaScript object.\n * Only supports static values that can be determined at build time.\n */\nfunction evaluateObjectExpression(\n node: t.ObjectExpression,\n path: NodePath,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const prop of node.properties) {\n if (t.isSpreadElement(prop)) {\n throw path.buildCodeFrameError(\n 'Spread elements are not supported in tastyStatic() - styles must be fully static',\n );\n }\n\n if (!t.isObjectProperty(prop)) {\n throw path.buildCodeFrameError(\n 'Only object properties are supported in tastyStatic()',\n );\n }\n\n // Get key\n let key: string;\n if (t.isIdentifier(prop.key)) {\n key = prop.key.name;\n } else if (t.isStringLiteral(prop.key)) {\n key = prop.key.value;\n } else {\n throw path.buildCodeFrameError(\n 'Dynamic property keys are not supported in tastyStatic()',\n );\n }\n\n // Get value\n const value = evaluateExpression(prop.value, path);\n result[key] = value;\n }\n\n return result;\n}\n\n/**\n * Evaluate an expression to a JavaScript value.\n */\nfunction evaluateExpression(node: t.Node, path: NodePath): unknown {\n if (t.isStringLiteral(node)) {\n return node.value;\n }\n\n if (t.isNumericLiteral(node)) {\n return node.value;\n }\n\n if (t.isBooleanLiteral(node)) {\n return node.value;\n }\n\n if (t.isNullLiteral(node)) {\n return null;\n }\n\n if (t.isIdentifier(node, { name: 'undefined' })) {\n return undefined;\n }\n\n if (t.isArrayExpression(node)) {\n return node.elements.map((el) => {\n if (el === null) return null;\n if (t.isSpreadElement(el)) {\n throw path.buildCodeFrameError(\n 'Spread elements are not supported in tastyStatic()',\n );\n }\n return evaluateExpression(el, path);\n });\n }\n\n if (t.isObjectExpression(node)) {\n return evaluateObjectExpression(node, path);\n }\n\n if (t.isTemplateLiteral(node)) {\n // Only support template literals without expressions\n if (node.expressions.length > 0) {\n throw path.buildCodeFrameError(\n 'Template literals with expressions are not supported in tastyStatic()',\n );\n }\n return node.quasis.map((q) => q.value.cooked).join('');\n }\n\n if (t.isUnaryExpression(node, { operator: '-' })) {\n const arg = evaluateExpression(node.argument, path);\n if (typeof arg === 'number') {\n return -arg;\n }\n }\n\n throw path.buildCodeFrameError(\n `Dynamic expressions are not supported in tastyStatic() - got ${node.type}. ` +\n 'All values must be static literals.',\n );\n}\n\n/**\n * Replace animation names in CSS string.\n * Wraps the keyframes replaceAnimationNames to work on full CSS blocks.\n */\nfunction replaceAnimationNamesInCSS(\n css: string,\n nameMap: Map<string, string>,\n): string {\n if (nameMap.size === 0) return css;\n\n // The CSS contains full rules like \".class { animation: name 1s; }\"\n // We need to replace animation names within declaration blocks\n return css.replace(\n /(animation(?:-name)?)\\s*:\\s*([^;}]+)/gi,\n (match, prop, value) => {\n let newValue = value;\n for (const [original, replacement] of nameMap) {\n // Word boundary replacement\n const pattern = new RegExp(`\\\\b${escapeRegex(original)}\\\\b`, 'g');\n newValue = newValue.replace(pattern, replacement);\n }\n return `${prop}: ${newValue}`;\n },\n );\n}\n\n/**\n * Escape special regex characters.\n */\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"babel.js","names":[],"sources":["../../src/zero/babel.ts"],"sourcesContent":["/**\n * Babel plugin for zero-runtime tasty static site generation.\n *\n * Transforms:\n * - `tastyStatic(styles)` → StaticStyle object { className, styles, toString() }\n * - `tastyStatic(base, styles)` → StaticStyle object with merged styles\n * - `tastyStatic(selector, styles)` → removed entirely\n *\n * Usage:\n * ```javascript\n * // babel.config.js\n * module.exports = {\n * plugins: [\n * ['@tenphi/tasty/babel-plugin', { output: 'public/tasty.css' }]\n * ]\n * };\n * ```\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nimport { declare } from '@babel/helper-plugin-utils';\nimport * as t from '@babel/types';\nimport { createJiti } from 'jiti';\n\nimport { configure, getGlobalConfigTokens } from '../config';\nimport type { RecipeStyles, Styles, ConfigTokens } from '../styles/types';\nimport { mergeStyles } from '../utils/merge-styles';\nimport { resolveRecipes } from '../utils/resolve-recipes';\nimport type { StyleHandlerDefinition } from '../utils/styles';\n\nimport { CSSWriter } from './css-writer';\nimport {\n extractKeyframesFromStyles,\n extractPropertiesFromStyles,\n extractStylesForSelector,\n extractStylesWithChunks,\n} from './extractor';\n\nimport type { NodePath, PluginPass } from '@babel/core';\nimport type { KeyframesSteps } from '../injector/types';\nimport type { StyleDetails, UnitHandler } from '../parser/types';\nimport type { TastyPlugin } from '../plugins/types';\n\n/**\n * Build-time configuration for zero-runtime mode.\n * Subset of TastyConfig that applies at build time.\n */\nexport interface TastyZeroConfig {\n /**\n * Global predefined states for advanced state mapping.\n * Example: { '@mobile': '@media(w < 768px)', '@dark': '@root(theme=dark)' }\n */\n states?: Record<string, string>;\n /**\n * Enable development mode features: source comments in generated CSS.\n * Default: false\n */\n devMode?: boolean;\n /**\n * Parser LRU cache size (default: 1000).\n * Larger values improve performance for builds with many unique style values.\n */\n parserCacheSize?: number;\n /**\n * Custom units for the style parser (merged with built-in units).\n * Units transform numeric values like `2x` → `calc(2 * var(--gap))`.\n * @example { em: 'em', vw: 'vw', custom: (n) => `${n * 10}px` }\n */\n units?: Record<string, string | UnitHandler>;\n /**\n * Custom functions for the style parser (merged with existing).\n * Functions process parsed style groups and return CSS values.\n * @example { myFunc: (groups) => groups.map(g => g.output).join(' ') }\n */\n funcs?: Record<string, (groups: StyleDetails[]) => string>;\n /**\n * Plugins that extend tasty with custom functions, units, states, and handlers.\n * Plugins are processed in order, with later plugins overriding earlier ones.\n * @example\n * ```ts\n * import { okhslPlugin } from '@tenphi/tasty';\n *\n * // babel.config.js\n * module.exports = {\n * plugins: [\n * ['@tenphi/tasty/babel-plugin', {\n * config: { plugins: [okhslPlugin()] }\n * }]\n * ]\n * };\n * ```\n */\n plugins?: TastyPlugin[];\n /**\n * Global keyframes definitions for static extraction.\n * Keys are animation names, values are keyframes step definitions.\n * @example { fadeIn: { from: { opacity: 0 }, to: { opacity: 1 } } }\n */\n keyframes?: Record<string, KeyframesSteps>;\n /**\n * Custom style handlers that transform style properties into CSS declarations.\n * Handlers replace built-in handlers for the same style name.\n * @example\n * ```ts\n * handlers: {\n * fill: ({ fill }) => fill ? { 'background-color': fill } : undefined,\n * elevation: ({ elevation }) => ({\n * 'box-shadow': `0 ${elevation}px ${elevation * 2}px rgba(0,0,0,0.1)`,\n * }),\n * }\n * ```\n */\n handlers?: Record<string, StyleHandlerDefinition>;\n /**\n * Design tokens injected as CSS custom properties on `:root`.\n * Values are parsed through the Tasty DSL. Supports state maps.\n * @example { '$gap': '4px', '#primary': { '': '#purple', '@dark': '#light-purple' } }\n */\n tokens?: ConfigTokens;\n /**\n * Predefined tokens replaced during style parsing (parse-time substitution).\n * Use `$name` for custom properties and `#name` for color tokens.\n * @example { $spacing: '2x', '#accent': '#purple' }\n */\n replaceTokens?: Record<`$${string}` | `#${string}`, string | number>;\n /**\n * Predefined style recipes -- named style bundles that can be applied via `recipe` style property.\n * Recipe values are flat tasty styles (no sub-element keys).\n * @example\n * ```ts\n * recipes: {\n * card: { padding: '4x', fill: '#surface', radius: '1r', border: true },\n * elevated: { shadow: '2x 2x 4x #shadow' },\n * }\n * ```\n */\n recipes?: Record<string, RecipeStyles>;\n /**\n * Automatically infer and register CSS @property declarations from values.\n * @default true\n */\n autoPropertyTypes?: boolean;\n}\n\nexport interface TastyZeroBabelOptions {\n /** Output path for generated CSS (default: 'tasty.css') */\n output?: string;\n /**\n * Tasty configuration for build-time processing.\n * Can be a static object or a factory function that returns fresh config.\n * A factory is called on each plugin invocation, enabling hot reload\n * of config values that depend on external files (e.g. theme tokens).\n */\n config?: TastyZeroConfig | (() => TastyZeroConfig);\n /**\n * Absolute path to a TypeScript/JavaScript module that default-exports\n * a `TastyZeroConfig` object. The module is loaded via jiti on each\n * plugin invocation, enabling hot reload when the file changes.\n *\n * This option is JSON-serializable and is the primary way Turbopack\n * passes config to the Babel plugin (since Turbopack loader options\n * must be plain primitives/objects/arrays).\n *\n * When both `config` and `configFile` are set, `config` takes precedence.\n *\n * @example '/absolute/path/to/tasty-zero.config.ts'\n */\n configFile?: string;\n /**\n * Absolute file paths whose content affects the generated CSS.\n * When any of these files change, babel-loader invalidates its cache\n * and re-runs the plugin with fresh config values.\n *\n * Typically includes theme files that define Glaze palettes or token values.\n * Paths must be absolute (resolved by the Next.js wrapper).\n */\n configDeps?: string[];\n /**\n * Automatically replace `@tenphi/tasty/static` imports with an import\n * of the generated CSS file. This eliminates the need for users to\n * manually import the CSS in their app entry point.\n *\n * @default true\n */\n injectImport?: boolean;\n}\n\n/**\n * Registry to track StaticStyle objects by their variable names.\n * Used to resolve base styles when extending.\n */\ntype StaticStyleRegistry = Record<\n string,\n {\n styles: Styles;\n className: string;\n }\n>;\n\ninterface PluginState extends PluginPass {\n staticStyleRegistry: StaticStyleRegistry;\n /** Current source file path (for devMode source comments) */\n sourceFile?: string;\n}\n\nfunction mtime(filePath: string): number | null {\n try {\n return fs.statSync(filePath).mtimeMs;\n } catch {\n return null;\n }\n}\n\nfunction clearRequireCacheTree(filePath: string): void {\n let resolved: string;\n\n try {\n resolved = require.resolve(filePath);\n } catch {\n return;\n }\n\n const mod = require.cache[resolved];\n\n if (!mod) return;\n\n const dir = resolved.substring(0, resolved.lastIndexOf('/'));\n\n if (mod.children) {\n for (const child of mod.children) {\n if (child.id.startsWith(dir) && !child.id.includes('node_modules')) {\n clearRequireCacheTree(child.id);\n }\n }\n }\n\n delete require.cache[resolved];\n}\n\n// @ts-expect-error PluginState vs PluginPass type mismatch in @babel/helper-plugin-utils\nexport default declare<TastyZeroBabelOptions>((api, options) => {\n api.assertVersion(7);\n\n const outputPath = options.output || 'tasty.css';\n const resolvedOutputPath = path.resolve(outputPath);\n const injectImport = options.injectImport ?? true;\n\n if (injectImport) {\n const dir = path.dirname(resolvedOutputPath);\n\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n if (!fs.existsSync(resolvedOutputPath)) {\n fs.writeFileSync(\n resolvedOutputPath,\n '/* Generated by @tenphi/tasty/zero - DO NOT EDIT */\\n',\n );\n }\n }\n\n const configDeps = [\n ...(options.configFile ? [options.configFile] : []),\n ...(options.configDeps || []),\n ];\n\n // Register external dependencies for babel-loader cache invalidation.\n // When any configDeps file changes, babel-loader discards the cached\n // transform result and re-runs the plugin, picking up fresh config.\n if (configDeps.length > 0) {\n api.cache.using(() => configDeps.map(mtime).join(','));\n\n for (const dep of configDeps) {\n try {\n (\n api as unknown as { addExternalDependency(path: string): void }\n ).addExternalDependency(dep);\n } catch {\n // addExternalDependency may not be available in all environments\n }\n }\n } else {\n api.cache.forever();\n }\n\n // When configDeps are set, clear the require cache so we get fresh values.\n if (configDeps.length > 0) {\n for (const dep of configDeps) {\n clearRequireCacheTree(dep);\n }\n }\n\n const configOption = options.config;\n let config: TastyZeroConfig;\n\n if (configOption) {\n config = typeof configOption === 'function' ? configOption() : configOption;\n } else if (options.configFile) {\n const jiti = createJiti(path.dirname(options.configFile), {\n moduleCache: false,\n });\n\n config = jiti(options.configFile) as TastyZeroConfig;\n } else {\n config = {};\n }\n\n const devMode = config.devMode ?? false;\n\n configure(config);\n\n const cssWriter = new CSSWriter(outputPath, { devMode });\n\n // Emit configured tokens as :root CSS custom properties\n const tokenStyles = getGlobalConfigTokens();\n if (tokenStyles && Object.keys(tokenStyles).length > 0) {\n const result = extractStylesForSelector(':root', tokenStyles);\n if (result.css) {\n cssWriter.add(':root:tokens', result.css);\n }\n }\n\n // Global registry for cross-file references (same build)\n const globalRegistry: StaticStyleRegistry = {};\n\n return {\n name: 'tasty-zero',\n\n pre(this: PluginState) {\n // Initialize per-file registry\n this.staticStyleRegistry = {};\n // Extract source filename for devMode comments\n if (devMode && this.filename) {\n // Get relative path or just filename\n this.sourceFile = this.filename.split('/').pop() || this.filename;\n }\n },\n\n visitor: {\n ImportDeclaration(\n nodePath: NodePath<t.ImportDeclaration>,\n state: PluginState,\n ) {\n const source = nodePath.node.source.value;\n\n if (\n source === '@tenphi/tasty/static' ||\n source.endsWith('/tasty/static')\n ) {\n if (injectImport) {\n let importPath = resolvedOutputPath;\n\n if (state.filename) {\n const sourceDir = path.dirname(state.filename);\n importPath = path.relative(sourceDir, resolvedOutputPath);\n\n if (!importPath.startsWith('.')) {\n importPath = './' + importPath;\n }\n }\n\n nodePath.replaceWith(\n t.importDeclaration([], t.stringLiteral(importPath)),\n );\n } else {\n nodePath.remove();\n }\n }\n },\n\n // Transform tastyStatic() calls\n CallExpression(path: NodePath<t.CallExpression>, state: PluginState) {\n const callee = path.node.callee;\n\n // Match tastyStatic(...) calls\n if (!t.isIdentifier(callee, { name: 'tastyStatic' })) {\n return;\n }\n\n const args = path.node.arguments;\n\n if (args.length === 0) {\n throw path.buildCodeFrameError(\n 'tastyStatic() requires at least one argument',\n );\n }\n\n const firstArg = args[0];\n\n if (t.isStringLiteral(firstArg)) {\n // Selector mode: tastyStatic(selector, styles)\n handleSelectorMode(\n path,\n args,\n cssWriter,\n state.sourceFile,\n config.keyframes,\n config.autoPropertyTypes,\n );\n } else if (t.isObjectExpression(firstArg)) {\n // Styles mode: tastyStatic(styles)\n handleStylesMode(\n path,\n args,\n cssWriter,\n state,\n globalRegistry,\n config.keyframes,\n config.autoPropertyTypes,\n );\n } else if (t.isIdentifier(firstArg)) {\n // Extension mode: tastyStatic(base, styles)\n handleExtensionMode(\n path,\n args,\n cssWriter,\n state,\n globalRegistry,\n config.keyframes,\n config.autoPropertyTypes,\n );\n } else {\n throw path.buildCodeFrameError(\n 'tastyStatic() first argument must be an object (styles), ' +\n 'identifier (base StaticStyle), or string (selector)',\n );\n }\n },\n\n // Track variable declarations to register StaticStyle objects\n VariableDeclarator(\n path: NodePath<t.VariableDeclarator>,\n state: PluginState,\n ) {\n const init = path.node.init;\n const id = path.node.id;\n\n // Check if this is a StaticStyle object (has className and styles properties)\n if (\n t.isIdentifier(id) &&\n t.isObjectExpression(init) &&\n isStaticStyleObject(init)\n ) {\n const variableName = id.name;\n const styles = extractStylesFromStaticStyleObject(init, path);\n const className = extractClassNameFromStaticStyleObject(init);\n\n if (styles && className) {\n state.staticStyleRegistry[variableName] = { styles, className };\n globalRegistry[variableName] = { styles, className };\n }\n }\n },\n },\n\n post() {\n // Write all collected CSS at the end of the build\n if (cssWriter.size > 0) {\n cssWriter.write();\n }\n },\n };\n});\n\n/**\n * Check if an object expression looks like a StaticStyle object\n */\nfunction isStaticStyleObject(node: t.ObjectExpression): boolean {\n const hasClassName = node.properties.some(\n (p) =>\n t.isObjectProperty(p) && t.isIdentifier(p.key, { name: 'className' }),\n );\n const hasStyles = node.properties.some(\n (p) => t.isObjectProperty(p) && t.isIdentifier(p.key, { name: 'styles' }),\n );\n return hasClassName && hasStyles;\n}\n\n/**\n * Extract styles object from a StaticStyle object expression\n */\nfunction extractStylesFromStaticStyleObject(\n node: t.ObjectExpression,\n path: NodePath,\n): Styles | null {\n for (const prop of node.properties) {\n if (\n t.isObjectProperty(prop) &&\n t.isIdentifier(prop.key, { name: 'styles' }) &&\n t.isObjectExpression(prop.value)\n ) {\n return evaluateObjectExpression(prop.value, path) as Styles;\n }\n }\n return null;\n}\n\n/**\n * Extract className from a StaticStyle object expression\n */\nfunction extractClassNameFromStaticStyleObject(\n node: t.ObjectExpression,\n): string | null {\n for (const prop of node.properties) {\n if (\n t.isObjectProperty(prop) &&\n t.isIdentifier(prop.key, { name: 'className' }) &&\n t.isStringLiteral(prop.value)\n ) {\n return prop.value.value;\n }\n }\n return null;\n}\n\n/**\n * Handle tastyStatic(styles) - returns StaticStyle object\n */\nfunction handleStylesMode(\n path: NodePath<t.CallExpression>,\n args: t.CallExpression['arguments'],\n cssWriter: CSSWriter,\n state: PluginState,\n globalRegistry: StaticStyleRegistry,\n globalKeyframes?: Record<string, KeyframesSteps>,\n autoPropertyTypes?: boolean,\n): void {\n const stylesArg = args[0];\n\n if (!t.isObjectExpression(stylesArg)) {\n throw path.buildCodeFrameError(\n 'tastyStatic(styles) argument must be a static object literal',\n );\n }\n\n // Evaluate styles object at build time\n const rawStyles = evaluateObjectExpression(stylesArg, path) as Styles;\n\n // Resolve recipes before extraction\n const styles = resolveRecipes(rawStyles);\n\n // Extract keyframes (deduplicated by content)\n const { keyframes, nameMap } = extractKeyframesFromStyles(\n styles,\n globalKeyframes,\n );\n\n // Add keyframes CSS\n for (const kf of keyframes) {\n cssWriter.add(kf.css, kf.css, state.sourceFile);\n }\n\n // Extract and add auto-inferred @property rules\n const properties = extractPropertiesFromStyles(styles, { autoPropertyTypes });\n for (const prop of properties) {\n cssWriter.add(prop.css, prop.css, state.sourceFile);\n }\n\n // Extract styles with chunking\n const chunks = extractStylesWithChunks(styles);\n\n // Add CSS to writer, replacing animation names if needed\n for (const chunk of chunks) {\n const css =\n nameMap.size > 0\n ? replaceAnimationNamesInCSS(chunk.css, nameMap)\n : chunk.css;\n cssWriter.add(chunk.className, css, state.sourceFile);\n }\n\n // Generate className\n const className =\n chunks.length > 0 ? chunks.map((c) => c.className).join(' ') : '';\n\n // Replace call with StaticStyle object\n const staticStyleObject = createStaticStyleAST(className, styles);\n path.replaceWith(staticStyleObject);\n\n // Register if this is being assigned to a variable\n registerIfVariableDeclaration(path, className, styles, state, globalRegistry);\n}\n\n/**\n * Handle tastyStatic(base, styles) - extends base with additional styles\n */\nfunction handleExtensionMode(\n path: NodePath<t.CallExpression>,\n args: t.CallExpression['arguments'],\n cssWriter: CSSWriter,\n state: PluginState,\n globalRegistry: StaticStyleRegistry,\n globalKeyframes?: Record<string, KeyframesSteps>,\n autoPropertyTypes?: boolean,\n): void {\n if (args.length < 2) {\n throw path.buildCodeFrameError(\n 'tastyStatic(base, styles) requires two arguments',\n );\n }\n\n const baseArg = args[0];\n const stylesArg = args[1];\n\n if (!t.isIdentifier(baseArg)) {\n throw path.buildCodeFrameError(\n 'tastyStatic(base, styles) first argument must be an identifier',\n );\n }\n\n if (!t.isObjectExpression(stylesArg)) {\n throw path.buildCodeFrameError(\n 'tastyStatic(base, styles) second argument must be a static object literal',\n );\n }\n\n const baseName = baseArg.name;\n\n // Look up base styles in registry\n const baseEntry =\n state.staticStyleRegistry[baseName] || globalRegistry[baseName];\n\n if (!baseEntry) {\n throw path.buildCodeFrameError(\n `Cannot find base StaticStyle '${baseName}'. ` +\n 'Make sure it is defined before being extended.',\n );\n }\n\n // Evaluate override styles\n const overrideStyles = evaluateObjectExpression(stylesArg, path) as Styles;\n\n // Merge styles using mergeStyles, then resolve recipes\n const mergedStyles = resolveRecipes(\n mergeStyles(baseEntry.styles, overrideStyles),\n );\n\n // Extract keyframes (deduplicated by content)\n const { keyframes, nameMap } = extractKeyframesFromStyles(\n mergedStyles,\n globalKeyframes,\n );\n\n // Add keyframes CSS\n for (const kf of keyframes) {\n cssWriter.add(kf.css, kf.css, state.sourceFile);\n }\n\n // Extract and add auto-inferred @property rules\n const properties = extractPropertiesFromStyles(mergedStyles, {\n autoPropertyTypes,\n });\n for (const prop of properties) {\n cssWriter.add(prop.css, prop.css, state.sourceFile);\n }\n\n // Extract styles with chunking\n const chunks = extractStylesWithChunks(mergedStyles);\n\n // Add CSS to writer, replacing animation names if needed\n for (const chunk of chunks) {\n const css =\n nameMap.size > 0\n ? replaceAnimationNamesInCSS(chunk.css, nameMap)\n : chunk.css;\n cssWriter.add(chunk.className, css, state.sourceFile);\n }\n\n // Generate className\n const className =\n chunks.length > 0 ? chunks.map((c) => c.className).join(' ') : '';\n\n // Replace call with StaticStyle object\n const staticStyleObject = createStaticStyleAST(className, mergedStyles);\n path.replaceWith(staticStyleObject);\n\n // Register if this is being assigned to a variable\n registerIfVariableDeclaration(\n path,\n className,\n mergedStyles,\n state,\n globalRegistry,\n );\n}\n\n/**\n * Handle tastyStatic(selector, styles) - removes the call entirely\n */\nfunction handleSelectorMode(\n path: NodePath<t.CallExpression>,\n args: t.CallExpression['arguments'],\n cssWriter: CSSWriter,\n sourceFile?: string,\n globalKeyframes?: Record<string, KeyframesSteps>,\n autoPropertyTypes?: boolean,\n): void {\n if (args.length < 2) {\n throw path.buildCodeFrameError(\n 'tastyStatic(selector, styles) requires two arguments',\n );\n }\n\n const selectorArg = args[0];\n const stylesArg = args[1];\n\n if (!t.isStringLiteral(selectorArg)) {\n throw path.buildCodeFrameError(\n 'tastyStatic(selector, styles) first argument must be a string literal',\n );\n }\n\n if (!t.isObjectExpression(stylesArg)) {\n throw path.buildCodeFrameError(\n 'tastyStatic(selector, styles) second argument must be a static object literal',\n );\n }\n\n const selector = selectorArg.value;\n const rawStyles = evaluateObjectExpression(stylesArg, path) as Styles;\n\n // Resolve recipes before extraction\n const styles = resolveRecipes(rawStyles);\n\n // Extract keyframes (deduplicated by content)\n const { keyframes, nameMap } = extractKeyframesFromStyles(\n styles,\n globalKeyframes,\n );\n\n // Add keyframes CSS\n for (const kf of keyframes) {\n cssWriter.add(kf.css, kf.css, sourceFile);\n }\n\n // Extract and add auto-inferred @property rules\n const properties = extractPropertiesFromStyles(styles, { autoPropertyTypes });\n for (const prop of properties) {\n cssWriter.add(prop.css, prop.css, sourceFile);\n }\n\n // Extract styles for selector\n const result = extractStylesForSelector(selector, styles);\n\n // Replace animation names if needed and add CSS\n const css =\n nameMap.size > 0\n ? replaceAnimationNamesInCSS(result.css, nameMap)\n : result.css;\n cssWriter.add(selector, css, sourceFile);\n\n // Remove the entire statement\n const parent = path.parentPath;\n if (parent && t.isExpressionStatement(parent.node)) {\n parent.remove();\n } else {\n // If used in an expression context (which would be incorrect usage),\n // replace with undefined\n path.replaceWith(t.identifier('undefined'));\n }\n}\n\n/**\n * Create a StaticStyle object AST node\n */\nfunction createStaticStyleAST(\n className: string,\n styles: Styles,\n): t.ObjectExpression {\n return t.objectExpression([\n t.objectProperty(t.identifier('className'), t.stringLiteral(className)),\n t.objectProperty(t.identifier('styles'), valueToAST(styles)),\n t.objectMethod(\n 'method',\n t.identifier('toString'),\n [],\n t.blockStatement([\n t.returnStatement(\n t.memberExpression(t.thisExpression(), t.identifier('className')),\n ),\n ]),\n ),\n ]);\n}\n\n/**\n * Register a StaticStyle in the registry if it's being assigned to a variable\n */\nfunction registerIfVariableDeclaration(\n path: NodePath,\n className: string,\n styles: Styles,\n state: PluginState,\n globalRegistry: StaticStyleRegistry,\n): void {\n const parent = path.parentPath;\n if (parent && t.isVariableDeclarator(parent.node)) {\n const id = parent.node.id;\n if (t.isIdentifier(id)) {\n const variableName = id.name;\n state.staticStyleRegistry[variableName] = { styles, className };\n globalRegistry[variableName] = { styles, className };\n }\n }\n}\n\n/**\n * Convert a JavaScript value to an AST node\n */\nfunction valueToAST(value: unknown): t.Expression {\n if (value === null) {\n return t.nullLiteral();\n }\n if (value === undefined) {\n return t.identifier('undefined');\n }\n if (typeof value === 'string') {\n return t.stringLiteral(value);\n }\n if (typeof value === 'number') {\n return t.numericLiteral(value);\n }\n if (typeof value === 'boolean') {\n return t.booleanLiteral(value);\n }\n if (Array.isArray(value)) {\n return t.arrayExpression(value.map(valueToAST));\n }\n if (typeof value === 'object') {\n const properties = Object.entries(value).map(([key, val]) =>\n t.objectProperty(\n /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key)\n ? t.identifier(key)\n : t.stringLiteral(key),\n valueToAST(val),\n ),\n );\n return t.objectExpression(properties);\n }\n // Fallback for unsupported types\n return t.identifier('undefined');\n}\n\n/**\n * Evaluate an ObjectExpression to a plain JavaScript object.\n * Only supports static values that can be determined at build time.\n */\nfunction evaluateObjectExpression(\n node: t.ObjectExpression,\n path: NodePath,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const prop of node.properties) {\n if (t.isSpreadElement(prop)) {\n throw path.buildCodeFrameError(\n 'Spread elements are not supported in tastyStatic() - styles must be fully static',\n );\n }\n\n if (!t.isObjectProperty(prop)) {\n throw path.buildCodeFrameError(\n 'Only object properties are supported in tastyStatic()',\n );\n }\n\n // Get key\n let key: string;\n if (t.isIdentifier(prop.key)) {\n key = prop.key.name;\n } else if (t.isStringLiteral(prop.key)) {\n key = prop.key.value;\n } else {\n throw path.buildCodeFrameError(\n 'Dynamic property keys are not supported in tastyStatic()',\n );\n }\n\n // Get value\n const value = evaluateExpression(prop.value, path);\n result[key] = value;\n }\n\n return result;\n}\n\n/**\n * Evaluate an expression to a JavaScript value.\n */\nfunction evaluateExpression(node: t.Node, path: NodePath): unknown {\n if (t.isStringLiteral(node)) {\n return node.value;\n }\n\n if (t.isNumericLiteral(node)) {\n return node.value;\n }\n\n if (t.isBooleanLiteral(node)) {\n return node.value;\n }\n\n if (t.isNullLiteral(node)) {\n return null;\n }\n\n if (t.isIdentifier(node, { name: 'undefined' })) {\n return undefined;\n }\n\n if (t.isArrayExpression(node)) {\n return node.elements.map((el) => {\n if (el === null) return null;\n if (t.isSpreadElement(el)) {\n throw path.buildCodeFrameError(\n 'Spread elements are not supported in tastyStatic()',\n );\n }\n return evaluateExpression(el, path);\n });\n }\n\n if (t.isObjectExpression(node)) {\n return evaluateObjectExpression(node, path);\n }\n\n if (t.isTemplateLiteral(node)) {\n // Only support template literals without expressions\n if (node.expressions.length > 0) {\n throw path.buildCodeFrameError(\n 'Template literals with expressions are not supported in tastyStatic()',\n );\n }\n return node.quasis.map((q) => q.value.cooked).join('');\n }\n\n if (t.isUnaryExpression(node, { operator: '-' })) {\n const arg = evaluateExpression(node.argument, path);\n if (typeof arg === 'number') {\n return -arg;\n }\n }\n\n throw path.buildCodeFrameError(\n `Dynamic expressions are not supported in tastyStatic() - got ${node.type}. ` +\n 'All values must be static literals.',\n );\n}\n\n/**\n * Replace animation names in CSS string.\n * Wraps the keyframes replaceAnimationNames to work on full CSS blocks.\n */\nfunction replaceAnimationNamesInCSS(\n css: string,\n nameMap: Map<string, string>,\n): string {\n if (nameMap.size === 0) return css;\n\n // The CSS contains full rules like \".class { animation: name 1s; }\"\n // We need to replace animation names within declaration blocks\n return css.replace(\n /(animation(?:-name)?)\\s*:\\s*([^;}]+)/gi,\n (match, prop, value) => {\n let newValue = value;\n for (const [original, replacement] of nameMap) {\n // Word boundary replacement\n const pattern = new RegExp(`\\\\b${escapeRegex(original)}\\\\b`, 'g');\n newValue = newValue.replace(pattern, replacement);\n }\n return `${prop}: ${newValue}`;\n },\n );\n}\n\n/**\n * Escape special regex characters.\n */\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n"],"mappings":"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"}
|
package/dist/zero/next.js
CHANGED
|
@@ -14,6 +14,10 @@ import { fileURLToPath } from "url";
|
|
|
14
14
|
* JSON-serializable options (`configFile` path instead of a function).
|
|
15
15
|
* The Babel plugin loads the config internally via jiti.
|
|
16
16
|
*
|
|
17
|
+
* The generated CSS is injected automatically — `@tenphi/tasty/static`
|
|
18
|
+
* imports are replaced with an import of the output CSS file at build time.
|
|
19
|
+
* No manual CSS import in layout files is needed.
|
|
20
|
+
*
|
|
17
21
|
* @example
|
|
18
22
|
* ```javascript
|
|
19
23
|
* // next.config.js
|
|
@@ -52,6 +56,7 @@ function withTastyZero(options = {}) {
|
|
|
52
56
|
] },
|
|
53
57
|
plugins: [[babelPluginPath, {
|
|
54
58
|
output: absoluteOutput,
|
|
59
|
+
injectImport: true,
|
|
55
60
|
...absoluteConfigFile ? { configFile: absoluteConfigFile } : tastyConfig ? { config: tastyConfig } : {},
|
|
56
61
|
...allDeps.length > 0 ? { configDeps: allDeps } : {}
|
|
57
62
|
}]]
|
|
@@ -85,7 +90,10 @@ function withTastyZero(options = {}) {
|
|
|
85
90
|
const projectRequire = createRequire(path.resolve(wpProjectDir, "package.json"));
|
|
86
91
|
const wpAbsoluteConfigFile = configFile ? path.resolve(wpProjectDir, configFile) : void 0;
|
|
87
92
|
const wpAllDeps = [...wpAbsoluteConfigFile ? [wpAbsoluteConfigFile] : [], ...configDeps.map((dep) => path.resolve(wpProjectDir, dep))];
|
|
88
|
-
const babelPluginOptions = {
|
|
93
|
+
const babelPluginOptions = {
|
|
94
|
+
output: wpAbsoluteOutput,
|
|
95
|
+
injectImport: true
|
|
96
|
+
};
|
|
89
97
|
if (wpAbsoluteConfigFile) {
|
|
90
98
|
const jiti = createJiti(wpProjectDir, { moduleCache: false });
|
|
91
99
|
babelPluginOptions.config = () => {
|
package/dist/zero/next.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"next.js","names":[],"sources":["../../src/zero/next.ts"],"sourcesContent":["/**\n * Next.js configuration wrapper for tasty-zero.\n *\n * Supports both webpack and Turbopack bundlers:\n * - **webpack**: Injects a babel-loader rule with the tasty-zero Babel plugin\n * via `webpack()` config hook. Config is passed as a jiti factory function.\n * - **Turbopack**: Adds a `turbopack.rules` entry with babel-loader and\n * JSON-serializable options (`configFile` path instead of a function).\n * The Babel plugin loads the config internally via jiti.\n *\n * @example\n * ```javascript\n * // next.config.js\n * const { withTastyZero } = require('@tenphi/tasty/next');\n *\n * module.exports = withTastyZero({\n * output: 'public/tasty.css',\n * configFile: './app/tasty-zero.config.ts',\n * })({\n * // your Next.js config\n * });\n * ```\n */\n\nimport { createRequire } from 'module';\nimport * as path from 'path';\nimport { fileURLToPath } from 'url';\n\nimport { createJiti } from 'jiti';\n\nimport type { TastyZeroBabelOptions, TastyZeroConfig } from './babel';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n// Next.js types (inline to avoid requiring next as a dependency)\ninterface WebpackConfigContext {\n isServer: boolean;\n dev: boolean;\n buildId: string;\n dir: string;\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any -- webpack/Next.js config types are complex */\ninterface TurbopackLoaderItem {\n loader: string;\n options?: Record<string, unknown>;\n}\n\ninterface TurbopackRuleConfig {\n loaders: (string | TurbopackLoaderItem)[];\n as?: string;\n condition?: unknown;\n}\n\ninterface TurbopackConfig {\n rules?: Record<string, TurbopackRuleConfig | TurbopackRuleConfig[]>;\n [key: string]: unknown;\n}\n\ninterface NextConfig {\n webpack?: (config: any, context: WebpackConfigContext) => any;\n turbopack?: TurbopackConfig;\n [key: string]: unknown;\n}\n\nexport interface TastyZeroNextOptions {\n /**\n * Output path for CSS relative to project root.\n * @default 'public/tasty.css'\n */\n output?: string;\n\n /**\n * Whether to enable the plugin.\n * @default true\n */\n enabled?: boolean;\n\n /**\n * Tasty configuration for build-time processing.\n * For static configs that don't change during dev.\n *\n * For configs that depend on theme files, use `configFile` instead.\n */\n config?: TastyZeroConfig;\n\n /**\n * Path to a TypeScript/JavaScript module that exports the tasty zero config\n * as its default export. The module is re-evaluated on each\n * compilation, enabling hot reload when the file (or its imports) change.\n *\n * @example './app/tasty-zero.config.ts'\n */\n configFile?: string;\n\n /**\n * Extra file paths (relative to project root) that the config depends on.\n * When any of these files change, the Babel cache is invalidated and\n * the config is re-evaluated.\n *\n * The `configFile` itself is always tracked automatically.\n * Use this for transitive dependencies that aren't directly imported\n * by the config file, or when using `config` instead of `configFile`.\n *\n * @example ['./app/theme.ts']\n */\n configDeps?: string[];\n}\n\n/**\n * Next.js configuration wrapper for tasty-zero.\n * Configures both webpack and Turbopack bundlers automatically.\n */\nexport function withTastyZero(options: TastyZeroNextOptions = {}) {\n const {\n output = 'public/tasty.css',\n enabled = true,\n config: tastyConfig,\n configFile,\n configDeps = [],\n } = options;\n\n return (nextConfig: NextConfig = {}): NextConfig => {\n if (!enabled) {\n return nextConfig;\n }\n\n const projectDir = process.cwd();\n const absoluteOutput = path.resolve(projectDir, output);\n const babelPluginPath = path.resolve(__dirname, 'babel.js');\n\n const absoluteConfigFile = configFile\n ? path.resolve(projectDir, configFile)\n : undefined;\n\n const allDeps = [\n ...(absoluteConfigFile ? [absoluteConfigFile] : []),\n ...configDeps.map((dep) => path.resolve(projectDir, dep)),\n ];\n\n // --- Turbopack configuration ---\n // Turbopack loader options must be JSON-serializable (no functions).\n // The Babel plugin loads config internally via `configFile` path + jiti.\n const turbopackBabelOptions: Record<string, unknown> = {\n babelrc: false,\n configFile: false,\n parserOpts: {\n plugins: ['typescript', 'jsx', 'decorators-legacy'],\n },\n plugins: [\n [\n babelPluginPath,\n {\n output: absoluteOutput,\n ...(absoluteConfigFile\n ? { configFile: absoluteConfigFile }\n : tastyConfig\n ? { config: tastyConfig }\n : {}),\n ...(allDeps.length > 0 ? { configDeps: allDeps } : {}),\n },\n ],\n ],\n };\n\n const existingTurbopack = nextConfig.turbopack || {};\n const existingRules = existingTurbopack.rules || {};\n\n const existingExperimental =\n (nextConfig.experimental as Record<string, unknown>) || {};\n\n return {\n ...nextConfig,\n\n experimental: {\n ...existingExperimental,\n turbopackUseBuiltinBabel: true,\n },\n\n turbopack: {\n ...existingTurbopack,\n rules: {\n ...existingRules,\n '*.{ts,tsx,js,jsx}': {\n condition: { not: 'foreign' },\n loaders: [\n {\n loader: 'babel-loader',\n options: turbopackBabelOptions,\n },\n ],\n },\n },\n },\n\n webpack(config: any, context: WebpackConfigContext) {\n const { dir } = context;\n\n const wpProjectDir = dir || projectDir;\n const wpAbsoluteOutput = path.resolve(wpProjectDir, output);\n const projectRequire = createRequire(\n path.resolve(wpProjectDir, 'package.json'),\n );\n\n const wpAbsoluteConfigFile = configFile\n ? path.resolve(wpProjectDir, configFile)\n : undefined;\n\n const wpAllDeps = [\n ...(wpAbsoluteConfigFile ? [wpAbsoluteConfigFile] : []),\n ...configDeps.map((dep) => path.resolve(wpProjectDir, dep)),\n ];\n\n const babelPluginOptions: TastyZeroBabelOptions = {\n output: wpAbsoluteOutput,\n };\n\n if (wpAbsoluteConfigFile) {\n const jiti = createJiti(wpProjectDir, {\n moduleCache: false,\n });\n\n babelPluginOptions.config = () => {\n return jiti(wpAbsoluteConfigFile) as TastyZeroConfig;\n };\n } else if (tastyConfig) {\n babelPluginOptions.config = tastyConfig;\n }\n\n if (wpAllDeps.length > 0) {\n babelPluginOptions.configDeps = wpAllDeps;\n }\n\n const babelPluginConfig = [babelPluginPath, babelPluginOptions];\n\n const existingRule = config.module?.rules?.find(\n (rule: any) =>\n rule.use?.loader === 'babel-loader' ||\n rule.use?.some?.((u: any) => u.loader === 'babel-loader'),\n );\n\n if (existingRule) {\n const babelUse = Array.isArray(existingRule.use)\n ? existingRule.use.find((u: any) => u.loader === 'babel-loader')\n : existingRule.use;\n\n if (babelUse?.options) {\n babelUse.options.plugins = babelUse.options.plugins || [];\n babelUse.options.plugins.push(babelPluginConfig);\n }\n } else {\n config.module = config.module || {};\n config.module.rules = config.module.rules || [];\n config.module.rules.push({\n test: /\\.(tsx?|jsx?)$/,\n exclude: /node_modules/,\n use: [\n {\n loader: projectRequire.resolve('babel-loader'),\n options: {\n babelrc: false,\n configFile: false,\n parserOpts: {\n plugins: ['typescript', 'jsx', 'decorators-legacy'],\n },\n plugins: [babelPluginConfig],\n },\n },\n ],\n });\n }\n\n if (typeof nextConfig.webpack === 'function') {\n return nextConfig.webpack(config, context);\n }\n\n return config;\n },\n };\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,MAAM,aAAa,cAAc,OAAO,KAAK,IAAI;AACjD,MAAM,YAAY,KAAK,QAAQ,WAAW;;;;;AAiF1C,SAAgB,cAAc,UAAgC,EAAE,EAAE;CAChE,MAAM,EACJ,SAAS,oBACT,UAAU,MACV,QAAQ,aACR,YACA,aAAa,EAAE,KACb;AAEJ,SAAQ,aAAyB,EAAE,KAAiB;AAClD,MAAI,CAAC,QACH,QAAO;EAGT,MAAM,aAAa,QAAQ,KAAK;EAChC,MAAM,iBAAiB,KAAK,QAAQ,YAAY,OAAO;EACvD,MAAM,kBAAkB,KAAK,QAAQ,WAAW,WAAW;EAE3D,MAAM,qBAAqB,aACvB,KAAK,QAAQ,YAAY,WAAW,GACpC;EAEJ,MAAM,UAAU,CACd,GAAI,qBAAqB,CAAC,mBAAmB,GAAG,EAAE,EAClD,GAAG,WAAW,KAAK,QAAQ,KAAK,QAAQ,YAAY,IAAI,CAAC,CAC1D;EAKD,MAAM,wBAAiD;GACrD,SAAS;GACT,YAAY;GACZ,YAAY,EACV,SAAS;IAAC;IAAc;IAAO;IAAoB,EACpD;GACD,SAAS,CACP,CACE,iBACA;IACE,QAAQ;IACR,GAAI,qBACA,EAAE,YAAY,oBAAoB,GAClC,cACE,EAAE,QAAQ,aAAa,GACvB,EAAE;IACR,GAAI,QAAQ,SAAS,IAAI,EAAE,YAAY,SAAS,GAAG,EAAE;IACtD,CACF,CACF;GACF;EAED,MAAM,oBAAoB,WAAW,aAAa,EAAE;EACpD,MAAM,gBAAgB,kBAAkB,SAAS,EAAE;EAEnD,MAAM,uBACH,WAAW,gBAA4C,EAAE;AAE5D,SAAO;GACL,GAAG;GAEH,cAAc;IACZ,GAAG;IACH,0BAA0B;IAC3B;GAED,WAAW;IACT,GAAG;IACH,OAAO;KACL,GAAG;KACH,qBAAqB;MACnB,WAAW,EAAE,KAAK,WAAW;MAC7B,SAAS,CACP;OACE,QAAQ;OACR,SAAS;OACV,CACF;MACF;KACF;IACF;GAED,QAAQ,QAAa,SAA+B;IAClD,MAAM,EAAE,QAAQ;IAEhB,MAAM,eAAe,OAAO;IAC5B,MAAM,mBAAmB,KAAK,QAAQ,cAAc,OAAO;IAC3D,MAAM,iBAAiB,cACrB,KAAK,QAAQ,cAAc,eAAe,CAC3C;IAED,MAAM,uBAAuB,aACzB,KAAK,QAAQ,cAAc,WAAW,GACtC;IAEJ,MAAM,YAAY,CAChB,GAAI,uBAAuB,CAAC,qBAAqB,GAAG,EAAE,EACtD,GAAG,WAAW,KAAK,QAAQ,KAAK,QAAQ,cAAc,IAAI,CAAC,CAC5D;IAED,MAAM,qBAA4C,EAChD,QAAQ,kBACT;AAED,QAAI,sBAAsB;KACxB,MAAM,OAAO,WAAW,cAAc,EACpC,aAAa,OACd,CAAC;AAEF,wBAAmB,eAAe;AAChC,aAAO,KAAK,qBAAqB;;eAE1B,YACT,oBAAmB,SAAS;AAG9B,QAAI,UAAU,SAAS,EACrB,oBAAmB,aAAa;IAGlC,MAAM,oBAAoB,CAAC,iBAAiB,mBAAmB;IAE/D,MAAM,eAAe,OAAO,QAAQ,OAAO,MACxC,SACC,KAAK,KAAK,WAAW,kBACrB,KAAK,KAAK,QAAQ,MAAW,EAAE,WAAW,eAAe,CAC5D;AAED,QAAI,cAAc;KAChB,MAAM,WAAW,MAAM,QAAQ,aAAa,IAAI,GAC5C,aAAa,IAAI,MAAM,MAAW,EAAE,WAAW,eAAe,GAC9D,aAAa;AAEjB,SAAI,UAAU,SAAS;AACrB,eAAS,QAAQ,UAAU,SAAS,QAAQ,WAAW,EAAE;AACzD,eAAS,QAAQ,QAAQ,KAAK,kBAAkB;;WAE7C;AACL,YAAO,SAAS,OAAO,UAAU,EAAE;AACnC,YAAO,OAAO,QAAQ,OAAO,OAAO,SAAS,EAAE;AAC/C,YAAO,OAAO,MAAM,KAAK;MACvB,MAAM;MACN,SAAS;MACT,KAAK,CACH;OACE,QAAQ,eAAe,QAAQ,eAAe;OAC9C,SAAS;QACP,SAAS;QACT,YAAY;QACZ,YAAY,EACV,SAAS;SAAC;SAAc;SAAO;SAAoB,EACpD;QACD,SAAS,CAAC,kBAAkB;QAC7B;OACF,CACF;MACF,CAAC;;AAGJ,QAAI,OAAO,WAAW,YAAY,WAChC,QAAO,WAAW,QAAQ,QAAQ,QAAQ;AAG5C,WAAO;;GAEV"}
|
|
1
|
+
{"version":3,"file":"next.js","names":[],"sources":["../../src/zero/next.ts"],"sourcesContent":["/**\n * Next.js configuration wrapper for tasty-zero.\n *\n * Supports both webpack and Turbopack bundlers:\n * - **webpack**: Injects a babel-loader rule with the tasty-zero Babel plugin\n * via `webpack()` config hook. Config is passed as a jiti factory function.\n * - **Turbopack**: Adds a `turbopack.rules` entry with babel-loader and\n * JSON-serializable options (`configFile` path instead of a function).\n * The Babel plugin loads the config internally via jiti.\n *\n * The generated CSS is injected automatically — `@tenphi/tasty/static`\n * imports are replaced with an import of the output CSS file at build time.\n * No manual CSS import in layout files is needed.\n *\n * @example\n * ```javascript\n * // next.config.js\n * const { withTastyZero } = require('@tenphi/tasty/next');\n *\n * module.exports = withTastyZero({\n * output: 'public/tasty.css',\n * configFile: './app/tasty-zero.config.ts',\n * })({\n * // your Next.js config\n * });\n * ```\n */\n\nimport { createRequire } from 'module';\nimport * as path from 'path';\nimport { fileURLToPath } from 'url';\n\nimport { createJiti } from 'jiti';\n\nimport type { TastyZeroBabelOptions, TastyZeroConfig } from './babel';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n// Next.js types (inline to avoid requiring next as a dependency)\ninterface WebpackConfigContext {\n isServer: boolean;\n dev: boolean;\n buildId: string;\n dir: string;\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any -- webpack/Next.js config types are complex */\ninterface TurbopackLoaderItem {\n loader: string;\n options?: Record<string, unknown>;\n}\n\ninterface TurbopackRuleConfig {\n loaders: (string | TurbopackLoaderItem)[];\n as?: string;\n condition?: unknown;\n}\n\ninterface TurbopackConfig {\n rules?: Record<string, TurbopackRuleConfig | TurbopackRuleConfig[]>;\n [key: string]: unknown;\n}\n\ninterface NextConfig {\n webpack?: (config: any, context: WebpackConfigContext) => any;\n turbopack?: TurbopackConfig;\n [key: string]: unknown;\n}\n\nexport interface TastyZeroNextOptions {\n /**\n * Output path for CSS relative to project root.\n * @default 'public/tasty.css'\n */\n output?: string;\n\n /**\n * Whether to enable the plugin.\n * @default true\n */\n enabled?: boolean;\n\n /**\n * Tasty configuration for build-time processing.\n * For static configs that don't change during dev.\n *\n * For configs that depend on theme files, use `configFile` instead.\n */\n config?: TastyZeroConfig;\n\n /**\n * Path to a TypeScript/JavaScript module that exports the tasty zero config\n * as its default export. The module is re-evaluated on each\n * compilation, enabling hot reload when the file (or its imports) change.\n *\n * @example './app/tasty-zero.config.ts'\n */\n configFile?: string;\n\n /**\n * Extra file paths (relative to project root) that the config depends on.\n * When any of these files change, the Babel cache is invalidated and\n * the config is re-evaluated.\n *\n * The `configFile` itself is always tracked automatically.\n * Use this for transitive dependencies that aren't directly imported\n * by the config file, or when using `config` instead of `configFile`.\n *\n * @example ['./app/theme.ts']\n */\n configDeps?: string[];\n}\n\n/**\n * Next.js configuration wrapper for tasty-zero.\n * Configures both webpack and Turbopack bundlers automatically.\n */\nexport function withTastyZero(options: TastyZeroNextOptions = {}) {\n const {\n output = 'public/tasty.css',\n enabled = true,\n config: tastyConfig,\n configFile,\n configDeps = [],\n } = options;\n\n return (nextConfig: NextConfig = {}): NextConfig => {\n if (!enabled) {\n return nextConfig;\n }\n\n const projectDir = process.cwd();\n const absoluteOutput = path.resolve(projectDir, output);\n const babelPluginPath = path.resolve(__dirname, 'babel.js');\n\n const absoluteConfigFile = configFile\n ? path.resolve(projectDir, configFile)\n : undefined;\n\n const allDeps = [\n ...(absoluteConfigFile ? [absoluteConfigFile] : []),\n ...configDeps.map((dep) => path.resolve(projectDir, dep)),\n ];\n\n // --- Turbopack configuration ---\n // Turbopack loader options must be JSON-serializable (no functions).\n // The Babel plugin loads config internally via `configFile` path + jiti.\n const turbopackBabelOptions: Record<string, unknown> = {\n babelrc: false,\n configFile: false,\n parserOpts: {\n plugins: ['typescript', 'jsx', 'decorators-legacy'],\n },\n plugins: [\n [\n babelPluginPath,\n {\n output: absoluteOutput,\n injectImport: true,\n ...(absoluteConfigFile\n ? { configFile: absoluteConfigFile }\n : tastyConfig\n ? { config: tastyConfig }\n : {}),\n ...(allDeps.length > 0 ? { configDeps: allDeps } : {}),\n },\n ],\n ],\n };\n\n const existingTurbopack = nextConfig.turbopack || {};\n const existingRules = existingTurbopack.rules || {};\n\n const existingExperimental =\n (nextConfig.experimental as Record<string, unknown>) || {};\n\n return {\n ...nextConfig,\n\n experimental: {\n ...existingExperimental,\n turbopackUseBuiltinBabel: true,\n },\n\n turbopack: {\n ...existingTurbopack,\n rules: {\n ...existingRules,\n '*.{ts,tsx,js,jsx}': {\n condition: { not: 'foreign' },\n loaders: [\n {\n loader: 'babel-loader',\n options: turbopackBabelOptions,\n },\n ],\n },\n },\n },\n\n webpack(config: any, context: WebpackConfigContext) {\n const { dir } = context;\n\n const wpProjectDir = dir || projectDir;\n const wpAbsoluteOutput = path.resolve(wpProjectDir, output);\n const projectRequire = createRequire(\n path.resolve(wpProjectDir, 'package.json'),\n );\n\n const wpAbsoluteConfigFile = configFile\n ? path.resolve(wpProjectDir, configFile)\n : undefined;\n\n const wpAllDeps = [\n ...(wpAbsoluteConfigFile ? [wpAbsoluteConfigFile] : []),\n ...configDeps.map((dep) => path.resolve(wpProjectDir, dep)),\n ];\n\n const babelPluginOptions: TastyZeroBabelOptions = {\n output: wpAbsoluteOutput,\n injectImport: true,\n };\n\n if (wpAbsoluteConfigFile) {\n const jiti = createJiti(wpProjectDir, {\n moduleCache: false,\n });\n\n babelPluginOptions.config = () => {\n return jiti(wpAbsoluteConfigFile) as TastyZeroConfig;\n };\n } else if (tastyConfig) {\n babelPluginOptions.config = tastyConfig;\n }\n\n if (wpAllDeps.length > 0) {\n babelPluginOptions.configDeps = wpAllDeps;\n }\n\n const babelPluginConfig = [babelPluginPath, babelPluginOptions];\n\n const existingRule = config.module?.rules?.find(\n (rule: any) =>\n rule.use?.loader === 'babel-loader' ||\n rule.use?.some?.((u: any) => u.loader === 'babel-loader'),\n );\n\n if (existingRule) {\n const babelUse = Array.isArray(existingRule.use)\n ? existingRule.use.find((u: any) => u.loader === 'babel-loader')\n : existingRule.use;\n\n if (babelUse?.options) {\n babelUse.options.plugins = babelUse.options.plugins || [];\n babelUse.options.plugins.push(babelPluginConfig);\n }\n } else {\n config.module = config.module || {};\n config.module.rules = config.module.rules || [];\n config.module.rules.push({\n test: /\\.(tsx?|jsx?)$/,\n exclude: /node_modules/,\n use: [\n {\n loader: projectRequire.resolve('babel-loader'),\n options: {\n babelrc: false,\n configFile: false,\n parserOpts: {\n plugins: ['typescript', 'jsx', 'decorators-legacy'],\n },\n plugins: [babelPluginConfig],\n },\n },\n ],\n });\n }\n\n if (typeof nextConfig.webpack === 'function') {\n return nextConfig.webpack(config, context);\n }\n\n return config;\n },\n };\n };\n}\n"],"mappings":"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"}
|