@styleframe/transpiler 1.0.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.
Files changed (57) hide show
  1. package/.tsbuildinfo +1 -0
  2. package/CHANGELOG.md +12 -0
  3. package/package.json +43 -0
  4. package/src/constants.ts +4 -0
  5. package/src/consume/at-rule.test.ts +339 -0
  6. package/src/consume/at-rule.ts +34 -0
  7. package/src/consume/consume.test.ts +259 -0
  8. package/src/consume/consume.ts +60 -0
  9. package/src/consume/container.test.ts +501 -0
  10. package/src/consume/container.ts +73 -0
  11. package/src/consume/css.test.ts +184 -0
  12. package/src/consume/css.ts +17 -0
  13. package/src/consume/declarations.test.ts +210 -0
  14. package/src/consume/declarations.ts +17 -0
  15. package/src/consume/index.ts +12 -0
  16. package/src/consume/primitive.test.ts +52 -0
  17. package/src/consume/primitive.ts +16 -0
  18. package/src/consume/ref.test.ts +84 -0
  19. package/src/consume/ref.ts +22 -0
  20. package/src/consume/root.test.ts +353 -0
  21. package/src/consume/root.ts +19 -0
  22. package/src/consume/selector.test.ts +441 -0
  23. package/src/consume/selector.ts +17 -0
  24. package/src/consume/theme.test.ts +215 -0
  25. package/src/consume/theme.ts +15 -0
  26. package/src/consume/utility.test.ts +696 -0
  27. package/src/consume/utility.ts +31 -0
  28. package/src/consume/variable.test.ts +197 -0
  29. package/src/consume/variable.ts +20 -0
  30. package/src/defaults.ts +21 -0
  31. package/src/generator/genAtRuleQuery.test.ts +148 -0
  32. package/src/generator/genAtRuleQuery.ts +3 -0
  33. package/src/generator/genDeclaration.test.ts +283 -0
  34. package/src/generator/genDeclaration.ts +9 -0
  35. package/src/generator/genDeclarationsBlock.test.ts +278 -0
  36. package/src/generator/genDeclarationsBlock.ts +7 -0
  37. package/src/generator/genDeclareVariable.test.ts +323 -0
  38. package/src/generator/genDeclareVariable.ts +6 -0
  39. package/src/generator/genInlineAtRule.test.ts +351 -0
  40. package/src/generator/genInlineAtRule.ts +5 -0
  41. package/src/generator/genReferenceVariable.test.ts +392 -0
  42. package/src/generator/genReferenceVariable.ts +5 -0
  43. package/src/generator/genSafePropertyName.test.ts +489 -0
  44. package/src/generator/genSafePropertyName.ts +5 -0
  45. package/src/generator/genSafeVariableName.test.ts +358 -0
  46. package/src/generator/genSafeVariableName.ts +21 -0
  47. package/src/generator/genSelector.test.ts +357 -0
  48. package/src/generator/genSelector.ts +5 -0
  49. package/src/generator/index.ts +9 -0
  50. package/src/index.ts +6 -0
  51. package/src/transpile.test.ts +825 -0
  52. package/src/transpile.ts +21 -0
  53. package/src/types.ts +15 -0
  54. package/src/utils.ts +18 -0
  55. package/src/vite-env.d.ts +1 -0
  56. package/tsconfig.json +7 -0
  57. package/vite.config.ts +5 -0
