@lightningjs/blits 0.10.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/docs/essentials/displaying_text.md +1 -1
  3. package/package.json +3 -3
  4. package/src/component/base/events.js +1 -1
  5. package/src/component/base/utils.js +34 -1
  6. package/src/component/setup/props.js +3 -1
  7. package/src/component/setup/props.test.js +51 -19
  8. package/src/component.d.ts +2 -1
  9. package/src/component.js +20 -13
  10. package/src/components/Circle.js +13 -12
  11. package/src/components/FPScounter.js +388 -536
  12. package/src/components/Image.js +7 -9
  13. package/src/components/Layout.js +49 -0
  14. package/src/components/Layout.orig.js +34 -0
  15. package/src/components/RouterView.js +6 -10
  16. package/src/components/Sprite.js +10 -12
  17. package/src/components/index.js +2 -2
  18. package/src/components/index.orig.js +2 -2
  19. package/src/engine.js +1 -1
  20. package/src/engines/L3/element.js +193 -180
  21. package/src/engines/L3/element.test.js +170 -0
  22. package/src/engines/L3/fontLoader.js +4 -5
  23. package/src/engines/L3/index.js +2 -2
  24. package/src/engines/L3/launch.js +7 -13
  25. package/src/engines/L3/shaderLoader.js +12 -0
  26. package/src/engines/index.js +1 -1
  27. package/src/launch.d.ts +19 -2
  28. package/src/lib/codegenerator/generator.js +212 -84
  29. package/src/lib/codegenerator/generator.test.js +657 -942
  30. package/src/lib/colors/colors.js +59 -46
  31. package/src/lib/precompiler/precompiler.js +2 -1
  32. package/src/lib/reactivity/effect.js +10 -13
  33. package/src/lib/reactivity/reactive.js +24 -14
  34. package/src/lib/symbols.js +1 -0
  35. package/src/router/router.js +17 -3
  36. package/boilerplate/js/default/src/renderer.js +0 -4
  37. package/src/components/Text.js +0 -119
  38. package/src/components/Text.orig.js +0 -81
