@tenphi/tasty 0.0.0-snapshot.08a6610
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/LICENSE +21 -0
- package/README.md +666 -0
- package/dist/_virtual/_rolldown/runtime.js +8 -0
- package/dist/chunks/cacheKey.js +70 -0
- package/dist/chunks/cacheKey.js.map +1 -0
- package/dist/chunks/definitions.d.ts +37 -0
- package/dist/chunks/definitions.js +259 -0
- package/dist/chunks/definitions.js.map +1 -0
- package/dist/chunks/renderChunk.js +61 -0
- package/dist/chunks/renderChunk.js.map +1 -0
- package/dist/config.d.ts +311 -0
- package/dist/config.js +458 -0
- package/dist/config.js.map +1 -0
- package/dist/core/index.d.ts +32 -0
- package/dist/core/index.js +26 -0
- package/dist/debug.d.ts +204 -0
- package/dist/debug.js +733 -0
- package/dist/debug.js.map +1 -0
- package/dist/hooks/useGlobalStyles.d.ts +30 -0
- package/dist/hooks/useGlobalStyles.js +83 -0
- package/dist/hooks/useGlobalStyles.js.map +1 -0
- package/dist/hooks/useKeyframes.d.ts +56 -0
- package/dist/hooks/useKeyframes.js +69 -0
- package/dist/hooks/useKeyframes.js.map +1 -0
- package/dist/hooks/useProperty.d.ts +79 -0
- package/dist/hooks/useProperty.js +114 -0
- package/dist/hooks/useProperty.js.map +1 -0
- package/dist/hooks/useRawCSS.d.ts +53 -0
- package/dist/hooks/useRawCSS.js +40 -0
- package/dist/hooks/useRawCSS.js.map +1 -0
- package/dist/hooks/useStyles.d.ts +45 -0
- package/dist/hooks/useStyles.js +248 -0
- package/dist/hooks/useStyles.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.js +33 -0
- package/dist/injector/index.d.ts +165 -0
- package/dist/injector/index.js +162 -0
- package/dist/injector/index.js.map +1 -0
- package/dist/injector/injector.d.ts +148 -0
- package/dist/injector/injector.js +430 -0
- package/dist/injector/injector.js.map +1 -0
- package/dist/injector/sheet-manager.d.ts +136 -0
- package/dist/injector/sheet-manager.js +729 -0
- package/dist/injector/sheet-manager.js.map +1 -0
- package/dist/injector/types.d.ts +144 -0
- package/dist/keyframes/index.js +206 -0
- package/dist/keyframes/index.js.map +1 -0
- package/dist/parser/classify.js +319 -0
- package/dist/parser/classify.js.map +1 -0
- package/dist/parser/const.js +33 -0
- package/dist/parser/const.js.map +1 -0
- package/dist/parser/lru.js +109 -0
- package/dist/parser/lru.js.map +1 -0
- package/dist/parser/parser.d.ts +25 -0
- package/dist/parser/parser.js +116 -0
- package/dist/parser/parser.js.map +1 -0
- package/dist/parser/tokenizer.js +69 -0
- package/dist/parser/tokenizer.js.map +1 -0
- package/dist/parser/types.d.ts +51 -0
- package/dist/parser/types.js +46 -0
- package/dist/parser/types.js.map +1 -0
- package/dist/pipeline/conditions.d.ts +134 -0
- package/dist/pipeline/conditions.js +406 -0
- package/dist/pipeline/conditions.js.map +1 -0
- package/dist/pipeline/exclusive.js +231 -0
- package/dist/pipeline/exclusive.js.map +1 -0
- package/dist/pipeline/index.d.ts +53 -0
- package/dist/pipeline/index.js +660 -0
- package/dist/pipeline/index.js.map +1 -0
- package/dist/pipeline/materialize.js +856 -0
- package/dist/pipeline/materialize.js.map +1 -0
- package/dist/pipeline/parseStateKey.d.ts +15 -0
- package/dist/pipeline/parseStateKey.js +451 -0
- package/dist/pipeline/parseStateKey.js.map +1 -0
- package/dist/pipeline/simplify.js +516 -0
- package/dist/pipeline/simplify.js.map +1 -0
- package/dist/pipeline/warnings.js +18 -0
- package/dist/pipeline/warnings.js.map +1 -0
- package/dist/plugins/okhsl-plugin.d.ts +35 -0
- package/dist/plugins/okhsl-plugin.js +371 -0
- package/dist/plugins/okhsl-plugin.js.map +1 -0
- package/dist/plugins/types.d.ts +76 -0
- package/dist/properties/index.js +236 -0
- package/dist/properties/index.js.map +1 -0
- package/dist/properties/property-type-resolver.d.ts +24 -0
- package/dist/properties/property-type-resolver.js +91 -0
- package/dist/properties/property-type-resolver.js.map +1 -0
- package/dist/ssr/astro.d.ts +29 -0
- package/dist/ssr/astro.js +65 -0
- package/dist/ssr/astro.js.map +1 -0
- package/dist/ssr/async-storage.d.ts +17 -0
- package/dist/ssr/async-storage.js +35 -0
- package/dist/ssr/async-storage.js.map +1 -0
- package/dist/ssr/collect-auto-properties.js +40 -0
- package/dist/ssr/collect-auto-properties.js.map +1 -0
- package/dist/ssr/collector.d.ts +85 -0
- package/dist/ssr/collector.js +183 -0
- package/dist/ssr/collector.js.map +1 -0
- package/dist/ssr/context.d.ts +8 -0
- package/dist/ssr/context.js +14 -0
- package/dist/ssr/context.js.map +1 -0
- package/dist/ssr/format-global-rules.js +22 -0
- package/dist/ssr/format-global-rules.js.map +1 -0
- package/dist/ssr/format-keyframes.js +70 -0
- package/dist/ssr/format-keyframes.js.map +1 -0
- package/dist/ssr/format-property.js +48 -0
- package/dist/ssr/format-property.js.map +1 -0
- package/dist/ssr/format-rules.js +70 -0
- package/dist/ssr/format-rules.js.map +1 -0
- package/dist/ssr/hydrate.d.ts +22 -0
- package/dist/ssr/hydrate.js +50 -0
- package/dist/ssr/hydrate.js.map +1 -0
- package/dist/ssr/index.d.ts +5 -0
- package/dist/ssr/index.js +12 -0
- package/dist/ssr/index.js.map +1 -0
- package/dist/ssr/next.d.ts +45 -0
- package/dist/ssr/next.js +71 -0
- package/dist/ssr/next.js.map +1 -0
- package/dist/ssr/ssr-collector-ref.js +12 -0
- package/dist/ssr/ssr-collector-ref.js.map +1 -0
- package/dist/states/index.d.ts +49 -0
- package/dist/states/index.js +416 -0
- package/dist/states/index.js.map +1 -0
- package/dist/static/index.d.ts +5 -0
- package/dist/static/index.js +5 -0
- package/dist/static/tastyStatic.d.ts +46 -0
- package/dist/static/tastyStatic.js +31 -0
- package/dist/static/tastyStatic.js.map +1 -0
- package/dist/static/types.d.ts +49 -0
- package/dist/static/types.js +24 -0
- package/dist/static/types.js.map +1 -0
- package/dist/styles/align.d.ts +15 -0
- package/dist/styles/align.js +14 -0
- package/dist/styles/align.js.map +1 -0
- package/dist/styles/border.d.ts +25 -0
- package/dist/styles/border.js +114 -0
- package/dist/styles/border.js.map +1 -0
- package/dist/styles/color.d.ts +14 -0
- package/dist/styles/color.js +23 -0
- package/dist/styles/color.js.map +1 -0
- package/dist/styles/createStyle.js +77 -0
- package/dist/styles/createStyle.js.map +1 -0
- package/dist/styles/dimension.js +97 -0
- package/dist/styles/dimension.js.map +1 -0
- package/dist/styles/display.d.ts +37 -0
- package/dist/styles/display.js +67 -0
- package/dist/styles/display.js.map +1 -0
- package/dist/styles/fade.d.ts +15 -0
- package/dist/styles/fade.js +58 -0
- package/dist/styles/fade.js.map +1 -0
- package/dist/styles/fill.d.ts +42 -0
- package/dist/styles/fill.js +52 -0
- package/dist/styles/fill.js.map +1 -0
- package/dist/styles/flow.d.ts +16 -0
- package/dist/styles/flow.js +12 -0
- package/dist/styles/flow.js.map +1 -0
- package/dist/styles/gap.d.ts +31 -0
- package/dist/styles/gap.js +37 -0
- package/dist/styles/gap.js.map +1 -0
- package/dist/styles/height.d.ts +17 -0
- package/dist/styles/height.js +20 -0
- package/dist/styles/height.js.map +1 -0
- package/dist/styles/index.d.ts +2 -0
- package/dist/styles/index.js +9 -0
- package/dist/styles/index.js.map +1 -0
- package/dist/styles/inset.d.ts +52 -0
- package/dist/styles/inset.js +150 -0
- package/dist/styles/inset.js.map +1 -0
- package/dist/styles/justify.d.ts +15 -0
- package/dist/styles/justify.js +14 -0
- package/dist/styles/justify.js.map +1 -0
- package/dist/styles/list.d.ts +16 -0
- package/dist/styles/list.js +98 -0
- package/dist/styles/list.js.map +1 -0
- package/dist/styles/margin.d.ts +24 -0
- package/dist/styles/margin.js +104 -0
- package/dist/styles/margin.js.map +1 -0
- package/dist/styles/outline.d.ts +29 -0
- package/dist/styles/outline.js +65 -0
- package/dist/styles/outline.js.map +1 -0
- package/dist/styles/padding.d.ts +24 -0
- package/dist/styles/padding.js +104 -0
- package/dist/styles/padding.js.map +1 -0
- package/dist/styles/predefined.d.ts +71 -0
- package/dist/styles/predefined.js +238 -0
- package/dist/styles/predefined.js.map +1 -0
- package/dist/styles/preset.d.ts +47 -0
- package/dist/styles/preset.js +126 -0
- package/dist/styles/preset.js.map +1 -0
- package/dist/styles/radius.d.ts +14 -0
- package/dist/styles/radius.js +51 -0
- package/dist/styles/radius.js.map +1 -0
- package/dist/styles/scrollbar.d.ts +25 -0
- package/dist/styles/scrollbar.js +48 -0
- package/dist/styles/scrollbar.js.map +1 -0
- package/dist/styles/shadow.d.ts +14 -0
- package/dist/styles/shadow.js +24 -0
- package/dist/styles/shadow.js.map +1 -0
- package/dist/styles/transition.d.ts +14 -0
- package/dist/styles/transition.js +158 -0
- package/dist/styles/transition.js.map +1 -0
- package/dist/styles/types.d.ts +508 -0
- package/dist/styles/width.d.ts +17 -0
- package/dist/styles/width.js +20 -0
- package/dist/styles/width.js.map +1 -0
- package/dist/tasty.d.ts +981 -0
- package/dist/tasty.js +206 -0
- package/dist/tasty.js.map +1 -0
- package/dist/types.d.ts +184 -0
- package/dist/utils/cache-wrapper.js +26 -0
- package/dist/utils/cache-wrapper.js.map +1 -0
- package/dist/utils/case-converter.js +8 -0
- package/dist/utils/case-converter.js.map +1 -0
- package/dist/utils/colors.d.ts +5 -0
- package/dist/utils/colors.js +9 -0
- package/dist/utils/colors.js.map +1 -0
- package/dist/utils/css-types.d.ts +7 -0
- package/dist/utils/dotize.d.ts +26 -0
- package/dist/utils/dotize.js +122 -0
- package/dist/utils/dotize.js.map +1 -0
- package/dist/utils/filter-base-props.d.ts +15 -0
- package/dist/utils/filter-base-props.js +45 -0
- package/dist/utils/filter-base-props.js.map +1 -0
- package/dist/utils/get-display-name.d.ts +7 -0
- package/dist/utils/get-display-name.js +10 -0
- package/dist/utils/get-display-name.js.map +1 -0
- package/dist/utils/hsl-to-rgb.js +38 -0
- package/dist/utils/hsl-to-rgb.js.map +1 -0
- package/dist/utils/is-dev-env.js +19 -0
- package/dist/utils/is-dev-env.js.map +1 -0
- package/dist/utils/is-valid-element-type.js +15 -0
- package/dist/utils/is-valid-element-type.js.map +1 -0
- package/dist/utils/merge-styles.d.ts +7 -0
- package/dist/utils/merge-styles.js +146 -0
- package/dist/utils/merge-styles.js.map +1 -0
- package/dist/utils/mod-attrs.d.ts +8 -0
- package/dist/utils/mod-attrs.js +21 -0
- package/dist/utils/mod-attrs.js.map +1 -0
- package/dist/utils/okhsl-to-rgb.js +296 -0
- package/dist/utils/okhsl-to-rgb.js.map +1 -0
- package/dist/utils/process-tokens.d.ts +31 -0
- package/dist/utils/process-tokens.js +171 -0
- package/dist/utils/process-tokens.js.map +1 -0
- package/dist/utils/resolve-recipes.d.ts +17 -0
- package/dist/utils/resolve-recipes.js +147 -0
- package/dist/utils/resolve-recipes.js.map +1 -0
- package/dist/utils/selector-transform.js +32 -0
- package/dist/utils/selector-transform.js.map +1 -0
- package/dist/utils/string.js +8 -0
- package/dist/utils/string.js.map +1 -0
- package/dist/utils/styles.d.ts +177 -0
- package/dist/utils/styles.js +730 -0
- package/dist/utils/styles.js.map +1 -0
- package/dist/utils/typography.d.ts +47 -0
- package/dist/utils/typography.js +43 -0
- package/dist/utils/typography.js.map +1 -0
- package/dist/utils/warnings.d.ts +16 -0
- package/dist/utils/warnings.js +16 -0
- package/dist/utils/warnings.js.map +1 -0
- package/dist/zero/babel.d.ts +147 -0
- package/dist/zero/babel.js +331 -0
- package/dist/zero/babel.js.map +1 -0
- package/dist/zero/css-writer.d.ts +45 -0
- package/dist/zero/css-writer.js +74 -0
- package/dist/zero/css-writer.js.map +1 -0
- package/dist/zero/extractor.d.ts +24 -0
- package/dist/zero/extractor.js +215 -0
- package/dist/zero/extractor.js.map +1 -0
- package/dist/zero/index.d.ts +3 -0
- package/dist/zero/index.js +4 -0
- package/dist/zero/next.d.ts +74 -0
- package/dist/zero/next.js +129 -0
- package/dist/zero/next.js.map +1 -0
- package/docs/adoption.md +286 -0
- package/docs/comparison.md +413 -0
- package/docs/configuration.md +242 -0
- package/docs/debug.md +505 -0
- package/docs/design-system.md +401 -0
- package/docs/dsl.md +540 -0
- package/docs/getting-started.md +201 -0
- package/docs/injector.md +528 -0
- package/docs/methodology.md +501 -0
- package/docs/runtime.md +291 -0
- package/docs/ssr.md +382 -0
- package/docs/styles.md +574 -0
- package/docs/tasty-static.md +421 -0
- package/package.json +209 -0
- package/tasty.config.ts +14 -0
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import { __require } from "../_virtual/_rolldown/runtime.js";
|
|
2
|
+
import { configure, getGlobalConfigTokens } from "../config.js";
|
|
3
|
+
import { mergeStyles } from "../utils/merge-styles.js";
|
|
4
|
+
import { resolveRecipes } from "../utils/resolve-recipes.js";
|
|
5
|
+
import { extractKeyframesFromStyles, extractPropertiesFromStyles, extractStylesForSelector, extractStylesWithChunks } from "./extractor.js";
|
|
6
|
+
import { CSSWriter } from "./css-writer.js";
|
|
7
|
+
import * as fs from "fs";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
import { declare } from "@babel/helper-plugin-utils";
|
|
10
|
+
import * as t from "@babel/types";
|
|
11
|
+
import { createJiti } from "jiti";
|
|
12
|
+
|
|
13
|
+
//#region src/zero/babel.ts
|
|
14
|
+
/**
|
|
15
|
+
* Babel plugin for zero-runtime tasty static site generation.
|
|
16
|
+
*
|
|
17
|
+
* Transforms:
|
|
18
|
+
* - `tastyStatic(styles)` → StaticStyle object { className, styles, toString() }
|
|
19
|
+
* - `tastyStatic(base, styles)` → StaticStyle object with merged styles
|
|
20
|
+
* - `tastyStatic(selector, styles)` → removed entirely
|
|
21
|
+
*
|
|
22
|
+
* Usage:
|
|
23
|
+
* ```javascript
|
|
24
|
+
* // babel.config.js
|
|
25
|
+
* module.exports = {
|
|
26
|
+
* plugins: [
|
|
27
|
+
* ['@tenphi/tasty/babel-plugin', { output: 'public/tasty.css' }]
|
|
28
|
+
* ]
|
|
29
|
+
* };
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
function mtime(filePath) {
|
|
33
|
+
try {
|
|
34
|
+
return fs.statSync(filePath).mtimeMs;
|
|
35
|
+
} catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function clearRequireCacheTree(filePath) {
|
|
40
|
+
let resolved;
|
|
41
|
+
try {
|
|
42
|
+
resolved = __require.resolve(filePath);
|
|
43
|
+
} catch {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const mod = __require.cache[resolved];
|
|
47
|
+
if (!mod) return;
|
|
48
|
+
const dir = resolved.substring(0, resolved.lastIndexOf("/"));
|
|
49
|
+
if (mod.children) {
|
|
50
|
+
for (const child of mod.children) if (child.id.startsWith(dir) && !child.id.includes("node_modules")) clearRequireCacheTree(child.id);
|
|
51
|
+
}
|
|
52
|
+
delete __require.cache[resolved];
|
|
53
|
+
}
|
|
54
|
+
var babel_default = declare((api, options) => {
|
|
55
|
+
api.assertVersion(7);
|
|
56
|
+
const outputPath = options.output || "tasty.css";
|
|
57
|
+
const configDeps = [...options.configFile ? [options.configFile] : [], ...options.configDeps || []];
|
|
58
|
+
if (configDeps.length > 0) {
|
|
59
|
+
api.cache.using(() => configDeps.map(mtime).join(","));
|
|
60
|
+
for (const dep of configDeps) try {
|
|
61
|
+
api.addExternalDependency(dep);
|
|
62
|
+
} catch {}
|
|
63
|
+
} else api.cache.forever();
|
|
64
|
+
if (configDeps.length > 0) for (const dep of configDeps) clearRequireCacheTree(dep);
|
|
65
|
+
const configOption = options.config;
|
|
66
|
+
let config;
|
|
67
|
+
if (configOption) config = typeof configOption === "function" ? configOption() : configOption;
|
|
68
|
+
else if (options.configFile) config = createJiti(path.dirname(options.configFile), { moduleCache: false })(options.configFile);
|
|
69
|
+
else config = {};
|
|
70
|
+
const devMode = config.devMode ?? false;
|
|
71
|
+
configure(config);
|
|
72
|
+
const cssWriter = new CSSWriter(outputPath, { devMode });
|
|
73
|
+
const tokenStyles = getGlobalConfigTokens();
|
|
74
|
+
if (tokenStyles && Object.keys(tokenStyles).length > 0) {
|
|
75
|
+
const result = extractStylesForSelector(":root", tokenStyles);
|
|
76
|
+
if (result.css) cssWriter.add(":root:tokens", result.css);
|
|
77
|
+
}
|
|
78
|
+
const globalRegistry = {};
|
|
79
|
+
return {
|
|
80
|
+
name: "tasty-zero",
|
|
81
|
+
pre() {
|
|
82
|
+
this.staticStyleRegistry = {};
|
|
83
|
+
if (devMode && this.filename) this.sourceFile = this.filename.split("/").pop() || this.filename;
|
|
84
|
+
},
|
|
85
|
+
visitor: {
|
|
86
|
+
ImportDeclaration(path) {
|
|
87
|
+
const source = path.node.source.value;
|
|
88
|
+
if (source === "@tenphi/tasty/static" || source.endsWith("/tasty/static")) path.remove();
|
|
89
|
+
},
|
|
90
|
+
CallExpression(path, state) {
|
|
91
|
+
const callee = path.node.callee;
|
|
92
|
+
if (!t.isIdentifier(callee, { name: "tastyStatic" })) return;
|
|
93
|
+
const args = path.node.arguments;
|
|
94
|
+
if (args.length === 0) throw path.buildCodeFrameError("tastyStatic() requires at least one argument");
|
|
95
|
+
const firstArg = args[0];
|
|
96
|
+
if (t.isStringLiteral(firstArg)) handleSelectorMode(path, args, cssWriter, state.sourceFile, config.keyframes, config.autoPropertyTypes);
|
|
97
|
+
else if (t.isObjectExpression(firstArg)) handleStylesMode(path, args, cssWriter, state, globalRegistry, config.keyframes, config.autoPropertyTypes);
|
|
98
|
+
else if (t.isIdentifier(firstArg)) handleExtensionMode(path, args, cssWriter, state, globalRegistry, config.keyframes, config.autoPropertyTypes);
|
|
99
|
+
else throw path.buildCodeFrameError("tastyStatic() first argument must be an object (styles), identifier (base StaticStyle), or string (selector)");
|
|
100
|
+
},
|
|
101
|
+
VariableDeclarator(path, state) {
|
|
102
|
+
const init = path.node.init;
|
|
103
|
+
const id = path.node.id;
|
|
104
|
+
if (t.isIdentifier(id) && t.isObjectExpression(init) && isStaticStyleObject(init)) {
|
|
105
|
+
const variableName = id.name;
|
|
106
|
+
const styles = extractStylesFromStaticStyleObject(init, path);
|
|
107
|
+
const className = extractClassNameFromStaticStyleObject(init);
|
|
108
|
+
if (styles && className) {
|
|
109
|
+
state.staticStyleRegistry[variableName] = {
|
|
110
|
+
styles,
|
|
111
|
+
className
|
|
112
|
+
};
|
|
113
|
+
globalRegistry[variableName] = {
|
|
114
|
+
styles,
|
|
115
|
+
className
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
post() {
|
|
122
|
+
if (cssWriter.size > 0) cssWriter.write();
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
});
|
|
126
|
+
/**
|
|
127
|
+
* Check if an object expression looks like a StaticStyle object
|
|
128
|
+
*/
|
|
129
|
+
function isStaticStyleObject(node) {
|
|
130
|
+
const hasClassName = node.properties.some((p) => t.isObjectProperty(p) && t.isIdentifier(p.key, { name: "className" }));
|
|
131
|
+
const hasStyles = node.properties.some((p) => t.isObjectProperty(p) && t.isIdentifier(p.key, { name: "styles" }));
|
|
132
|
+
return hasClassName && hasStyles;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Extract styles object from a StaticStyle object expression
|
|
136
|
+
*/
|
|
137
|
+
function extractStylesFromStaticStyleObject(node, path) {
|
|
138
|
+
for (const prop of node.properties) if (t.isObjectProperty(prop) && t.isIdentifier(prop.key, { name: "styles" }) && t.isObjectExpression(prop.value)) return evaluateObjectExpression(prop.value, path);
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Extract className from a StaticStyle object expression
|
|
143
|
+
*/
|
|
144
|
+
function extractClassNameFromStaticStyleObject(node) {
|
|
145
|
+
for (const prop of node.properties) if (t.isObjectProperty(prop) && t.isIdentifier(prop.key, { name: "className" }) && t.isStringLiteral(prop.value)) return prop.value.value;
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Handle tastyStatic(styles) - returns StaticStyle object
|
|
150
|
+
*/
|
|
151
|
+
function handleStylesMode(path, args, cssWriter, state, globalRegistry, globalKeyframes, autoPropertyTypes) {
|
|
152
|
+
const stylesArg = args[0];
|
|
153
|
+
if (!t.isObjectExpression(stylesArg)) throw path.buildCodeFrameError("tastyStatic(styles) argument must be a static object literal");
|
|
154
|
+
const styles = resolveRecipes(evaluateObjectExpression(stylesArg, path));
|
|
155
|
+
const { keyframes, nameMap } = extractKeyframesFromStyles(styles, globalKeyframes);
|
|
156
|
+
for (const kf of keyframes) cssWriter.add(kf.css, kf.css, state.sourceFile);
|
|
157
|
+
const properties = extractPropertiesFromStyles(styles, { autoPropertyTypes });
|
|
158
|
+
for (const prop of properties) cssWriter.add(prop.css, prop.css, state.sourceFile);
|
|
159
|
+
const chunks = extractStylesWithChunks(styles);
|
|
160
|
+
for (const chunk of chunks) {
|
|
161
|
+
const css = nameMap.size > 0 ? replaceAnimationNamesInCSS(chunk.css, nameMap) : chunk.css;
|
|
162
|
+
cssWriter.add(chunk.className, css, state.sourceFile);
|
|
163
|
+
}
|
|
164
|
+
const className = chunks.length > 0 ? chunks.map((c) => c.className).join(" ") : "";
|
|
165
|
+
const staticStyleObject = createStaticStyleAST(className, styles);
|
|
166
|
+
path.replaceWith(staticStyleObject);
|
|
167
|
+
registerIfVariableDeclaration(path, className, styles, state, globalRegistry);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Handle tastyStatic(base, styles) - extends base with additional styles
|
|
171
|
+
*/
|
|
172
|
+
function handleExtensionMode(path, args, cssWriter, state, globalRegistry, globalKeyframes, autoPropertyTypes) {
|
|
173
|
+
if (args.length < 2) throw path.buildCodeFrameError("tastyStatic(base, styles) requires two arguments");
|
|
174
|
+
const baseArg = args[0];
|
|
175
|
+
const stylesArg = args[1];
|
|
176
|
+
if (!t.isIdentifier(baseArg)) throw path.buildCodeFrameError("tastyStatic(base, styles) first argument must be an identifier");
|
|
177
|
+
if (!t.isObjectExpression(stylesArg)) throw path.buildCodeFrameError("tastyStatic(base, styles) second argument must be a static object literal");
|
|
178
|
+
const baseName = baseArg.name;
|
|
179
|
+
const baseEntry = state.staticStyleRegistry[baseName] || globalRegistry[baseName];
|
|
180
|
+
if (!baseEntry) throw path.buildCodeFrameError(`Cannot find base StaticStyle '${baseName}'. Make sure it is defined before being extended.`);
|
|
181
|
+
const overrideStyles = evaluateObjectExpression(stylesArg, path);
|
|
182
|
+
const mergedStyles = resolveRecipes(mergeStyles(baseEntry.styles, overrideStyles));
|
|
183
|
+
const { keyframes, nameMap } = extractKeyframesFromStyles(mergedStyles, globalKeyframes);
|
|
184
|
+
for (const kf of keyframes) cssWriter.add(kf.css, kf.css, state.sourceFile);
|
|
185
|
+
const properties = extractPropertiesFromStyles(mergedStyles, { autoPropertyTypes });
|
|
186
|
+
for (const prop of properties) cssWriter.add(prop.css, prop.css, state.sourceFile);
|
|
187
|
+
const chunks = extractStylesWithChunks(mergedStyles);
|
|
188
|
+
for (const chunk of chunks) {
|
|
189
|
+
const css = nameMap.size > 0 ? replaceAnimationNamesInCSS(chunk.css, nameMap) : chunk.css;
|
|
190
|
+
cssWriter.add(chunk.className, css, state.sourceFile);
|
|
191
|
+
}
|
|
192
|
+
const className = chunks.length > 0 ? chunks.map((c) => c.className).join(" ") : "";
|
|
193
|
+
const staticStyleObject = createStaticStyleAST(className, mergedStyles);
|
|
194
|
+
path.replaceWith(staticStyleObject);
|
|
195
|
+
registerIfVariableDeclaration(path, className, mergedStyles, state, globalRegistry);
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Handle tastyStatic(selector, styles) - removes the call entirely
|
|
199
|
+
*/
|
|
200
|
+
function handleSelectorMode(path, args, cssWriter, sourceFile, globalKeyframes, autoPropertyTypes) {
|
|
201
|
+
if (args.length < 2) throw path.buildCodeFrameError("tastyStatic(selector, styles) requires two arguments");
|
|
202
|
+
const selectorArg = args[0];
|
|
203
|
+
const stylesArg = args[1];
|
|
204
|
+
if (!t.isStringLiteral(selectorArg)) throw path.buildCodeFrameError("tastyStatic(selector, styles) first argument must be a string literal");
|
|
205
|
+
if (!t.isObjectExpression(stylesArg)) throw path.buildCodeFrameError("tastyStatic(selector, styles) second argument must be a static object literal");
|
|
206
|
+
const selector = selectorArg.value;
|
|
207
|
+
const styles = resolveRecipes(evaluateObjectExpression(stylesArg, path));
|
|
208
|
+
const { keyframes, nameMap } = extractKeyframesFromStyles(styles, globalKeyframes);
|
|
209
|
+
for (const kf of keyframes) cssWriter.add(kf.css, kf.css, sourceFile);
|
|
210
|
+
const properties = extractPropertiesFromStyles(styles, { autoPropertyTypes });
|
|
211
|
+
for (const prop of properties) cssWriter.add(prop.css, prop.css, sourceFile);
|
|
212
|
+
const result = extractStylesForSelector(selector, styles);
|
|
213
|
+
const css = nameMap.size > 0 ? replaceAnimationNamesInCSS(result.css, nameMap) : result.css;
|
|
214
|
+
cssWriter.add(selector, css, sourceFile);
|
|
215
|
+
const parent = path.parentPath;
|
|
216
|
+
if (parent && t.isExpressionStatement(parent.node)) parent.remove();
|
|
217
|
+
else path.replaceWith(t.identifier("undefined"));
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Create a StaticStyle object AST node
|
|
221
|
+
*/
|
|
222
|
+
function createStaticStyleAST(className, styles) {
|
|
223
|
+
return t.objectExpression([
|
|
224
|
+
t.objectProperty(t.identifier("className"), t.stringLiteral(className)),
|
|
225
|
+
t.objectProperty(t.identifier("styles"), valueToAST(styles)),
|
|
226
|
+
t.objectMethod("method", t.identifier("toString"), [], t.blockStatement([t.returnStatement(t.memberExpression(t.thisExpression(), t.identifier("className")))]))
|
|
227
|
+
]);
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Register a StaticStyle in the registry if it's being assigned to a variable
|
|
231
|
+
*/
|
|
232
|
+
function registerIfVariableDeclaration(path, className, styles, state, globalRegistry) {
|
|
233
|
+
const parent = path.parentPath;
|
|
234
|
+
if (parent && t.isVariableDeclarator(parent.node)) {
|
|
235
|
+
const id = parent.node.id;
|
|
236
|
+
if (t.isIdentifier(id)) {
|
|
237
|
+
const variableName = id.name;
|
|
238
|
+
state.staticStyleRegistry[variableName] = {
|
|
239
|
+
styles,
|
|
240
|
+
className
|
|
241
|
+
};
|
|
242
|
+
globalRegistry[variableName] = {
|
|
243
|
+
styles,
|
|
244
|
+
className
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Convert a JavaScript value to an AST node
|
|
251
|
+
*/
|
|
252
|
+
function valueToAST(value) {
|
|
253
|
+
if (value === null) return t.nullLiteral();
|
|
254
|
+
if (value === void 0) return t.identifier("undefined");
|
|
255
|
+
if (typeof value === "string") return t.stringLiteral(value);
|
|
256
|
+
if (typeof value === "number") return t.numericLiteral(value);
|
|
257
|
+
if (typeof value === "boolean") return t.booleanLiteral(value);
|
|
258
|
+
if (Array.isArray(value)) return t.arrayExpression(value.map(valueToAST));
|
|
259
|
+
if (typeof value === "object") {
|
|
260
|
+
const properties = Object.entries(value).map(([key, val]) => t.objectProperty(/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key) ? t.identifier(key) : t.stringLiteral(key), valueToAST(val)));
|
|
261
|
+
return t.objectExpression(properties);
|
|
262
|
+
}
|
|
263
|
+
return t.identifier("undefined");
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Evaluate an ObjectExpression to a plain JavaScript object.
|
|
267
|
+
* Only supports static values that can be determined at build time.
|
|
268
|
+
*/
|
|
269
|
+
function evaluateObjectExpression(node, path) {
|
|
270
|
+
const result = {};
|
|
271
|
+
for (const prop of node.properties) {
|
|
272
|
+
if (t.isSpreadElement(prop)) throw path.buildCodeFrameError("Spread elements are not supported in tastyStatic() - styles must be fully static");
|
|
273
|
+
if (!t.isObjectProperty(prop)) throw path.buildCodeFrameError("Only object properties are supported in tastyStatic()");
|
|
274
|
+
let key;
|
|
275
|
+
if (t.isIdentifier(prop.key)) key = prop.key.name;
|
|
276
|
+
else if (t.isStringLiteral(prop.key)) key = prop.key.value;
|
|
277
|
+
else throw path.buildCodeFrameError("Dynamic property keys are not supported in tastyStatic()");
|
|
278
|
+
result[key] = evaluateExpression(prop.value, path);
|
|
279
|
+
}
|
|
280
|
+
return result;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Evaluate an expression to a JavaScript value.
|
|
284
|
+
*/
|
|
285
|
+
function evaluateExpression(node, path) {
|
|
286
|
+
if (t.isStringLiteral(node)) return node.value;
|
|
287
|
+
if (t.isNumericLiteral(node)) return node.value;
|
|
288
|
+
if (t.isBooleanLiteral(node)) return node.value;
|
|
289
|
+
if (t.isNullLiteral(node)) return null;
|
|
290
|
+
if (t.isIdentifier(node, { name: "undefined" })) return;
|
|
291
|
+
if (t.isArrayExpression(node)) return node.elements.map((el) => {
|
|
292
|
+
if (el === null) return null;
|
|
293
|
+
if (t.isSpreadElement(el)) throw path.buildCodeFrameError("Spread elements are not supported in tastyStatic()");
|
|
294
|
+
return evaluateExpression(el, path);
|
|
295
|
+
});
|
|
296
|
+
if (t.isObjectExpression(node)) return evaluateObjectExpression(node, path);
|
|
297
|
+
if (t.isTemplateLiteral(node)) {
|
|
298
|
+
if (node.expressions.length > 0) throw path.buildCodeFrameError("Template literals with expressions are not supported in tastyStatic()");
|
|
299
|
+
return node.quasis.map((q) => q.value.cooked).join("");
|
|
300
|
+
}
|
|
301
|
+
if (t.isUnaryExpression(node, { operator: "-" })) {
|
|
302
|
+
const arg = evaluateExpression(node.argument, path);
|
|
303
|
+
if (typeof arg === "number") return -arg;
|
|
304
|
+
}
|
|
305
|
+
throw path.buildCodeFrameError(`Dynamic expressions are not supported in tastyStatic() - got ${node.type}. All values must be static literals.`);
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Replace animation names in CSS string.
|
|
309
|
+
* Wraps the keyframes replaceAnimationNames to work on full CSS blocks.
|
|
310
|
+
*/
|
|
311
|
+
function replaceAnimationNamesInCSS(css, nameMap) {
|
|
312
|
+
if (nameMap.size === 0) return css;
|
|
313
|
+
return css.replace(/(animation(?:-name)?)\s*:\s*([^;}]+)/gi, (match, prop, value) => {
|
|
314
|
+
let newValue = value;
|
|
315
|
+
for (const [original, replacement] of nameMap) {
|
|
316
|
+
const pattern = new RegExp(`\\b${escapeRegex(original)}\\b`, "g");
|
|
317
|
+
newValue = newValue.replace(pattern, replacement);
|
|
318
|
+
}
|
|
319
|
+
return `${prop}: ${newValue}`;
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Escape special regex characters.
|
|
324
|
+
*/
|
|
325
|
+
function escapeRegex(str) {
|
|
326
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
//#endregion
|
|
330
|
+
export { babel_default as default };
|
|
331
|
+
//# sourceMappingURL=babel.js.map
|
|
@@ -0,0 +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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuMA,SAAS,MAAM,UAAiC;AAC9C,KAAI;AACF,SAAO,GAAG,SAAS,SAAS,CAAC;SACvB;AACN,SAAO;;;AAIX,SAAS,sBAAsB,UAAwB;CACrD,IAAI;AAEJ,KAAI;AACF,uBAAmB,QAAQ,SAAS;SAC9B;AACN;;CAGF,MAAM,gBAAc,MAAM;AAE1B,KAAI,CAAC,IAAK;CAEV,MAAM,MAAM,SAAS,UAAU,GAAG,SAAS,YAAY,IAAI,CAAC;AAE5D,KAAI,IAAI,UACN;OAAK,MAAM,SAAS,IAAI,SACtB,KAAI,MAAM,GAAG,WAAW,IAAI,IAAI,CAAC,MAAM,GAAG,SAAS,eAAe,CAChE,uBAAsB,MAAM,GAAG;;AAKrC,kBAAe,MAAM;;AAIvB,oBAAe,SAAgC,KAAK,YAAY;AAC9D,KAAI,cAAc,EAAE;CAEpB,MAAM,aAAa,QAAQ,UAAU;CACrC,MAAM,aAAa,CACjB,GAAI,QAAQ,aAAa,CAAC,QAAQ,WAAW,GAAG,EAAE,EAClD,GAAI,QAAQ,cAAc,EAAE,CAC7B;AAKD,KAAI,WAAW,SAAS,GAAG;AACzB,MAAI,MAAM,YAAY,WAAW,IAAI,MAAM,CAAC,KAAK,IAAI,CAAC;AAEtD,OAAK,MAAM,OAAO,WAChB,KAAI;AACF,GACE,IACA,sBAAsB,IAAI;UACtB;OAKV,KAAI,MAAM,SAAS;AAIrB,KAAI,WAAW,SAAS,EACtB,MAAK,MAAM,OAAO,WAChB,uBAAsB,IAAI;CAI9B,MAAM,eAAe,QAAQ;CAC7B,IAAI;AAEJ,KAAI,aACF,UAAS,OAAO,iBAAiB,aAAa,cAAc,GAAG;UACtD,QAAQ,WAKjB,UAJa,WAAW,KAAK,QAAQ,QAAQ,WAAW,EAAE,EACxD,aAAa,OACd,CAAC,CAEY,QAAQ,WAAW;KAEjC,UAAS,EAAE;CAGb,MAAM,UAAU,OAAO,WAAW;AAElC,WAAU,OAAO;CAEjB,MAAM,YAAY,IAAI,UAAU,YAAY,EAAE,SAAS,CAAC;CAGxD,MAAM,cAAc,uBAAuB;AAC3C,KAAI,eAAe,OAAO,KAAK,YAAY,CAAC,SAAS,GAAG;EACtD,MAAM,SAAS,yBAAyB,SAAS,YAAY;AAC7D,MAAI,OAAO,IACT,WAAU,IAAI,gBAAgB,OAAO,IAAI;;CAK7C,MAAM,iBAAsC,EAAE;AAE9C,QAAO;EACL,MAAM;EAEN,MAAuB;AAErB,QAAK,sBAAsB,EAAE;AAE7B,OAAI,WAAW,KAAK,SAElB,MAAK,aAAa,KAAK,SAAS,MAAM,IAAI,CAAC,KAAK,IAAI,KAAK;;EAI7D,SAAS;GAEP,kBAAkB,MAAqC;IACrD,MAAM,SAAS,KAAK,KAAK,OAAO;AAEhC,QACE,WAAW,0BACX,OAAO,SAAS,gBAAgB,CAEhC,MAAK,QAAQ;;GAKjB,eAAe,MAAkC,OAAoB;IACnE,MAAM,SAAS,KAAK,KAAK;AAGzB,QAAI,CAAC,EAAE,aAAa,QAAQ,EAAE,MAAM,eAAe,CAAC,CAClD;IAGF,MAAM,OAAO,KAAK,KAAK;AAEvB,QAAI,KAAK,WAAW,EAClB,OAAM,KAAK,oBACT,+CACD;IAGH,MAAM,WAAW,KAAK;AAEtB,QAAI,EAAE,gBAAgB,SAAS,CAE7B,oBACE,MACA,MACA,WACA,MAAM,YACN,OAAO,WACP,OAAO,kBACR;aACQ,EAAE,mBAAmB,SAAS,CAEvC,kBACE,MACA,MACA,WACA,OACA,gBACA,OAAO,WACP,OAAO,kBACR;aACQ,EAAE,aAAa,SAAS,CAEjC,qBACE,MACA,MACA,WACA,OACA,gBACA,OAAO,WACP,OAAO,kBACR;QAED,OAAM,KAAK,oBACT,+GAED;;GAKL,mBACE,MACA,OACA;IACA,MAAM,OAAO,KAAK,KAAK;IACvB,MAAM,KAAK,KAAK,KAAK;AAGrB,QACE,EAAE,aAAa,GAAG,IAClB,EAAE,mBAAmB,KAAK,IAC1B,oBAAoB,KAAK,EACzB;KACA,MAAM,eAAe,GAAG;KACxB,MAAM,SAAS,mCAAmC,MAAM,KAAK;KAC7D,MAAM,YAAY,sCAAsC,KAAK;AAE7D,SAAI,UAAU,WAAW;AACvB,YAAM,oBAAoB,gBAAgB;OAAE;OAAQ;OAAW;AAC/D,qBAAe,gBAAgB;OAAE;OAAQ;OAAW;;;;GAI3D;EAED,OAAO;AAEL,OAAI,UAAU,OAAO,EACnB,WAAU,OAAO;;EAGtB;EACD;;;;AAKF,SAAS,oBAAoB,MAAmC;CAC9D,MAAM,eAAe,KAAK,WAAW,MAClC,MACC,EAAE,iBAAiB,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC,CACxE;CACD,MAAM,YAAY,KAAK,WAAW,MAC/B,MAAM,EAAE,iBAAiB,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC,CAC1E;AACD,QAAO,gBAAgB;;;;;AAMzB,SAAS,mCACP,MACA,MACe;AACf,MAAK,MAAM,QAAQ,KAAK,WACtB,KACE,EAAE,iBAAiB,KAAK,IACxB,EAAE,aAAa,KAAK,KAAK,EAAE,MAAM,UAAU,CAAC,IAC5C,EAAE,mBAAmB,KAAK,MAAM,CAEhC,QAAO,yBAAyB,KAAK,OAAO,KAAK;AAGrD,QAAO;;;;;AAMT,SAAS,sCACP,MACe;AACf,MAAK,MAAM,QAAQ,KAAK,WACtB,KACE,EAAE,iBAAiB,KAAK,IACxB,EAAE,aAAa,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC,IAC/C,EAAE,gBAAgB,KAAK,MAAM,CAE7B,QAAO,KAAK,MAAM;AAGtB,QAAO;;;;;AAMT,SAAS,iBACP,MACA,MACA,WACA,OACA,gBACA,iBACA,mBACM;CACN,MAAM,YAAY,KAAK;AAEvB,KAAI,CAAC,EAAE,mBAAmB,UAAU,CAClC,OAAM,KAAK,oBACT,+DACD;CAOH,MAAM,SAAS,eAHG,yBAAyB,WAAW,KAAK,CAGnB;CAGxC,MAAM,EAAE,WAAW,YAAY,2BAC7B,QACA,gBACD;AAGD,MAAK,MAAM,MAAM,UACf,WAAU,IAAI,GAAG,KAAK,GAAG,KAAK,MAAM,WAAW;CAIjD,MAAM,aAAa,4BAA4B,QAAQ,EAAE,mBAAmB,CAAC;AAC7E,MAAK,MAAM,QAAQ,WACjB,WAAU,IAAI,KAAK,KAAK,KAAK,KAAK,MAAM,WAAW;CAIrD,MAAM,SAAS,wBAAwB,OAAO;AAG9C,MAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,MACJ,QAAQ,OAAO,IACX,2BAA2B,MAAM,KAAK,QAAQ,GAC9C,MAAM;AACZ,YAAU,IAAI,MAAM,WAAW,KAAK,MAAM,WAAW;;CAIvD,MAAM,YACJ,OAAO,SAAS,IAAI,OAAO,KAAK,MAAM,EAAE,UAAU,CAAC,KAAK,IAAI,GAAG;CAGjE,MAAM,oBAAoB,qBAAqB,WAAW,OAAO;AACjE,MAAK,YAAY,kBAAkB;AAGnC,+BAA8B,MAAM,WAAW,QAAQ,OAAO,eAAe;;;;;AAM/E,SAAS,oBACP,MACA,MACA,WACA,OACA,gBACA,iBACA,mBACM;AACN,KAAI,KAAK,SAAS,EAChB,OAAM,KAAK,oBACT,mDACD;CAGH,MAAM,UAAU,KAAK;CACrB,MAAM,YAAY,KAAK;AAEvB,KAAI,CAAC,EAAE,aAAa,QAAQ,CAC1B,OAAM,KAAK,oBACT,iEACD;AAGH,KAAI,CAAC,EAAE,mBAAmB,UAAU,CAClC,OAAM,KAAK,oBACT,4EACD;CAGH,MAAM,WAAW,QAAQ;CAGzB,MAAM,YACJ,MAAM,oBAAoB,aAAa,eAAe;AAExD,KAAI,CAAC,UACH,OAAM,KAAK,oBACT,iCAAiC,SAAS,mDAE3C;CAIH,MAAM,iBAAiB,yBAAyB,WAAW,KAAK;CAGhE,MAAM,eAAe,eACnB,YAAY,UAAU,QAAQ,eAAe,CAC9C;CAGD,MAAM,EAAE,WAAW,YAAY,2BAC7B,cACA,gBACD;AAGD,MAAK,MAAM,MAAM,UACf,WAAU,IAAI,GAAG,KAAK,GAAG,KAAK,MAAM,WAAW;CAIjD,MAAM,aAAa,4BAA4B,cAAc,EAC3D,mBACD,CAAC;AACF,MAAK,MAAM,QAAQ,WACjB,WAAU,IAAI,KAAK,KAAK,KAAK,KAAK,MAAM,WAAW;CAIrD,MAAM,SAAS,wBAAwB,aAAa;AAGpD,MAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,MACJ,QAAQ,OAAO,IACX,2BAA2B,MAAM,KAAK,QAAQ,GAC9C,MAAM;AACZ,YAAU,IAAI,MAAM,WAAW,KAAK,MAAM,WAAW;;CAIvD,MAAM,YACJ,OAAO,SAAS,IAAI,OAAO,KAAK,MAAM,EAAE,UAAU,CAAC,KAAK,IAAI,GAAG;CAGjE,MAAM,oBAAoB,qBAAqB,WAAW,aAAa;AACvE,MAAK,YAAY,kBAAkB;AAGnC,+BACE,MACA,WACA,cACA,OACA,eACD;;;;;AAMH,SAAS,mBACP,MACA,MACA,WACA,YACA,iBACA,mBACM;AACN,KAAI,KAAK,SAAS,EAChB,OAAM,KAAK,oBACT,uDACD;CAGH,MAAM,cAAc,KAAK;CACzB,MAAM,YAAY,KAAK;AAEvB,KAAI,CAAC,EAAE,gBAAgB,YAAY,CACjC,OAAM,KAAK,oBACT,wEACD;AAGH,KAAI,CAAC,EAAE,mBAAmB,UAAU,CAClC,OAAM,KAAK,oBACT,gFACD;CAGH,MAAM,WAAW,YAAY;CAI7B,MAAM,SAAS,eAHG,yBAAyB,WAAW,KAAK,CAGnB;CAGxC,MAAM,EAAE,WAAW,YAAY,2BAC7B,QACA,gBACD;AAGD,MAAK,MAAM,MAAM,UACf,WAAU,IAAI,GAAG,KAAK,GAAG,KAAK,WAAW;CAI3C,MAAM,aAAa,4BAA4B,QAAQ,EAAE,mBAAmB,CAAC;AAC7E,MAAK,MAAM,QAAQ,WACjB,WAAU,IAAI,KAAK,KAAK,KAAK,KAAK,WAAW;CAI/C,MAAM,SAAS,yBAAyB,UAAU,OAAO;CAGzD,MAAM,MACJ,QAAQ,OAAO,IACX,2BAA2B,OAAO,KAAK,QAAQ,GAC/C,OAAO;AACb,WAAU,IAAI,UAAU,KAAK,WAAW;CAGxC,MAAM,SAAS,KAAK;AACpB,KAAI,UAAU,EAAE,sBAAsB,OAAO,KAAK,CAChD,QAAO,QAAQ;KAIf,MAAK,YAAY,EAAE,WAAW,YAAY,CAAC;;;;;AAO/C,SAAS,qBACP,WACA,QACoB;AACpB,QAAO,EAAE,iBAAiB;EACxB,EAAE,eAAe,EAAE,WAAW,YAAY,EAAE,EAAE,cAAc,UAAU,CAAC;EACvE,EAAE,eAAe,EAAE,WAAW,SAAS,EAAE,WAAW,OAAO,CAAC;EAC5D,EAAE,aACA,UACA,EAAE,WAAW,WAAW,EACxB,EAAE,EACF,EAAE,eAAe,CACf,EAAE,gBACA,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,EAAE,WAAW,YAAY,CAAC,CAClE,CACF,CAAC,CACH;EACF,CAAC;;;;;AAMJ,SAAS,8BACP,MACA,WACA,QACA,OACA,gBACM;CACN,MAAM,SAAS,KAAK;AACpB,KAAI,UAAU,EAAE,qBAAqB,OAAO,KAAK,EAAE;EACjD,MAAM,KAAK,OAAO,KAAK;AACvB,MAAI,EAAE,aAAa,GAAG,EAAE;GACtB,MAAM,eAAe,GAAG;AACxB,SAAM,oBAAoB,gBAAgB;IAAE;IAAQ;IAAW;AAC/D,kBAAe,gBAAgB;IAAE;IAAQ;IAAW;;;;;;;AAQ1D,SAAS,WAAW,OAA8B;AAChD,KAAI,UAAU,KACZ,QAAO,EAAE,aAAa;AAExB,KAAI,UAAU,OACZ,QAAO,EAAE,WAAW,YAAY;AAElC,KAAI,OAAO,UAAU,SACnB,QAAO,EAAE,cAAc,MAAM;AAE/B,KAAI,OAAO,UAAU,SACnB,QAAO,EAAE,eAAe,MAAM;AAEhC,KAAI,OAAO,UAAU,UACnB,QAAO,EAAE,eAAe,MAAM;AAEhC,KAAI,MAAM,QAAQ,MAAM,CACtB,QAAO,EAAE,gBAAgB,MAAM,IAAI,WAAW,CAAC;AAEjD,KAAI,OAAO,UAAU,UAAU;EAC7B,MAAM,aAAa,OAAO,QAAQ,MAAM,CAAC,KAAK,CAAC,KAAK,SAClD,EAAE,eACA,6BAA6B,KAAK,IAAI,GAClC,EAAE,WAAW,IAAI,GACjB,EAAE,cAAc,IAAI,EACxB,WAAW,IAAI,CAChB,CACF;AACD,SAAO,EAAE,iBAAiB,WAAW;;AAGvC,QAAO,EAAE,WAAW,YAAY;;;;;;AAOlC,SAAS,yBACP,MACA,MACyB;CACzB,MAAM,SAAkC,EAAE;AAE1C,MAAK,MAAM,QAAQ,KAAK,YAAY;AAClC,MAAI,EAAE,gBAAgB,KAAK,CACzB,OAAM,KAAK,oBACT,mFACD;AAGH,MAAI,CAAC,EAAE,iBAAiB,KAAK,CAC3B,OAAM,KAAK,oBACT,wDACD;EAIH,IAAI;AACJ,MAAI,EAAE,aAAa,KAAK,IAAI,CAC1B,OAAM,KAAK,IAAI;WACN,EAAE,gBAAgB,KAAK,IAAI,CACpC,OAAM,KAAK,IAAI;MAEf,OAAM,KAAK,oBACT,2DACD;AAKH,SAAO,OADO,mBAAmB,KAAK,OAAO,KAAK;;AAIpD,QAAO;;;;;AAMT,SAAS,mBAAmB,MAAc,MAAyB;AACjE,KAAI,EAAE,gBAAgB,KAAK,CACzB,QAAO,KAAK;AAGd,KAAI,EAAE,iBAAiB,KAAK,CAC1B,QAAO,KAAK;AAGd,KAAI,EAAE,iBAAiB,KAAK,CAC1B,QAAO,KAAK;AAGd,KAAI,EAAE,cAAc,KAAK,CACvB,QAAO;AAGT,KAAI,EAAE,aAAa,MAAM,EAAE,MAAM,aAAa,CAAC,CAC7C;AAGF,KAAI,EAAE,kBAAkB,KAAK,CAC3B,QAAO,KAAK,SAAS,KAAK,OAAO;AAC/B,MAAI,OAAO,KAAM,QAAO;AACxB,MAAI,EAAE,gBAAgB,GAAG,CACvB,OAAM,KAAK,oBACT,qDACD;AAEH,SAAO,mBAAmB,IAAI,KAAK;GACnC;AAGJ,KAAI,EAAE,mBAAmB,KAAK,CAC5B,QAAO,yBAAyB,MAAM,KAAK;AAG7C,KAAI,EAAE,kBAAkB,KAAK,EAAE;AAE7B,MAAI,KAAK,YAAY,SAAS,EAC5B,OAAM,KAAK,oBACT,wEACD;AAEH,SAAO,KAAK,OAAO,KAAK,MAAM,EAAE,MAAM,OAAO,CAAC,KAAK,GAAG;;AAGxD,KAAI,EAAE,kBAAkB,MAAM,EAAE,UAAU,KAAK,CAAC,EAAE;EAChD,MAAM,MAAM,mBAAmB,KAAK,UAAU,KAAK;AACnD,MAAI,OAAO,QAAQ,SACjB,QAAO,CAAC;;AAIZ,OAAM,KAAK,oBACT,gEAAgE,KAAK,KAAK,uCAE3E;;;;;;AAOH,SAAS,2BACP,KACA,SACQ;AACR,KAAI,QAAQ,SAAS,EAAG,QAAO;AAI/B,QAAO,IAAI,QACT,2CACC,OAAO,MAAM,UAAU;EACtB,IAAI,WAAW;AACf,OAAK,MAAM,CAAC,UAAU,gBAAgB,SAAS;GAE7C,MAAM,UAAU,IAAI,OAAO,MAAM,YAAY,SAAS,CAAC,MAAM,IAAI;AACjE,cAAW,SAAS,QAAQ,SAAS,YAAY;;AAEnD,SAAO,GAAG,KAAK,IAAI;GAEtB;;;;;AAMH,SAAS,YAAY,KAAqB;AACxC,QAAO,IAAI,QAAQ,uBAAuB,OAAO"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
//#region src/zero/css-writer.d.ts
|
|
2
|
+
interface CSSWriterOptions {
|
|
3
|
+
/** Enable source comments in output (e.g., "from: Button.tsx") */
|
|
4
|
+
devMode?: boolean;
|
|
5
|
+
}
|
|
6
|
+
declare class CSSWriter {
|
|
7
|
+
private cssBlocks;
|
|
8
|
+
private outputPath;
|
|
9
|
+
private devMode;
|
|
10
|
+
constructor(outputPath: string, options?: CSSWriterOptions);
|
|
11
|
+
/**
|
|
12
|
+
* Add CSS block with deduplication key
|
|
13
|
+
* @param key - Unique key for deduplication
|
|
14
|
+
* @param css - CSS content
|
|
15
|
+
* @param source - Optional source file path (used in devMode)
|
|
16
|
+
*/
|
|
17
|
+
add(key: string, css: string, source?: string): void;
|
|
18
|
+
/**
|
|
19
|
+
* Check if a key already exists
|
|
20
|
+
*/
|
|
21
|
+
has(key: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Get the number of CSS blocks
|
|
24
|
+
*/
|
|
25
|
+
get size(): number;
|
|
26
|
+
/**
|
|
27
|
+
* Write all collected CSS to the output file
|
|
28
|
+
*/
|
|
29
|
+
write(): void;
|
|
30
|
+
/**
|
|
31
|
+
* Get all CSS as string (for testing or in-memory use)
|
|
32
|
+
*/
|
|
33
|
+
getCSS(): string;
|
|
34
|
+
/**
|
|
35
|
+
* Clear all collected CSS
|
|
36
|
+
*/
|
|
37
|
+
clear(): void;
|
|
38
|
+
/**
|
|
39
|
+
* Get the output path
|
|
40
|
+
*/
|
|
41
|
+
getOutputPath(): string;
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { CSSWriter };
|
|
45
|
+
//# sourceMappingURL=css-writer.d.ts.map
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
|
|
4
|
+
//#region src/zero/css-writer.ts
|
|
5
|
+
var CSSWriter = class {
|
|
6
|
+
cssBlocks = /* @__PURE__ */ new Map();
|
|
7
|
+
outputPath;
|
|
8
|
+
devMode;
|
|
9
|
+
constructor(outputPath, options = {}) {
|
|
10
|
+
this.outputPath = outputPath;
|
|
11
|
+
this.devMode = options.devMode ?? false;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Add CSS block with deduplication key
|
|
15
|
+
* @param key - Unique key for deduplication
|
|
16
|
+
* @param css - CSS content
|
|
17
|
+
* @param source - Optional source file path (used in devMode)
|
|
18
|
+
*/
|
|
19
|
+
add(key, css, source) {
|
|
20
|
+
this.cssBlocks.set(key, {
|
|
21
|
+
css,
|
|
22
|
+
source
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Check if a key already exists
|
|
27
|
+
*/
|
|
28
|
+
has(key) {
|
|
29
|
+
return this.cssBlocks.has(key);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get the number of CSS blocks
|
|
33
|
+
*/
|
|
34
|
+
get size() {
|
|
35
|
+
return this.cssBlocks.size;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Write all collected CSS to the output file
|
|
39
|
+
*/
|
|
40
|
+
write() {
|
|
41
|
+
const outputDir = path.dirname(this.outputPath);
|
|
42
|
+
if (!fs.existsSync(outputDir)) fs.mkdirSync(outputDir, { recursive: true });
|
|
43
|
+
const cssBlocks = [];
|
|
44
|
+
for (const block of this.cssBlocks.values()) if (this.devMode && block.source) cssBlocks.push(`/* from: ${block.source} */\n${block.css}`);
|
|
45
|
+
else cssBlocks.push(block.css);
|
|
46
|
+
const css = cssBlocks.join("\n\n");
|
|
47
|
+
fs.writeFileSync(this.outputPath, `/* Generated by @tenphi/tasty/zero - DO NOT EDIT */\n\n` + css);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get all CSS as string (for testing or in-memory use)
|
|
51
|
+
*/
|
|
52
|
+
getCSS() {
|
|
53
|
+
const cssBlocks = [];
|
|
54
|
+
for (const block of this.cssBlocks.values()) if (this.devMode && block.source) cssBlocks.push(`/* from: ${block.source} */\n${block.css}`);
|
|
55
|
+
else cssBlocks.push(block.css);
|
|
56
|
+
return cssBlocks.join("\n\n");
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Clear all collected CSS
|
|
60
|
+
*/
|
|
61
|
+
clear() {
|
|
62
|
+
this.cssBlocks.clear();
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Get the output path
|
|
66
|
+
*/
|
|
67
|
+
getOutputPath() {
|
|
68
|
+
return this.outputPath;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
//#endregion
|
|
73
|
+
export { CSSWriter };
|
|
74
|
+
//# sourceMappingURL=css-writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"css-writer.js","names":[],"sources":["../../src/zero/css-writer.ts"],"sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\n\nexport interface CSSWriterOptions {\n /** Enable source comments in output (e.g., \"from: Button.tsx\") */\n devMode?: boolean;\n}\n\ninterface CSSBlock {\n css: string;\n source?: string;\n}\n\nexport class CSSWriter {\n private cssBlocks = new Map<string, CSSBlock>();\n private outputPath: string;\n private devMode: boolean;\n\n constructor(outputPath: string, options: CSSWriterOptions = {}) {\n this.outputPath = outputPath;\n this.devMode = options.devMode ?? false;\n }\n\n /**\n * Add CSS block with deduplication key\n * @param key - Unique key for deduplication\n * @param css - CSS content\n * @param source - Optional source file path (used in devMode)\n */\n add(key: string, css: string, source?: string): void {\n this.cssBlocks.set(key, { css, source });\n }\n\n /**\n * Check if a key already exists\n */\n has(key: string): boolean {\n return this.cssBlocks.has(key);\n }\n\n /**\n * Get the number of CSS blocks\n */\n get size(): number {\n return this.cssBlocks.size;\n }\n\n /**\n * Write all collected CSS to the output file\n */\n write(): void {\n const outputDir = path.dirname(this.outputPath);\n\n // Ensure directory exists\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true });\n }\n\n // Combine all CSS blocks with optional source comments\n const cssBlocks: string[] = [];\n for (const block of this.cssBlocks.values()) {\n if (this.devMode && block.source) {\n cssBlocks.push(`/* from: ${block.source} */\\n${block.css}`);\n } else {\n cssBlocks.push(block.css);\n }\n }\n const css = cssBlocks.join('\\n\\n');\n\n // Add header comment\n const header = `/* Generated by @tenphi/tasty/zero - DO NOT EDIT */\\n\\n`;\n\n fs.writeFileSync(this.outputPath, header + css);\n }\n\n /**\n * Get all CSS as string (for testing or in-memory use)\n */\n getCSS(): string {\n const cssBlocks: string[] = [];\n for (const block of this.cssBlocks.values()) {\n if (this.devMode && block.source) {\n cssBlocks.push(`/* from: ${block.source} */\\n${block.css}`);\n } else {\n cssBlocks.push(block.css);\n }\n }\n return cssBlocks.join('\\n\\n');\n }\n\n /**\n * Clear all collected CSS\n */\n clear(): void {\n this.cssBlocks.clear();\n }\n\n /**\n * Get the output path\n */\n getOutputPath(): string {\n return this.outputPath;\n }\n}\n"],"mappings":";;;;AAaA,IAAa,YAAb,MAAuB;CACrB,AAAQ,4BAAY,IAAI,KAAuB;CAC/C,AAAQ;CACR,AAAQ;CAER,YAAY,YAAoB,UAA4B,EAAE,EAAE;AAC9D,OAAK,aAAa;AAClB,OAAK,UAAU,QAAQ,WAAW;;;;;;;;CASpC,IAAI,KAAa,KAAa,QAAuB;AACnD,OAAK,UAAU,IAAI,KAAK;GAAE;GAAK;GAAQ,CAAC;;;;;CAM1C,IAAI,KAAsB;AACxB,SAAO,KAAK,UAAU,IAAI,IAAI;;;;;CAMhC,IAAI,OAAe;AACjB,SAAO,KAAK,UAAU;;;;;CAMxB,QAAc;EACZ,MAAM,YAAY,KAAK,QAAQ,KAAK,WAAW;AAG/C,MAAI,CAAC,GAAG,WAAW,UAAU,CAC3B,IAAG,UAAU,WAAW,EAAE,WAAW,MAAM,CAAC;EAI9C,MAAM,YAAsB,EAAE;AAC9B,OAAK,MAAM,SAAS,KAAK,UAAU,QAAQ,CACzC,KAAI,KAAK,WAAW,MAAM,OACxB,WAAU,KAAK,YAAY,MAAM,OAAO,OAAO,MAAM,MAAM;MAE3D,WAAU,KAAK,MAAM,IAAI;EAG7B,MAAM,MAAM,UAAU,KAAK,OAAO;AAKlC,KAAG,cAAc,KAAK,YAFP,4DAE4B,IAAI;;;;;CAMjD,SAAiB;EACf,MAAM,YAAsB,EAAE;AAC9B,OAAK,MAAM,SAAS,KAAK,UAAU,QAAQ,CACzC,KAAI,KAAK,WAAW,MAAM,OACxB,WAAU,KAAK,YAAY,MAAM,OAAO,OAAO,MAAM,MAAM;MAE3D,WAAU,KAAK,MAAM,IAAI;AAG7B,SAAO,UAAU,KAAK,OAAO;;;;;CAM/B,QAAc;AACZ,OAAK,UAAU,OAAO;;;;;CAMxB,gBAAwB;AACtB,SAAO,KAAK"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Styles } from "../styles/types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/zero/extractor.d.ts
|
|
4
|
+
interface ExtractedChunk {
|
|
5
|
+
className: string;
|
|
6
|
+
css: string;
|
|
7
|
+
}
|
|
8
|
+
interface ExtractedSelector {
|
|
9
|
+
selector: string;
|
|
10
|
+
css: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Extract styles using chunking (for className mode).
|
|
14
|
+
* Returns multiple classes, one per chunk.
|
|
15
|
+
*/
|
|
16
|
+
declare function extractStylesWithChunks(styles: Styles): ExtractedChunk[];
|
|
17
|
+
/**
|
|
18
|
+
* Extract styles for a specific selector (for global/selector mode).
|
|
19
|
+
* Returns a single CSS block.
|
|
20
|
+
*/
|
|
21
|
+
declare function extractStylesForSelector(selector: string, styles: Styles): ExtractedSelector;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { ExtractedChunk, ExtractedSelector, extractStylesForSelector, extractStylesWithChunks };
|
|
24
|
+
//# sourceMappingURL=extractor.d.ts.map
|