@lightningjs/blits 1.30.1 → 1.31.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 (70) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/package.json +4 -3
  3. package/src/router/router.js +2 -0
  4. package/vite/preCompiler.js +6 -1
  5. package/.editorconfig +0 -7
  6. package/.eslintignore +0 -1
  7. package/.eslintrc.cjs +0 -65
  8. package/.github/workflows/comment-lint-results.yml +0 -125
  9. package/.github/workflows/comment-test-results.yml +0 -109
  10. package/.github/workflows/deploy-docs.yml +0 -27
  11. package/.github/workflows/run-blits-tests.yml +0 -142
  12. package/.github/workflows/run-lint.yml +0 -128
  13. package/.husky/pre-commit +0 -1
  14. package/.husky/pre-push +0 -1
  15. package/.vscode/extensions.json +0 -7
  16. package/.vscode/settings.json +0 -9
  17. package/banner.png +0 -0
  18. package/docs/.nojekyll +0 -0
  19. package/docs/README.md +0 -19
  20. package/docs/_sidebar.md +0 -37
  21. package/docs/built-in/directives.md +0 -50
  22. package/docs/built-in/for-loop.md +0 -204
  23. package/docs/built-in/layout.md +0 -168
  24. package/docs/components/component_state.md +0 -90
  25. package/docs/components/computed_properties.md +0 -45
  26. package/docs/components/lifecycle_events.md +0 -42
  27. package/docs/components/methods.md +0 -45
  28. package/docs/components/props.md +0 -56
  29. package/docs/components/user_input.md +0 -186
  30. package/docs/components/utility_methods.md +0 -320
  31. package/docs/components/watchers.md +0 -34
  32. package/docs/essentials/application_root.md +0 -19
  33. package/docs/essentials/components.md +0 -68
  34. package/docs/essentials/displaying_images.md +0 -67
  35. package/docs/essentials/displaying_text.md +0 -135
  36. package/docs/essentials/element_attributes.md +0 -195
  37. package/docs/essentials/settings.md +0 -117
  38. package/docs/essentials/template_syntax.md +0 -83
  39. package/docs/getting_started/file_structure.md +0 -58
  40. package/docs/getting_started/getting_started.md +0 -45
  41. package/docs/getting_started/intro.md +0 -20
  42. package/docs/index.html +0 -47
  43. package/docs/performance/lazy-loading.md +0 -161
  44. package/docs/plugins/global_app_state.md +0 -98
  45. package/docs/plugins/language.md +0 -172
  46. package/docs/plugins/text-to-speech-announcer.md +0 -120
  47. package/docs/plugins/theme.md +0 -176
  48. package/docs/router/basics.md +0 -175
  49. package/docs/router/hooks.md +0 -70
  50. package/docs/router/transitions.md +0 -146
  51. package/docs/sidebar.json +0 -171
  52. package/docs/transitions_animations/transitions.md +0 -150
  53. package/jsconfig.json +0 -12
  54. package/src/component/setup/props.test.js +0 -238
  55. package/src/component.test.js +0 -388
  56. package/src/components/Circle.orig.js +0 -31
  57. package/src/components/FPScounter.orig.js +0 -121
  58. package/src/components/RouterView.orig.js +0 -54
  59. package/src/components/Sprite.orig.js +0 -58
  60. package/src/components/index.orig.js +0 -28
  61. package/src/engines/L3/element.test.js +0 -579
  62. package/src/helpers/deepEqualArray.test.js +0 -127
  63. package/src/lib/codegenerator/generator.test.js +0 -3801
  64. package/src/lib/colors/colors.test.js +0 -290
  65. package/src/lib/componentId.test.js +0 -84
  66. package/src/lib/eventListeners.test.js +0 -236
  67. package/src/lib/reactivity/effect.test.js +0 -35
  68. package/src/lib/reactivity/reactive.test.js +0 -27
  69. package/src/lib/templateparser/parser.test.js +0 -1411
  70. package/src/router/router.test.js +0 -473