@@ -0,0 +1,339 @@
1
+ import type { Root, StyleframeOptions } from "@styleframe/core";
2
+ import {
3
+ createAtRuleFunction,
4
+ createRefFunction,
5
+ createRoot,
6
+ } from "@styleframe/core";
7
+ import { createAtRuleConsumer } from "./at-rule";
8
+ import { consume } from "./consume";
9
+
10
+ describe("createAtRuleConsumer", () => {
11
+ let root: Root;
12
+ let atRule: ReturnType<typeof createAtRuleFunction>;
13
+ let ref: ReturnType<typeof createRefFunction>;
14
+
15
+ const consumeAtRule = createAtRuleConsumer(consume);
16
+ const options: StyleframeOptions = {};
17
+
18
+ beforeEach(() => {
19
+ root = createRoot();
20
+ atRule = createAtRuleFunction(root, root);
21
+ ref = createRefFunction(root, root);
22
+ });
23
+
24
+ it("should create a simple at-rule with no body", () => {
25
+ const importRule = atRule("import", '"./styles.css"');
26
+
27
+ const result = consumeAtRule(importRule, options);
28
+
29
+ expect(result).toBe('@import "./styles.css";');
30
+ });
31
+
32
+ it("should create a media query with declarations", () => {
33
+ const mediaRule = atRule("media", "(min-width: 768px)", {
34
+ padding: "2rem",
35
+ fontSize: "18px",
36
+ });
37
+
38
+ const result = consumeAtRule(mediaRule, options);
39
+
40
+ expect(result).toBe(`@media (min-width: 768px) {
41
+ padding: 2rem;
42
+ font-size: 18px;
43
+ }`);
44
+ });
45
+
46
+ it("should create an at-rule with variables", () => {
47
+ const mediaRule = atRule("media", "(min-width: 768px)", ({ variable }) => {
48
+ variable("breakpoint-padding", "2rem");
49
+
50
+ return {
51
+ padding: ref("breakpoint-padding"),
52
+ };
53
+ });
54
+
55
+ const result = consumeAtRule(mediaRule, options);
56
+
57
+ expect(result).toBe(`@media (min-width: 768px) {
58
+ \t--breakpoint-padding: 2rem;
59
+ \t
60
+ \tpadding: var(--breakpoint-padding);
61
+ }`);
62
+ });
63
+
64
+ it("should create an at-rule with nested selectors", () => {
65
+ const mediaRule = atRule("media", "(min-width: 768px)", ({ selector }) => {
66
+ selector(".card", {
67
+ width: "50%",
68
+ margin: "0 auto",
69
+ });
70
+
71
+ selector(".button", {
72
+ padding: "1rem 2rem",
73
+ });
74
+ });
75
+
76
+ const result = consumeAtRule(mediaRule, options);
77
+
78
+ expect(result).toBe(`@media (min-width: 768px) {
79
+ \t.card {
80
+ \t\twidth: 50%;
81
+ \t\tmargin: 0 auto;
82
+ \t}
83
+ \t
84
+ \t.button {
85
+ \t\tpadding: 1rem 2rem;
86
+ \t}
87
+ }`);
88
+ });
89
+
90
+ it("should create an at-rule with variables, declarations, and children", () => {
91
+ const mediaRule = atRule(
92
+ "media",
93
+ "(min-width: 1024px)",
94
+ ({ variable, selector }) => {
95
+ const spacingVar = variable("large-spacing", "3rem");
96
+
97
+ selector(".container", {
98
+ maxWidth: "1200px",
99
+ padding: ref(spacingVar),
100
+ });
101
+
102
+ return {
103
+ fontSize: "20px",
104
+ };
105
+ },
106
+ );
107
+
108
+ const result = consumeAtRule(mediaRule, options);
109
+
110
+ expect(result).toBe(`@media (min-width: 1024px) {
111
+ \t--large-spacing: 3rem;
112
+ \t
113
+ \tfont-size: 20px;
114
+ \t
115
+ \t.container {
116
+ \t\tmax-width: 1200px;
117
+ \t\tpadding: var(--large-spacing);
118
+ \t}
119
+ }`);
120
+ });
121
+
122
+ it("should handle keyframes at-rule", () => {
123
+ const keyframesRule = atRule("keyframes", "fadeIn", ({ selector }) => {
124
+ selector("0%", {
125
+ opacity: "0",
126
+ transform: "translateY(20px)",
127
+ });
128
+
129
+ selector("100%", {
130
+ opacity: "1",
131
+ transform: "translateY(0)",
132
+ });
133
+ });
134
+
135
+ const result = consumeAtRule(keyframesRule, options);
136
+
137
+ expect(result).toBe(`@keyframes fadeIn {
138
+ \t0% {
139
+ \t\topacity: 0;
140
+ \t\ttransform: translateY(20px);
141
+ \t}
142
+ \t
143
+ \t100% {
144
+ \t\topacity: 1;
145
+ \t\ttransform: translateY(0);
146
+ \t}
147
+ }`);
148
+ });
149
+
150
+ it("should handle supports at-rule", () => {
151
+ const supportsRule = atRule(
152
+ "supports",
153
+ "(display: grid)",
154
+ ({ selector }) => {
155
+ selector(".layout", {
156
+ display: "grid",
157
+ gridTemplateColumns: "repeat(3, 1fr)",
158
+ gap: "1rem",
159
+ });
160
+ },
161
+ );
162
+
163
+ const result = consumeAtRule(supportsRule, options);
164
+
165
+ expect(result).toBe(`@supports (display: grid) {
166
+ \t.layout {
167
+ \t\tdisplay: grid;
168
+ \t\tgrid-template-columns: repeat(3, 1fr);
169
+ \t\tgap: 1rem;
170
+ \t}
171
+ }`);
172
+ });
173
+
174
+ it("should handle container queries", () => {
175
+ const containerRule = atRule(
176
+ "container",
177
+ "(min-width: 400px)",
178
+ ({ selector }) => {
179
+ selector(".card-content", {
180
+ fontSize: "1.2rem",
181
+ padding: "1.5rem",
182
+ });
183
+ },
184
+ );
185
+
186
+ const result = consumeAtRule(containerRule, options);
187
+
188
+ expect(result).toBe(`@container (min-width: 400px) {
189
+ \t.card-content {
190
+ \t\tfont-size: 1.2rem;
191
+ \t\tpadding: 1.5rem;
192
+ \t}
193
+ }`);
194
+ });
195
+
196
+ it("should handle nested at-rules", () => {
197
+ const mediaRule = atRule("media", "(min-width: 768px)", ({ atRule }) => {
198
+ atRule("supports", "(display: flex)", ({ selector }) => {
199
+ selector(".flex-container", {
200
+ display: "flex",
201
+ alignItems: "center",
202
+ });
203
+ });
204
+ });
205
+
206
+ const result = consumeAtRule(mediaRule, options);
207
+
208
+ expect(result).toBe(`@media (min-width: 768px) {
209
+ \t@supports (display: flex) {
210
+ \t\t.flex-container {
211
+ \t\t\tdisplay: flex;
212
+ \t\t\talign-items: center;
213
+ \t\t}
214
+ \t}
215
+ }`);
216
+ });
217
+
218
+ it("should handle empty at-rules with only the rule part", () => {
219
+ const mediaRule = atRule("media", "(min-width: 768px)", {});
220
+
221
+ const result = consumeAtRule(mediaRule, options);
222
+
223
+ expect(result).toBe("@media (min-width: 768px) {}");
224
+ });
225
+
226
+ it("should handle at-rules with complex rule strings", () => {
227
+ const mediaRule = atRule(
228
+ "media",
229
+ "screen and (min-width: 768px) and (max-width: 1024px)",
230
+ {
231
+ fontSize: "16px",
232
+ },
233
+ );
234
+
235
+ const result = consumeAtRule(mediaRule, options);
236
+
237
+ expect(result).toBe(
238
+ `@media screen and (min-width: 768px) and (max-width: 1024px) {
239
+ \tfont-size: 16px;
240
+ }`,
241
+ );
242
+ });
243
+
244
+ it("should respect variable prefix in options", () => {
245
+ const prefixOptions: StyleframeOptions = {
246
+ variables: {
247
+ name: ({ name }) => `--sf-${name}`,
248
+ },
249
+ };
250
+
251
+ const mediaRule = atRule("media", "(min-width: 768px)", ({ variable }) => {
252
+ variable("responsive-padding", "2rem");
253
+
254
+ return {
255
+ padding: ref("responsive-padding"),
256
+ };
257
+ });
258
+
259
+ const result = consumeAtRule(mediaRule, prefixOptions);
260
+
261
+ expect(result).toBe(`@media (min-width: 768px) {
262
+ \t--sf-responsive-padding: 2rem;
263
+ \t
264
+ \tpadding: var(--sf-responsive-padding);
265
+ }`);
266
+ });
267
+
268
+ it("should handle at-rules with custom indentation", () => {
269
+ const customOptions: StyleframeOptions = {
270
+ indent: " ", // 4 spaces instead of default 2
271
+ };
272
+
273
+ const mediaRule = atRule("media", "(min-width: 768px)", {
274
+ padding: "2rem",
275
+ fontSize: "18px",
276
+ });
277
+
278
+ const result = consumeAtRule(mediaRule, customOptions);
279
+
280
+ expect(result).toBe(`@media (min-width: 768px) {
281
+ \tpadding: 2rem;
282
+ \tfont-size: 18px;
283
+ }`);
284
+ });
285
+
286
+ it("should handle page at-rules", () => {
287
+ const pageRule = atRule("page", ":first", {
288
+ marginTop: "50mm",
289
+ });
290
+
291
+ const result = consumeAtRule(pageRule, options);
292
+
293
+ expect(result).toBe(`@page :first {
294
+ \tmargin-top: 50mm;
295
+ }`);
296
+ });
297
+
298
+ it("should handle font-face at-rules", () => {
299
+ const fontFaceRule = atRule("font-face", "", {
300
+ fontFamily: '"MyFont"',
301
+ src: 'url("myfont.woff2") format("woff2")',
302
+ fontWeight: "normal",
303
+ fontStyle: "normal",
304
+ });
305
+
306
+ const result = consumeAtRule(fontFaceRule, options);
307
+
308
+ expect(result).toBe(`@font-face {
309
+ \tfont-family: "MyFont";
310
+ \tsrc: url("myfont.woff2") format("woff2");
311
+ \tfont-weight: normal;
312
+ \tfont-style: normal;
313
+ }`);
314
+ });
315
+
316
+ it("should handle layer at-rules", () => {
317
+ const layerRule = atRule("layer", "utilities", ({ selector }) => {
318
+ selector(".text-center", {
319
+ textAlign: "center",
320
+ });
321
+
322
+ selector(".hidden", {
323
+ display: "none",
324
+ });
325
+ });
326
+
327
+ const result = consumeAtRule(layerRule, options);
328
+
329
+ expect(result).toBe(`@layer utilities {
330
+ \t.text-center {
331
+ \t\ttext-align: center;
332
+ \t}
333
+ \t
334
+ \t.hidden {
335
+ \t\tdisplay: none;
336
+ \t}
337
+ }`);
338
+ });
339
+ });
@@ -0,0 +1,34 @@
1
+ import type { AtRule, StyleframeOptions } from "@styleframe/core";
2
+ import { STATEMENT_AT_RULES, STATEMENT_OR_BLOCK_AT_RULES } from "../constants";
3
+ import { genAtRuleQuery } from "../generator";
4
+ import type { ConsumeFunction } from "../types";
5
+ import { createContainerConsumer } from "./container";
6
+
7
+ /**
8
+ * Consumes a generic at-rule instance, equivalent to setting a CSS at-rule
9
+ * such as @media, @supports, @keyframes, etc.
10
+ */
11
+ export function createAtRuleConsumer(consume: ConsumeFunction) {
12
+ const consumeContainer = createContainerConsumer(consume);
13
+
14
+ return function consumeAtRule(
15
+ instance: AtRule,
16
+ options: StyleframeOptions,
17
+ ): string {
18
+ const isStatement = STATEMENT_AT_RULES.includes(instance.identifier);
19
+ const isStatementOrBlock = STATEMENT_OR_BLOCK_AT_RULES.includes(
20
+ instance.identifier,
21
+ );
22
+
23
+ const hasDeclarations = Object.keys(instance.declarations).length > 0;
24
+ const hasVariables = instance.variables.length > 0;
25
+ const hasChildren = instance.children.length > 0;
26
+
27
+ const query = genAtRuleQuery(instance.identifier, instance.rule);
28
+
29
+ return isStatement ||
30
+ (isStatementOrBlock && !(hasDeclarations || hasVariables || hasChildren))
31
+ ? `${query};`
32
+ : consumeContainer(query, instance, options);
33
+ };
34
+ }
@@ -0,0 +1,259 @@
1
+ import type { Root, StyleframeOptions } from "@styleframe/core";
2
+ import {
3
+ createAtRuleFunction,
4
+ createCssFunction,
5
+ createRefFunction,
6
+ createRoot,
7
+ createSelectorFunction,
8
+ createThemeFunction,
9
+ createUtilityFunction,
10
+ createVariableFunction,
11
+ isUtility,
12
+ } from "@styleframe/core";
13
+ import { consume } from "./consume";
14
+
15
+ describe("consume", () => {
16
+ let root: Root;
17
+ let variable: ReturnType<typeof createVariableFunction>;
18
+ let ref: ReturnType<typeof createRefFunction>;
19
+ let css: ReturnType<typeof createCssFunction>;
20
+ let selector: ReturnType<typeof createSelectorFunction>;
21
+ let theme: ReturnType<typeof createThemeFunction>;
22
+ let atRule: ReturnType<typeof createAtRuleFunction>;
23
+ let utility: ReturnType<typeof createUtilityFunction>;
24
+
25
+ const options: StyleframeOptions = {};
26
+
27
+ beforeEach(() => {
28
+ root = createRoot();
29
+ variable = createVariableFunction(root, root);
30
+ ref = createRefFunction(root, root);
31
+ css = createCssFunction(root, root);
32
+ selector = createSelectorFunction(root, root);
33
+ theme = createThemeFunction(root, root);
34
+ atRule = createAtRuleFunction(root, root);
35
+ utility = createUtilityFunction(root, root);
36
+ });
37
+
38
+ it("should consume a variable instance", () => {
39
+ const colorVar = variable("primary-color", "#006cff");
40
+ const result = consume(colorVar, options);
41
+
42
+ expect(result).toBe("--primary-color: #006cff;");
43
+ });
44
+
45
+ it("should consume a reference instance", () => {
46
+ const colorRef = ref("primary-color");
47
+ const result = consume(colorRef, options);
48
+
49
+ expect(result).toBe("var(--primary-color)");
50
+ });
51
+
52
+ it("should consume a CSS instance", () => {
53
+ const cssValue = css`16px solid #000`;
54
+ const result = consume(cssValue, options);
55
+
56
+ expect(result).toBe("16px solid #000");
57
+ });
58
+
59
+ it("should consume a selector instance", () => {
60
+ const buttonSelector = selector(".button", {
61
+ padding: "0.5rem 1rem",
62
+ backgroundColor: "#006cff",
63
+ });
64
+
65
+ const result = consume(buttonSelector, options);
66
+
67
+ expect(result).toEqual(`.button {
68
+ \tpadding: 0.5rem 1rem;
69
+ \tbackground-color: #006cff;
70
+ }`);
71
+ });
72
+
73
+ it("should consume a theme instance", () => {
74
+ const lightTheme = theme("light", ({ variable: v }) => {
75
+ v("background-color", "#ffffff");
76
+ v("text-color", "#000000");
77
+ });
78
+
79
+ const result = consume(lightTheme, options);
80
+
81
+ expect(result).toEqual(`[data-theme="light"] {
82
+ \t--background-color: #ffffff;
83
+ \t--text-color: #000000;
84
+ }`);
85
+ });
86
+
87
+ it("should consume an at-rule instance", () => {
88
+ const mediaRule = atRule("media", "(min-width: 768px)", {
89
+ fontSize: "18px",
90
+ });
91
+
92
+ const result = consume(mediaRule, options);
93
+
94
+ expect(result).toEqual(`@media (min-width: 768px) {
95
+ \tfont-size: 18px;
96
+ }`);
97
+ });
98
+
99
+ it("should consume a utility instance", () => {
100
+ const createMarginUtility = utility("margin", ({ value }) => ({
101
+ margin: value,
102
+ }));
103
+
104
+ createMarginUtility({
105
+ sm: "8px",
106
+ md: "16px",
107
+ });
108
+
109
+ const marginUtility = root.children.find(
110
+ (u) => isUtility(u) && u.name === "margin",
111
+ );
112
+ const result = consume(marginUtility, options);
113
+
114
+ expect(result).toEqual(`._margin\\:sm {
115
+ \tmargin: 8px;
116
+ }`);
117
+ });
118
+
119
+ it("should consume primitive values", () => {
120
+ expect(consume("test string", options)).toBe("test string");
121
+ expect(consume(42, options)).toBe("42");
122
+ expect(consume(true, options)).toBe("true");
123
+ expect(consume(false, options)).toBe("false");
124
+ expect(consume(null, options)).toBe("");
125
+ expect(consume(undefined, options)).toBe("");
126
+ });
127
+
128
+ it("should consume complex nested structures", () => {
129
+ variable("card-bg", "#ffffff");
130
+ variable("card-shadow", "0 2px 4px rgba(0,0,0,0.1)");
131
+
132
+ selector(".card", ({ variable, selector }) => {
133
+ const colorVar = variable("card-bg", "#ffffff");
134
+ const shadowVar = variable("card-shadow", "0 2px 4px rgba(0,0,0,0.1)");
135
+
136
+ selector("&:hover", {
137
+ transform: "translateY(-2px)",
138
+ boxShadow: ref(shadowVar),
139
+ });
140
+
141
+ return {
142
+ backgroundColor: ref(colorVar),
143
+ borderRadius: "8px",
144
+ padding: "1rem",
145
+ };
146
+ });
147
+
148
+ theme("dark", ({ variable, selector }) => {
149
+ const colorVar = variable("card-bg", "#333");
150
+ variable("card-shadow", "0 2px 4px rgba(0,0,0,0.2)");
151
+
152
+ selector(".card", ({ variable, selector }) => {
153
+ variable("shadow", ref(colorVar));
154
+
155
+ selector("&:hover", {
156
+ transform: "translateY(-6px)",
157
+ });
158
+
159
+ return {
160
+ boxShadow: ref("shadow"),
161
+ border: "1px solid #ccc",
162
+ };
163
+ });
164
+ });
165
+
166
+ const result = consume(root, options);
167
+ const expected = `:root {
168
+ \t--card-bg: #ffffff;
169
+ \t--card-shadow: 0 2px 4px rgba(0,0,0,0.1);
170
+ }
171
+
172
+ .card {
173
+ \t--card-bg: #ffffff;
174
+ \t--card-shadow: 0 2px 4px rgba(0,0,0,0.1);
175
+ \t
176
+ \tbackground-color: var(--card-bg);
177
+ \tborder-radius: 8px;
178
+ \tpadding: 1rem;
179
+ \t
180
+ \t&:hover {
181
+ \t\ttransform: translateY(-2px);
182
+ \t\tbox-shadow: var(--card-shadow);
183
+ \t}
184
+ }
185
+
186
+ [data-theme="dark"] {
187
+ \t--card-bg: #333;
188
+ \t--card-shadow: 0 2px 4px rgba(0,0,0,0.2);
189
+ \t
190
+ \t.card {
191
+ \t\t--shadow: var(--card-bg);
192
+ \t\t
193
+ \t\tbox-shadow: var(--shadow);
194
+ \t\tborder: 1px solid #ccc;
195
+ \t\t
196
+ \t\t&:hover {
197
+ \t\t\ttransform: translateY(-6px);
198
+ \t\t}
199
+ \t}
200
+ }`;
201
+
202
+ expect(result).toEqual(expected);
203
+ });
204
+
205
+ it("should preserve variable references across different instance types", () => {
206
+ const colorVar = variable("brand-color", "#006cff");
207
+
208
+ // Test in selector
209
+ const buttonSelector = selector(".button", {
210
+ backgroundColor: ref(colorVar),
211
+ });
212
+
213
+ // Test in CSS
214
+ const borderStyle = css`2px solid ${ref(colorVar)}`;
215
+
216
+ // Test in theme
217
+ const brandTheme = theme("brand", ({ selector }) => {
218
+ selector(".accent", {
219
+ color: ref(colorVar),
220
+ });
221
+ });
222
+
223
+ const selectorResult = consume(buttonSelector, options);
224
+ const cssResult = consume(borderStyle, options);
225
+ const themeResult = consume(brandTheme, options);
226
+
227
+ expect(selectorResult).toEqual(`.button {
228
+ \tbackground-color: var(--brand-color);
229
+ }`);
230
+ expect(cssResult).toBe("2px solid var(--brand-color)");
231
+ expect(themeResult).toContain("color: var(--brand-color);");
232
+ });
233
+
234
+ it("should handle options consistently across all instance types", () => {
235
+ const prefixOptions: StyleframeOptions = {
236
+ variables: {
237
+ name: ({ name }) => `--app-${name}`,
238
+ },
239
+ };
240
+
241
+ const colorVar = variable("primary", "#006cff");
242
+ const colorRef = ref("secondary");
243
+ const buttonSelector = selector(".button", {
244
+ backgroundColor: ref(colorVar),
245
+ color: colorRef,
246
+ });
247
+
248
+ const varResult = consume(colorVar, prefixOptions);
249
+ const refResult = consume(colorRef, prefixOptions);
250
+ const selectorResult = consume(buttonSelector, prefixOptions);
251
+
252
+ expect(varResult).toBe("--app-primary: #006cff;");
253
+ expect(refResult).toBe("var(--app-secondary)");
254
+ expect(selectorResult).toEqual(`.button {
255
+ \tbackground-color: var(--app-primary);
256
+ \tcolor: var(--app-secondary);
257
+ }`);
258
+ });
259
+ });
@@ -0,0 +1,60 @@
1
+ import type { StyleframeOptions } from "@styleframe/core";
2
+ import {
3
+ isAtRule,
4
+ isCSS,
5
+ isRef,
6
+ isRoot,
7
+ isSelector,
8
+ isTheme,
9
+ isUtility,
10
+ isVariable,
11
+ } from "@styleframe/core";
12
+ import { createAtRuleConsumer } from "./at-rule";
13
+ import { createCSSConsumer } from "./css";
14
+ import { createPrimitiveConsumer } from "./primitive";
15
+ import { createRefConsumer } from "./ref";
16
+ import { createRootConsumer } from "./root";
17
+ import { createSelectorConsumer } from "./selector";
18
+ import { createThemeConsumer } from "./theme";
19
+ import { createUtilityConsumer } from "./utility";
20
+ import { createVariableConsumer } from "./variable";
21
+
22
+ /**
23
+ * Consumes any token instance and returns the CSS string representation
24
+ */
25
+ export function consume(instance: unknown, options: StyleframeOptions): string {
26
+ const consumeRoot = createRootConsumer(consume);
27
+ const consumeSelector = createSelectorConsumer(consume);
28
+ const consumeUtility = createUtilityConsumer(consume);
29
+ const consumeAtRule = createAtRuleConsumer(consume);
30
+ // const consumeRecipe = createRecipeConsumer(consume);
31
+ const consumeTheme = createThemeConsumer(consume);
32
+ const consumeVariable = createVariableConsumer(consume);
33
+ const consumeRef = createRefConsumer(consume);
34
+ const consumeCSS = createCSSConsumer(consume);
35
+ const consumePrimitive = createPrimitiveConsumer(consume);
36
+
37
+ switch (true) {
38
+ case isSelector(instance):
39
+ return consumeSelector(instance, options);
40
+ case isUtility(instance):
41
+ return consumeUtility(instance, options);
42
+ case isAtRule(instance):
43
+ return consumeAtRule(instance, options);
44
+ // case isRecipe(instance):
45
+ // return consumeRecipe(instance, options);
46
+ // break;
47
+ case isRoot(instance):
48
+ return consumeRoot(instance, options);
49
+ case isTheme(instance):
50
+ return consumeTheme(instance, options);
51
+ case isVariable(instance):
52
+ return consumeVariable(instance, options);
53
+ case isRef(instance):
54
+ return consumeRef(instance, options);
55
+ case isCSS(instance):
56
+ return consumeCSS(instance, options);
57
+ default:
58
+ return consumePrimitive(instance, options);
59
+ }
60
+ }