@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.
- package/.tsbuildinfo +1 -0
- package/CHANGELOG.md +12 -0
- package/package.json +43 -0
- package/src/constants.ts +4 -0
- package/src/consume/at-rule.test.ts +339 -0
- package/src/consume/at-rule.ts +34 -0
- package/src/consume/consume.test.ts +259 -0
- package/src/consume/consume.ts +60 -0
- package/src/consume/container.test.ts +501 -0
- package/src/consume/container.ts +73 -0
- package/src/consume/css.test.ts +184 -0
- package/src/consume/css.ts +17 -0
- package/src/consume/declarations.test.ts +210 -0
- package/src/consume/declarations.ts +17 -0
- package/src/consume/index.ts +12 -0
- package/src/consume/primitive.test.ts +52 -0
- package/src/consume/primitive.ts +16 -0
- package/src/consume/ref.test.ts +84 -0
- package/src/consume/ref.ts +22 -0
- package/src/consume/root.test.ts +353 -0
- package/src/consume/root.ts +19 -0
- package/src/consume/selector.test.ts +441 -0
- package/src/consume/selector.ts +17 -0
- package/src/consume/theme.test.ts +215 -0
- package/src/consume/theme.ts +15 -0
- package/src/consume/utility.test.ts +696 -0
- package/src/consume/utility.ts +31 -0
- package/src/consume/variable.test.ts +197 -0
- package/src/consume/variable.ts +20 -0
- package/src/defaults.ts +21 -0
- package/src/generator/genAtRuleQuery.test.ts +148 -0
- package/src/generator/genAtRuleQuery.ts +3 -0
- package/src/generator/genDeclaration.test.ts +283 -0
- package/src/generator/genDeclaration.ts +9 -0
- package/src/generator/genDeclarationsBlock.test.ts +278 -0
- package/src/generator/genDeclarationsBlock.ts +7 -0
- package/src/generator/genDeclareVariable.test.ts +323 -0
- package/src/generator/genDeclareVariable.ts +6 -0
- package/src/generator/genInlineAtRule.test.ts +351 -0
- package/src/generator/genInlineAtRule.ts +5 -0
- package/src/generator/genReferenceVariable.test.ts +392 -0
- package/src/generator/genReferenceVariable.ts +5 -0
- package/src/generator/genSafePropertyName.test.ts +489 -0
- package/src/generator/genSafePropertyName.ts +5 -0
- package/src/generator/genSafeVariableName.test.ts +358 -0
- package/src/generator/genSafeVariableName.ts +21 -0
- package/src/generator/genSelector.test.ts +357 -0
- package/src/generator/genSelector.ts +5 -0
- package/src/generator/index.ts +9 -0
- package/src/index.ts +6 -0
- package/src/transpile.test.ts +825 -0
- package/src/transpile.ts +21 -0
- package/src/types.ts +15 -0
- package/src/utils.ts +18 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +7 -0
- package/vite.config.ts +5 -0
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
import type { Root, StyleframeOptions } from "@styleframe/core";
|
|
2
|
+
import {
|
|
3
|
+
createRefFunction,
|
|
4
|
+
createRoot,
|
|
5
|
+
createSelectorFunction,
|
|
6
|
+
createVariableFunction,
|
|
7
|
+
} from "@styleframe/core";
|
|
8
|
+
import { consume } from "./consume";
|
|
9
|
+
import { createRootConsumer } from "./root";
|
|
10
|
+
|
|
11
|
+
describe("createRootConsumer", () => {
|
|
12
|
+
let root: Root;
|
|
13
|
+
let variable: ReturnType<typeof createVariableFunction>;
|
|
14
|
+
let ref: ReturnType<typeof createRefFunction>;
|
|
15
|
+
let selector: ReturnType<typeof createSelectorFunction>;
|
|
16
|
+
|
|
17
|
+
const consumeRoot = createRootConsumer(consume);
|
|
18
|
+
const options: StyleframeOptions = {};
|
|
19
|
+
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
root = createRoot();
|
|
22
|
+
variable = createVariableFunction(root, root);
|
|
23
|
+
ref = createRefFunction(root, root);
|
|
24
|
+
selector = createSelectorFunction(root, root);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("should handle empty root", () => {
|
|
28
|
+
const result = consumeRoot(root, options);
|
|
29
|
+
expect(result).toBe("");
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("should handle root with only variables", () => {
|
|
33
|
+
variable("primary", "#0066ff");
|
|
34
|
+
variable("secondary", "#ff6b6b");
|
|
35
|
+
|
|
36
|
+
const result = consumeRoot(root, options);
|
|
37
|
+
expect(result).toBe(`:root {
|
|
38
|
+
\t--primary: #0066ff;
|
|
39
|
+
\t--secondary: #ff6b6b;
|
|
40
|
+
}`);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("should handle root with only declarations", () => {
|
|
44
|
+
root.declarations = {
|
|
45
|
+
fontSize: "16px",
|
|
46
|
+
lineHeight: "1.5",
|
|
47
|
+
fontFamily: "system-ui, sans-serif",
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const result = consumeRoot(root, options);
|
|
51
|
+
expect(result).toBe(`:root {
|
|
52
|
+
\tfont-size: 16px;
|
|
53
|
+
\tline-height: 1.5;
|
|
54
|
+
\tfont-family: system-ui, sans-serif;
|
|
55
|
+
}`);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("should handle root with only children", () => {
|
|
59
|
+
selector(".button", {
|
|
60
|
+
padding: "0.5rem 1rem",
|
|
61
|
+
borderRadius: "4px",
|
|
62
|
+
});
|
|
63
|
+
selector(".card", {
|
|
64
|
+
boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const result = consumeRoot(root, options);
|
|
68
|
+
expect(result).toBe(`.button {
|
|
69
|
+
\tpadding: 0.5rem 1rem;
|
|
70
|
+
\tborder-radius: 4px;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.card {
|
|
74
|
+
\tbox-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
75
|
+
}`);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("should handle root with variables and declarations", () => {
|
|
79
|
+
const colorVar = variable("text-color", "#333333");
|
|
80
|
+
const sizeVar = variable("base-font-size", "16px");
|
|
81
|
+
root.declarations = {
|
|
82
|
+
color: ref(colorVar),
|
|
83
|
+
fontSize: ref(sizeVar),
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const result = consumeRoot(root, options);
|
|
87
|
+
expect(result).toBe(`:root {
|
|
88
|
+
\t--text-color: #333333;
|
|
89
|
+
\t--base-font-size: 16px;
|
|
90
|
+
\t
|
|
91
|
+
\tcolor: var(--text-color);
|
|
92
|
+
\tfont-size: var(--base-font-size);
|
|
93
|
+
}`);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("should handle root with variables and children", () => {
|
|
97
|
+
const primaryVar = variable("primary", "#0066ff");
|
|
98
|
+
const dangerVar = variable("danger", "#ff0000");
|
|
99
|
+
selector(".btn-primary", {
|
|
100
|
+
backgroundColor: ref(primaryVar),
|
|
101
|
+
color: "white",
|
|
102
|
+
});
|
|
103
|
+
selector(".alert-danger", {
|
|
104
|
+
borderColor: ref(dangerVar),
|
|
105
|
+
color: ref(dangerVar),
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const result = consumeRoot(root, options);
|
|
109
|
+
expect(result).toBe(`:root {
|
|
110
|
+
\t--primary: #0066ff;
|
|
111
|
+
\t--danger: #ff0000;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.btn-primary {
|
|
115
|
+
\tbackground-color: var(--primary);
|
|
116
|
+
\tcolor: white;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.alert-danger {
|
|
120
|
+
\tborder-color: var(--danger);
|
|
121
|
+
\tcolor: var(--danger);
|
|
122
|
+
}`);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("should handle root with declarations and children", () => {
|
|
126
|
+
root.declarations = {
|
|
127
|
+
boxSizing: "border-box",
|
|
128
|
+
margin: "0",
|
|
129
|
+
padding: "0",
|
|
130
|
+
};
|
|
131
|
+
selector("body", {
|
|
132
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
133
|
+
lineHeight: "1.6",
|
|
134
|
+
});
|
|
135
|
+
selector("h1, h2, h3", {
|
|
136
|
+
marginTop: "0",
|
|
137
|
+
lineHeight: "1.2",
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const result = consumeRoot(root, options);
|
|
141
|
+
expect(result).toBe(`:root {
|
|
142
|
+
\tbox-sizing: border-box;
|
|
143
|
+
\tmargin: 0;
|
|
144
|
+
\tpadding: 0;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
body {
|
|
148
|
+
\tfont-family: system-ui, -apple-system, sans-serif;
|
|
149
|
+
\tline-height: 1.6;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
h1, h2, h3 {
|
|
153
|
+
\tmargin-top: 0;
|
|
154
|
+
\tline-height: 1.2;
|
|
155
|
+
}`);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("should handle root with variables, declarations, and children", () => {
|
|
159
|
+
const spacingVar = variable("spacing-unit", "8px");
|
|
160
|
+
const primaryVar = variable("primary", "#0066ff");
|
|
161
|
+
const bgVar = variable("background", "#ffffff");
|
|
162
|
+
|
|
163
|
+
root.declarations = {
|
|
164
|
+
"--global-padding": ref(spacingVar),
|
|
165
|
+
backgroundColor: ref(bgVar),
|
|
166
|
+
color: "#333",
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
selector(".container", {
|
|
170
|
+
maxWidth: "1200px",
|
|
171
|
+
margin: "0 auto",
|
|
172
|
+
padding: ref(spacingVar),
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
selector(".button", {
|
|
176
|
+
padding: "calc(var(--spacing-unit) * 2)",
|
|
177
|
+
backgroundColor: ref(primaryVar),
|
|
178
|
+
border: "none",
|
|
179
|
+
borderRadius: "4px",
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
const result = consumeRoot(root, options);
|
|
183
|
+
|
|
184
|
+
expect(result).toBe(`:root {
|
|
185
|
+
\t--spacing-unit: 8px;
|
|
186
|
+
\t--primary: #0066ff;
|
|
187
|
+
\t--background: #ffffff;
|
|
188
|
+
\t
|
|
189
|
+
\t--global-padding: var(--spacing-unit);
|
|
190
|
+
\tbackground-color: var(--background);
|
|
191
|
+
\tcolor: #333;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.container {
|
|
195
|
+
\tmax-width: 1200px;
|
|
196
|
+
\tmargin: 0 auto;
|
|
197
|
+
\tpadding: var(--spacing-unit);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.button {
|
|
201
|
+
\tpadding: calc(var(--spacing-unit) * 2);
|
|
202
|
+
\tbackground-color: var(--primary);
|
|
203
|
+
\tborder: none;
|
|
204
|
+
\tborder-radius: 4px;
|
|
205
|
+
}`);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it("should handle custom options with variable prefix", () => {
|
|
209
|
+
const customOptions: StyleframeOptions = {
|
|
210
|
+
variables: {
|
|
211
|
+
name: ({ name }) => `--app-${name}`,
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
const themeVar = variable("theme-color", "#663399");
|
|
215
|
+
root.declarations = {
|
|
216
|
+
accentColor: ref(themeVar),
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const result = consumeRoot(root, customOptions);
|
|
220
|
+
|
|
221
|
+
expect(result).toBe(
|
|
222
|
+
`:root {
|
|
223
|
+
\t--app-theme-color: #663399;
|
|
224
|
+
\t
|
|
225
|
+
\taccent-color: var(--app-theme-color);
|
|
226
|
+
}`,
|
|
227
|
+
);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it("should handle complex variable values", () => {
|
|
231
|
+
variable(
|
|
232
|
+
"elevation-1",
|
|
233
|
+
"0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)",
|
|
234
|
+
);
|
|
235
|
+
variable("transition-default", "all 0.3s cubic-bezier(.25,.8,.25,1)");
|
|
236
|
+
variable(
|
|
237
|
+
"font-stack",
|
|
238
|
+
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
const result = consumeRoot(root, options);
|
|
242
|
+
|
|
243
|
+
const expected = `:root {
|
|
244
|
+
\t--elevation-1: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
|
|
245
|
+
\t--transition-default: all 0.3s cubic-bezier(.25,.8,.25,1);
|
|
246
|
+
\t--font-stack: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
247
|
+
}`;
|
|
248
|
+
expect(result).toBe(expected);
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it("should handle nested selectors in children", () => {
|
|
252
|
+
selector("nav", ({ selector }) => {
|
|
253
|
+
selector("ul", ({ selector }) => {
|
|
254
|
+
selector("li", {
|
|
255
|
+
listStyle: "none",
|
|
256
|
+
display: "inline-block",
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
return {
|
|
260
|
+
margin: "0",
|
|
261
|
+
padding: "0",
|
|
262
|
+
};
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
return {
|
|
266
|
+
backgroundColor: "#f5f5f5",
|
|
267
|
+
padding: "1rem",
|
|
268
|
+
};
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
const result = consumeRoot(root, options);
|
|
272
|
+
|
|
273
|
+
expect(result).toBe(`nav {
|
|
274
|
+
\tbackground-color: #f5f5f5;
|
|
275
|
+
\tpadding: 1rem;
|
|
276
|
+
\t
|
|
277
|
+
\tul {
|
|
278
|
+
\t\tmargin: 0;
|
|
279
|
+
\t\tpadding: 0;
|
|
280
|
+
\t\t
|
|
281
|
+
\t\tli {
|
|
282
|
+
\t\t\tlist-style: none;
|
|
283
|
+
\t\t\tdisplay: inline-block;
|
|
284
|
+
\t\t}
|
|
285
|
+
\t}
|
|
286
|
+
}`);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it("should handle media queries as children", () => {
|
|
290
|
+
variable("mobile-breakpoint", "768px");
|
|
291
|
+
selector("@media (max-width: 768px)", ({ selector }) => {
|
|
292
|
+
selector(".container", {
|
|
293
|
+
padding: "1rem",
|
|
294
|
+
maxWidth: "100%",
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
return {};
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
const result = consumeRoot(root, options);
|
|
301
|
+
|
|
302
|
+
expect(result).toBe(`:root {
|
|
303
|
+
\t--mobile-breakpoint: 768px;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
@media (max-width: 768px) {
|
|
307
|
+
\t.container {
|
|
308
|
+
\t\tpadding: 1rem;
|
|
309
|
+
\t\tmax-width: 100%;
|
|
310
|
+
\t}
|
|
311
|
+
}`);
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
it("should handle undefined properties gracefully", () => {
|
|
315
|
+
const emptyRoot = createRoot();
|
|
316
|
+
const result = consumeRoot(emptyRoot, options);
|
|
317
|
+
expect(result).toBe("");
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it("should handle reference values with fallbacks", () => {
|
|
321
|
+
const colorVar = variable("brand-color", "#0066ff");
|
|
322
|
+
root.declarations = {
|
|
323
|
+
color: ref("text-color", "#333"),
|
|
324
|
+
backgroundColor: ref(colorVar),
|
|
325
|
+
borderColor: ref("border-color", "currentColor"),
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
const result = consumeRoot(root, options);
|
|
329
|
+
|
|
330
|
+
expect(result).toBe(`:root {
|
|
331
|
+
\t--brand-color: #0066ff;
|
|
332
|
+
\t
|
|
333
|
+
\tcolor: var(--text-color, #333);
|
|
334
|
+
\tbackground-color: var(--brand-color);
|
|
335
|
+
\tborder-color: var(--border-color, currentColor);
|
|
336
|
+
}`);
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it("should properly delegate to container consumer", () => {
|
|
340
|
+
// This test verifies that createRootConsumer correctly uses createContainerConsumer
|
|
341
|
+
const colorVar = variable("color", "blue");
|
|
342
|
+
root.declarations = { display: "block" };
|
|
343
|
+
|
|
344
|
+
const result = consumeRoot(root, options);
|
|
345
|
+
|
|
346
|
+
// Should produce the same output as if we called consumeContainer with ":root"
|
|
347
|
+
expect(result).toBe(`:root {
|
|
348
|
+
\t--color: blue;
|
|
349
|
+
\t
|
|
350
|
+
\tdisplay: block;
|
|
351
|
+
}`);
|
|
352
|
+
});
|
|
353
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Root, StyleframeOptions } from "@styleframe/core";
|
|
2
|
+
import type { ConsumeFunction } from "../types";
|
|
3
|
+
import { createContainerConsumer } from "./container";
|
|
4
|
+
|
|
5
|
+
export function createRootConsumer(consume: ConsumeFunction) {
|
|
6
|
+
const consumeContainer = createContainerConsumer(consume);
|
|
7
|
+
|
|
8
|
+
return function consumeRoot(instance: Root, options: StyleframeOptions) {
|
|
9
|
+
return instance.themes
|
|
10
|
+
.reduce(
|
|
11
|
+
(acc, theme) => {
|
|
12
|
+
acc.push(consume(theme, options));
|
|
13
|
+
return acc;
|
|
14
|
+
},
|
|
15
|
+
[consumeContainer(":root", instance, options)], // Default theme (root)
|
|
16
|
+
)
|
|
17
|
+
.join("\n\n");
|
|
18
|
+
};
|
|
19
|
+
}
|