@@ -1,1411 +0,0 @@
1
- /*
2
- * Copyright 2023 Comcast Cable Communications Management, LLC
3
- * Licensed under the Apache License, Version 2.0 (the "License");
4
- * you may not use this file except in compliance with the License.
5
- * You may obtain a copy of the License at
6
- *
7
- * http://www.apache.org/licenses/LICENSE-2.0
8
- *
9
- * Unless required by applicable law or agreed to in writing, software
10
- * distributed under the License is distributed on an "AS IS" BASIS,
11
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- * See the License for the specific language governing permissions and
13
- * limitations under the License.
14
- *
15
- * SPDX-License-Identifier: Apache-2.0
16
- */
17
-
18
- import test from 'tape'
19
- import parser from './parser.js'
20
- import symbols from '../symbols.js'
21
- const { componentType } = symbols
22
- import { initLog } from '../log.js'
23
- initLog()
24
-
25
- test('Type', (assert) => {
26
- const expected = 'function'
27
- const actual = typeof parser
28
-
29
- assert.equal(actual, expected, 'Parser should be a function')
30
- assert.end()
31
- })
32
-
33
- test('Returns an object', (assert) => {
34
- const result = parser()
35
- const expected = 'object'
36
- const actual = typeof result
37
-
38
- assert.equal(actual, expected, 'Parser should return an object')
39
- assert.ok('children' in result, 'Parser should return an object with a children key')
40
- assert.ok(Array.isArray(result.children), 'Children key returned by parser should be an array')
41
- assert.end()
42
- })
43
-
44
- test('Parse simple single tag', (assert) => {
45
- const template = '<Component></Component>'
46
-
47
- const expected = {
48
- children: [
49
- {
50
- [componentType]: 'Component',
51
- },
52
- ],
53
- }
54
- const actual = parser(template)
55
-
56
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
57
- assert.end()
58
- })
59
-
60
- test('Parse simple tag and simple nested tag', (assert) => {
61
- const template = '<Component><Element></Element></Component>'
62
-
63
- const expected = {
64
- children: [
65
- {
66
- [componentType]: 'Component',
67
- children: [
68
- {
69
- [componentType]: 'Element',
70
- },
71
- ],
72
- },
73
- ],
74
- }
75
- const actual = parser(template)
76
-
77
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
78
- assert.end()
79
- })
80
-
81
- test('Parse simple single tag with static attributes', (assert) => {
82
- const template = '<Component x="10" y="20"></Component>'
83
-
84
- const expected = {
85
- children: [
86
- {
87
- [componentType]: 'Component',
88
- x: '10',
89
- y: '20',
90
- },
91
- ],
92
- }
93
- const actual = parser(template)
94
-
95
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
96
- assert.end()
97
- })
98
-
99
- test('Parse tag with attributes and nested tag with attributes', (assert) => {
100
- const template = '<Component x="10" y="20"><Element w="100" h="300"></Element></Component>'
101
-
102
- const expected = {
103
- children: [
104
- {
105
- [componentType]: 'Component',
106
- x: '10',
107
- y: '20',
108
- children: [
109
- {
110
- [componentType]: 'Element',
111
- w: '100',
112
- h: '300',
113
- },
114
- ],
115
- },
116
- ],
117
- }
118
- const actual = parser(template)
119
-
120
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
121
- assert.end()
122
- })
123
-
124
- test('Parse tag with attributes and 2 nested tags with attributes', (assert) => {
125
- const template = `
126
- <Component x="10" y="20">
127
- <Element w="100" h="300" x="0"></Element>
128
- <Element w="100" h="300" x="50"></Element>
129
- </Component>`
130
-
131
- const expected = {
132
- children: [
133
- {
134
- [componentType]: 'Component',
135
- x: '10',
136
- y: '20',
137
- children: [
138
- {
139
- [componentType]: 'Element',
140
- w: '100',
141
- h: '300',
142
- x: '0',
143
- },
144
- {
145
- [componentType]: 'Element',
146
- w: '100',
147
- h: '300',
148
- x: '50',
149
- },
150
- ],
151
- },
152
- ],
153
- }
154
- const actual = parser(template)
155
-
156
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
157
- assert.end()
158
- })
159
-
160
- test('Parse tag with attributes and deep nested tag with attributes', (assert) => {
161
- const template = `
162
- <Component x="10" y="20">
163
- <Element w="100" h="300" x="0"></Element>
164
- <Element w="100" h="300" x="50">
165
- <Button label="Hello"></Button>
166
- <Button label="World"></Button>
167
- </Element>
168
- </Component>`
169
-
170
- const expected = {
171
- children: [
172
- {
173
- [componentType]: 'Component',
174
- x: '10',
175
- y: '20',
176
- children: [
177
- {
178
- [componentType]: 'Element',
179
- w: '100',
180
- h: '300',
181
- x: '0',
182
- },
183
- {
184
- [componentType]: 'Element',
185
- w: '100',
186
- h: '300',
187
- x: '50',
188
- children: [
189
- {
190
- [componentType]: 'Button',
191
- label: 'Hello',
192
- },
193
- {
194
- [componentType]: 'Button',
195
- label: 'World',
196
- },
197
- ],
198
- },
199
- ],
200
- },
201
- ],
202
- }
203
- const actual = parser(template)
204
-
205
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
206
- assert.end()
207
- })
208
-
209
- test('Parse simple single tag with dynamic attributes', (assert) => {
210
- const template = '<Component x="$x" y="$y"></Component>'
211
-
212
- const expected = {
213
- children: [
214
- {
215
- [componentType]: 'Component',
216
- x: '$x',
217
- y: '$y',
218
- },
219
- ],
220
- }
221
- const actual = parser(template)
222
-
223
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
224
- assert.end()
225
- })
226
-
227
- test('Parse tag with attributes and reactive attributes', (assert) => {
228
- const template = '<Component x="10" y="20" :w="foo" :h="test" test="ok"></Component>'
229
-
230
- const expected = {
231
- children: [
232
- {
233
- [componentType]: 'Component',
234
- x: '10',
235
- y: '20',
236
- ':w': 'foo',
237
- ':h': 'test',
238
- test: 'ok',
239
- },
240
- ],
241
- }
242
- const actual = parser(template)
243
-
244
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
245
- assert.end()
246
- })
247
-
248
- test("Parse simple single tag where one of the attributes has a dash in it's name", (assert) => {
249
- const template = '<Component x="10" y="20" my-Attribute="this"></Component>'
250
-
251
- const expected = {
252
- children: [
253
- {
254
- [componentType]: 'Component',
255
- 'my-Attribute': 'this',
256
- x: '10',
257
- y: '20',
258
- },
259
- ],
260
- }
261
- const actual = parser(template)
262
-
263
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
264
- assert.end()
265
- })
266
-
267
- test('Parse nested self closing tag', (assert) => {
268
- const template = '<Component><Input /></Component>'
269
-
270
- const expected = {
271
- children: [
272
- {
273
- [componentType]: 'Component',
274
- children: [
275
- {
276
- [componentType]: 'Input',
277
- },
278
- ],
279
- },
280
- ],
281
- }
282
- const actual = parser(template)
283
-
284
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
285
- assert.end()
286
- })
287
-
288
- test('Parse multiple nested self closing tags', (assert) => {
289
- const template = '<Component><Input /><Input /><Input /></Component>'
290
-
291
- const expected = {
292
- children: [
293
- {
294
- [componentType]: 'Component',
295
- children: [
296
- {
297
- [componentType]: 'Input',
298
- },
299
- {
300
- [componentType]: 'Input',
301
- },
302
- {
303
- [componentType]: 'Input',
304
- },
305
- ],
306
- },
307
- ],
308
- }
309
- const actual = parser(template)
310
-
311
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
312
- assert.end()
313
- })
314
-
315
- test('Parse attributes which values have spaces in it', (assert) => {
316
- const template = '<Component attribute="I have spaces"></Component>'
317
-
318
- const expected = {
319
- children: [
320
- {
321
- [componentType]: 'Component',
322
- attribute: 'I have spaces',
323
- },
324
- ],
325
- }
326
- const actual = parser(template)
327
-
328
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
329
- assert.end()
330
- })
331
-
332
- test('Parse attributes with an expression in it', (assert) => {
333
- const template = `
334
- <Component
335
- :attribute1="$foo * 2"
336
- :attribute2="$ok ? 'Yes' : 'No'"
337
- :attribute3="$text.split('').reverse().join('')"
338
- :attribute4="$size > 100 ? 110 : $size"
339
- :attribute5="Math.min($size, 100)"
340
- />`
341
-
342
- const expected = {
343
- children: [
344
- {
345
- [componentType]: 'Component',
346
- ':attribute1': '$foo * 2',
347
- ':attribute2': "$ok ? 'Yes' : 'No'",
348
- ':attribute3': "$text.split('').reverse().join('')",
349
- ':attribute4': '$size > 100 ? 110 : $size',
350
- ':attribute5': 'Math.min($size, 100)',
351
- },
352
- ],
353
- }
354
- const actual = parser(template)
355
-
356
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
357
- assert.end()
358
- })
359
-
360
- test('Parse template with commented tag (and skip it)', (assert) => {
361
- const template = `
362
- <Component x="10" y="20">
363
- <!--Element w="100" h="300" x="0"></Element-->
364
- <Element w="100" h="300" x="50">
365
- <Button label="Hello"></Button>
366
- <!--Button label="World"></Button-->
367
- </Element>
368
- </Component>`
369
-
370
- const expected = {
371
- children: [
372
- {
373
- [componentType]: 'Component',
374
- x: '10',
375
- y: '20',
376
- children: [
377
- {
378
- [componentType]: 'Element',
379
- w: '100',
380
- h: '300',
381
- x: '50',
382
- children: [
383
- {
384
- [componentType]: 'Button',
385
- label: 'Hello',
386
- },
387
- ],
388
- },
389
- ],
390
- },
391
- ],
392
- }
393
- const actual = parser(template)
394
-
395
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
396
- assert.end()
397
- })
398
-
399
- test('Parse template with comment spanned across multiple tags (and skip it)', (assert) => {
400
- const template = `
401
- <Component x="10" y="20">
402
- <!--Element w="100" h="300" x="0"></Element-->
403
- <Element w="100" h="300" x="50">
404
- <!--Button label="Hello"></Button>
405
- <Button label="World"></Button-->
406
- </Element>
407
- </Component>`
408
-
409
- const expected = {
410
- children: [
411
- {
412
- [componentType]: 'Component',
413
- x: '10',
414
- y: '20',
415
- children: [
416
- {
417
- [componentType]: 'Element',
418
- w: '100',
419
- h: '300',
420
- x: '50',
421
- },
422
- ],
423
- },
424
- ],
425
- }
426
- const actual = parser(template)
427
-
428
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
429
- assert.end()
430
- })
431
-
432
- test('Parse template with enclosing comment (and skip it)', (assert) => {
433
- const template = `
434
- <Component x="10" y="20">
435
- <Element w="100" h="300" x="0"></Element>
436
- <Element w="100" h="300" x="50">
437
- <!--
438
- <Button label="Hello"></Button>
439
- <Button label="World"></Button>
440
- -->
441
- </Element>
442
- </Component>`
443
-
444
- const expected = {
445
- children: [
446
- {
447
- [componentType]: 'Component',
448
- x: '10',
449
- y: '20',
450
- children: [
451
- {
452
- [componentType]: 'Element',
453
- w: '100',
454
- h: '300',
455
- x: '0',
456
- },
457
- {
458
- [componentType]: 'Element',
459
- w: '100',
460
- h: '300',
461
- x: '50',
462
- },
463
- ],
464
- },
465
- ],
466
- }
467
- const actual = parser(template)
468
-
469
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
470
- assert.end()
471
- })
472
-
473
- test('Parse template with for loop', (assert) => {
474
- const template = `
475
- <List>
476
- <ListItem :for="item in $items" />
477
- </List>`
478
-
479
- const expected = {
480
- children: [
481
- {
482
- [componentType]: 'List',
483
- children: [
484
- {
485
- [componentType]: 'ListItem',
486
- ':for': 'item in $items',
487
- },
488
- ],
489
- },
490
- ],
491
- }
492
- const actual = parser(template)
493
-
494
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
495
- assert.end()
496
- })
497
-
498
- test('Parse template with a conditional (if-statement)', (assert) => {
499
- const template = `
500
- <Component :if="$loggedIn === true">
501
- <Text value="Welcome" />
502
- <Avatar :user="$user" />
503
- </Component>`
504
-
505
- const expected = {
506
- children: [
507
- {
508
- [componentType]: 'Component',
509
- ':if': '$loggedIn === true',
510
- children: [
511
- {
512
- [componentType]: 'Text',
513
- value: 'Welcome',
514
- },
515
- {
516
- [componentType]: 'Avatar',
517
- ':user': '$user',
518
- },
519
- ],
520
- },
521
- ],
522
- }
523
- const actual = parser(template)
524
-
525
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
526
- assert.end()
527
- })
528
-
529
- test('Parse template with a visibility toggle (show-statement)', (assert) => {
530
- const template = `
531
- <Poster w="200" h="500">
532
- <Label :text="$text" />
533
- <Image src="$image" />
534
- <Star :show="$favorited === true" />
535
- </Poster>`
536
-
537
- const expected = {
538
- children: [
539
- {
540
- [componentType]: 'Poster',
541
- w: '200',
542
- h: '500',
543
- children: [
544
- {
545
- [componentType]: 'Label',
546
- ':text': '$text',
547
- },
548
- {
549
- [componentType]: 'Image',
550
- src: '$image',
551
- },
552
- {
553
- [componentType]: 'Star',
554
- ':show': '$favorited === true',
555
- },
556
- ],
557
- },
558
- ],
559
- }
560
- const actual = parser(template)
561
-
562
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
563
- assert.end()
564
- })
565
-
566
- test('Parse template with a nameless tag', (assert) => {
567
- const template = `
568
- <>
569
- <Component x="50" y="20">
570
- <Component w="100" h="20" />
571
- </Component>
572
- </>`
573
-
574
- const expected = {
575
- children: [
576
- {
577
- [componentType]: null,
578
- children: [
579
- {
580
- [componentType]: 'Component',
581
- x: '50',
582
- y: '20',
583
- children: [
584
- {
585
- [componentType]: 'Component',
586
- w: '100',
587
- h: '20',
588
- },
589
- ],
590
- },
591
- ],
592
- },
593
- ],
594
- }
595
- const actual = parser(template)
596
-
597
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
598
- assert.end()
599
- })
600
-
601
- test('Parse template with a transition argument (single value)', (assert) => {
602
- const template = `
603
- <Element x.transition="$offset" y="200">
604
- </Element>`
605
-
606
- const expected = {
607
- children: [
608
- {
609
- [componentType]: 'Element',
610
- x: '{transition: $offset}',
611
- y: '200',
612
- },
613
- ],
614
- }
615
- const actual = parser(template)
616
-
617
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
618
- assert.end()
619
- })
620
-
621
- test('Parse template with a transition argument (object)', (assert) => {
622
- const template = `
623
- <Element :x.transition="{v: $offset, d: 2000}" y="200">
624
- </Element>`
625
-
626
- const expected = {
627
- children: [
628
- {
629
- [componentType]: 'Element',
630
- ':x': '{transition: {v: $offset, d: 2000}}',
631
- y: '200',
632
- },
633
- ],
634
- }
635
- const actual = parser(template)
636
-
637
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
638
- assert.end()
639
- })
640
-
641
- test('Parse template with a different modifier', (assert) => {
642
- const template = `
643
- <Element x.modifier="ok" y="200">
644
- </Element>`
645
-
646
- const expected = {
647
- children: [
648
- {
649
- [componentType]: 'Element',
650
- x: '{modifier: ok}',
651
- y: '200',
652
- },
653
- ],
654
- }
655
- const actual = parser(template)
656
-
657
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
658
- assert.end()
659
- })
660
-
661
- test('Parse template with a full transition object (without the transition modifier)', (assert) => {
662
- const template = `
663
- <Element :x="{transition: {v: $offset, d: 2000, p: 100}}" y="200">
664
- </Element>`
665
-
666
- const expected = {
667
- children: [
668
- {
669
- [componentType]: 'Element',
670
- ':x': '{transition: {v: $offset, d: 2000, p: 100}}',
671
- y: '200',
672
- },
673
- ],
674
- }
675
- const actual = parser(template)
676
-
677
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
678
- assert.end()
679
- })
680
-
681
- test('Parse template with attributes with values spread over multiple lines', (assert) => {
682
- const template = `
683
- <Component>
684
- <Element
685
- w="160" h="160" x="40" y="40" color="#fb923c"
686
- :effects="[$shader(
687
- 'radius',
688
- {radius: 44}
689
- )]"
690
- />
691
- <Element
692
- w="120" h="120"
693
- x="100" y="100"
694
- :effects="[
695
- $shader(
696
- 'radius',
697
- {
698
- radius: 45
699
- }
700
- )
701
- ]"
702
- />
703
- </Component>`
704
-
705
- const expected = {
706
- children: [
707
- {
708
- [componentType]: 'Component',
709
- children: [
710
- {
711
- [componentType]: 'Element',
712
- w: '160',
713
- h: '160',
714
- x: '40',
715
- y: '40',
716
- color: '0xfb923cff',
717
- ':effects': "[$shader( 'radius', {radius: 44} )]",
718
- },
719
- {
720
- [componentType]: 'Element',
721
- w: '120',
722
- h: '120',
723
- x: '100',
724
- y: '100',
725
- ':effects': "[ $shader( 'radius', { radius: 45 } ) ]",
726
- },
727
- ],
728
- },
729
- ],
730
- }
731
-
732
- const actual = parser(template)
733
-
734
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
735
- assert.end()
736
- })
737
-
738
- test('Parse template with inline text between tags', (assert) => {
739
- const template = `
740
- <Component>
741
- <Element w="160" h="160" x="40" y="40" color="#fb923c">Lorem ipsum</Element>
742
- </Component>`
743
-
744
- const expected = {
745
- children: [
746
- {
747
- [componentType]: 'Component',
748
- children: [
749
- {
750
- [componentType]: 'Element',
751
- w: '160',
752
- h: '160',
753
- x: '40',
754
- y: '40',
755
- color: '0xfb923cff',
756
- content: 'Lorem ipsum',
757
- },
758
- ],
759
- },
760
- ],
761
- }
762
-
763
- const actual = parser(template)
764
-
765
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
766
- assert.end()
767
- })
768
-
769
- test('Parse template with multiple inline texts between different tags', (assert) => {
770
- const template = `
771
- <Component>
772
- <Element w="160" h="160" x="40" y="40" color="#fb923c">Lorem ipsum</Element>
773
- <Element>dolor sit amet</Element>
774
- <Element>
775
- <Text>consectetur adipiscing elit</Text>
776
- <Element>
777
- <Text>sed do eiusmod tempor</Text>
778
- </Element>
779
- </Element>
780
-
781
- </Component>`
782
-
783
- const expected = {
784
- children: [
785
- {
786
- [componentType]: 'Component',
787
- children: [
788
- {
789
- [componentType]: 'Element',
790
- w: '160',
791
- h: '160',
792
- x: '40',
793
- y: '40',
794
- color: '0xfb923cff',
795
- content: 'Lorem ipsum',
796
- },
797
- {
798
- [componentType]: 'Element',
799
- content: 'dolor sit amet',
800
- },
801
- {
802
- [componentType]: 'Element',
803
- children: [
804
- {
805
- [componentType]: 'Text',
806
- content: 'consectetur adipiscing elit',
807
- },
808
- {
809
- [componentType]: 'Element',
810
- children: [
811
- {
812
- [componentType]: 'Text',
813
- content: 'sed do eiusmod tempor',
814
- },
815
- ],
816
- },
817
- ],
818
- },
819
- ],
820
- },
821
- ],
822
- }
823
-
824
- const actual = parser(template)
825
-
826
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
827
- assert.end()
828
- })
829
-
830
- test('Parse template with attribute name starts with @ character', (assert) => {
831
- const template = `
832
- <Component>
833
- <Element w="160" h="160" x="40" y="40" color="#fb923c" @loaded="@loaded" />
834
- </Component>`
835
-
836
- const expected = {
837
- children: [
838
- {
839
- [componentType]: 'Component',
840
- children: [
841
- {
842
- [componentType]: 'Element',
843
- w: '160',
844
- h: '160',
845
- x: '40',
846
- y: '40',
847
- color: '0xfb923cff',
848
- '@loaded': '@loaded',
849
- },
850
- ],
851
- },
852
- ],
853
- }
854
-
855
- const actual = parser(template)
856
-
857
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
858
- assert.end()
859
- })
860
-
861
- test('Parse template with attribute values with delimited either single or double quotes', (assert) => {
862
- const template = `
863
- <Component>
864
- <Element
865
- w='160' h="160" x='40' y='40' color="#fb923c"
866
- :effects='[$shader(
867
- "radius",
868
- {radius: 44}
869
- )]'
870
- />
871
- <Element
872
- w='120' h="120"
873
- x='100' y="100"
874
- :effects="[
875
- $shader(
876
- 'radius',
877
- {
878
- radius: 45
879
- }
880
- )
881
- ]"
882
- />
883
- </Component>`
884
-
885
- const expected = {
886
- children: [
887
- {
888
- [componentType]: 'Component',
889
- children: [
890
- {
891
- [componentType]: 'Element',
892
- w: '160',
893
- h: '160',
894
- x: '40',
895
- y: '40',
896
- color: '0xfb923cff',
897
- ':effects': '[$shader( "radius", {radius: 44} )]',
898
- },
899
- {
900
- [componentType]: 'Element',
901
- w: '120',
902
- h: '120',
903
- x: '100',
904
- y: '100',
905
- ':effects': "[ $shader( 'radius', { radius: 45 } ) ]",
906
- },
907
- ],
908
- },
909
- ],
910
- }
911
-
912
- const actual = parser(template)
913
-
914
- assert.deepEqual(actual, expected, 'Parser should return object representation of template')
915
- assert.end()
916
- })
917
-
918
- test('Parse template with multiple top level elements and parsing should fail', (assert) => {
919
- const template = `
920
- <Component>
921
- <Element
922
- w='160' h="160" x='40' y='40' color="#fb923c"
923
- :effects='[$shader(
924
- "radius",
925
- {radius: 44}
926
- )]'
927
- />
928
- </Component>
929
- <Component>
930
- <Element
931
- w='120' h="120"
932
- x='100' y="100"
933
- :effects="[
934
- $shader(
935
- 'radius',
936
- {
937
- radius: 45
938
- }
939
- )
940
- ]"
941
- />
942
- </Component>`
943
-
944
- try {
945
- parser(template)
946
- assert.fail('Parser should throw TemplateStructureError:MultipleTopLevelTags')
947
- } catch (error) {
948
- assert.equal(error.name, 'TemplateStructureError', 'Parser should throw TemplateStructureError')
949
- assert.ok(
950
- error.message.startsWith('MultipleTopLevelTags'),
951
- 'Parser should throw TemplateStructureError:MultipleTopLevelTags'
952
- )
953
- }
954
-
955
- assert.end()
956
- })
957
-
958
- test('Parse template with unclosed tag and parsing should fail', (assert) => {
959
- const template = `
960
- <Component>
961
- <Element>
962
- </Component>
963
- `
964
-
965
- try {
966
- parser(template)
967
- assert.fail('Parser should throw TemplateStructureError:MismatchedClosingTag')
968
- } catch (error) {
969
- assert.equal(error.name, 'TemplateStructureError', 'Parser should throw TemplateStructureError')
970
- assert.ok(
971
- error.message.startsWith('MismatchedClosingTag'),
972
- 'Parser should throw TemplateStructureError:MismatchedClosingTag'
973
- )
974
- }
975
- assert.end()
976
- })
977
-
978
- test('Parse template with multiple unclosed tags and parsing should fail', (assert) => {
979
- const template = `
980
- <Component>
981
- <Element>
982
- <Button />
983
- <Text>Lorem Ipsum</Text>
984
- <Element>
985
- <Button />
986
- <Text>Lorem Ipsum</Text>
987
- </Component>
988
- `
989
-
990
- try {
991
- parser(template)
992
- assert.fail('Parser should throw TemplateStructureError:MismatchedClosingTag')
993
- } catch (error) {
994
- assert.equal(error.name, 'TemplateStructureError', 'Parser should throw TemplateStructureError')
995
- assert.ok(
996
- error.message.startsWith('MismatchedClosingTag'),
997
- 'Parser should throw TemplateStructureError:MismatchedClosingTag'
998
- )
999
- }
1000
- assert.end()
1001
- })
1002
-
1003
- test('Parse template with an unclosed tag and parsing should fail', (assert) => {
1004
- const template = `
1005
- <Component>
1006
- `
1007
-
1008
- try {
1009
- parser(template)
1010
- assert.fail('Parser should throw TemplateStructureError:UnclosedTags')
1011
- } catch (error) {
1012
- assert.equal(error.name, 'TemplateStructureError', 'Parser should throw TemplateStructureError')
1013
- assert.ok(
1014
- error.message.startsWith('UnclosedTags'),
1015
- 'Parser should throw TemplateStructureError:UnclosedTags'
1016
- )
1017
- }
1018
- assert.end()
1019
- })
1020
-
1021
- test('Parse template with an invalid closing tag and parsing should fail', (assert) => {
1022
- const template = `
1023
- <Component>
1024
- <Element>
1025
- </Element/>
1026
- </Component>
1027
- `
1028
-
1029
- try {
1030
- parser(template)
1031
- assert.fail('Parser should throw TemplateParseError:InvalidClosingTag')
1032
- } catch (error) {
1033
- assert.equal(error.name, 'TemplateParseError', 'Parser should throw TemplateParseError')
1034
- assert.ok(
1035
- error.message.startsWith('InvalidClosingTag'),
1036
- 'Parser should throw TemplateParseError:InvalidClosingTag'
1037
- )
1038
- }
1039
-
1040
- assert.end()
1041
- })
1042
-
1043
- test('Parse template with multiple self-closing tags at the top level and parsing should fail', (assert) => {
1044
- const template = `
1045
- <Component/>
1046
- <Element/>
1047
- `
1048
-
1049
- try {
1050
- parser(template)
1051
- assert.fail('Parser should throw TemplateStructureError:MultipleTopLevelTags')
1052
- } catch (error) {
1053
- assert.equal(error.name, 'TemplateStructureError', 'Parser should throw TemplateStructureError')
1054
- assert.ok(
1055
- error.message.startsWith('MultipleTopLevelTags'),
1056
- 'Parser should throw TemplateStructureError:MultipleTopLevelTags'
1057
- )
1058
- }
1059
-
1060
- assert.end()
1061
- })
1062
-
1063
- test('Parse template with a closing tag at the beginning and parsing should fail', (assert) => {
1064
- const template = `
1065
- </Element>
1066
- <Component>
1067
- <Element/>
1068
- </Component>
1069
- `
1070
-
1071
- try {
1072
- parser(template)
1073
- assert.fail('Parser should throw TemplateStructureError:MismatchedClosingTag')
1074
- } catch (error) {
1075
- assert.equal(error.name, 'TemplateStructureError', 'Parser should throw TemplateStructureError')
1076
- assert.ok(
1077
- error.message.startsWith('MismatchedClosingTag'),
1078
- 'Parser should throw TemplateStructureError:MismatchedClosingTag'
1079
- )
1080
- }
1081
-
1082
- assert.end()
1083
- })
1084
-
1085
- test('Parse template with a closing tag that has attributes and parsing should fail', (assert) => {
1086
- const template = `
1087
- <Component>
1088
- <Text>Lorem ipsum dolor sit amet</Text>
1089
- <Element></Element x="200">
1090
- </Component>
1091
- `
1092
-
1093
- try {
1094
- parser(template)
1095
- assert.fail('Parser should throw TemplateParseError:AttributesInClosingTag')
1096
- } catch (error) {
1097
- assert.equal(error.name, 'TemplateParseError', 'Parser should throw TemplateParseError')
1098
- assert.ok(
1099
- error.message.startsWith('AttributesInClosingTag'),
1100
- 'Parser should throw TemplateParseError:AttributesInClosingTag'
1101
- )
1102
- }
1103
-
1104
- assert.end()
1105
- })
1106
-
1107
- test('Parse template with an invalid tag and parsing should fail', (assert) => {
1108
- const template = `
1109
- <@Element x="200" />
1110
- `
1111
-
1112
- try {
1113
- parser(template)
1114
- assert.fail('Parser should throw TemplateParseError:InvalidTag')
1115
- } catch (error) {
1116
- assert.equal(error.name, 'TemplateParseError', 'Parser should throw TemplateParseError')
1117
- assert.ok(
1118
- error.message.startsWith('InvalidTag'),
1119
- 'Parser should throw TemplateParseError:InvalidTag'
1120
- )
1121
- }
1122
-
1123
- assert.end()
1124
- })
1125
-
1126
- test('Parse template with an invalid attribute value and parsing should fail', (assert) => {
1127
- const template = `
1128
- <Element x=" />
1129
- `
1130
-
1131
- try {
1132
- parser(template)
1133
- assert.fail('Parser should throw TemplateParseError:MissingOrInvalidAttributeValue')
1134
- } catch (error) {
1135
- assert.equal(error.name, 'TemplateParseError', 'Parser should throw TemplateParseError')
1136
- assert.ok(
1137
- error.message.startsWith('MissingOrInvalidAttributeValue'),
1138
- 'Parser should throw TemplateParseError:MissingOrInvalidAttributeValue'
1139
- )
1140
- }
1141
-
1142
- assert.end()
1143
- })
1144
-
1145
- test('Parse template with an invalid attribute name and parsing should fail', (assert) => {
1146
- const template = `
1147
- <Element invalid^attribute="hello" />
1148
- `
1149
-
1150
- try {
1151
- parser(template)
1152
- assert.fail('Parser should throw TemplateParseError:InvalidAttribute')
1153
- } catch (error) {
1154
- assert.equal(error.name, 'TemplateParseError', 'Parser should throw TemplateParseError')
1155
- assert.ok(
1156
- error.message.startsWith('InvalidAttribute'),
1157
- 'Parser should throw TemplateParseError:InvalidAttribute'
1158
- )
1159
- }
1160
-
1161
- assert.end()
1162
- })
1163
-
1164
- test('Parse template with an invalid attribute name by providing parent component and parsing should fail', (assert) => {
1165
- const template = `
1166
- <Element invalid^attribute="hello" />
1167
- `
1168
-
1169
- try {
1170
- parser(template, 'Item', {
1171
- [componentType]: 'Section',
1172
- parent: {
1173
- [componentType]: 'List',
1174
- parent: {
1175
- [componentType]: 'Menu',
1176
- parent: {
1177
- [componentType]: 'Blits.App',
1178
- },
1179
- },
1180
- },
1181
- })
1182
- assert.fail('Parser should throw TemplateParseError:InvalidAttribute')
1183
- } catch (error) {
1184
- assert.equal(error.name, 'TemplateParseError', 'Parser should throw TemplateParseError')
1185
- assert.ok(
1186
- error.message.startsWith('InvalidAttribute'),
1187
- 'Parser should throw TemplateParseError:InvalidAttribute'
1188
- )
1189
- assert.ok(
1190
- error.message.includes('Blits.App/Menu/List/Section/Item'),
1191
- 'Error message should contain the component hierarchy'
1192
- )
1193
- }
1194
-
1195
- assert.end()
1196
- })
1197
-
1198
- test('Parse template with an invalid attribute name by providing parent component without component name and parsing should fail', (assert) => {
1199
- const template = `
1200
- <Element invalid^attribute="hello" />
1201
- `
1202
-
1203
- try {
1204
- parser(template, null, {
1205
- [componentType]: 'Section',
1206
- parent: {
1207
- [componentType]: 'List',
1208
- parent: {
1209
- [componentType]: 'Menu',
1210
- parent: {
1211
- [componentType]: 'Blits.App',
1212
- },
1213
- },
1214
- },
1215
- })
1216
- assert.fail('Parser should throw TemplateParseError:InvalidAttribute')
1217
- } catch (error) {
1218
- assert.equal(error.name, 'TemplateParseError', 'Parser should throw TemplateParseError')
1219
- assert.ok(
1220
- error.message.startsWith('InvalidAttribute'),
1221
- 'Parser should throw TemplateParseError:InvalidAttribute'
1222
- )
1223
- assert.ok(
1224
- error.message.includes('Blits.App/Menu/List/Section/'),
1225
- 'Error message should contain the component hierarchy without the component name'
1226
- )
1227
- }
1228
-
1229
- assert.end()
1230
- })
1231
-
1232
- test('Parse template with an invalid attribute name by providing component file path and parsing should fail', (assert) => {
1233
- const template = `
1234
- <Element invalid^attribute="hello" />
1235
- `
1236
-
1237
- try {
1238
- parser(template, 'Item', null, 'src/components/Menu/List/Section/Item.js')
1239
- assert.fail('Parser should throw TemplateParseError:InvalidAttribute')
1240
- } catch (error) {
1241
- assert.equal(error.name, 'TemplateParseError', 'Parser should throw TemplateParseError')
1242
- assert.ok(
1243
- error.message.startsWith('InvalidAttribute'),
1244
- 'Parser should throw TemplateParseError:InvalidAttribute'
1245
- )
1246
- assert.ok(
1247
- error.message.includes('src/components/Menu/List/Section/Item.js'),
1248
- 'Error message should contain the component file path'
1249
- )
1250
- }
1251
-
1252
- assert.end()
1253
- })
1254
-
1255
- test('Parse template with color and effects attributes and parsing should convert color values', (assert) => {
1256
- const template = `
1257
- <Element :color="$backgroundColor">
1258
- <Element color="{top: '#44037a', bottom: '#240244'}" />
1259
- <Element color="#44037a" />
1260
- <Element color="{top: '#44037a'}" :effects="[$shader('radius', {radius: $radius})]" />
1261
- <Element :color="$colors.color2" :effects="[$shader('radius', {radius: $radius / 2})]" />
1262
- <Element color="transparent" :effects="[$shader('radius', {radius: 10}), $shader('border', {width: 20, color: '#60a5fa'})]" />
1263
- <Element color="#fba" />
1264
- <Element color="#23dd21" />
1265
- <Element color="#993322ff" />
1266
- <Element color="ddd" />
1267
- <Element color="ddffaa" />
1268
- <Element color="ddffaa00" />
1269
- <Element color="#E6E6E6" />
1270
- <Element data="49b383f" color="#ddfa" />
1271
- <Element color="rgba(255, 255, 255, 0.5)" />
1272
- <Element color="hsl(120, 100%, 50%)" />
1273
- <Element color="hsla(120, 100%, 50%, 0.5)" />
1274
- <Element color="rgb(135, 206, 235)" />
1275
- <Element color="rgba(135, 206, 235, -0.5)" />
1276
- <Element color="rgba(222, 125, 44, 1.3)" />
1277
- <Element color="0xccccccff" />
1278
- <Element notColor="#dbbeee" />
1279
- </Element>
1280
- `
1281
-
1282
- const expected = {
1283
- children: [
1284
- {
1285
- ':color': '$backgroundColor',
1286
- [componentType]: 'Element',
1287
- children: [
1288
- {
1289
- color: "{top: '0x44037aff', bottom: '0x240244ff'}",
1290
- [componentType]: 'Element',
1291
- },
1292
- {
1293
- color: '0x44037aff',
1294
- [componentType]: 'Element',
1295
- },
1296
- {
1297
- color: "{top: '0x44037aff'}",
1298
- ':effects': "[$shader('radius', {radius: $radius})]",
1299
- [componentType]: 'Element',
1300
- },
1301
- {
1302
- ':color': '$colors.color2',
1303
- ':effects': "[$shader('radius', {radius: $radius / 2})]",
1304
- [componentType]: 'Element',
1305
- },
1306
- {
1307
- color: '0x00000000',
1308
- ':effects':
1309
- "[$shader('radius', {radius: 10}), $shader('border', {width: 20, color: '0x60a5faff'})]",
1310
- [componentType]: 'Element',
1311
- },
1312
- {
1313
- color: '0xffbbaaff',
1314
- [componentType]: 'Element',
1315
- },
1316
- {
1317
- color: '0x23dd21ff',
1318
- [componentType]: 'Element',
1319
- },
1320
- {
1321
- color: '0x993322ff',
1322
- [componentType]: 'Element',
1323
- },
1324
- {
1325
- color: '0xddddddff',
1326
- [componentType]: 'Element',
1327
- },
1328
- {
1329
- color: '0xddffaaff',
1330
- [componentType]: 'Element',
1331
- },
1332
- {
1333
- color: '0xddffaa00',
1334
- [componentType]: 'Element',
1335
- },
1336
- {
1337
- color: '0xe6e6e6ff',
1338
- [componentType]: 'Element',
1339
- },
1340
- {
1341
- data: '49b383f',
1342
- color: '#ddfa',
1343
- [componentType]: 'Element',
1344
- },
1345
- {
1346
- color: '0xffffff80',
1347
- [componentType]: 'Element',
1348
- },
1349
- {
1350
- color: '0xffffffff',
1351
- [componentType]: 'Element',
1352
- },
1353
- {
1354
- color: '0xffffffff',
1355
- [componentType]: 'Element',
1356
- },
1357
- {
1358
- color: '0x87ceebff',
1359
- [componentType]: 'Element',
1360
- },
1361
- {
1362
- color: '0x87ceeb00',
1363
- [componentType]: 'Element',
1364
- },
1365
- {
1366
- color: '0xde7d2cff',
1367
- [componentType]: 'Element',
1368
- },
1369
- {
1370
- color: '0xccccccff',
1371
- [componentType]: 'Element',
1372
- },
1373
- {
1374
- notColor: '#dbbeee',
1375
- [componentType]: 'Element',
1376
- },
1377
- ],
1378
- },
1379
- ],
1380
- }
1381
-
1382
- const actual = parser(template)
1383
-
1384
- assert.deepEqual(
1385
- actual,
1386
- expected,
1387
- 'Parser should return object representation of template with color values converted'
1388
- )
1389
- assert.end()
1390
- })
1391
-
1392
- test('Parse template with :for attribute on root element and parsing should fail', (assert) => {
1393
- const template = `
1394
- <Element :for="item in $items">
1395
- <Text content="$item.name" />
1396
- </Element>
1397
- `
1398
-
1399
- try {
1400
- parser(template)
1401
- assert.fail('Parser should throw TemplateStructureError:ForAttributeOnRootElement')
1402
- } catch (error) {
1403
- assert.equal(error.name, 'TemplateStructureError', 'Parser should throw TemplateStructureError')
1404
- assert.ok(
1405
- error.message.startsWith('ForAttributeOnRootElement'),
1406
- 'Parser should throw TemplateStructureError:ForAttributeOnRootElement'
1407
- )
1408
- }
1409
-
1410
- assert.end()
1411
- })