@@ -80,8 +80,10 @@ test('The contex key is an object', (assert) => {
80
80
 
81
81
  test('Generate render and effect code for an empty template', (assert) => {
82
82
  const expectedRender = `
83
- function anonymous(parent,component,context) {
83
+ function anonymous(parent, component, context, components, effect, getRaw) {
84
84
  const elms = []
85
+ let componentType
86
+ const rootComponent = component
85
87
  return elms
86
88
  }
87
89
  `
@@ -110,17 +112,13 @@ test('Generate render and effect code for a template with a single simple elemen
110
112
  }
111
113
 
112
114
  const expectedRender = `
113
- function anonymous(parent,component,context) {
115
+ function anonymous(parent, component, context, components, effect, getRaw) {
114
116
  const elms = []
115
-
116
- if(!elms[0]) {
117
- elms[0] = this.element({parent: parent || 'root'}, component)
118
- }
117
+ let componentType
118
+ const rootComponent = component
119
119
  const elementConfig0 = {}
120
-
121
- if(!elms[0].nodeId) {
122
- elms[0].populate(elementConfig0)
123
- }
120
+ elms[0] = this.element({ parent: parent || 'root' }, component)
121
+ elms[0].populate(elementConfig0)
124
122
  return elms
125
123
  }
126
124
  `
@@ -154,30 +152,18 @@ test('Generate code for a template with a simple element and a simple nested ele
154
152
  }
155
153
 
156
154
  const expectedRender = `
157
- function anonymous(parent,component,context) {
158
- const elms = []
159
-
160
- if(!elms[0]) {
161
- elms[0] = this.element({parent: parent || 'root'}, component)
162
- }
163
- const elementConfig0 = {}
164
-
165
- if(!elms[0].nodeId) {
155
+ function anonymous(parent, component, context, components, effect, getRaw) {
156
+ const elms = []
157
+ let componentType
158
+ const rootComponent = component
159
+ const elementConfig0 = {}
160
+ elms[0] = this.element({ parent: parent || 'root' }, component)
166
161
  elms[0].populate(elementConfig0)
167
- }
168
-
169
- parent = elms[0]
170
-
171
- if(!elms[1]) {
172
- elms[1] = this.element({parent: parent || 'root'}, component)
173
- }
174
- const elementConfig1 = {}
175
-
176
- if(!elms[1].nodeId) {
162
+ parent = elms[0]
163
+ const elementConfig1 = {}
164
+ elms[1] = this.element({ parent: parent || 'root' }, component)
177
165
  elms[1].populate(elementConfig1)
178
- }
179
-
180
- return elms
166
+ return elms
181
167
  }
182
168
  `
183
169
 
@@ -207,20 +193,16 @@ test('Generate code for a template with a single element with attributes', (asse
207
193
  }
208
194
 
209
195
  const expectedRender = `
210
- function anonymous(parent,component,context) {
196
+ function anonymous(parent, component, context, components, effect, getRaw) {
211
197
  const elms = []
212
-
213
- if(!elms[0]) {
214
- elms[0] = this.element({parent: parent || 'root'}, component)
215
- }
198
+ let componentType
199
+ const rootComponent = component
216
200
  const elementConfig0 = {}
201
+ elms[0] = this.element({ parent: parent || 'root' }, component)
217
202
 
218
203
  elementConfig0['x'] = 10
219
204
  elementConfig0['y'] = 20
220
-
221
- if(!elms[0].nodeId) {
222
- elms[0].populate(elementConfig0)
223
- }
205
+ elms[0].populate(elementConfig0)
224
206
  return elms
225
207
  }
226
208
  `
@@ -251,20 +233,15 @@ test('Generate code for a template with a single element with attributes with a
251
233
  }
252
234
 
253
235
  const expectedRender = `
254
- function anonymous(parent,component,context) {
236
+ function anonymous(parent, component, context, components, effect, getRaw) {
255
237
  const elms = []
256
-
257
- if(!elms[0]) {
258
- elms[0] = this.element({parent: parent || 'root'}, component)
259
- }
238
+ let componentType
239
+ const rootComponent = component
260
240
  const elementConfig0 = {}
261
-
241
+ elms[0] = this.element({ parent: parent || 'root' }, component)
262
242
  elementConfig0['one'] = true
263
243
  elementConfig0['two'] = false
264
-
265
- if(!elms[0].nodeId) {
266
- elms[0].populate(elementConfig0)
267
- }
244
+ elms[0].populate(elementConfig0)
268
245
  return elms
269
246
  }
270
247
  `
@@ -302,34 +279,25 @@ test('Generate code for a template with attributes and a nested element with att
302
279
  }
303
280
 
304
281
  const expectedRender = `
305
- function anonymous(parent,component,context) {
282
+ function anonymous(parent, component, context, components, effect, getRaw) {
306
283
  const elms = []
307
-
308
- if(!elms[0]) {
309
- elms[0] = this.element({parent: parent || 'root'}, component)
310
- }
284
+ let componentType
285
+ const rootComponent = component
311
286
  const elementConfig0 = {}
312
287
 
288
+ elms[0] = this.element({ parent: parent || 'root' }, component)
313
289
  elementConfig0['x'] = 10
314
290
  elementConfig0['y'] = 20
315
-
316
- if(!elms[0].nodeId) {
317
- elms[0].populate(elementConfig0)
318
- }
291
+ elms[0].populate(elementConfig0)
319
292
 
320
293
  parent = elms[0]
321
294
 
322
- if(!elms[1]) {
323
- elms[1] = this.element({parent: parent || 'root'}, component)
324
- }
325
295
  const elementConfig1 = {}
326
296
 
297
+ elms[1] = this.element({ parent: parent || 'root' }, component)
327
298
  elementConfig1['w'] = 100
328
299
  elementConfig1['h'] = 300
329
-
330
- if(!elms[1].nodeId) {
331
- elms[1].populate(elementConfig1)
332
- }
300
+ elms[1].populate(elementConfig1)
333
301
 
334
302
  return elms
335
303
  }
@@ -375,51 +343,36 @@ test('Generate code for a template with attributes and 2 nested elements with at
375
343
  }
376
344
 
377
345
  const expectedRender = `
378
- function anonymous(parent,component,context) {
346
+ function anonymous(parent, component, context, components, effect, getRaw) {
379
347
  const elms = []
380
-
381
- if(!elms[0]) {
382
- elms[0] = this.element({parent: parent || 'root'}, component)
383
- }
384
-
348
+ let componentType
349
+ const rootComponent = component
385
350
  const elementConfig0 = {}
386
351
 
352
+ elms[0] = this.element({ parent: parent || 'root' }, component)
387
353
  elementConfig0['x'] = 10
388
354
  elementConfig0['y'] = 20
389
-
390
- if(!elms[0].nodeId) {
391
- elms[0].populate(elementConfig0)
392
- }
355
+ elms[0].populate(elementConfig0)
393
356
 
394
357
  parent = elms[0]
395
358
 
396
- if(!elms[1]) {
397
- elms[1] = this.element({parent: parent || 'root'}, component)
398
- }
399
359
  const elementConfig1 = {}
400
360
 
361
+ elms[1] = this.element({ parent: parent || 'root' }, component)
401
362
  elementConfig1['w'] = 100
402
363
  elementConfig1['h'] = 300
403
364
  elementConfig1['x'] = 0
404
-
405
- if(!elms[1].nodeId) {
406
- elms[1].populate(elementConfig1)
407
- }
365
+ elms[1].populate(elementConfig1)
408
366
 
409
367
  parent = elms[0]
410
368
 
411
- if(!elms[2]) {
412
- elms[2] = this.element({parent: parent || 'root'}, component)
413
- }
414
369
  const elementConfig2 = {}
415
370
 
371
+ elms[2] = this.element({ parent: parent || 'root' }, component)
416
372
  elementConfig2['w'] = 100
417
373
  elementConfig2['h'] = 300
418
374
  elementConfig2['x'] = 50
419
-
420
- if(!elms[2].nodeId) {
421
- elms[2].populate(elementConfig2)
422
- }
375
+ elms[2].populate(elementConfig2)
423
376
 
424
377
  return elms
425
378
  }
@@ -475,78 +428,52 @@ test('Generate code for a template with attributes and deep nested elements with
475
428
  }
476
429
 
477
430
  const expectedRender = `
478
- function anonymous(parent,component,context) {
431
+ function anonymous(parent, component, context, components, effect, getRaw) {
479
432
  const elms = []
480
-
481
- if(!elms[0]) {
482
- elms[0] = this.element({parent: parent || 'root'}, component)
483
- }
433
+ let componentType
434
+ const rootComponent = component
484
435
  const elementConfig0 = {}
485
436
 
437
+ elms[0] = this.element({ parent: parent || 'root' }, component)
486
438
  elementConfig0['x'] = 10
487
439
  elementConfig0['y'] = 20
488
-
489
- if(!elms[0].nodeId) {
490
- elms[0].populate(elementConfig0)
491
- }
440
+ elms[0].populate(elementConfig0)
492
441
 
493
442
  parent = elms[0]
494
443
 
495
- if(!elms[1]) {
496
- elms[1] = this.element({parent: parent || 'root'}, component)
497
- }
498
-
499
444
  const elementConfig1 = {}
500
445
 
446
+ elms[1] = this.element({ parent: parent || 'root' }, component)
501
447
  elementConfig1['w'] = 100
502
448
  elementConfig1['h'] = 300
503
449
  elementConfig1['x'] = 0
504
-
505
- if(!elms[1].nodeId) {
506
- elms[1].populate(elementConfig1)
507
- }
450
+ elms[1].populate(elementConfig1)
508
451
 
509
452
  parent = elms[0]
510
453
 
511
- if(!elms[2]) {
512
- elms[2] = this.element({parent: parent || 'root'}, component)
513
- }
514
-
515
454
  const elementConfig2 = {}
516
455
 
456
+ elms[2] = this.element({ parent: parent || 'root' }, component)
517
457
  elementConfig2['w'] = 100
518
458
  elementConfig2['h'] = 300
519
459
  elementConfig2['x'] = 50
520
-
521
- if(!elms[2].nodeId) {
522
- elms[2].populate(elementConfig2)
523
- }
460
+ elms[2].populate(elementConfig2)
524
461
 
525
462
  parent = elms[2]
526
463
 
527
- if(!elms[3]) {
528
- elms[3] = this.element({parent: parent || 'root'}, component)
529
- }
530
464
  const elementConfig3 = {}
531
465
 
466
+ elms[3] = this.element({ parent: parent || 'root' }, component)
532
467
  elementConfig3['label'] = "Hello"
533
-
534
- if(!elms[3].nodeId) {
535
- elms[3].populate(elementConfig3)
536
- }
468
+ elms[3].populate(elementConfig3)
537
469
 
538
470
  parent = elms[2]
539
471
 
540
- if(!elms[4]) {
541
- elms[4] = this.element({parent: parent || 'root'}, component)
542
- }
543
472
  const elementConfig4 = {}
544
473
 
474
+ elms[4] = this.element({ parent: parent || 'root' }, component)
545
475
  elementConfig4['label'] = "World"
546
-
547
- if(!elms[4].nodeId) {
548
- elms[4].populate(elementConfig4)
549
- }
476
+ elms[4].populate(elementConfig4)
550
477
 
551
478
  return elms
552
479
  }
@@ -581,36 +508,34 @@ test('Generate code for a template with simple dynamic attributes', (assert) =>
581
508
  }
582
509
 
583
510
  const expectedRender = `
584
- function anonymous(parent,component,context) {
511
+ function anonymous(parent, component, context, components, effect, getRaw) {
585
512
  const elms = []
586
-
587
- if(!elms[0]) {
588
- elms[0] = this.element({parent: parent || 'root'}, component)
589
- }
513
+ let componentType
514
+ const rootComponent = component
590
515
  const elementConfig0 = {}
591
516
 
517
+ elms[0] = this.element({ parent: parent || 'root' }, component)
592
518
  elementConfig0['x'] = 10
593
519
  elementConfig0['y'] = 20
520
+ elementConfig0['w'] = component.foo
521
+ elementConfig0['h'] = component.test
594
522
  elementConfig0['test'] = "ok"
595
-
596
- if(!elms[0].nodeId) {
597
- elms[0].populate(elementConfig0)
598
- }
523
+ elms[0].populate(elementConfig0)
599
524
 
600
525
  return elms
601
526
  }
602
527
  `
603
528
 
604
529
  const expectedEffect1 = `
605
- function anonymous(component,elms,context) {
530
+ function anonymous(component, elms, context, components, rootComponent, effect) {
606
531
  elms[0].set('w', component.foo)
607
532
  }
608
533
  `
609
534
 
610
535
  const expectedEffect2 = `
611
- function anonymous(component,elms,context) {
536
+ function anonymous(component, elms, context, components, rootComponent, effect) {
612
537
  elms[0].set('h', component.test)
613
- }
538
+ }
614
539
  `
615
540
 
616
541
  const actual = generator.call(scope, templateObject)
@@ -651,21 +576,17 @@ test('Generate code for a template with an attribute with a dash', (assert) => {
651
576
  }
652
577
 
653
578
  const expectedRender = `
654
- function anonymous(parent,component,context) {
579
+ function anonymous(parent, component, context, components, effect, getRaw) {
655
580
  const elms = []
656
-
657
- if(!elms[0]) {
658
- elms[0] = this.element({parent: parent || 'root'}, component)
659
- }
581
+ let componentType
582
+ const rootComponent = component
660
583
  const elementConfig0 = {}
661
584
 
662
- elementConfig0['my-Attribute'] = "does it work?"
585
+ elms[0] = this.element({ parent: parent || 'root' }, component)
586
+ elementConfig0['my-Attribute'] = "doesitwork?"
663
587
  elementConfig0['x'] = 10
664
588
  elementConfig0['y'] = 20
665
-
666
- if(!elms[0].nodeId) {
667
- elms[0].populate(elementConfig0)
668
- }
589
+ elms[0].populate(elementConfig0)
669
590
 
670
591
  return elms
671
592
  }
@@ -699,36 +620,36 @@ test('Generate code for a template with dynamic attributes with code to be evalu
699
620
  }
700
621
 
701
622
  const expectedRender = `
702
- function anonymous(parent,component,context) {
623
+ function anonymous(parent, component, context, components, effect, getRaw) {
703
624
  const elms = []
704
-
705
- if(!elms[0]) {
706
- elms[0] = this.element({parent: parent || 'root'}, component)
707
- }
625
+ let componentType
626
+ const rootComponent = component
708
627
  const elementConfig0 = {}
709
628
 
710
- if(!elms[0].nodeId) {
711
- elms[0].populate(elementConfig0)
712
- }
629
+ elms[0] = this.element({ parent: parent || 'root' }, component)
630
+ elementConfig0['attribute1'] = component.foo * 2
631
+ elementConfig0['attribute2'] = component.ok ? 'Yes' : 'No'
632
+ elementConfig0['attribute3'] = component.text.split('').reverse().join('')
633
+ elms[0].populate(elementConfig0)
713
634
 
714
635
  return elms
715
636
  }
716
637
  `
717
638
 
718
639
  const expectedEffect1 = `
719
- function anonymous(component,elms,context) {
640
+ function anonymous(component, elms, context, components, rootComponent, effect) {
720
641
  elms[0].set('attribute1', component.foo * 2)
721
642
  }
722
643
  `
723
644
 
724
645
  const expectedEffect2 = `
725
- function anonymous(component,elms,context) {
646
+ function anonymous(component, elms, context, components, rootComponent, effect) {
726
647
  elms[0].set('attribute2', component.ok ? 'Yes' : 'No')
727
648
  }
728
649
  `
729
650
 
730
651
  const expectedEffect3 = `
731
- function anonymous(component,elms,context) {
652
+ function anonymous(component, elms, context, components, rootComponent, effect) {
732
653
  elms[0].set('attribute3', component.text.split('').reverse().join(''))
733
654
  }
734
655
  `
@@ -776,21 +697,18 @@ test('Generate code for a template with @-listeners', (assert) => {
776
697
  }
777
698
 
778
699
  const expectedRender = `
779
- function anonymous(parent,component,context) {
700
+ function anonymous(parent, component, context, components, effect, getRaw) {
780
701
  const elms = []
781
-
782
- if(!elms[0]) {
783
- elms[0] = this.element({parent: parent || 'root'}, component)
784
- }
702
+ let componentType
703
+ const rootComponent = component
785
704
  const elementConfig0 = {}
786
705
 
706
+ elms[0] = this.element({ parent: parent || 'root' }, component)
787
707
  elementConfig0['src'] = "myImage.png"
788
708
  elementConfig0['@loaded'] = component['loadedCallback'] && component['loadedCallback'].bind(component)
789
709
  elementConfig0['@error'] = component['errorCallback'] && component['errorCallback'].bind(component)
710
+ elms[0].populate(elementConfig0)
790
711
 
791
- if(!elms[0].nodeId) {
792
- elms[0].populate(elementConfig0)
793
- }
794
712
  return elms
795
713
  }
796
714
  `
@@ -833,82 +751,79 @@ test('Generate code for a template with custom components', (assert) => {
833
751
  }
834
752
 
835
753
  const expectedRender = `
836
- function anonymous(parent,component,context) {
754
+ function anonymous(parent, component, context, components, effect, getRaw) {
837
755
  const elms = []
838
-
839
- if(!elms[0]) {
840
- elms[0] = this.element({parent: parent || 'root'}, component)
841
- }
756
+ let componentType
757
+ const rootComponent = component
842
758
  const elementConfig0 = {}
843
759
 
844
- if(!elms[0].nodeId) {
845
- elms[0].populate(elementConfig0)
846
- }
847
-
848
- const cmp1 = (context.components && context.components['Poster']) ||
849
- component[Symbol.for('components')]['Poster']
760
+ elms[0] = this.element({ parent: parent || 'root' }, component)
761
+ elms[0].populate(elementConfig0)
850
762
 
763
+ const cmp1 = (context.components && context.components['Poster']) || components['Poster']
851
764
  parent = elms[0]
852
-
853
- if(!elms[1]) {
854
- elms[1] = this.element({parent: parent || 'root'}, component)
855
- }
856
-
857
765
  const elementConfig1 = {}
766
+
767
+ elms[1] = this.element({ parent: parent || 'root' }, component)
858
768
  if(typeof cmp1 !== 'undefined') {
859
769
  for(let key in cmp1.config.props) {
860
- delete elementConfig1[cmp1.config.props[key]]
770
+ delete elementConfig1[cmp1.config.props[key]]
861
771
  }
862
772
  }
863
-
864
- if(!elms[1].nodeId) {
865
- elms[1].populate(elementConfig1)
866
- }
867
-
773
+ elms[1].populate(elementConfig1)
868
774
  parent = elms[1]
869
775
  const props2 = {}
870
- if(!elms[2]) {
871
- const componentType = props2['is'] || 'Poster'
872
- elms[2] = (context.components && context.components[componentType] || component[Symbol.for('components')][componentType] || (() => { console.error('component Poster not found')})).call(null, {props: props2}, elms[1], component)
873
- if (elms[2][Symbol.for('slots')][0]) {
874
- parent = elms[2][Symbol.for('slots')][0]
875
- component = elms[2]
876
- } else {
877
- parent = elms[2][Symbol.for('children')][0]
878
- }
879
- }
880
-
881
- const cmp3 = (context.components && context.components['Poster']) ||
882
- component[Symbol.for('components')]['Poster']
776
+ componentType = props2['is'] || 'Poster'
777
+ let component2
883
778
 
884
- parent = elms[0]
779
+ if (typeof componentType === 'string') {
780
+ component2 = context.components && context.components[componentType] || components[componentType]
781
+ if (!component2) {
782
+ throw new Error('Component "Poster" not found')
783
+ }
784
+ } else if (typeof componentType === 'function' && componentType.name === 'factory') {
785
+ component2 = componentType
786
+ }
885
787
 
886
- if(!elms[3]) {
887
- elms[3] = this.element({parent: parent || 'root'}, component)
788
+ elms[2] = component2.call(null, { props: props2 }, elms[1], component)
789
+ if(elms[2][Symbol.for('slots')][0]) {
790
+ parent = elms[2][Symbol.for('slots')][0]
791
+ component = elms[2]
792
+ } else {
793
+ parent = elms[2][Symbol.for('children')][0]
888
794
  }
889
795
 
796
+ const cmp3 = (context.components && context.components['Poster']) || components['Poster']
797
+ parent = elms[0]
890
798
  const elementConfig3 = {}
799
+
800
+ elms[3] = this.element({ parent: parent || 'root' }, component)
891
801
  if(typeof cmp3 !== 'undefined') {
892
802
  for(let key in cmp3.config.props) {
893
- delete elementConfig3[cmp3.config.props[key]]
803
+ delete elementConfig3[cmp3.config.props[key]]
894
804
  }
895
805
  }
896
-
897
- if(!elms[3].nodeId) {
898
- elms[3].populate(elementConfig3)
899
- }
900
-
806
+ elms[3].populate(elementConfig3)
901
807
  parent = elms[3]
902
808
  const props4 = {}
903
- if(!elms[4]) {
904
- const componentType = props4['is'] || 'Poster'
905
- elms[4] = (context.components && context.components[componentType] || component[Symbol.for('components')][componentType] || (() => { console.error('component Poster not found')})).call(null, {props: props4}, elms[3], component)
906
- if (elms[4][Symbol.for('slots')][0]) {
907
- parent = elms[4][Symbol.for('slots')][0]
908
- component = elms[4]
909
- } else {
910
- parent = elms[4][Symbol.for('children')][0]
809
+ componentType = props4['is'] || 'Poster'
810
+ let component4
811
+ if (typeof componentType === 'string') {
812
+ component4 = context.components && context.components[componentType] || components[componentType]
813
+ if (!component4) {
814
+ throw new Error('Component "Poster" not found')
815
+ }
816
+ } else if (typeof componentType === 'function' && componentType.name === 'factory') {
817
+ component4 = componentType
911
818
  }
819
+
820
+ elms[4] = component4.call(null, { props: props4 }, elms[3], component)
821
+
822
+ if(elms[4][Symbol.for('slots')][0]) {
823
+ parent = elms[4][Symbol.for('slots')][0]
824
+ component = elms[4]
825
+ } else {
826
+ parent = elms[4][Symbol.for('children')][0]
912
827
  }
913
828
 
914
829
  return elms
@@ -954,82 +869,83 @@ test('Generate code for a template with an unregistered custom component', (asse
954
869
  }
955
870
 
956
871
  const expectedRender = `
957
- function anonymous(parent,component,context) {
872
+ function anonymous(parent, component, context, components, effect, getRaw) {
958
873
  const elms = []
959
-
960
- if(!elms[0]) {
961
- elms[0] = this.element({parent: parent || 'root'}, component)
962
- }
874
+ let componentType
875
+ const rootComponent = component
963
876
  const elementConfig0 = {}
964
877
 
965
- if(!elms[0].nodeId) {
966
- elms[0].populate(elementConfig0)
967
- }
968
-
969
- const cmp1 = (context.components && context.components['Poster']) ||
970
- component[Symbol.for('components')]['Poster']
878
+ elms[0] = this.element({ parent: parent || 'root' }, component)
879
+ elms[0].populate(elementConfig0)
971
880
 
881
+ const cmp1 = (context.components && context.components['Poster']) || components['Poster']
972
882
  parent = elms[0]
973
-
974
- if(!elms[1]) {
975
- elms[1] = this.element({parent: parent || 'root'}, component)
976
- }
977
-
978
883
  const elementConfig1 = {}
884
+
885
+ elms[1] = this.element({ parent: parent || 'root' }, component)
979
886
  if(typeof cmp1 !== 'undefined') {
980
887
  for(let key in cmp1.config.props) {
981
- delete elementConfig1[cmp1.config.props[key]]
888
+ delete elementConfig1[cmp1.config.props[key]]
982
889
  }
983
890
  }
984
-
985
- if(!elms[1].nodeId) {
986
- elms[1].populate(elementConfig1)
987
- }
988
-
891
+ elms[1].populate(elementConfig1)
989
892
  parent = elms[1]
893
+
990
894
  const props2 = {}
991
- if(!elms[2]) {
992
- const componentType = props2['is'] || 'Poster'
993
- elms[2] = (context.components && context.components[componentType] || component[Symbol.for('components')][componentType] || (() => { console.error('component Poster not found')})).call(null, {props: props2}, elms[1], component)
994
- if (elms[2][Symbol.for('slots')][0]) {
995
- parent = elms[2][Symbol.for('slots')][0]
996
- component = elms[2]
997
- } else {
998
- parent = elms[2][Symbol.for('children')][0]
999
- }
1000
- }
895
+ componentType = props2['is'] || 'Poster'
896
+ let component2
1001
897
 
1002
- const cmp3 = (context.components && context.components['Poster2']) ||
1003
- component[Symbol.for('components')]['Poster2']
898
+ if(typeof componentType === 'string') {
899
+ component2 = context.components && context.components[componentType] || components[componentType]
900
+ if(!component2) {
901
+ throw new Error('Component "Poster" not found')
902
+ }
903
+ } else if(typeof componentType === 'function' && componentType.name === 'factory') {
904
+ component2 = componentType
905
+ }
1004
906
 
1005
- parent = elms[0]
907
+ elms[2] = component2.call(null, { props: props2 }, elms[1], component)
1006
908
 
1007
- if(!elms[3]) {
1008
- elms[3] = this.element({parent: parent || 'root'}, component)
909
+ if(elms[2][Symbol.for('slots')][0]) {
910
+ parent = elms[2][Symbol.for('slots')][0]
911
+ component = elms[2]
912
+ } else {
913
+ parent = elms[2][Symbol.for('children')][0]
1009
914
  }
1010
915
 
916
+ const cmp3 = (context.components && context.components['Poster2']) || components['Poster2']
917
+ parent = elms[0]
1011
918
  const elementConfig3 = {}
919
+
920
+ elms[3] = this.element({ parent: parent || 'root' }, component)
1012
921
  if(typeof cmp3 !== 'undefined') {
1013
922
  for(let key in cmp3.config.props) {
1014
- delete elementConfig3[cmp3.config.props[key]]
923
+ delete elementConfig3[cmp3.config.props[key]]
1015
924
  }
1016
925
  }
926
+ elms[3].populate(elementConfig3)
927
+ parent = elms[3]
1017
928
 
1018
- if(!elms[3].nodeId) {
1019
- elms[3].populate(elementConfig3)
929
+ const props4 = {}
930
+ componentType = props4['is'] || 'Poster2'
931
+ let component4
932
+
933
+ if(typeof componentType === 'string') {
934
+ component4 = context.components && context.components[componentType] || components[componentType]
935
+ if(!component4) {
936
+ throw new Error('Component "Poster2" not found')
937
+ }
938
+ } else if(typeof componentType === 'function' && componentType.name === 'factory') {
939
+ component4 = componentType
1020
940
  }
1021
941
 
1022
- parent = elms[3]
1023
- const props4 = {}
1024
- if(!elms[4]) {
1025
- const componentType = props4['is'] || 'Poster2'
1026
- elms[4] = (context.components && context.components[componentType] || component[Symbol.for('components')][componentType] || (() => { console.error('component Poster2 not found')})).call(null, {props: props4}, elms[3], component)
1027
- if (elms[4][Symbol.for('slots')][0]) {
1028
- parent = elms[4][Symbol.for('slots')][0]
1029
- component = elms[4]
1030
- } else {
1031
- parent = elms[4][Symbol.for('children')][0]
1032
- }
942
+ elms[4] = component4.call(null, { props: props4 }, elms[3], component)
943
+
944
+ if(elms[4][Symbol.for('slots')][0]) {
945
+ parent = elms[4][Symbol.for('slots')][0]
946
+ component = elms[4]
947
+ } else {
948
+ parent = elms[4][Symbol.for('children')][0]
1033
949
  }
1034
950
 
1035
951
  return elms
@@ -1078,96 +994,86 @@ test('Generate code for a template with custom components with arguments', (asse
1078
994
  }
1079
995
 
1080
996
  const expectedRender = `
1081
- function anonymous(parent,component,context) {
997
+ function anonymous(parent, component, context, components, effect, getRaw) {
1082
998
  const elms = []
1083
-
1084
- if(!elms[0]) {
1085
- elms[0] = this.element({parent: parent || 'root'}, component)
1086
- }
999
+ let componentType
1000
+ const rootComponent = component
1087
1001
  const elementConfig0 = {}
1088
1002
 
1089
- if(!elms[0].nodeId) {
1090
- elms[0].populate(elementConfig0)
1091
- }
1092
-
1093
- const cmp1 = (context.components && context.components['Poster']) ||
1094
- component[Symbol.for('components')]['Poster']
1003
+ elms[0] = this.element({ parent: parent || 'root' }, component)
1004
+ elms[0].populate(elementConfig0)
1095
1005
 
1006
+ const cmp1 = (context.components && context.components['Poster']) || components['Poster']
1096
1007
  parent = elms[0]
1097
-
1098
- if(!elms[1]) {
1099
- elms[1] = this.element({parent: parent || 'root'}, component)
1100
- }
1101
-
1102
1008
  const elementConfig1 = {}
1103
1009
 
1010
+ elms[1] = this.element({ parent: parent || 'root' }, component)
1104
1011
  elementConfig1['x'] = 10
1105
-
1106
1012
  if(typeof cmp1 !== 'undefined') {
1107
1013
  for(let key in cmp1.config.props) {
1108
- delete elementConfig1[cmp1.config.props[key]]
1014
+ delete elementConfig1[cmp1.config.props[key]]
1109
1015
  }
1110
1016
  }
1111
-
1112
- if(!elms[1].nodeId) {
1113
- elms[1].populate(elementConfig1)
1114
- }
1115
-
1017
+ elms[1].populate(elementConfig1)
1116
1018
  parent = elms[1]
1117
- const props2 = {}
1118
1019
 
1020
+ const props2 = {}
1119
1021
  props2['x'] = 10
1120
-
1121
- if(!elms[2]) {
1122
- const componentType = props2['is'] || 'Poster'
1123
- elms[2] = (context.components && context.components[componentType] || component[Symbol.for('components')][componentType] || (() => { console.error('component Poster not found')})).call(null, {props: props2}, elms[1], component)
1124
- if (elms[2][Symbol.for('slots')][0]) {
1125
- parent = elms[2][Symbol.for('slots')][0]
1126
- component = elms[2]
1127
- } else {
1128
- parent = elms[2][Symbol.for('children')][0]
1129
- }
1022
+ componentType = props2['is'] || 'Poster'
1023
+ let component2
1024
+ if (typeof componentType === 'string') {
1025
+ component2 = context.components && context.components[componentType] || components[componentType]
1026
+ if (!component2) {
1027
+ throw new Error('Component "Poster" not found')
1028
+ }
1029
+ } else if (typeof componentType === 'function' && componentType.name === 'factory') {
1030
+ component2 = componentType
1130
1031
  }
1131
-
1132
- const cmp3 = (context.components && context.components['Poster']) ||
1133
- component[Symbol.for('components')]['Poster']
1134
-
1135
- parent = elms[0]
1136
-
1137
- if(!elms[3]) {
1138
- elms[3] = this.element({parent: parent || 'root'}, component)
1032
+ elms[2] = component2.call(null, { props: props2 }, elms[1], component)
1033
+ if(elms[2][Symbol.for('slots')][0]) {
1034
+ parent = elms[2][Symbol.for('slots')][0]
1035
+ component = elms[2]
1036
+ } else {
1037
+ parent = elms[2][Symbol.for('children')][0]
1139
1038
  }
1140
1039
 
1040
+ const cmp3 = (context.components && context.components['Poster']) || components['Poster']
1041
+ parent = elms[0]
1141
1042
  const elementConfig3 = {}
1142
1043
 
1044
+ elms[3] = this.element({ parent: parent || 'root' }, component)
1143
1045
  elementConfig3['x'] = 100
1144
1046
  elementConfig3['img'] = component.img
1145
-
1146
1047
  if(typeof cmp3 !== 'undefined') {
1147
1048
  for(let key in cmp3.config.props) {
1148
- delete elementConfig3[cmp3.config.props[key]]
1049
+ delete elementConfig3[cmp3.config.props[key]]
1149
1050
  }
1150
1051
  }
1151
-
1152
- if(!elms[3].nodeId) {
1153
- elms[3].populate(elementConfig3)
1154
- }
1155
-
1052
+ elms[3].populate(elementConfig3)
1156
1053
  parent = elms[3]
1157
- const props4 = {}
1158
1054
 
1055
+ const props4 = {}
1159
1056
  props4['x'] = 100
1160
1057
  props4['img'] = component.img
1058
+ componentType = props4['is'] || 'Poster'
1059
+ let component4
1161
1060
 
1162
- if(!elms[4]) {
1163
- const componentType = props4['is'] || 'Poster'
1164
- elms[4] = (context.components && context.components[componentType] || component[Symbol.for('components')][componentType] || (() => { console.error('component Poster not found')})).call(null, {props: props4}, elms[3], component)
1165
- if (elms[4][Symbol.for('slots')][0]) {
1166
- parent = elms[4][Symbol.for('slots')][0]
1167
- component = elms[4]
1168
- } else {
1169
- parent = elms[4][Symbol.for('children')][0]
1170
- }
1061
+ if (typeof componentType === 'string') {
1062
+ component4=context.components && context.components[componentType] || components[componentType]
1063
+ if (!component4) {
1064
+ throw new Error('Component "Poster" not found')
1065
+ }
1066
+ } else if (typeof componentType === 'function' && componentType.name === 'factory') {
1067
+ component4 = componentType
1068
+ }
1069
+
1070
+ elms[4] = component4.call(null, { props: props4 }, elms[3], component)
1071
+
1072
+ if(elms[4][Symbol.for('slots')][0]) {
1073
+ parent = elms[4][Symbol.for('slots')][0]
1074
+ component = elms[4]
1075
+ } else {
1076
+ parent = elms[4][Symbol.for('children')][0]
1171
1077
  }
1172
1078
 
1173
1079
  return elms
@@ -1217,96 +1123,90 @@ test('Generate code for a template with custom components with reactive props',
1217
1123
  }
1218
1124
 
1219
1125
  const expectedRender = `
1220
- function anonymous(parent,component,context) {
1126
+ function anonymous(parent, component, context, components, effect, getRaw) {
1221
1127
  const elms = []
1222
-
1223
- if(!elms[0]) {
1224
- elms[0] = this.element({parent: parent || 'root'}, component)
1225
- }
1128
+ let componentType
1129
+ const rootComponent = component
1226
1130
  const elementConfig0 = {}
1227
1131
 
1228
- if(!elms[0].nodeId) {
1229
- elms[0].populate(elementConfig0)
1230
- }
1231
-
1232
- const cmp1 = (context.components && context.components['Poster']) ||
1233
- component[Symbol.for('components')]['Poster']
1132
+ elms[0] = this.element({ parent: parent || 'root' }, component)
1133
+ elms[0].populate(elementConfig0)
1234
1134
 
1135
+ const cmp1 = (context.components && context.components['Poster']) || components['Poster']
1235
1136
  parent = elms[0]
1236
-
1237
- if(!elms[1]) {
1238
- elms[1] = this.element({parent: parent || 'root'}, component)
1239
- }
1240
-
1241
1137
  const elementConfig1 = {}
1242
1138
 
1139
+ elms[1] = this.element({ parent: parent || 'root' }, component)
1243
1140
  elementConfig1['x'] = 10
1244
-
1141
+ elementConfig1['img'] = component.image
1245
1142
  if(typeof cmp1 !== 'undefined') {
1246
1143
  for(let key in cmp1.config.props) {
1247
- delete elementConfig1[cmp1.config.props[key]]
1144
+ delete elementConfig1[cmp1.config.props[key]]
1248
1145
  }
1249
1146
  }
1250
-
1251
- if(!elms[1].nodeId) {
1252
- elms[1].populate(elementConfig1)
1253
- }
1254
-
1147
+ elms[1].populate(elementConfig1)
1255
1148
  parent = elms[1]
1256
- const props2 = {}
1257
1149
 
1150
+ const props2 = {}
1258
1151
  props2['x'] = 10
1259
1152
  props2['img'] = component.image
1153
+ componentType = props2['is'] || 'Poster'
1154
+ let component2
1260
1155
 
1261
- if(!elms[2]) {
1262
- const componentType = props2['is'] || 'Poster'
1263
- elms[2] = (context.components && context.components[componentType] || component[Symbol.for('components')][componentType] || (() => { console.error('component Poster not found')})).call(null, {props: props2}, elms[1], component)
1264
- if (elms[2][Symbol.for('slots')][0]) {
1265
- parent = elms[2][Symbol.for('slots')][0]
1266
- component = elms[2]
1267
- } else {
1268
- parent = elms[2][Symbol.for('children')][0]
1269
- }
1156
+ if (typeof componentType === 'string') {
1157
+ component2 = context.components && context.components[componentType] || components[componentType]
1158
+ if (!component2) {
1159
+ throw new Error('Component "Poster" not found')
1160
+ }
1161
+ } else if (typeof componentType === 'function' && componentType.name === 'factory') {
1162
+ component2 = componentType
1270
1163
  }
1271
1164
 
1272
- const cmp3 = (context.components && context.components['Poster']) ||
1273
- component[Symbol.for('components')]['Poster']
1274
-
1275
- parent = elms[0]
1165
+ elms[2] = component2.call(null, { props: props2 }, elms[1], component)
1276
1166
 
1277
- if(!elms[3]) {
1278
- elms[3] = this.element({parent: parent || 'root'}, component)
1167
+ if(elms[2][Symbol.for('slots')][0]) {
1168
+ parent = elms[2][Symbol.for('slots')][0]
1169
+ component = elms[2]
1170
+ } else {
1171
+ parent = elms[2][Symbol.for('children')][0]
1279
1172
  }
1280
1173
 
1174
+ const cmp3 = (context.components && context.components['Poster']) || components['Poster']
1175
+ parent = elms[0]
1281
1176
  const elementConfig3 = {}
1282
1177
 
1178
+ elms[3] = this.element({ parent: parent || 'root' }, component)
1283
1179
  elementConfig3['x'] = 100
1284
-
1180
+ elementConfig3['img'] = component.image
1285
1181
  if(typeof cmp3 !== 'undefined') {
1286
1182
  for(let key in cmp3.config.props) {
1287
- delete elementConfig3[cmp3.config.props[key]]
1183
+ delete elementConfig3[cmp3.config.props[key]]
1288
1184
  }
1289
1185
  }
1290
-
1291
- if(!elms[3].nodeId) {
1292
- elms[3].populate(elementConfig3)
1293
- }
1294
-
1186
+ elms[3].populate(elementConfig3)
1295
1187
  parent = elms[3]
1296
- const props4 = {}
1297
1188
 
1189
+ const props4 = {}
1298
1190
  props4['x'] = 100
1299
1191
  props4['img'] = component.image
1192
+ componentType = props4['is'] || 'Poster'
1193
+ let component4
1300
1194
 
1301
- if(!elms[4]) {
1302
- const componentType = props4['is'] || 'Poster'
1303
- elms[4] = (context.components && context.components[componentType] || component[Symbol.for('components')][componentType] || (() => { console.error('component Poster not found')})).call(null, {props: props4}, elms[3], component)
1304
- if (elms[4][Symbol.for('slots')][0]) {
1305
- parent = elms[4][Symbol.for('slots')][0]
1306
- component = elms[4]
1307
- } else {
1308
- parent = elms[4][Symbol.for('children')][0]
1309
- }
1195
+ if (typeof componentType === 'string') {
1196
+ component4 = context.components && context.components[componentType] || components[componentType]
1197
+ if (!component4) {
1198
+ throw new Error('Component "Poster" not found')
1199
+ }
1200
+ } else if (typeof componentType === 'function' && componentType.name === 'factory') {
1201
+ component4 = componentType
1202
+ }
1203
+
1204
+ elms[4] = component4.call(null, { props: props4 }, elms[3], component)
1205
+ if(elms[4][Symbol.for('slots')][0]) {
1206
+ parent = elms[4][Symbol.for('slots')][0]
1207
+ component = elms[4]
1208
+ } else {
1209
+ parent = elms[4][Symbol.for('children')][0]
1310
1210
  }
1311
1211
 
1312
1212
  return elms
@@ -1314,25 +1214,25 @@ test('Generate code for a template with custom components with reactive props',
1314
1214
  `
1315
1215
 
1316
1216
  const expectedEffect1 = `
1317
- function anonymous(component,elms,context) {
1217
+ function anonymous(component,elms,context,components,rootComponent,effect) {
1318
1218
  elms[1].set('img', component.image)
1319
1219
  }
1320
1220
  `
1321
1221
 
1322
1222
  const expectedEffect2 = `
1323
- function anonymous(component,elms,context) {
1223
+ function anonymous(component,elms,context,components,rootComponent,effect) {
1324
1224
  elms[2][Symbol.for('props')]['img'] = component.image
1325
1225
  }
1326
1226
  `
1327
1227
 
1328
1228
  const expectedEffect3 = `
1329
- function anonymous(component,elms,context) {
1229
+ function anonymous(component,elms,context,components,rootComponent,effect) {
1330
1230
  elms[3].set('img', component.image)
1331
1231
  }
1332
1232
  `
1333
1233
 
1334
1234
  const expectedEffect4 = `
1335
- function anonymous(component,elms,context) {
1235
+ function anonymous(component,elms,context,components,rootComponent,effect) {
1336
1236
  elms[4][Symbol.for('props')]['img'] = component.image
1337
1237
  }
1338
1238
  `
@@ -1389,20 +1289,16 @@ test('Generate code for a template with a transition attributes', (assert) => {
1389
1289
  }
1390
1290
 
1391
1291
  const expectedRender = `
1392
- function anonymous(parent,component,context) {
1292
+ function anonymous(parent, component, context, components, effect, getRaw) {
1393
1293
  const elms = []
1394
-
1395
- if(!elms[0]) {
1396
- elms[0] = this.element({parent: parent || 'root'}, component)
1397
- }
1294
+ let componentType
1295
+ const rootComponent = component
1398
1296
  const elementConfig0 = {}
1399
1297
 
1400
- elementConfig0['x'] = "{transition: $myX}"
1401
- elementConfig0['y'] = "{transition: {v: $myY, d: 600, p: 100}}"
1402
-
1403
- if(!elms[0].nodeId) {
1404
- elms[0].populate(elementConfig0)
1405
- }
1298
+ elms[0] = this.element({ parent: parent || 'root' }, component)
1299
+ elementConfig0['x'] = "{transition:$myX}"
1300
+ elementConfig0['y'] = "{transition:{v:$myY,d:600,p:100}}"
1301
+ elms[0].populate(elementConfig0)
1406
1302
 
1407
1303
  return elms
1408
1304
  }
@@ -1453,85 +1349,70 @@ test('Generate code for a template with slot content', (assert) => {
1453
1349
  }
1454
1350
 
1455
1351
  const expectedRender = `
1456
- function anonymous(parent,component,context) {
1352
+ function anonymous(parent, component, context, components, effect, getRaw) {
1457
1353
  const elms = []
1458
-
1459
- if(!elms[0]) {
1460
- elms[0] = this.element({parent: parent || 'root'}, component)
1461
- }
1354
+ let componentType
1355
+ const rootComponent = component
1462
1356
  const elementConfig0 = {}
1463
1357
 
1464
- if(!elms[0].nodeId) {
1465
- elms[0].populate(elementConfig0)
1466
- }
1467
-
1468
- const cmp1 = (context.components && context.components['Page']) ||
1469
- component[Symbol.for('components')]['Page']
1358
+ elms[0] = this.element({ parent: parent || 'root' }, component)
1359
+ elms[0].populate(elementConfig0)
1470
1360
 
1361
+ const cmp1 = (context.components && context.components['Page']) || components['Page']
1471
1362
  parent = elms[0]
1472
-
1473
- if(!elms[1]) {
1474
- elms[1] = this.element({parent: parent || 'root'}, component)
1475
- }
1476
1363
  const elementConfig1 = {}
1364
+
1365
+ elms[1] = this.element({ parent: parent || 'root' }, component)
1477
1366
  elementConfig1['w'] = 1920
1478
1367
  elementConfig1['h'] = 1080
1479
-
1480
1368
  if(typeof cmp1 !== 'undefined') {
1481
1369
  for(let key in cmp1.config.props) {
1482
- delete elementConfig1[cmp1.config.props[key]]
1370
+ delete elementConfig1[cmp1.config.props[key]]
1483
1371
  }
1484
1372
  }
1485
-
1486
- if(!elms[1].nodeId) {
1487
- elms[1].populate(elementConfig1)
1488
- }
1489
-
1373
+ elms[1].populate(elementConfig1)
1490
1374
  parent = elms[1]
1375
+
1491
1376
  const props2 = {}
1492
1377
  props2['w'] = 1920
1493
1378
  props2['h'] = 1080
1379
+ componentType = props2['is'] || 'Page'
1380
+ let component2
1494
1381
 
1495
-
1496
- if(!elms[2]) {
1497
- const componentType = props2['is'] || 'Page'
1498
- elms[2] = (context.components && context.components[componentType] || component[Symbol.for('components')][componentType] || (() => { console.error('component Page not found')})).call(null, {props: props2}, elms[1], component)
1499
- if (elms[2][Symbol.for('slots')][0]) {
1500
- parent = elms[2][Symbol.for('slots')][0]
1501
- component = elms[2]
1502
- } else {
1503
- parent = elms[2][Symbol.for('children')][0]
1504
- }
1382
+ if (typeof componentType === 'string') {
1383
+ component2 = context.components && context.components[componentType] || components[componentType]
1384
+ if (!component2) {
1385
+ throw new Error('Component "Page" not found')
1386
+ }
1387
+ } else if (typeof componentType === 'function' && componentType.name === 'factory') {
1388
+ component2 = componentType
1505
1389
  }
1506
-
1507
- if(!elms[3]) {
1508
- elms[3] = this.element({parent: parent || 'root'}, component)
1390
+ elms[2] = component2.call(null, { props: props2 }, elms[1], component)
1391
+ if(elms[2][Symbol.for('slots')][0]) {
1392
+ parent = elms[2][Symbol.for('slots')][0]
1393
+ component = elms[2]
1394
+ } else {
1395
+ parent = elms[2][Symbol.for('children')][0]
1509
1396
  }
1510
1397
 
1511
1398
  const elementConfig3 = {}
1512
-
1513
- if(!elms[3].nodeId) {
1514
- elms[3].populate(elementConfig3)
1515
- }
1399
+ elms[3] = this.element({ parent: parent || 'root' }, component)
1400
+ elms[3].populate(elementConfig3)
1516
1401
  parent = elms[3]
1517
1402
 
1518
-
1519
- if(!elms[4]) {
1520
- elms[4] = this.element({parent: parent || 'root'}, component)
1521
- }
1522
1403
  const elementConfig4 = {}
1404
+ elms[4] = this.element({ parent: parent || 'root' }, component)
1523
1405
  elementConfig4['x'] = 100
1524
1406
  elementConfig4['y'] = component.y
1525
- if(!elms[4].nodeId) {
1526
- elms[4].populate(elementConfig4)
1527
- }
1407
+ elementConfig4['rotation'] = component.rotate
1408
+ elms[4].populate(elementConfig4)
1528
1409
 
1529
1410
  return elms
1530
1411
  }
1531
1412
  `
1532
1413
 
1533
1414
  const expectedEffect1 = `
1534
- function anonymous(component,elms,context) {
1415
+ function anonymous(component,elms,context,components,rootComponent,effect){
1535
1416
  elms[4].set('rotation', component.rotate)
1536
1417
  }
1537
1418
  `
@@ -1589,82 +1470,66 @@ test('Generate code for a template with slot content, using a named slot', (asse
1589
1470
  }
1590
1471
 
1591
1472
  const expectedRender = `
1592
- function anonymous(parent,component,context) {
1473
+ function anonymous(parent, component, context, components, effect, getRaw) {
1593
1474
  const elms = []
1594
-
1595
- if(!elms[0]) {
1596
- elms[0] = this.element({parent: parent || 'root'}, component)
1597
- }
1475
+ let componentType
1476
+ const rootComponent = component
1598
1477
  const elementConfig0 = {}
1599
1478
 
1600
- if(!elms[0].nodeId) {
1601
- elms[0].populate(elementConfig0)
1602
- }
1603
-
1604
- const cmp1 = (context.components && context.components['Page']) ||
1605
- component[Symbol.for('components')]['Page']
1479
+ elms[0] = this.element({ parent: parent || 'root' }, component)
1480
+ elms[0].populate(elementConfig0)
1606
1481
 
1482
+ const cmp1 = (context.components && context.components['Page']) || components['Page']
1607
1483
  parent = elms[0]
1608
-
1609
- if(!elms[1]) {
1610
- elms[1] = this.element({parent: parent || 'root'}, component)
1611
- }
1612
1484
  const elementConfig1 = {}
1485
+
1486
+ elms[1] = this.element({ parent: parent || 'root' }, component)
1613
1487
  elementConfig1['w'] = 1920
1614
1488
  elementConfig1['h'] = 1080
1615
-
1616
1489
  if(typeof cmp1 !== 'undefined') {
1617
1490
  for(let key in cmp1.config.props) {
1618
- delete elementConfig1[cmp1.config.props[key]]
1491
+ delete elementConfig1[cmp1.config.props[key]]
1619
1492
  }
1620
1493
  }
1621
1494
 
1622
- if(!elms[1].nodeId) {
1623
- elms[1].populate(elementConfig1)
1624
- }
1625
-
1495
+ elms[1].populate(elementConfig1)
1626
1496
  parent = elms[1]
1497
+
1627
1498
  const props2 = {}
1628
1499
  props2['w'] = 1920
1629
1500
  props2['h'] = 1080
1501
+ componentType = props2['is'] || 'Page'
1502
+ let component2
1630
1503
 
1631
-
1632
- if(!elms[2]) {
1633
- const componentType = props2['is'] || 'Page'
1634
- elms[2] = (context.components && context.components[componentType] || component[Symbol.for('components')][componentType] || (() => { console.error('component Page not found')})).call(null, {props: props2}, elms[1], component)
1635
- if (elms[2][Symbol.for('slots')][0]) {
1636
- parent = elms[2][Symbol.for('slots')][0]
1637
- component = elms[2]
1638
- } else {
1639
- parent = elms[2][Symbol.for('children')][0]
1640
- }
1504
+ if (typeof componentType === 'string') {
1505
+ component2 = context.components && context.components[componentType] || components[componentType]
1506
+ if (!component2) {
1507
+ throw new Error('Component "Page" not found')
1508
+ }
1509
+ } else if (typeof componentType === 'function' && componentType.name === 'factory') {
1510
+ component2 = componentType
1641
1511
  }
1642
1512
 
1643
- if(!elms[3]) {
1644
- elms[3] = this.element({parent: parent || 'root'}, component)
1513
+ elms[2] = component2.call(null, { props: props2 }, elms[1], component)
1514
+ if(elms[2][Symbol.for('slots')][0]) {
1515
+ parent = elms[2][Symbol.for('slots')][0]
1516
+ component = elms[2]
1517
+ } else {
1518
+ parent = elms[2][Symbol.for('children')][0]
1645
1519
  }
1646
1520
 
1647
1521
  const elementConfig3 = {}
1648
-
1649
- if(!elms[3].nodeId) {
1650
- elms[3].populate(elementConfig3)
1651
- }
1522
+ elms[3] = this.element({ parent: parent || 'root' }, component)
1523
+ elms[3].populate(elementConfig3)
1652
1524
  parent = elms[3]
1653
1525
 
1654
-
1655
- if(!elms[4]) {
1656
- elms[4] = this.element({parent: parent || 'root'}, component)
1657
- }
1658
1526
  const elementConfig4 = {}
1527
+ elms[4] = this.element({ parent: parent || 'root' }, component)
1659
1528
  elementConfig4['x'] = 100
1660
1529
  elementConfig4['y'] = component.y
1661
-
1662
1530
  elementConfig4['parent'] = component[Symbol.for('slots')].filter(slot => slot.ref === 'mySlot').shift() || component[Symbol.for('slots')][0] || parent
1663
1531
  elementConfig4['slot'] = "mySlot"
1664
-
1665
- if(!elms[4].nodeId) {
1666
- elms[4].populate(elementConfig4)
1667
- }
1532
+ elms[4].populate(elementConfig4)
1668
1533
 
1669
1534
  return elms
1670
1535
  }
@@ -1710,46 +1575,29 @@ test('Generate code for a template with a slot', (assert) => {
1710
1575
  }
1711
1576
 
1712
1577
  const expectedRender = `
1713
- function anonymous(parent,component,context) {
1578
+ function anonymous(parent, component, context, components, effect, getRaw) {
1714
1579
  const elms = []
1715
-
1716
- if(!elms[0]) {
1717
- elms[0] = this.element({parent: parent || 'root'}, component)
1718
- }
1580
+ let componentType
1581
+ const rootComponent = component
1719
1582
  const elementConfig0 = {}
1720
1583
 
1721
- if(!elms[0].nodeId) {
1722
- elms[0].populate(elementConfig0)
1723
- }
1724
-
1584
+ elms[0] = this.element({ parent: parent || 'root' }, component)
1585
+ elms[0].populate(elementConfig0)
1725
1586
  parent = elms[0]
1726
1587
 
1727
- if(!elms[1]) {
1728
- elms[1] = this.element({parent: parent || 'root'}, component)
1729
- }
1730
1588
  const elementConfig1 = {}
1589
+ elms[1] = this.element({ parent: parent || 'root' }, component)
1731
1590
  elementConfig1['w'] = 1920
1732
1591
  elementConfig1['h'] = 1080
1733
-
1734
- if(!elms[1].nodeId) {
1735
- elms[1].populate(elementConfig1)
1736
- }
1737
-
1592
+ elms[1].populate(elementConfig1)
1738
1593
  parent = elms[1]
1739
1594
 
1740
- if(!elms[2]) {
1741
- elms[2] = this.element({parent: parent || 'root'}, component)
1742
- }
1743
-
1744
1595
  const elementConfig2 = {}
1745
-
1596
+ elms[2] = this.element({ parent: parent || 'root' }, component)
1746
1597
  elementConfig2[Symbol.for('isSlot')] = true
1747
1598
  elementConfig2['x'] = 100
1748
1599
  elementConfig2['y'] = component.y
1749
-
1750
- if(!elms[2].nodeId) {
1751
- elms[2].populate(elementConfig2)
1752
- }
1600
+ elms[2].populate(elementConfig2)
1753
1601
 
1754
1602
  return elms
1755
1603
  }
@@ -1787,52 +1635,21 @@ test('Generate code for a template with inline Text', (assert) => {
1787
1635
  }
1788
1636
 
1789
1637
  const expectedRender = `
1790
- function anonymous(parent,component,context) {
1638
+ function anonymous(parent, component, context, components, effect, getRaw) {
1791
1639
  const elms = []
1792
-
1793
- if(!elms[0]) {
1794
- elms[0] = this.element({parent: parent || 'root'}, component)
1795
- }
1640
+ let componentType
1641
+ const rootComponent = component
1796
1642
  const elementConfig0 = {}
1797
1643
 
1798
- if(!elms[0].nodeId) {
1799
- elms[0].populate(elementConfig0)
1800
- }
1801
-
1802
- const cmp1 = (context.components && context.components['Text']) ||
1803
- component[Symbol.for('components')]['Text']
1804
-
1644
+ elms[0] = this.element({ parent: parent || 'root' }, component)
1645
+ elms[0].populate(elementConfig0)
1805
1646
  parent = elms[0]
1806
- if(!elms[1]) {
1807
- elms[1] = this.element({parent: parent || 'root'}, component)
1808
- }
1809
1647
 
1810
1648
  const elementConfig1 = {}
1811
- elementConfig1['content'] = 'Hello Blits!'
1812
- if(typeof cmp1 !== 'undefined') {
1813
- for(let key in cmp1.config.props) {
1814
- delete elementConfig1[cmp1.config.props[key]]
1815
- }
1816
- }
1817
-
1818
- if(!elms[1].nodeId) {
1819
- elms[1].populate(elementConfig1)
1820
- }
1821
-
1822
- parent = elms[1]
1823
- const props2 = {}
1824
- props2['content'] = 'Hello Blits!'
1825
-
1826
- if(!elms[2]) {
1827
- const componentType = props2['is'] || 'Text'
1828
- elms[2] = (context.components && context.components[componentType] || component[Symbol.for('components')][componentType] || (() => { console.error('component Text not found')})).call(null, {props: props2}, elms[1], component)
1829
- if (elms[2][Symbol.for('slots')][0]) {
1830
- parent = elms[2][Symbol.for('slots')][0]
1831
- component = elms[2]
1832
- } else {
1833
- parent = elms[2][Symbol.for('children')][0]
1834
- }
1835
- }
1649
+ elms[1] = this.element({ parent: parent || 'root' }, component)
1650
+ elementConfig1['content'] = 'HelloBlits!'
1651
+ elementConfig1['__textnode'] = true
1652
+ elms[1].populate(elementConfig1)
1836
1653
 
1837
1654
  return elms
1838
1655
  }
@@ -1868,52 +1685,21 @@ test('Generate code for a template with inline dynamic Text', (assert) => {
1868
1685
  }
1869
1686
 
1870
1687
  const expectedRender = `
1871
- function anonymous(parent,component,context) {
1688
+ function anonymous(parent, component, context, components, effect, getRaw) {
1872
1689
  const elms = []
1873
-
1874
- if(!elms[0]) {
1875
- elms[0] = this.element({parent: parent || 'root'}, component)
1876
- }
1690
+ let componentType
1691
+ const rootComponent = component
1877
1692
  const elementConfig0 = {}
1878
1693
 
1879
- if(!elms[0].nodeId) {
1880
- elms[0].populate(elementConfig0)
1881
- }
1882
-
1883
- const cmp1 = (context.components && context.components['Text']) ||
1884
- component[Symbol.for('components')]['Text']
1885
-
1694
+ elms[0] = this.element({ parent: parent || 'root' }, component)
1695
+ elms[0].populate(elementConfig0)
1886
1696
  parent = elms[0]
1887
- if(!elms[1]) {
1888
- elms[1] = this.element({parent: parent || 'root'}, component)
1889
- }
1890
1697
 
1891
1698
  const elementConfig1 = {}
1699
+ elms[1] = this.element({ parent: parent || 'root' }, component)
1892
1700
  elementConfig1['content'] = component.myText
1893
- if(typeof cmp1 !== 'undefined') {
1894
- for(let key in cmp1.config.props) {
1895
- delete elementConfig1[cmp1.config.props[key]]
1896
- }
1897
- }
1898
-
1899
- if(!elms[1].nodeId) {
1900
- elms[1].populate(elementConfig1)
1901
- }
1902
-
1903
- parent = elms[1]
1904
- const props2 = {}
1905
- props2['content'] = component.myText
1906
-
1907
- if(!elms[2]) {
1908
- const componentType = props2['is'] || 'Text'
1909
- elms[2] = (context.components && context.components[componentType] || component[Symbol.for('components')][componentType] || (() => { console.error('component Text not found')})).call(null, {props: props2}, elms[1], component)
1910
- if (elms[2][Symbol.for('slots')][0]) {
1911
- parent = elms[2][Symbol.for('slots')][0]
1912
- component = elms[2]
1913
- } else {
1914
- parent = elms[2][Symbol.for('children')][0]
1915
- }
1916
- }
1701
+ elementConfig1['__textnode'] = true
1702
+ elms[1].populate(elementConfig1)
1917
1703
 
1918
1704
  return elms
1919
1705
  }
@@ -1949,52 +1735,21 @@ test('Generate code for a template with inline dynamic Text embedded in static t
1949
1735
  }
1950
1736
 
1951
1737
  const expectedRender = `
1952
- function anonymous(parent,component,context) {
1738
+ function anonymous(parent, component, context, components, effect, getRaw) {
1953
1739
  const elms = []
1954
-
1955
- if(!elms[0]) {
1956
- elms[0] = this.element({parent: parent || 'root'}, component)
1957
- }
1740
+ let componentType
1741
+ const rootComponent = component
1958
1742
  const elementConfig0 = {}
1959
1743
 
1960
- if(!elms[0].nodeId) {
1961
- elms[0].populate(elementConfig0)
1962
- }
1963
-
1964
- const cmp1 = (context.components && context.components['Text']) ||
1965
- component[Symbol.for('components')]['Text']
1966
-
1744
+ elms[0] = this.element({ parent: parent || 'root' }, component)
1745
+ elms[0].populate(elementConfig0)
1967
1746
  parent = elms[0]
1968
- if(!elms[1]) {
1969
- elms[1] = this.element({parent: parent || 'root'}, component)
1970
- }
1971
1747
 
1972
1748
  const elementConfig1 = {}
1973
- elementConfig1['content'] = 'Hello ' + component.firstname + ' ' + component.lastname + ', how are you?'
1974
- if(typeof cmp1 !== 'undefined') {
1975
- for(let key in cmp1.config.props) {
1976
- delete elementConfig1[cmp1.config.props[key]]
1977
- }
1978
- }
1979
-
1980
- if(!elms[1].nodeId) {
1981
- elms[1].populate(elementConfig1)
1982
- }
1983
-
1984
- parent = elms[1]
1985
- const props2 = {}
1986
- props2['content'] = 'Hello ' + component.firstname + ' ' + component.lastname + ', how are you?'
1987
-
1988
- if(!elms[2]) {
1989
- const componentType = props2['is'] || 'Text'
1990
- elms[2] = (context.components && context.components[componentType] || component[Symbol.for('components')][componentType] || (() => { console.error('component Text not found')})).call(null, {props: props2}, elms[1], component)
1991
- if (elms[2][Symbol.for('slots')][0]) {
1992
- parent = elms[2][Symbol.for('slots')][0]
1993
- component = elms[2]
1994
- } else {
1995
- parent = elms[2][Symbol.for('children')][0]
1996
- }
1997
- }
1749
+ elms[1] = this.element({ parent: parent || 'root' }, component)
1750
+ elementConfig1['content'] = 'Hello' + component.firstname + ' ' + component.lastname + ', how are you?'
1751
+ elementConfig1['__textnode'] = true
1752
+ elms[1].populate(elementConfig1)
1998
1753
 
1999
1754
  return elms
2000
1755
  }
@@ -2035,36 +1790,25 @@ test('Generate code for a template with a single element with attributes with pe
2035
1790
  }
2036
1791
 
2037
1792
  const expectedRender = `
2038
- function anonymous(parent,component,context) {
1793
+ function anonymous(parent, component, context, components, effect, getRaw) {
2039
1794
  const elms = []
2040
-
2041
- if(!elms[0]) {
2042
- elms[0] = this.element({parent: parent || 'root'}, component)
2043
- }
1795
+ let componentType
1796
+ const rootComponent = component
2044
1797
  const elementConfig0 = {}
2045
1798
 
1799
+ elms[0] = this.element({ parent: parent || 'root' }, component)
2046
1800
  elementConfig0['w'] = 1920
2047
1801
  elementConfig0['h'] = 1080
2048
-
2049
- if(!elms[0].nodeId) {
2050
- elms[0].populate(elementConfig0)
2051
- }
2052
-
1802
+ elms[0].populate(elementConfig0)
2053
1803
  parent = elms[0]
2054
1804
 
2055
- if(!elms[1]) {
2056
- elms[1] = this.element({parent: parent || 'root'}, component)
2057
- }
2058
1805
  const elementConfig1 = {}
2059
-
2060
- elementConfig1['w'] = parent.node.width * (50/100)
2061
- elementConfig1['h'] = parent.node.height * (40/100)
2062
- elementConfig1['x'] = parent.node.width * (10/100)
2063
- elementConfig1['y'] = parent.node.height * (20/100)
2064
-
2065
- if(!elms[1].nodeId) {
2066
- elms[1].populate(elementConfig1)
2067
- }
1806
+ elms[1] = this.element({ parent: parent || 'root' }, component)
1807
+ elementConfig1['w'] = parent.node.width * (50 / 100)
1808
+ elementConfig1['h'] = parent.node.height * (40 / 100)
1809
+ elementConfig1['x'] = parent.node.width * (10 / 100)
1810
+ elementConfig1['y'] = parent.node.height * (20 / 100)
1811
+ elms[1].populate(elementConfig1)
2068
1812
 
2069
1813
  return elms
2070
1814
  }
@@ -2100,57 +1844,57 @@ test('Generate code for a template with a simple for-loop on an Element', (asser
2100
1844
  }
2101
1845
 
2102
1846
  const expectedRender = `
2103
- function anonymous(parent,component,context) {
2104
- const elms = []
2105
-
2106
- if(!elms[0]) {
2107
- elms[0] = this.element({parent: parent || 'root'}, component)
2108
- }
2109
- const elementConfig0 = {}
2110
-
2111
- if(!elms[0].nodeId) {
2112
- elms[0].populate(elementConfig0)
1847
+ function anonymous(parent, component, context, components, effect, getRaw) {
1848
+ const elms = []
1849
+ let componentType
1850
+ const rootComponent = component
1851
+ const elementConfig0 = {}
1852
+ elms[0] = this.element({ parent: parent || 'root' }, component)
1853
+ elms[0].populate(elementConfig0)
1854
+ parent = elms[0]
1855
+ const created1 = []
1856
+ const forloop1 = (collection = [], elms, created) => {
1857
+ const rawCollection = getRaw(collection)
1858
+ const keys = new Set(rawCollection.map((item) => '' + undefined))
1859
+ let i = created.length
1860
+ while (i--) {
1861
+ const key = created[i]
1862
+ if (!keys.has(key)) {
1863
+ elms[1][key] && elms[1][key].destroy()
1864
+ delete elms[1][key]
1865
+ }
2113
1866
  }
2114
-
2115
- return elms
2116
- }
2117
- `
2118
-
2119
- const expectedEffect1 = `
2120
- function anonymous(component,elms,context) {
2121
- parent = elms[0]
2122
- const collection = component.items
2123
- const keys = []
2124
- for(let __index = 0; __index < collection.length; __index++) {
1867
+ created.length = 0
1868
+ const length = collection.length
1869
+ for (let __index = 0; __index < length; __index++) {
1870
+ const scope = Object.create(component)
2125
1871
  parent = elms[0]
2126
- if(!component.key) keys.length = 0
2127
- const scope = Object.assign(component, {
2128
- key: Math.random(),
2129
- index: __index,
2130
- item: collection[__index],
2131
- })
2132
- keys.push(scope.key.toString())
2133
-
1872
+ scope['index'] = __index
1873
+ scope['item'] = rawCollection[__index]
1874
+ scope['key'] = __index
1875
+ created.push(scope.key)
2134
1876
  parent = elms[0]
2135
- elms[1] = elms[1] || {}
2136
- if(!elms[1][scope.key]) {
2137
- elms[1][scope.key] = this.element({parent: parent || 'root'}, component)
1877
+ if (elms[1] === undefined) {
1878
+ elms[1] = {}
2138
1879
  }
2139
-
2140
1880
  const elementConfig1 = {}
2141
- if(!elms[1][scope.key].nodeId) {
1881
+ if (!elms[1][scope.key]) {
1882
+ elms[1][scope.key] = this.element({ parent: parent || 'root' }, component)
1883
+ }
1884
+ if (!elms[1][scope.key].nodeId) {
2142
1885
  elms[1][scope.key].populate(elementConfig1)
2143
1886
  }
2144
- }
2145
- if(elms[1]) {
2146
- Object.keys(elms[1]).forEach(key => {
2147
- if(keys.indexOf(key) === -1) {
2148
- elms[1][key].destroy && elms[1][key].destroy()
2149
- delete elms[1][key]
2150
- }
2151
- })
1887
+ scope['item'] = collection[__index]
1888
+ if (elms[1][0] && elms[1][0].forComponent && elms[1][0].forComponent.___layout) {
1889
+ elms[1][0].forComponent.___layout()
1890
+ }
2152
1891
  }
2153
1892
  }
1893
+ effect(() => {
1894
+ forloop1(component.items, elms, created1)
1895
+ }, 'items')
1896
+ return elms
1897
+ }
2154
1898
  `
2155
1899
 
2156
1900
  const actual = generator.call(scope, templateObject)
@@ -2162,14 +1906,8 @@ test('Generate code for a template with a simple for-loop on an Element', (asser
2162
1906
  )
2163
1907
 
2164
1908
  assert.ok(
2165
- Array.isArray(actual.effects) && actual.effects.length === 1,
2166
- 'Generator should return an effects array with 1 function'
2167
- )
2168
-
2169
- assert.equal(
2170
- normalize(actual.effects[0].toString()),
2171
- normalize(expectedEffect1),
2172
- 'Generator should return an effect function for the for loop'
1909
+ Array.isArray(actual.effects) && actual.effects.length === 0,
1910
+ 'Generator should return an empty effect array'
2173
1911
  )
2174
1912
 
2175
1913
  assert.end()
@@ -2191,57 +1929,57 @@ test('Generate code for a template with a simple for-loop on an Element with a c
2191
1929
  }
2192
1930
 
2193
1931
  const expectedRender = `
2194
- function anonymous(parent,component,context) {
2195
- const elms = []
2196
-
2197
- if(!elms[0]) {
2198
- elms[0] = this.element({parent: parent || 'root'}, component)
2199
- }
2200
- const elementConfig0 = {}
2201
-
2202
- if(!elms[0].nodeId) {
2203
- elms[0].populate(elementConfig0)
1932
+ function anonymous(parent, component, context, components, effect, getRaw) {
1933
+ const elms = []
1934
+ let componentType
1935
+ const rootComponent = component
1936
+ const elementConfig0 = {}
1937
+ elms[0] = this.element({ parent: parent || 'root' }, component)
1938
+ elms[0].populate(elementConfig0)
1939
+ parent = elms[0]
1940
+ const created1 = []
1941
+ const forloop1 = (collection = [], elms, created) => {
1942
+ const rawCollection = getRaw(collection)
1943
+ const keys = new Set(rawCollection.map((item) => '' + undefined))
1944
+ let i = created.length
1945
+ while (i--) {
1946
+ const key = created[i]
1947
+ if (!keys.has(key)) {
1948
+ elms[1][key] && elms[1][key].destroy()
1949
+ delete elms[1][key]
1950
+ }
2204
1951
  }
2205
-
2206
- return elms
2207
- }
2208
- `
2209
-
2210
- const expectedEffect1 = `
2211
- function anonymous(component,elms,context) {
2212
- parent = elms[0]
2213
- const collection = component.items
2214
- const keys = []
2215
- for(let __index = 0; __index < collection.length; __index++) {
1952
+ created.length = 0
1953
+ const length = collection.length
1954
+ for (let __index = 0; __index < length; __index++) {
1955
+ const scope = Object.create(component)
2216
1956
  parent = elms[0]
2217
- if(!component.key) keys.length = 0
2218
- const scope = Object.assign(component, {
2219
- key: Math.random(),
2220
- customIndex: __index,
2221
- item: collection[__index],
2222
- })
2223
- keys.push(scope.key.toString())
2224
-
1957
+ scope['customIndex'] = __index
1958
+ scope['item'] = rawCollection[__index]
1959
+ scope['key'] = __index
1960
+ created.push(scope.key)
2225
1961
  parent = elms[0]
2226
- elms[1] = elms[1] || {}
2227
- if(!elms[1][scope.key]) {
2228
- elms[1][scope.key] = this.element({parent: parent || 'root'}, component)
1962
+ if (elms[1] === undefined) {
1963
+ elms[1] = {}
2229
1964
  }
2230
-
2231
1965
  const elementConfig1 = {}
2232
- if(!elms[1][scope.key].nodeId) {
1966
+ if (!elms[1][scope.key]) {
1967
+ elms[1][scope.key] = this.element({ parent: parent || 'root' }, component)
1968
+ }
1969
+ if (!elms[1][scope.key].nodeId) {
2233
1970
  elms[1][scope.key].populate(elementConfig1)
2234
1971
  }
2235
- }
2236
- if(elms[1]) {
2237
- Object.keys(elms[1]).forEach(key => {
2238
- if(keys.indexOf(key) === -1) {
2239
- elms[1][key].destroy && elms[1][key].destroy()
2240
- delete elms[1][key]
2241
- }
2242
- })
1972
+ scope['item'] = collection[__index]
1973
+ if (elms[1][0] && elms[1][0].forComponent && elms[1][0].forComponent.___layout) {
1974
+ elms[1][0].forComponent.___layout()
1975
+ }
2243
1976
  }
2244
1977
  }
1978
+ effect(() => {
1979
+ forloop1(component.items, elms, created1)
1980
+ }, 'items')
1981
+ return elms
1982
+ }
2245
1983
  `
2246
1984
 
2247
1985
  const actual = generator.call(scope, templateObject)
@@ -2253,14 +1991,8 @@ test('Generate code for a template with a simple for-loop on an Element with a c
2253
1991
  )
2254
1992
 
2255
1993
  assert.ok(
2256
- Array.isArray(actual.effects) && actual.effects.length === 1,
2257
- 'Generator should return an effects array with 1 function'
2258
- )
2259
-
2260
- assert.equal(
2261
- normalize(actual.effects[0].toString()),
2262
- normalize(expectedEffect1),
2263
- 'Generator should return an effect function for the for loop'
1994
+ Array.isArray(actual.effects) && actual.effects.length === 0,
1995
+ 'Generator should return an empty effects array'
2264
1996
  )
2265
1997
 
2266
1998
  assert.end()
@@ -2283,59 +2015,57 @@ test('Generate code for a template with a simple for-loop on an Element with a k
2283
2015
  }
2284
2016
 
2285
2017
  const expectedRender = `
2286
- function anonymous(parent,component,context) {
2287
- const elms = []
2288
-
2289
- if(!elms[0]) {
2290
- elms[0] = this.element({parent: parent || 'root'}, component)
2291
- }
2292
- const elementConfig0 = {}
2293
-
2294
- if(!elms[0].nodeId) {
2295
- elms[0].populate(elementConfig0)
2018
+ function anonymous(parent, component, context, components, effect, getRaw) {
2019
+ const elms = []
2020
+ let componentType
2021
+ const rootComponent = component
2022
+ const elementConfig0 = {}
2023
+ elms[0] = this.element({ parent: parent || 'root' }, component)
2024
+ elms[0].populate(elementConfig0)
2025
+ parent = elms[0]
2026
+ const created1 = []
2027
+ const forloop1 = (collection = [], elms, created) => {
2028
+ const rawCollection = getRaw(collection)
2029
+ const keys = new Set(rawCollection.map((item) => '' + item.id))
2030
+ let i = created.length
2031
+ while (i--) {
2032
+ const key = created[i]
2033
+ if (!keys.has(key)) {
2034
+ elms[1][key] && elms[1][key].destroy()
2035
+ delete elms[1][key]
2036
+ }
2296
2037
  }
2297
-
2298
- return elms
2299
- }
2300
- `
2301
-
2302
- const expectedEffect1 = `
2303
- function anonymous(component,elms,context) {
2304
- parent = elms[0]
2305
- const collection = component.items
2306
- const keys = []
2307
- for(let __index = 0; __index < collection.length; __index++) {
2038
+ created.length = 0
2039
+ const length = collection.length
2040
+ for (let __index = 0; __index < length; __index++) {
2041
+ const scope = Object.create(component)
2308
2042
  parent = elms[0]
2309
- if(!component.key) keys.length = 0
2310
- const scope = Object.assign(component, {
2311
- key: Math.random(),
2312
- index: __index,
2313
- item: collection[__index],
2314
- })
2315
- keys.push(scope.item.id)
2316
-
2043
+ scope['index'] = __index
2044
+ scope['item'] = rawCollection[__index]
2045
+ scope['key'] = scope.item.id
2046
+ created.push(scope.key)
2317
2047
  parent = elms[0]
2318
- elms[1] = elms[1] || {}
2319
- if(!elms[1][scope.item.id]) {
2320
- elms[1][scope.item.id] = this.element({parent: parent || 'root'}, component)
2048
+ if (elms[1] === undefined) {
2049
+ elms[1] = {}
2321
2050
  }
2322
-
2323
2051
  const elementConfig1 = {}
2324
- elementConfig1['key'] = scope.item.id
2325
-
2326
- if(!elms[1][scope.item.id].nodeId) {
2327
- elms[1][scope.item.id].populate(elementConfig1)
2052
+ if (!elms[1][scope.key]) {
2053
+ elms[1][scope.key] = this.element({ parent: parent || 'root' }, component)
2054
+ }
2055
+ if (!elms[1][scope.key].nodeId) {
2056
+ elms[1][scope.key].populate(elementConfig1)
2057
+ }
2058
+ scope['item'] = collection[__index]
2059
+ if (elms[1][0] && elms[1][0].forComponent && elms[1][0].forComponent.___layout) {
2060
+ elms[1][0].forComponent.___layout()
2328
2061
  }
2329
- }
2330
- if(elms[1]) {
2331
- Object.keys(elms[1]).forEach(key => {
2332
- if(keys.indexOf(key) === -1) {
2333
- elms[1][key].destroy && elms[1][key].destroy()
2334
- delete elms[1][key]
2335
- }
2336
- })
2337
2062
  }
2338
2063
  }
2064
+ effect(() => {
2065
+ forloop1(component.items, elms, created1)
2066
+ }, 'items')
2067
+ return elms
2068
+ }
2339
2069
  `
2340
2070
 
2341
2071
  const actual = generator.call(scope, templateObject)
@@ -2347,14 +2077,8 @@ test('Generate code for a template with a simple for-loop on an Element with a k
2347
2077
  )
2348
2078
 
2349
2079
  assert.ok(
2350
- Array.isArray(actual.effects) && actual.effects.length === 1,
2351
- 'Generator should return an effects array with 1 function'
2352
- )
2353
-
2354
- assert.equal(
2355
- normalize(actual.effects[0].toString()),
2356
- normalize(expectedEffect1),
2357
- 'Generator should return an effect function for the for loop'
2080
+ Array.isArray(actual.effects) && actual.effects.length === 0,
2081
+ 'Generator should return an empty effects array'
2358
2082
  )
2359
2083
 
2360
2084
  assert.end()
@@ -2377,84 +2101,89 @@ test('Generate code for a template with a simple for-loop on a Component with a
2377
2101
  }
2378
2102
 
2379
2103
  const expectedRender = `
2380
- function anonymous(parent,component,context) {
2381
- const elms = []
2382
-
2383
- if(!elms[0]) {
2384
- elms[0] = this.element({parent: parent || 'root'}, component)
2385
- }
2386
- const elementConfig0 = {}
2387
-
2388
- if(!elms[0].nodeId) {
2389
- elms[0].populate(elementConfig0)
2104
+ function anonymous(parent, component, context, components, effect, getRaw) {
2105
+ const elms = []
2106
+ let componentType
2107
+ const rootComponent = component
2108
+ const elementConfig0 = {}
2109
+ elms[0] = this.element({ parent: parent || 'root' }, component)
2110
+ elms[0].populate(elementConfig0)
2111
+ parent = elms[0]
2112
+ const created1 = []
2113
+ const forloop1 = (collection = [], elms, created) => {
2114
+ const rawCollection = getRaw(collection)
2115
+ const keys = new Set(rawCollection.map((item) => '' + item.id))
2116
+ let i = created.length
2117
+ while (i--) {
2118
+ const key = created[i]
2119
+ if (!keys.has(key)) {
2120
+ elms[1][key] && elms[1][key].destroy()
2121
+ delete elms[1][key]
2122
+ elms[2][key] && elms[2][key].destroy()
2123
+ delete elms[2][key]
2124
+ }
2390
2125
  }
2391
-
2392
- return elms
2393
- }
2394
- `
2395
-
2396
- const expectedEffect1 = `
2397
- function anonymous(component,elms,context) {
2398
- parent = elms[0]
2399
- const collection = component.items
2400
- const keys = []
2401
- for(let __index = 0; __index < collection.length; __index++) {
2126
+ created.length = 0
2127
+ const length = collection.length
2128
+ for (let __index = 0; __index < length; __index++) {
2129
+ const scope = Object.create(component)
2402
2130
  parent = elms[0]
2403
- if(!component.key) keys.length = 0
2404
- const scope = Object.assign(component, {
2405
- key: Math.random(),
2406
- myIndex: __index,
2407
- item: collection[__index],
2408
- })
2409
- keys.push(item.id)
2410
-
2411
- const cmp1 = (context.components && context.components['ListItem']) ||
2412
- component[Symbol.for('components')]['ListItem']
2413
-
2414
- elms[1] = elms[1] || {}
2415
- if(!elms[1][item.id]) {
2416
- elms[1][item.id] = this.element({parent: parent || 'root'}, component)
2131
+ scope['myIndex'] = __index
2132
+ scope['item'] = rawCollection[__index]
2133
+ scope['key'] = item.id
2134
+ created.push(scope.key)
2135
+ const cmp1 = (context.components && context.components['ListItem']) || components['ListItem']
2136
+ if (elms[1] === undefined) {
2137
+ elms[1] = {}
2417
2138
  }
2418
-
2419
2139
  const elementConfig1 = {}
2420
- elementConfig1['key'] = "item.id"
2421
-
2422
- if(typeof cmp1 !== 'undefined') {
2423
- for(let key in cmp1.config.props) {
2140
+ if (!elms[1][scope.key]) {
2141
+ elms[1][scope.key] = this.element({ parent: parent || 'root' }, component)
2142
+ }
2143
+ if (typeof cmp1 !== 'undefined') {
2144
+ for (let key in cmp1.config.props) {
2424
2145
  delete elementConfig1[cmp1.config.props[key]]
2425
2146
  }
2426
2147
  }
2427
-
2428
- if(!elms[1][item.id].nodeId) {
2429
- elms[1][item.id].populate(elementConfig1)
2148
+ if (!elms[1][scope.key].nodeId) {
2149
+ elms[1][scope.key].populate(elementConfig1)
2430
2150
  }
2431
-
2432
- elms[2] = elms[2] || {}
2433
- parent = elms[1][item.id]
2434
-
2151
+ if (elms[2] === undefined) {
2152
+ elms[2] = {}
2153
+ }
2154
+ parent = elms[1][scope.key]
2435
2155
  const props2 = {}
2436
- props2['key'] = "item.id"
2437
-
2438
- if(!elms[2][item.id]) {
2439
- const componentType = props2['is'] || 'ListItem'
2440
- elms[2][item.id] = (context.components && context.components[componentType] || component[Symbol.for('components')][componentType] || (() => { console.error('component ListItem not found')})).call(null, {props: props2}, elms[1][item.id], component)
2441
- if (elms[2][item.id][Symbol.for('slots')][0]) {
2442
- parent = elms[2][item.id][Symbol.for('slots')][0]
2443
- component = elms[2][item.id]
2156
+ if (!elms[2][scope.key]) {
2157
+ componentType = props2['is'] || 'ListItem'
2158
+ let component2
2159
+ if (typeof componentType === 'string') {
2160
+ component2 =
2161
+ context.components && context.components[componentType] || components[componentType]
2162
+ if (!component2) {
2163
+ throw new Error('Component "ListItem" not found')
2164
+ }
2165
+ } else if (typeof componentType === 'function' && componentType.name === 'factory') {
2166
+ component2 = componentType
2167
+ }
2168
+ elms[2][scope.key] = component2.call(null, { props: props2 }, elms[1][scope.key], component)
2169
+ if (elms[2][scope.key][Symbol.for('slots')][0]) {
2170
+ parent = elms[2][scope.key][Symbol.for('slots')][0]
2171
+ component = elms[2][scope.key]
2444
2172
  } else {
2445
- parent = elms[2][item.id][Symbol.for('children')][0]
2173
+ parent = elms[2][scope.key][Symbol.for('children')][0]
2446
2174
  }
2447
2175
  }
2448
- }
2449
- if(elms[1]) {
2450
- Object.keys(elms[1]).forEach(key => {
2451
- if(keys.indexOf(key) === -1) {
2452
- elms[1][key].destroy && elms[1][key].destroy()
2453
- delete elms[1][key]
2454
- }
2455
- })
2176
+ scope['item'] = collection[__index]
2177
+ if (elms[1][0] && elms[1][0].forComponent && elms[1][0].forComponent.___layout) {
2178
+ elms[1][0].forComponent.___layout()
2179
+ }
2456
2180
  }
2457
2181
  }
2182
+ effect(() => {
2183
+ forloop1(component.items, elms, created1)
2184
+ }, 'items')
2185
+ return elms
2186
+ }
2458
2187
  `
2459
2188
 
2460
2189
  const actual = generator.call(scope, templateObject)
@@ -2466,14 +2195,8 @@ test('Generate code for a template with a simple for-loop on a Component with a
2466
2195
  )
2467
2196
 
2468
2197
  assert.ok(
2469
- Array.isArray(actual.effects) && actual.effects.length === 1,
2470
- 'Generator should return an effects array with 1 function'
2471
- )
2472
-
2473
- assert.equal(
2474
- normalize(actual.effects[0].toString()),
2475
- normalize(expectedEffect1),
2476
- 'Generator should return an effect function for the for loop'
2198
+ Array.isArray(actual.effects) && actual.effects.length === 0,
2199
+ 'Generator should return an empty effects array'
2477
2200
  )
2478
2201
 
2479
2202
  assert.end()
@@ -2497,61 +2220,59 @@ test('Generate code for a template with a simple for-loop on an Element with an
2497
2220
  }
2498
2221
 
2499
2222
  const expectedRender = `
2500
- function anonymous(parent,component,context) {
2501
- const elms = []
2502
-
2503
- if(!elms[0]) {
2504
- elms[0] = this.element({parent: parent || 'root'}, component)
2505
- }
2506
- const elementConfig0 = {}
2507
-
2508
- if(!elms[0].nodeId) {
2509
- elms[0].populate(elementConfig0)
2223
+ function anonymous(parent, component, context, components, effect, getRaw) {
2224
+ const elms = []
2225
+ let componentType
2226
+ const rootComponent = component
2227
+ const elementConfig0 = {}
2228
+ elms[0] = this.element({ parent: parent || 'root' }, component)
2229
+ elms[0].populate(elementConfig0)
2230
+ parent = elms[0]
2231
+ const created1 = []
2232
+ const forloop1 = (collection = [], elms, created) => {
2233
+ const rawCollection = getRaw(collection)
2234
+ const keys = new Set(rawCollection.map((item) => '' + item.id))
2235
+ let i = created.length
2236
+ while (i--) {
2237
+ const key = created[i]
2238
+ if (!keys.has(key)) {
2239
+ elms[1][key] && elms[1][key].destroy()
2240
+ delete elms[1][key]
2241
+ }
2510
2242
  }
2511
-
2512
- return elms
2513
- }
2514
- `
2515
-
2516
- const expectedEffect1 = `
2517
- function anonymous(component,elms,context) {
2518
- parent = elms[0]
2519
- const collection = component.items
2520
- const keys = []
2521
- for(let __index = 0; __index < collection.length; __index++) {
2243
+ created.length = 0
2244
+ const length = collection.length
2245
+ for (let __index = 0; __index < length; __index++) {
2246
+ const scope = Object.create(component)
2522
2247
  parent = elms[0]
2523
- if(!component.key) keys.length = 0
2524
- const scope = Object.assign(component, {
2525
- key: Math.random(),
2526
- index: __index,
2527
- item: collection[__index],
2528
- __ref: 'myref'+__index
2529
- })
2530
- keys.push(item.id)
2531
-
2248
+ scope['index'] = __index
2249
+ scope['item'] = rawCollection[__index]
2250
+ scope['key'] = item.id
2251
+ scope['__ref'] = 'myref' + __index
2252
+ created.push(scope.key)
2532
2253
  parent = elms[0]
2533
- elms[1] = elms[1] || {}
2534
- if(!elms[1][item.id]) {
2535
- elms[1][item.id] = this.element({parent: parent || 'root'}, component)
2254
+ if (elms[1] === undefined) {
2255
+ elms[1] = {}
2536
2256
  }
2537
-
2538
2257
  const elementConfig1 = {}
2539
- elementConfig1['key'] = "item.id"
2258
+ if (!elms[1][scope.key]) {
2259
+ elms[1][scope.key] = this.element({ parent: parent || 'root' }, component)
2260
+ }
2540
2261
  elementConfig1['ref'] = scope.__ref
2541
-
2542
- if(!elms[1][item.id].nodeId) {
2543
- elms[1][item.id].populate(elementConfig1)
2262
+ if (!elms[1][scope.key].nodeId) {
2263
+ elms[1][scope.key].populate(elementConfig1)
2264
+ }
2265
+ scope['item'] = collection[__index]
2266
+ if (elms[1][0] && elms[1][0].forComponent && elms[1][0].forComponent.___layout) {
2267
+ elms[1][0].forComponent.___layout()
2544
2268
  }
2545
- }
2546
- if(elms[1]) {
2547
- Object.keys(elms[1]).forEach(key => {
2548
- if(keys.indexOf(key) === -1) {
2549
- elms[1][key].destroy && elms[1][key].destroy()
2550
- delete elms[1][key]
2551
- }
2552
- })
2553
2269
  }
2554
2270
  }
2271
+ effect(() => {
2272
+ forloop1(component.items, elms, created1)
2273
+ }, 'items')
2274
+ return elms
2275
+ }
2555
2276
  `
2556
2277
 
2557
2278
  const actual = generator.call(scope, templateObject)
@@ -2563,15 +2284,9 @@ test('Generate code for a template with a simple for-loop on an Element with an
2563
2284
  )
2564
2285
 
2565
2286
  assert.ok(
2566
- Array.isArray(actual.effects) && actual.effects.length === 1,
2287
+ Array.isArray(actual.effects) && actual.effects.length === 0,
2567
2288
  'Generator should return an effects array with 1 function'
2568
2289
  )
2569
2290
 
2570
- assert.equal(
2571
- normalize(actual.effects[0].toString()),
2572
- normalize(expectedEffect1),
2573
- 'Generator should return an effect function for the for loop'
2574
- )
2575
-
2576
2291
  assert.end()
2577
2292
  })