@canvasengine/compiler 2.0.0-beta.33 → 2.0.0-beta.35
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/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +4 -1
- package/index.ts +0 -253
- package/tests/compiler.spec.ts +0 -1159
- package/tsconfig.json +0 -29
- package/tsup.config.ts +0 -14
- /package/{grammar.pegjs → dist/grammar.pegjs} +0 -0
package/tests/compiler.spec.ts
DELETED
|
@@ -1,1159 +0,0 @@
|
|
|
1
|
-
import pkg from "peggy";
|
|
2
|
-
import fs from "fs";
|
|
3
|
-
import { beforeAll, describe, test, expect } from "vitest";
|
|
4
|
-
|
|
5
|
-
const { generate } = pkg;
|
|
6
|
-
let parser: any;
|
|
7
|
-
|
|
8
|
-
beforeAll(() => {
|
|
9
|
-
const grammar = fs.readFileSync("packages/compiler/grammar.pegjs", "utf8");
|
|
10
|
-
parser = generate(grammar);
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
describe("Compiler", () => {
|
|
14
|
-
test("should compile comment", () => {
|
|
15
|
-
const input = `
|
|
16
|
-
<Canvas>
|
|
17
|
-
<!-- Comment -->
|
|
18
|
-
</Canvas>
|
|
19
|
-
`;
|
|
20
|
-
const output = parser.parse(input);
|
|
21
|
-
expect(output).toBe(`h(Canvas)`);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
test("should compile multiple comment", () => {
|
|
25
|
-
const input = `
|
|
26
|
-
<Canvas>
|
|
27
|
-
<!-- Comment -->
|
|
28
|
-
<!-- Comment -->
|
|
29
|
-
</Canvas>
|
|
30
|
-
`;
|
|
31
|
-
const output = parser.parse(input);
|
|
32
|
-
expect(output).toBe(`h(Canvas)`);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
test("should compile multiple line comment", () => {
|
|
36
|
-
const input = `
|
|
37
|
-
<Canvas>
|
|
38
|
-
<!--
|
|
39
|
-
Comment
|
|
40
|
-
Comment
|
|
41
|
-
-->
|
|
42
|
-
</Canvas>
|
|
43
|
-
`;
|
|
44
|
-
const output = parser.parse(input);
|
|
45
|
-
expect(output).toBe(`h(Canvas)`);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test("should compile simple component", () => {
|
|
49
|
-
const input = `<Canvas />`;
|
|
50
|
-
const output = parser.parse(input);
|
|
51
|
-
expect(output).toBe(`h(Canvas)`);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
describe("Dot notation", () => {
|
|
55
|
-
test("should compile component with dot notation", () => {
|
|
56
|
-
const input = `<MyComp.test />`;
|
|
57
|
-
const output = parser.parse(input);
|
|
58
|
-
expect(output).toBe(`h(MyComp.test)`);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test("object function call", () => {
|
|
62
|
-
const input = `<MyComp.test() />`;
|
|
63
|
-
const output = parser.parse(input);
|
|
64
|
-
expect(output).toBe(`h(MyComp.test())`);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
test("function call with return object", () => {
|
|
68
|
-
const input = `<MyComp().test />`;
|
|
69
|
-
const output = parser.parse(input);
|
|
70
|
-
expect(output).toBe(`h(MyComp().test)`);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
test("function call with return object and params", () => {
|
|
74
|
-
const input = `<MyComp().test(x, y) />`;
|
|
75
|
-
const output = parser.parse(input);
|
|
76
|
-
expect(output).toBe(`h(MyComp().test(x, y))`);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
test("function call and params with return object and", () => {
|
|
80
|
-
const input = `<MyComp(x, y).test />`;
|
|
81
|
-
const output = parser.parse(input);
|
|
82
|
-
expect(output).toBe(`h(MyComp(x, y).test)`);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
test("function call", () => {
|
|
86
|
-
const input = `<MyComp() />`;
|
|
87
|
-
const output = parser.parse(input);
|
|
88
|
-
expect(output).toBe(`h(MyComp())`);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
test("function call and params", () => {
|
|
92
|
-
const input = `<MyComp(x, y) />`;
|
|
93
|
-
const output = parser.parse(input);
|
|
94
|
-
expect(output).toBe(`h(MyComp(x, y))`);
|
|
95
|
-
});
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
test("should compile component with dynamic attribute", () => {
|
|
99
|
-
const input = `<Canvas width={x} />`;
|
|
100
|
-
const output = parser.parse(input);
|
|
101
|
-
expect(output).toBe(`h(Canvas, { width: x })`);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
test("should compile component with spread operator", () => {
|
|
105
|
-
const input = `<Canvas ...obj />`;
|
|
106
|
-
const output = parser.parse(input);
|
|
107
|
-
expect(output).toBe(`h(Canvas, obj)`);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
test("should compile component with spread operator object", () => {
|
|
111
|
-
const input = `<Canvas ...obj.prop />`;
|
|
112
|
-
const output = parser.parse(input);
|
|
113
|
-
expect(output).toBe(`h(Canvas, obj.prop)`);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
test("should compile component with spread operator function", () => {
|
|
117
|
-
const input = `<Canvas ...fn() />`;
|
|
118
|
-
const output = parser.parse(input);
|
|
119
|
-
expect(output).toBe(`h(Canvas, fn())`);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
test("should compile component with spread operator function and params", () => {
|
|
123
|
-
const input = `<Canvas ...fn(x, y) />`;
|
|
124
|
-
const output = parser.parse(input);
|
|
125
|
-
expect(output).toBe(`h(Canvas, fn(x, y))`);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
test("should compile component with dynamic attribute but is not a signal", () => {
|
|
129
|
-
const input = `<Canvas width={20} />`;
|
|
130
|
-
const output = parser.parse(input);
|
|
131
|
-
expect(output).toBe(`h(Canvas, { width: 20 })`);
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
test("should compile if/else condition", () => {
|
|
135
|
-
const input = `
|
|
136
|
-
@if (sprite) {
|
|
137
|
-
<Sprite />
|
|
138
|
-
}
|
|
139
|
-
@else {
|
|
140
|
-
<Text text="No sprite" />
|
|
141
|
-
}
|
|
142
|
-
`;
|
|
143
|
-
const output = parser.parse(input);
|
|
144
|
-
expect(output).toBe(`cond(sprite, () => h(Sprite), () => h(Text, { text: 'No sprite' }))`);
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
test("should compile if/else if condition", () => {
|
|
148
|
-
const input = `
|
|
149
|
-
@if (score >= 90) {
|
|
150
|
-
<Text text="A+" />
|
|
151
|
-
}
|
|
152
|
-
@else if (score >= 80) {
|
|
153
|
-
<Text text="A" />
|
|
154
|
-
}
|
|
155
|
-
`;
|
|
156
|
-
const output = parser.parse(input);
|
|
157
|
-
expect(output).toBe(`cond(computed(() => score() >= 90), () => h(Text, { text: 'A+' }), [computed(() => score() >= 80), () => h(Text, { text: 'A' })])`);
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
test("should compile if/else if/else condition", () => {
|
|
161
|
-
const input = `
|
|
162
|
-
@if (score >= 90) {
|
|
163
|
-
<Text text="A+" />
|
|
164
|
-
}
|
|
165
|
-
@else if (score >= 80) {
|
|
166
|
-
<Text text="A" />
|
|
167
|
-
}
|
|
168
|
-
@else {
|
|
169
|
-
<Text text="F" />
|
|
170
|
-
}
|
|
171
|
-
`;
|
|
172
|
-
const output = parser.parse(input);
|
|
173
|
-
expect(output).toBe(`cond(computed(() => score() >= 90), () => h(Text, { text: 'A+' }), [computed(() => score() >= 80), () => h(Text, { text: 'A' })], () => h(Text, { text: 'F' }))`);
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
test("should compile if/else if/else condition within canvas", () => {
|
|
177
|
-
const input = `<Canvas>
|
|
178
|
-
<Container>
|
|
179
|
-
@if (score >= 90) {
|
|
180
|
-
<Text text="Grade: A+" x={100} y={100} color="gold" size={24} />
|
|
181
|
-
<Text text="Excellent work!" x={100} y={130} color="gold" size={16} />
|
|
182
|
-
}
|
|
183
|
-
</Container>
|
|
184
|
-
</Canvas>
|
|
185
|
-
`;
|
|
186
|
-
|
|
187
|
-
const output = parser.parse(input);
|
|
188
|
-
expect(output).toBe(`h(Canvas, null, h(Container, null, cond(computed(() => score() >= 90), () => [h(Text, { text: 'Grade: A+', x: 100, y: 100, color: 'gold', size: 24 }), h(Text, { text: 'Excellent work!', x: 100, y: 130, color: 'gold', size: 16 })])))`);
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
test("should compile multiple else if conditions", () => {
|
|
192
|
-
const input = `
|
|
193
|
-
@if (score >= 90) {
|
|
194
|
-
<Text text="A+" />
|
|
195
|
-
}
|
|
196
|
-
@else if (score >= 80) {
|
|
197
|
-
<Text text="A" />
|
|
198
|
-
}
|
|
199
|
-
@else if (score >= 70) {
|
|
200
|
-
<Text text="B" />
|
|
201
|
-
}
|
|
202
|
-
@else if (score >= 60) {
|
|
203
|
-
<Text text="C" />
|
|
204
|
-
}
|
|
205
|
-
@else {
|
|
206
|
-
<Text text="F" />
|
|
207
|
-
}
|
|
208
|
-
`;
|
|
209
|
-
const output = parser.parse(input);
|
|
210
|
-
expect(output).toBe(`cond(computed(() => score() >= 90), () => h(Text, { text: 'A+' }), [computed(() => score() >= 80), () => h(Text, { text: 'A' })], [computed(() => score() >= 70), () => h(Text, { text: 'B' })], [computed(() => score() >= 60), () => h(Text, { text: 'C' })], () => h(Text, { text: 'F' }))`);
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
test("should compile if/else with multiple elements", () => {
|
|
214
|
-
const input = `
|
|
215
|
-
@if (user.role === 'admin') {
|
|
216
|
-
<Text text="Admin Panel" />
|
|
217
|
-
<Text text="Settings" />
|
|
218
|
-
}
|
|
219
|
-
@else {
|
|
220
|
-
<Text text="Please log in" />
|
|
221
|
-
}
|
|
222
|
-
`;
|
|
223
|
-
const output = parser.parse(input);
|
|
224
|
-
expect(output).toBe(`cond(computed(() => user().role() === 'admin'), () => [h(Text, { text: 'Admin Panel' }), h(Text, { text: 'Settings' })], () => h(Text, { text: 'Please log in' }))`);
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
test("should compile nested if/else conditions", () => {
|
|
228
|
-
const input = `
|
|
229
|
-
@if (user) {
|
|
230
|
-
@if (user.isActive) {
|
|
231
|
-
<Text text="Active user" />
|
|
232
|
-
}
|
|
233
|
-
@else {
|
|
234
|
-
<Text text="Inactive user" />
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
@else {
|
|
238
|
-
<Text text="No user" />
|
|
239
|
-
}
|
|
240
|
-
`;
|
|
241
|
-
const output = parser.parse(input);
|
|
242
|
-
expect(output).toBe(`cond(user, () => cond(user.isActive, () => h(Text, { text: 'Active user' }), () => h(Text, { text: 'Inactive user' })), () => h(Text, { text: 'No user' }))`);
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
test("should compile if/else if with simple conditions", () => {
|
|
246
|
-
const input = `
|
|
247
|
-
@if (theme === 'dark') {
|
|
248
|
-
<Text text="Dark mode" />
|
|
249
|
-
}
|
|
250
|
-
@else if (theme === 'light') {
|
|
251
|
-
<Text text="Light mode" />
|
|
252
|
-
}
|
|
253
|
-
@else {
|
|
254
|
-
<Text text="Auto mode" />
|
|
255
|
-
}
|
|
256
|
-
`;
|
|
257
|
-
const output = parser.parse(input);
|
|
258
|
-
expect(output).toBe(`cond(computed(() => theme() === 'dark'), () => h(Text, { text: 'Dark mode' }), [computed(() => theme() === 'light'), () => h(Text, { text: 'Light mode' })], () => h(Text, { text: 'Auto mode' }))`);
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
test("should compile if/else with function conditions", () => {
|
|
262
|
-
const input = `
|
|
263
|
-
@if (isVisible()) {
|
|
264
|
-
<Sprite />
|
|
265
|
-
}
|
|
266
|
-
@else {
|
|
267
|
-
<Text text="Hidden" />
|
|
268
|
-
}
|
|
269
|
-
`;
|
|
270
|
-
const output = parser.parse(input);
|
|
271
|
-
expect(output).toBe(`cond(isVisible(), () => h(Sprite), () => h(Text, { text: 'Hidden' }))`);
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
test("should compile if/else if with object property conditions", () => {
|
|
275
|
-
const input = `
|
|
276
|
-
@if (sprite.visible) {
|
|
277
|
-
<Sprite />
|
|
278
|
-
}
|
|
279
|
-
@else if (sprite.loading) {
|
|
280
|
-
<Text text="Loading..." />
|
|
281
|
-
}
|
|
282
|
-
@else {
|
|
283
|
-
<Text text="Not available" />
|
|
284
|
-
}
|
|
285
|
-
`;
|
|
286
|
-
const output = parser.parse(input);
|
|
287
|
-
expect(output).toBe(`cond(sprite.visible, () => h(Sprite), [sprite.loading, () => h(Text, { text: 'Loading...' })], () => h(Text, { text: 'Not available' }))`);
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
test("should compile component with templating string", () => {
|
|
291
|
-
const input = `<Canvas width={\`direction: \${direction}\`} />`;
|
|
292
|
-
const output = parser.parse(input);
|
|
293
|
-
expect(output).toBe(`h(Canvas, { width: \`direction: \${direction()}\` })`);
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
test("should compile component with templating string with @ (literal)", () => {
|
|
297
|
-
const input = `<Canvas width={\`direction: \${@direction}\`} />`;
|
|
298
|
-
const output = parser.parse(input);
|
|
299
|
-
expect(output).toBe(`h(Canvas, { width: \`direction: \${direction}\` })`);
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
test("should compile component with object attribute", () => {
|
|
303
|
-
const input = `<Canvas width={ {x: 10, y: 20} } />`;
|
|
304
|
-
const output = parser.parse(input);
|
|
305
|
-
expect(output).toBe(`h(Canvas, { width: { x: 10, y: 20 } })`);
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
test("should compile component with complex object attribute", () => {
|
|
309
|
-
const input = `<Sprite
|
|
310
|
-
sheet={{
|
|
311
|
-
definition,
|
|
312
|
-
playing: "stand",
|
|
313
|
-
params: {
|
|
314
|
-
direction: "right"
|
|
315
|
-
},
|
|
316
|
-
onFinish
|
|
317
|
-
}}
|
|
318
|
-
/>`;
|
|
319
|
-
const output = parser.parse(input);
|
|
320
|
-
expect(output).toBe(`h(Sprite, { sheet: { definition, playing: "stand", params: { direction: "right" }, onFinish } })`);
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
test("should compile component with deep object attribute", () => {
|
|
324
|
-
const input = `<Canvas width={deep.value} />`;
|
|
325
|
-
const output = parser.parse(input);
|
|
326
|
-
expect(output).toBe(`h(Canvas, { width: computed(() => deep().value()) })`);
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
test('should compile component with deep object attribute', () => {
|
|
330
|
-
const input = `<Button
|
|
331
|
-
style={{
|
|
332
|
-
backgroundColor: {
|
|
333
|
-
normal: "#6c757d",
|
|
334
|
-
hover: "#5a6268",
|
|
335
|
-
pressed: "#545b62"
|
|
336
|
-
},
|
|
337
|
-
text: {
|
|
338
|
-
fontSize: 16,
|
|
339
|
-
color: "#ffffff"
|
|
340
|
-
}
|
|
341
|
-
}}
|
|
342
|
-
/>`;
|
|
343
|
-
const output = parser.parse(input);
|
|
344
|
-
expect(output).toBe(`h(Button, { style: { backgroundColor: { normal: "#6c757d", hover: "#5a6268", pressed: "#545b62" }, text: { fontSize: 16, color: "#ffffff" } } })`);
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
test('should compile component with deep object attribute and shorthand', () => {
|
|
348
|
-
const input = `<Canvas>
|
|
349
|
-
<Container>
|
|
350
|
-
<Sprite x y sheet={{
|
|
351
|
-
definition,
|
|
352
|
-
playing: animationPlaying,
|
|
353
|
-
params: {
|
|
354
|
-
direction
|
|
355
|
-
}
|
|
356
|
-
}}
|
|
357
|
-
controls />
|
|
358
|
-
</Container>
|
|
359
|
-
</Canvas>
|
|
360
|
-
`;
|
|
361
|
-
const output = parser.parse(input);
|
|
362
|
-
expect(output).toBe(`h(Canvas, null, h(Container, null, h(Sprite, { x, y, sheet: { definition, playing: animationPlaying, params: { direction } }, controls })))`);
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
test("should compile component with deep object attribute but not transform to signal", () => {
|
|
366
|
-
const input = `<Canvas width={@deep.value} />`;
|
|
367
|
-
const output = parser.parse(input);
|
|
368
|
-
expect(output).toBe(`h(Canvas, { width: computed(() => deep.value()) })`);
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
test("should compile component with deep object attribute but not all transform to signal", () => {
|
|
372
|
-
const input = `<Canvas width={@deep.@value} />`;
|
|
373
|
-
const output = parser.parse(input);
|
|
374
|
-
expect(output).toBe(`h(Canvas, { width: deep.value })`);
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
test("should compile component with dynamic object attribute", () => {
|
|
378
|
-
const input = `<Canvas width={ {x: x, y: 20} } />`;
|
|
379
|
-
const output = parser.parse(input);
|
|
380
|
-
expect(output).toBe(`h(Canvas, { width: { x: x, y: 20 } })`);
|
|
381
|
-
});
|
|
382
|
-
|
|
383
|
-
test("should compile component with array attribute", () => {
|
|
384
|
-
const input = `<Canvas width={ [10, 20] } />`;
|
|
385
|
-
const output = parser.parse(input);
|
|
386
|
-
expect(output).toBe(`h(Canvas, { width: [10, 20] })`);
|
|
387
|
-
});
|
|
388
|
-
|
|
389
|
-
test("should compile component with dynamic array attribute", () => {
|
|
390
|
-
const input = `<Canvas width={ [x, 20] } />`;
|
|
391
|
-
const output = parser.parse(input);
|
|
392
|
-
expect(output).toBe(`h(Canvas, { width: [x, 20] })`);
|
|
393
|
-
});
|
|
394
|
-
|
|
395
|
-
test("should compile component with standalone dynamic attribute", () => {
|
|
396
|
-
const input = `<Canvas width />`;
|
|
397
|
-
const output = parser.parse(input);
|
|
398
|
-
expect(output).toBe(`h(Canvas, { width })`);
|
|
399
|
-
});
|
|
400
|
-
|
|
401
|
-
test("should compile component with computed dynamic attribute", () => {
|
|
402
|
-
const input = `<Canvas width={x * 2} />`;
|
|
403
|
-
const output = parser.parse(input);
|
|
404
|
-
expect(output).toBe(`h(Canvas, { width: computed(() => x() * 2) })`);
|
|
405
|
-
});
|
|
406
|
-
|
|
407
|
-
test("should compile component with multiple computed dynamic attributes", () => {
|
|
408
|
-
const input = `<Canvas width={x * 2 * y} />`;
|
|
409
|
-
const output = parser.parse(input);
|
|
410
|
-
expect(output).toBe(`h(Canvas, { width: computed(() => x() * 2 * y()) })`);
|
|
411
|
-
});
|
|
412
|
-
|
|
413
|
-
test("should compile component with static string attribute", () => {
|
|
414
|
-
const input = `<Canvas width="val" />`;
|
|
415
|
-
const output = parser.parse(input);
|
|
416
|
-
expect(output).toBe(`h(Canvas, { width: 'val' })`);
|
|
417
|
-
});
|
|
418
|
-
|
|
419
|
-
test("should compile component with static string attribute with dash", () => {
|
|
420
|
-
const input = `<Canvas max-width="val" />`;
|
|
421
|
-
const output = parser.parse(input);
|
|
422
|
-
expect(output).toBe(`h(Canvas, { 'max-width': 'val' })`);
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
test("should compile component with static attribute (with number)", () => {
|
|
426
|
-
const input = `<Canvas width="10" />`;
|
|
427
|
-
const output = parser.parse(input);
|
|
428
|
-
expect(output).toBe(`h(Canvas, { width: '10' })`);
|
|
429
|
-
});
|
|
430
|
-
|
|
431
|
-
test("should compile component with children", () => {
|
|
432
|
-
const input = `
|
|
433
|
-
<Canvas>
|
|
434
|
-
<Sprite />
|
|
435
|
-
<Text />
|
|
436
|
-
</Canvas>
|
|
437
|
-
`;
|
|
438
|
-
const output = parser.parse(input);
|
|
439
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
440
|
-
`h(Canvas,null,[h(Sprite),h(Text)])`.replace(/\s+/g, "")
|
|
441
|
-
);
|
|
442
|
-
});
|
|
443
|
-
|
|
444
|
-
test("should compile component with multiple children", () => {
|
|
445
|
-
const input = `<Container>
|
|
446
|
-
<Container></Container>
|
|
447
|
-
<Container></Container>
|
|
448
|
-
</Container>
|
|
449
|
-
`;
|
|
450
|
-
const output = parser.parse(input);
|
|
451
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
452
|
-
`h(Container,null,[h(Container),h(Container)])`.replace(/\s+/g, "")
|
|
453
|
-
);
|
|
454
|
-
});
|
|
455
|
-
|
|
456
|
-
test("should compile component with multi children", () => {
|
|
457
|
-
const input = `
|
|
458
|
-
<Sprite />
|
|
459
|
-
<Sprite />
|
|
460
|
-
`;
|
|
461
|
-
const output = parser.parse(input);
|
|
462
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
463
|
-
`[h(Sprite),h(Sprite)]`.replace(/\s+/g, "")
|
|
464
|
-
);
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
test("should compile component with event handler", () => {
|
|
468
|
-
const input = `<Sprite click={fn} />`;
|
|
469
|
-
const output = parser.parse(input);
|
|
470
|
-
expect(output).toBe(`h(Sprite, { click: fn })`);
|
|
471
|
-
});
|
|
472
|
-
|
|
473
|
-
test("should compile component with standalone event handler", () => {
|
|
474
|
-
const input = `<Sprite click />`;
|
|
475
|
-
const output = parser.parse(input);
|
|
476
|
-
expect(output).toBe(`h(Sprite, { click })`);
|
|
477
|
-
});
|
|
478
|
-
|
|
479
|
-
test('should compile component with inline event handler', () => {
|
|
480
|
-
const input = `<Sprite click={() => console.log('click')} />`;
|
|
481
|
-
const output = parser.parse(input);
|
|
482
|
-
expect(output).toBe(`h(Sprite, { click: () => console.log('click') })`);
|
|
483
|
-
});
|
|
484
|
-
|
|
485
|
-
test("should compile component with component attribute", () => {
|
|
486
|
-
const input = `<Canvas child={<Sprite />} />`;
|
|
487
|
-
const output = parser.parse(input);
|
|
488
|
-
expect(output).toBe(`h(Canvas, { child: h(Sprite) })`);
|
|
489
|
-
});
|
|
490
|
-
|
|
491
|
-
test("should compile component with function returns component attribute", () => {
|
|
492
|
-
const input = `<Canvas child={() => <Sprite />} />`;
|
|
493
|
-
const output = parser.parse(input);
|
|
494
|
-
expect(output).toBe(`h(Canvas, { child: () => h(Sprite) })`);
|
|
495
|
-
});
|
|
496
|
-
|
|
497
|
-
test("should compile component with function (with params) returns component attribute", () => {
|
|
498
|
-
const input = `<Canvas child={(x, y) => <Sprite />} />`;
|
|
499
|
-
const output = parser.parse(input);
|
|
500
|
-
expect(output).toBe(`h(Canvas, { child: (x, y) => h(Sprite) })`);
|
|
501
|
-
});
|
|
502
|
-
|
|
503
|
-
test("should compile component with destructuring function (with params)", () => {
|
|
504
|
-
const input = `<Canvas child={({ x, y }) => <Sprite />} />`;
|
|
505
|
-
const output = parser.parse(input);
|
|
506
|
-
expect(output).toBe(`h(Canvas, { child: ({x, y}) => h(Sprite) })`);
|
|
507
|
-
});
|
|
508
|
-
|
|
509
|
-
test("should compile component with function returns component attribute and data", () => {
|
|
510
|
-
const input = `<Canvas child={() => <Text text="Hello" />} />`;
|
|
511
|
-
const output = parser.parse(input);
|
|
512
|
-
expect(output).toBe(`h(Canvas, { child: () => h(Text, { text: 'Hello' }) })`);
|
|
513
|
-
});
|
|
514
|
-
|
|
515
|
-
test("should compile component with function returns component attribute and child", () => {
|
|
516
|
-
const input = `<Canvas child={() => <Container>
|
|
517
|
-
<Text text="Hello" />
|
|
518
|
-
</Container>} />`;
|
|
519
|
-
const output = parser.parse(input);
|
|
520
|
-
expect(output).toBe(`h(Canvas, { child: () => h(Container, null, h(Text, { text: 'Hello' })) })`);
|
|
521
|
-
});
|
|
522
|
-
|
|
523
|
-
test("should compile component with function returns component attribute and children", () => {
|
|
524
|
-
const input = `<Canvas child={() => <Container>
|
|
525
|
-
<Text text="Hello 1" />
|
|
526
|
-
<Text text="Hello 2" />
|
|
527
|
-
</Container>} />`;
|
|
528
|
-
const output = parser.parse(input);
|
|
529
|
-
expect(output).toBe(`h(Canvas, { child: () => h(Container, null, [h(Text, { text: 'Hello 1' }), h(Text, { text: 'Hello 2' })]) })`);
|
|
530
|
-
});
|
|
531
|
-
});
|
|
532
|
-
|
|
533
|
-
describe("Loop", () => {
|
|
534
|
-
test("loop in canvas", () => {
|
|
535
|
-
const input = `
|
|
536
|
-
<Canvas>
|
|
537
|
-
@for (sprite of sprites) {
|
|
538
|
-
<Sprite />
|
|
539
|
-
}
|
|
540
|
-
</Canvas>
|
|
541
|
-
`;
|
|
542
|
-
const output = parser.parse(input);
|
|
543
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
544
|
-
`h(Canvas,null,loop(sprites,sprite=>h(Sprite)))`.replace(/\s+/g, "")
|
|
545
|
-
);
|
|
546
|
-
});
|
|
547
|
-
|
|
548
|
-
test("should compile loop", () => {
|
|
549
|
-
const input = `
|
|
550
|
-
@for (sprite of sprites) {
|
|
551
|
-
<Sprite />
|
|
552
|
-
}
|
|
553
|
-
`;
|
|
554
|
-
const output = parser.parse(input);
|
|
555
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
556
|
-
`loop(sprites,sprite=>h(Sprite))`.replace(/\s+/g, "")
|
|
557
|
-
);
|
|
558
|
-
});
|
|
559
|
-
|
|
560
|
-
test("should compile loop with object", () => {
|
|
561
|
-
const input = `
|
|
562
|
-
@for (sprite of sprites.items) {
|
|
563
|
-
<Sprite />
|
|
564
|
-
}
|
|
565
|
-
`;
|
|
566
|
-
const output = parser.parse(input);
|
|
567
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
568
|
-
`loop(sprites.items,sprite=>h(Sprite))`.replace(/\s+/g, "")
|
|
569
|
-
);
|
|
570
|
-
});
|
|
571
|
-
|
|
572
|
-
test("should compile loop with deep object", () => {
|
|
573
|
-
const input = `
|
|
574
|
-
@for (sprite of sprites.items.items) {
|
|
575
|
-
<Sprite />
|
|
576
|
-
}
|
|
577
|
-
`;
|
|
578
|
-
const output = parser.parse(input);
|
|
579
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
580
|
-
`loop(sprites.items.items,sprite=>h(Sprite))`.replace(/\s+/g, "")
|
|
581
|
-
);
|
|
582
|
-
});
|
|
583
|
-
|
|
584
|
-
test("should compile loop with function", () => {
|
|
585
|
-
const input = `
|
|
586
|
-
@for (sprite of sprites()) {
|
|
587
|
-
<Sprite />
|
|
588
|
-
}
|
|
589
|
-
`;
|
|
590
|
-
const output = parser.parse(input);
|
|
591
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
592
|
-
`loop(sprites(),sprite=>h(Sprite))`.replace(/\s+/g, "")
|
|
593
|
-
);
|
|
594
|
-
});
|
|
595
|
-
|
|
596
|
-
test("should compile loop with function and params", () => {
|
|
597
|
-
const input = `
|
|
598
|
-
@for (sprite of sprites(x, y)) {
|
|
599
|
-
<Sprite />
|
|
600
|
-
}
|
|
601
|
-
`;
|
|
602
|
-
const output = parser.parse(input);
|
|
603
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
604
|
-
`loop(sprites(x,y),sprite=>h(Sprite))`.replace(/\s+/g, "")
|
|
605
|
-
);
|
|
606
|
-
});
|
|
607
|
-
|
|
608
|
-
test("should compile loop with object and function and params", () => {
|
|
609
|
-
const input = `
|
|
610
|
-
@for (sprite of sprites.items(x, y)) {
|
|
611
|
-
<Sprite />
|
|
612
|
-
}
|
|
613
|
-
`;
|
|
614
|
-
const output = parser.parse(input);
|
|
615
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
616
|
-
`loop(sprites.items(x,y),sprite=>h(Sprite))`.replace(/\s+/g, "")
|
|
617
|
-
);
|
|
618
|
-
});
|
|
619
|
-
|
|
620
|
-
test("should compile loop with destructuring", () => {
|
|
621
|
-
const input = `
|
|
622
|
-
@for ((sprite, index) of sprites) {
|
|
623
|
-
<Sprite key={index} />
|
|
624
|
-
}
|
|
625
|
-
`;
|
|
626
|
-
const output = parser.parse(input);
|
|
627
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
628
|
-
`loop(sprites,(sprite,index)=>h(Sprite, { key: index }))`.replace(/\s+/g, "")
|
|
629
|
-
);
|
|
630
|
-
});
|
|
631
|
-
|
|
632
|
-
test("should compile nestedloop", () => {
|
|
633
|
-
const input = `
|
|
634
|
-
@for (sprite of sprites) {
|
|
635
|
-
@for (other of others) {
|
|
636
|
-
<Sprite />
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
`;
|
|
640
|
-
const output = parser.parse(input);
|
|
641
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
642
|
-
`loop(sprites,sprite=>loop(others,other=>h(Sprite)))`.replace(
|
|
643
|
-
/\s+/g,
|
|
644
|
-
""
|
|
645
|
-
)
|
|
646
|
-
);
|
|
647
|
-
});
|
|
648
|
-
});
|
|
649
|
-
|
|
650
|
-
describe("Condition", () => {
|
|
651
|
-
test("should compile condition", () => {
|
|
652
|
-
const input = `
|
|
653
|
-
@if (sprite) {
|
|
654
|
-
<Sprite />
|
|
655
|
-
}
|
|
656
|
-
`;
|
|
657
|
-
const output = parser.parse(input);
|
|
658
|
-
expect(output).toBe(`cond(sprite, () => h(Sprite))`);
|
|
659
|
-
});
|
|
660
|
-
|
|
661
|
-
test("should compile negative condition", () => {
|
|
662
|
-
const input = `
|
|
663
|
-
@if (!sprite) {
|
|
664
|
-
<Sprite />
|
|
665
|
-
}
|
|
666
|
-
`;
|
|
667
|
-
const output = parser.parse(input);
|
|
668
|
-
expect(output).toBe(`cond(computed(() => !sprite()), () => h(Sprite))`);
|
|
669
|
-
});
|
|
670
|
-
|
|
671
|
-
test("should compile negative condition with multiple condition", () => {
|
|
672
|
-
const input = `
|
|
673
|
-
@if (!sprite && other) {
|
|
674
|
-
<Sprite />
|
|
675
|
-
}
|
|
676
|
-
`;
|
|
677
|
-
const output = parser.parse(input);
|
|
678
|
-
expect(output).toBe(`cond(computed(() => !sprite() && other()), () => h(Sprite))`);
|
|
679
|
-
});
|
|
680
|
-
|
|
681
|
-
test("should compile negative condition with multiple condition (or)", () => {
|
|
682
|
-
const input = `
|
|
683
|
-
@if (!sprite || other) {
|
|
684
|
-
<Sprite />
|
|
685
|
-
}
|
|
686
|
-
`;
|
|
687
|
-
const output = parser.parse(input);
|
|
688
|
-
expect(output).toBe(`cond(computed(() => !sprite() || other()), () => h(Sprite))`);
|
|
689
|
-
});
|
|
690
|
-
|
|
691
|
-
test("should compile condition when sprite is visible", () => {
|
|
692
|
-
const input = `
|
|
693
|
-
@if (sprite.visible) {
|
|
694
|
-
<Sprite />
|
|
695
|
-
}
|
|
696
|
-
`;
|
|
697
|
-
const output = parser.parse(input);
|
|
698
|
-
expect(output).toBe(`cond(sprite.visible, () => h(Sprite))`);
|
|
699
|
-
});
|
|
700
|
-
|
|
701
|
-
test("should compile condition when function value", () => {
|
|
702
|
-
const input = `
|
|
703
|
-
@if (val()) {
|
|
704
|
-
<Sprite />
|
|
705
|
-
}
|
|
706
|
-
`;
|
|
707
|
-
const output = parser.parse(input);
|
|
708
|
-
expect(output).toBe(`cond(val(), () => h(Sprite))`);
|
|
709
|
-
});
|
|
710
|
-
|
|
711
|
-
test("should compile condition for multiple sprites", () => {
|
|
712
|
-
const input = `
|
|
713
|
-
@if (sprite) {
|
|
714
|
-
<Sprite />
|
|
715
|
-
}
|
|
716
|
-
@if (other) {
|
|
717
|
-
<Sprite />
|
|
718
|
-
}
|
|
719
|
-
`;
|
|
720
|
-
const output = parser.parse(input);
|
|
721
|
-
expect(output).toBe(
|
|
722
|
-
`[cond(sprite, () => h(Sprite)),cond(other, () => h(Sprite))]`
|
|
723
|
-
);
|
|
724
|
-
});
|
|
725
|
-
|
|
726
|
-
test("should compile nested condition when sprite is visible", () => {
|
|
727
|
-
const input = `
|
|
728
|
-
@if (sprite.visible) {
|
|
729
|
-
@if (deep) {
|
|
730
|
-
<Sprite />
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
`;
|
|
734
|
-
const output = parser.parse(input);
|
|
735
|
-
expect(output).toBe(
|
|
736
|
-
`cond(sprite.visible, () => cond(deep, () => h(Sprite)))`
|
|
737
|
-
);
|
|
738
|
-
});
|
|
739
|
-
|
|
740
|
-
test("should compile condition with nested sprite when sprite is visible", () => {
|
|
741
|
-
const input = `
|
|
742
|
-
@if (sprite.visible) {
|
|
743
|
-
<Sprite />
|
|
744
|
-
@if (deep) {
|
|
745
|
-
<Sprite />
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
`;
|
|
749
|
-
const output = parser.parse(input);
|
|
750
|
-
expect(output).toBe(
|
|
751
|
-
`cond(sprite.visible, () => [h(Sprite), cond(deep, () => h(Sprite))])`
|
|
752
|
-
);
|
|
753
|
-
});
|
|
754
|
-
|
|
755
|
-
test("should compile condition with multiple sprites when sprite is visible", () => {
|
|
756
|
-
const input = `
|
|
757
|
-
@if (sprite.visible) {
|
|
758
|
-
<Sprite />
|
|
759
|
-
@if (deep) {
|
|
760
|
-
<Sprite />
|
|
761
|
-
}
|
|
762
|
-
<Sprite />
|
|
763
|
-
}
|
|
764
|
-
`;
|
|
765
|
-
const output = parser.parse(input);
|
|
766
|
-
expect(output).toBe(
|
|
767
|
-
`cond(sprite.visible, () => [h(Sprite), cond(deep, () => h(Sprite)), h(Sprite)])`
|
|
768
|
-
);
|
|
769
|
-
});
|
|
770
|
-
|
|
771
|
-
test("should compile if/else within canvas", () => {
|
|
772
|
-
const input = `
|
|
773
|
-
<Canvas>
|
|
774
|
-
@if (showSprite) {
|
|
775
|
-
<Sprite />
|
|
776
|
-
}
|
|
777
|
-
@else {
|
|
778
|
-
<Text text="No sprite" />
|
|
779
|
-
}
|
|
780
|
-
</Canvas>
|
|
781
|
-
`;
|
|
782
|
-
const output = parser.parse(input);
|
|
783
|
-
expect(output).toBe(
|
|
784
|
-
`h(Canvas, null, cond(showSprite, () => h(Sprite), () => h(Text, { text: 'No sprite' })))`
|
|
785
|
-
);
|
|
786
|
-
});
|
|
787
|
-
|
|
788
|
-
test("should compile if/else if/else within loop", () => {
|
|
789
|
-
const input = `
|
|
790
|
-
@for (item of items) {
|
|
791
|
-
@if (item.type === 'sprite') {
|
|
792
|
-
<Sprite />
|
|
793
|
-
}
|
|
794
|
-
@else if (item.type === 'text') {
|
|
795
|
-
<Text />
|
|
796
|
-
}
|
|
797
|
-
@else {
|
|
798
|
-
<Container />
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
`;
|
|
802
|
-
const output = parser.parse(input);
|
|
803
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
804
|
-
`loop(items,item=>cond(computed(()=>item().type()==='sprite'),()=>h(Sprite),[computed(()=>item().type()==='text'),()=>h(Text)],()=>h(Container)))`.replace(/\s+/g, "")
|
|
805
|
-
);
|
|
806
|
-
});
|
|
807
|
-
});
|
|
808
|
-
|
|
809
|
-
describe("Condition in Loops", () => {
|
|
810
|
-
test("should compile condition within a loop", () => { // New test for condition in a loop
|
|
811
|
-
const input = `
|
|
812
|
-
<Canvas>
|
|
813
|
-
@for (sprite of sprites) {
|
|
814
|
-
@if (sprite.visible) {
|
|
815
|
-
<Sprite />
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
</Canvas>
|
|
819
|
-
`;
|
|
820
|
-
const output = parser.parse(input);
|
|
821
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
822
|
-
`h(Canvas,null,loop(sprites,sprite=>cond(sprite.visible,()=>h(Sprite))))`.replace(/\s+/g, "")
|
|
823
|
-
);
|
|
824
|
-
});
|
|
825
|
-
|
|
826
|
-
test("should compile elements within a loop", () => { // New test for elements in a loop
|
|
827
|
-
const input = `
|
|
828
|
-
<Canvas>
|
|
829
|
-
@for (sprite of sprites) {
|
|
830
|
-
<Sprite />
|
|
831
|
-
}
|
|
832
|
-
</Canvas>
|
|
833
|
-
`;
|
|
834
|
-
const output = parser.parse(input);
|
|
835
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
836
|
-
`h(Canvas,null,loop(sprites,sprite=>h(Sprite)))`.replace(/\s+/g, "")
|
|
837
|
-
);
|
|
838
|
-
});
|
|
839
|
-
|
|
840
|
-
test("should compile multiple loops at the same level", () => { // New test for multiple loops
|
|
841
|
-
const input = `
|
|
842
|
-
<Canvas>
|
|
843
|
-
@for (sprite of sprites) {
|
|
844
|
-
<Sprite />
|
|
845
|
-
}
|
|
846
|
-
@for (other of others) {
|
|
847
|
-
<Sprite />
|
|
848
|
-
}
|
|
849
|
-
</Canvas>
|
|
850
|
-
`;
|
|
851
|
-
const output = parser.parse(input);
|
|
852
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
853
|
-
`h(Canvas,null,[loop(sprites,sprite=>h(Sprite)),loop(others,other=>h(Sprite))])`.replace(/\s+/g, "")
|
|
854
|
-
);
|
|
855
|
-
});
|
|
856
|
-
|
|
857
|
-
});
|
|
858
|
-
|
|
859
|
-
describe('Svg', () => {
|
|
860
|
-
test('should compile svg', () => {
|
|
861
|
-
const input = `<svg>
|
|
862
|
-
<path d="M 100 350 l 150 -300" stroke="red" stroke-width="4"/>
|
|
863
|
-
</svg>`;
|
|
864
|
-
const output = parser.parse(input);
|
|
865
|
-
expect(output).toBe('h(Svg, { content: `<svg><path d="M 100 350 l 150 -300" stroke="red" stroke-width="4"/></svg>` })');
|
|
866
|
-
});
|
|
867
|
-
|
|
868
|
-
test('should compile svg with canvas', () => {
|
|
869
|
-
const input = `<Canvas antialias={true}>
|
|
870
|
-
<svg height="400" width="450" xmlns="http://www.w3.org/2000/svg"></svg></Canvas>`;
|
|
871
|
-
const output = parser.parse(input);
|
|
872
|
-
expect(output).toBe('h(Canvas, { antialias: true }, h(Svg, { content: `<svg height="400" width="450" xmlns="http://www.w3.org/2000/svg"></svg>` }))');
|
|
873
|
-
});
|
|
874
|
-
});
|
|
875
|
-
|
|
876
|
-
describe('DOM', () => {
|
|
877
|
-
test('should compile input DOM', () => {
|
|
878
|
-
const input = `<input type="text" />`;
|
|
879
|
-
const output = parser.parse(input);
|
|
880
|
-
expect(output).toBe('h(DOMElement, { element: "input", attrs: { type: \'text\' } })');
|
|
881
|
-
});
|
|
882
|
-
|
|
883
|
-
test('should compile div DOM', () => {
|
|
884
|
-
const input = `<div class="container" />`;
|
|
885
|
-
const output = parser.parse(input);
|
|
886
|
-
expect(output).toBe('h(DOMElement, { element: "div", attrs: { class: \'container\' } })');
|
|
887
|
-
});
|
|
888
|
-
|
|
889
|
-
test('should compile button DOM', () => {
|
|
890
|
-
const input = `<button type="submit" />`;
|
|
891
|
-
const output = parser.parse(input);
|
|
892
|
-
expect(output).toBe('h(DOMElement, { element: "button", attrs: { type: \'submit\' } })');
|
|
893
|
-
});
|
|
894
|
-
|
|
895
|
-
test('should compile button DOM', () => {
|
|
896
|
-
const input = `<button>Text</button>`;
|
|
897
|
-
const output = parser.parse(input);
|
|
898
|
-
expect(output).toBe('h(DOMElement, { element: "button", textContent: \'Text\' })');
|
|
899
|
-
});
|
|
900
|
-
|
|
901
|
-
test('should compile textarea DOM with dynamic attributes', () => {
|
|
902
|
-
const input = `<textarea rows={rows} cols={cols} />`;
|
|
903
|
-
const output = parser.parse(input);
|
|
904
|
-
expect(output).toBe('h(DOMElement, { element: "textarea", attrs: { rows: rows, cols: cols } })');
|
|
905
|
-
});
|
|
906
|
-
|
|
907
|
-
test('should not transform Canvas to DOM', () => {
|
|
908
|
-
const input = `<Canvas width={800} />`;
|
|
909
|
-
const output = parser.parse(input);
|
|
910
|
-
expect(output).toBe('h(Canvas, { width: 800 })');
|
|
911
|
-
});
|
|
912
|
-
|
|
913
|
-
test('should not transform Sprite to DOM', () => {
|
|
914
|
-
const input = `<Sprite image="test.png" />`;
|
|
915
|
-
const output = parser.parse(input);
|
|
916
|
-
expect(output).toBe('h(Sprite, { image: \'test.png\' })');
|
|
917
|
-
});
|
|
918
|
-
|
|
919
|
-
// Tests avec imbrications DOM
|
|
920
|
-
test('should compile nested DOM elements', () => {
|
|
921
|
-
const input = `<div class="container">
|
|
922
|
-
<p>Hello World</p>
|
|
923
|
-
</div>`;
|
|
924
|
-
const output = parser.parse(input);
|
|
925
|
-
expect(output).toBe('h(DOMElement, { element: "div", attrs: { class: \'container\' } }, h(DOMElement, { element: "p", textContent: \'Hello World\' }))');
|
|
926
|
-
});
|
|
927
|
-
|
|
928
|
-
test('should compile deeply nested DOM elements', () => {
|
|
929
|
-
const input = `<div class="wrapper">
|
|
930
|
-
<section>
|
|
931
|
-
<h1>Title</h1>
|
|
932
|
-
<p>Content</p>
|
|
933
|
-
</section>
|
|
934
|
-
</div>`;
|
|
935
|
-
const output = parser.parse(input);
|
|
936
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
937
|
-
`h(DOMElement, { element: "div", attrs: { class: 'wrapper' } }, h(DOMElement, { element: "section" }, [h(DOMElement, { element: "h1", textContent: 'Title' }), h(DOMElement, { element: "p", textContent: 'Content' })]))`.replace(/\s+/g, "")
|
|
938
|
-
);
|
|
939
|
-
});
|
|
940
|
-
|
|
941
|
-
test('should compile DOM with multiple children', () => {
|
|
942
|
-
const input = `<ul>
|
|
943
|
-
<li>Item 1</li>
|
|
944
|
-
<li>Item 2</li>
|
|
945
|
-
<li>Item 3</li>
|
|
946
|
-
</ul>`;
|
|
947
|
-
const output = parser.parse(input);
|
|
948
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
949
|
-
`h(DOMElement, { element: "ul" }, [h(DOMElement, { element: "li", textContent: 'Item 1' }), h(DOMElement, { element: "li", textContent: 'Item 2' }), h(DOMElement, { element: "li", textContent: 'Item 3' })])`.replace(/\s+/g, "")
|
|
950
|
-
);
|
|
951
|
-
});
|
|
952
|
-
|
|
953
|
-
test('should compile mixed DOM and framework components', () => {
|
|
954
|
-
const input = `<div class="game-container">
|
|
955
|
-
<Canvas width={800} height={600} />
|
|
956
|
-
<div class="ui">
|
|
957
|
-
<button>Start Game</button>
|
|
958
|
-
</div>
|
|
959
|
-
</div>`;
|
|
960
|
-
const output = parser.parse(input);
|
|
961
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
962
|
-
`h(DOMElement, { element: "div", attrs: { class: 'game-container' } }, [h(Canvas, { width: 800, height: 600 }), h(DOMElement, { element: "div", attrs: { class: 'ui' } }, h(DOMElement, { element: "button", textContent: 'Start Game' }))])`.replace(/\s+/g, "")
|
|
963
|
-
);
|
|
964
|
-
});
|
|
965
|
-
|
|
966
|
-
test('should compile DOM with attributes and text content', () => {
|
|
967
|
-
const input = `<button class="btn primary" type="submit">Submit Form</button>`;
|
|
968
|
-
const output = parser.parse(input);
|
|
969
|
-
expect(output).toBe('h(DOMElement, { element: "button", attrs: { class: \'btn primary\', type: \'submit\' }, textContent: \'Submit Form\' })');
|
|
970
|
-
});
|
|
971
|
-
});
|
|
972
|
-
|
|
973
|
-
describe('DOM with special attributes', () => {
|
|
974
|
-
test('should compile DOM with special attributes', () => {
|
|
975
|
-
const input = `<input type="password" x={100} y={100} />`;
|
|
976
|
-
const output = parser.parse(input);
|
|
977
|
-
expect(output).toBe('h(DOMElement, { element: "input", attrs: { type: \'password\' }, x: 100, y: 100 })');
|
|
978
|
-
});
|
|
979
|
-
|
|
980
|
-
test('should compile DOM with text object', () => {
|
|
981
|
-
const input = `<p>{{ object.x }}</p>`;
|
|
982
|
-
const output = parser.parse(input);
|
|
983
|
-
expect(output).toBe('h(DOMElement, { element: "p", textContent: computed(() => object().x()) })');
|
|
984
|
-
});
|
|
985
|
-
|
|
986
|
-
test('should compile DOM with text object with @', () => {
|
|
987
|
-
const input = `<p>{{ @object.x }}</p>`;
|
|
988
|
-
const output = parser.parse(input);
|
|
989
|
-
expect(output).toBe('h(DOMElement, { element: "p", textContent: computed(() => object.x()) })');
|
|
990
|
-
});
|
|
991
|
-
|
|
992
|
-
test('should compile DOM with text object with literal ', () => {
|
|
993
|
-
const input = `<p>{{ @object.@x }}</p>`;
|
|
994
|
-
const output = parser.parse(input);
|
|
995
|
-
expect(output).toBe('h(DOMElement, { element: "p", textContent: object.x })');
|
|
996
|
-
});
|
|
997
|
-
});
|
|
998
|
-
|
|
999
|
-
describe('DOM with Control Structures', () => {
|
|
1000
|
-
test('should compile @for loop with DOM elements', () => {
|
|
1001
|
-
const input = `
|
|
1002
|
-
@for (item of items) {
|
|
1003
|
-
<li>{item.name}</li>
|
|
1004
|
-
}
|
|
1005
|
-
`;
|
|
1006
|
-
const output = parser.parse(input);
|
|
1007
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
1008
|
-
`loop(items, item => h(DOMElement, { element: "li", textContent: computed(() => item().name()) }))`.replace(/\s+/g, "")
|
|
1009
|
-
);
|
|
1010
|
-
});
|
|
1011
|
-
|
|
1012
|
-
test('Use literal text content', () => {
|
|
1013
|
-
const input = `
|
|
1014
|
-
<p>{@text}</p>
|
|
1015
|
-
`;
|
|
1016
|
-
const output = parser.parse(input);
|
|
1017
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
1018
|
-
`h(DOMElement, { element: "p", textContent: text })`.replace(/\s+/g, "")
|
|
1019
|
-
);
|
|
1020
|
-
})
|
|
1021
|
-
|
|
1022
|
-
test('should compile @for loop with nested DOM structure', () => {
|
|
1023
|
-
const input = `
|
|
1024
|
-
<ul class="menu">
|
|
1025
|
-
@for (item of menuItems) {
|
|
1026
|
-
<li class="menu-item">
|
|
1027
|
-
<a href={item.url}>{item.title}</a>
|
|
1028
|
-
</li>
|
|
1029
|
-
}
|
|
1030
|
-
</ul>
|
|
1031
|
-
`;
|
|
1032
|
-
const output = parser.parse(input);
|
|
1033
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
1034
|
-
`h(DOMElement, { element: "ul", attrs: { class: 'menu' } }, loop(menuItems, item => h(DOMElement, { element: "li", attrs: { class: 'menu-item' } }, h(DOMElement, { element: "a", attrs: { href: computed(() => item().url()) }, textContent: computed(() => item().title()) }))))`.replace(/\s+/g, "")
|
|
1035
|
-
);
|
|
1036
|
-
});
|
|
1037
|
-
|
|
1038
|
-
test('should compile @if condition with DOM elements', () => {
|
|
1039
|
-
const input = `
|
|
1040
|
-
@if (showMessage) {
|
|
1041
|
-
<div class="alert">
|
|
1042
|
-
<p>Important message!</p>
|
|
1043
|
-
</div>
|
|
1044
|
-
}
|
|
1045
|
-
`;
|
|
1046
|
-
const output = parser.parse(input);
|
|
1047
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
1048
|
-
`cond(showMessage, () => h(DOMElement, { element: "div", attrs: { class: 'alert' } }, h(DOMElement, { element: "p", textContent: 'Important message!' })))`.replace(/\s+/g, "")
|
|
1049
|
-
);
|
|
1050
|
-
});
|
|
1051
|
-
|
|
1052
|
-
test('should compile @if condition with simple DOM element', () => {
|
|
1053
|
-
const input = `
|
|
1054
|
-
@if (isVisible) {
|
|
1055
|
-
<button>Click me</button>
|
|
1056
|
-
}
|
|
1057
|
-
`;
|
|
1058
|
-
const output = parser.parse(input);
|
|
1059
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
1060
|
-
`cond(isVisible, () => h(DOMElement, { element: "button", textContent: 'Click me' }))`.replace(/\s+/g, "")
|
|
1061
|
-
);
|
|
1062
|
-
});
|
|
1063
|
-
|
|
1064
|
-
test('should compile nested @for and @if with DOM', () => {
|
|
1065
|
-
const input = `
|
|
1066
|
-
<div class="container">
|
|
1067
|
-
@for (section of sections) {
|
|
1068
|
-
@if (section.visible) {
|
|
1069
|
-
<section class="content">
|
|
1070
|
-
<h2>{section.title}</h2>
|
|
1071
|
-
<div class="items">
|
|
1072
|
-
@for (item of section.items) {
|
|
1073
|
-
<div class="item">{item.name}</div>
|
|
1074
|
-
}
|
|
1075
|
-
</div>
|
|
1076
|
-
</section>
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
</div>
|
|
1080
|
-
`;
|
|
1081
|
-
const output = parser.parse(input);
|
|
1082
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
1083
|
-
`h(DOMElement, { element: "div", attrs: { class: 'container' } }, loop(sections, section => cond(section.visible, () => h(DOMElement, { element: "section", attrs: { class: 'content' } }, [h(DOMElement, { element: "h2", textContent: computed(() => section().title()) }), h(DOMElement, { element: "div", attrs: { class: 'items' } }, loop(section.items, item => h(DOMElement, { element: "div", attrs: { class: 'item' }, textContent: computed(() => item().name()) })))]))))`.replace(/\s+/g, "")
|
|
1084
|
-
);
|
|
1085
|
-
});
|
|
1086
|
-
|
|
1087
|
-
test('should compile @for with DOM table structure', () => {
|
|
1088
|
-
const input = `
|
|
1089
|
-
<table>
|
|
1090
|
-
<thead>
|
|
1091
|
-
<tr>
|
|
1092
|
-
<th>Name</th>
|
|
1093
|
-
<th>Age</th>
|
|
1094
|
-
</tr>
|
|
1095
|
-
</thead>
|
|
1096
|
-
<tbody>
|
|
1097
|
-
@for (user of users) {
|
|
1098
|
-
<tr>
|
|
1099
|
-
<td>{user.name}</td>
|
|
1100
|
-
<td>{user.age}</td>
|
|
1101
|
-
</tr>
|
|
1102
|
-
}
|
|
1103
|
-
</tbody>
|
|
1104
|
-
</table>
|
|
1105
|
-
`;
|
|
1106
|
-
const output = parser.parse(input);
|
|
1107
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
1108
|
-
`h(DOMElement, { element: "table" }, [h(DOMElement, { element: "thead" }, h(DOMElement, { element: "tr" }, [h(DOMElement, { element: "th", textContent: 'Name' }), h(DOMElement, { element: "th", textContent: 'Age' })])), h(DOMElement, { element: "tbody" }, loop(users, user => h(DOMElement, { element: "tr" }, [h(DOMElement, { element: "td", textContent: computed(() => user().name()) }), h(DOMElement, { element: "td", textContent: computed(() => user().age()) })])))])`.replace(/\s+/g, "")
|
|
1109
|
-
);
|
|
1110
|
-
});
|
|
1111
|
-
|
|
1112
|
-
test('should compile @if with multiple DOM conditions', () => {
|
|
1113
|
-
const input = `
|
|
1114
|
-
<div class="status">
|
|
1115
|
-
@if (isLoading) {
|
|
1116
|
-
<div class="spinner">Loading...</div>
|
|
1117
|
-
}
|
|
1118
|
-
@if (hasError) {
|
|
1119
|
-
<div class="error">Error occurred!</div>
|
|
1120
|
-
}
|
|
1121
|
-
@if (isSuccess) {
|
|
1122
|
-
<div class="success">Success!</div>
|
|
1123
|
-
}
|
|
1124
|
-
</div>
|
|
1125
|
-
`;
|
|
1126
|
-
const output = parser.parse(input);
|
|
1127
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
1128
|
-
`h(DOMElement, { element: "div", attrs: { class: 'status' } }, [cond(isLoading, () => h(DOMElement, { element: "div", attrs: { class: 'spinner' }, textContent: 'Loading...' })), cond(hasError, () => h(DOMElement, { element: "div", attrs: { class: 'error' }, textContent: 'Error occurred!' })), cond(isSuccess, () => h(DOMElement, { element: "div", attrs: { class: 'success' }, textContent: 'Success!' }))])`.replace(/\s+/g, "")
|
|
1129
|
-
);
|
|
1130
|
-
});
|
|
1131
|
-
|
|
1132
|
-
test('should compile mixed Canvas and DOM with control structures', () => {
|
|
1133
|
-
const input = `
|
|
1134
|
-
<div class="game-wrapper">
|
|
1135
|
-
<Canvas width={800} height={600}>
|
|
1136
|
-
@for (sprite of sprites) {
|
|
1137
|
-
<Sprite x={sprite.x} y={sprite.y} />
|
|
1138
|
-
}
|
|
1139
|
-
</Canvas>
|
|
1140
|
-
<div class="ui-overlay">
|
|
1141
|
-
@if (showScore) {
|
|
1142
|
-
<div class="score">Score: {score}</div>
|
|
1143
|
-
}
|
|
1144
|
-
@if (showMenu) {
|
|
1145
|
-
<div class="menu">
|
|
1146
|
-
@for (option of menuOptions) {
|
|
1147
|
-
<button class="menu-btn">{option.label}</button>
|
|
1148
|
-
}
|
|
1149
|
-
</div>
|
|
1150
|
-
}
|
|
1151
|
-
</div>
|
|
1152
|
-
</div>
|
|
1153
|
-
`;
|
|
1154
|
-
const output = parser.parse(input);
|
|
1155
|
-
expect(output.replace(/\s+/g, "")).toBe(
|
|
1156
|
-
`h(DOMElement, { element: "div", attrs: { class: 'game-wrapper' } }, [h(Canvas, { width: 800, height: 600 }, loop(sprites, sprite => h(Sprite, { x: computed(() => sprite().x()), y: computed(() => sprite().y()) }))), h(DOMElement, { element: "div", attrs: { class: 'ui-overlay' } }, [cond(showScore, () => h(DOMElement, { element: "div", attrs: { class: 'score' }, textContent: computed(() => 'Score: ' + computed(() => score())) })), cond(showMenu, () => h(DOMElement, { element: "div", attrs: { class: 'menu' } }, loop(menuOptions, option => h(DOMElement, { element: "button", attrs: { class: 'menu-btn' }, textContent: computed(() => option().label()) }))))])])`.replace(/\s+/g, "")
|
|
1157
|
-
);
|
|
1158
|
-
});
|
|
1159
|
-
});
|