glass-easel-miniprogram-adapter 0.1.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 (50) hide show
  1. package/README.md +49 -0
  2. package/dist/glass_easel_miniprogram_adapter.d.ts +1 -0
  3. package/dist/glass_easel_miniprogram_adapter.js +2 -0
  4. package/dist/glass_easel_miniprogram_adapter.js.map +1 -0
  5. package/dist/types/src/backend.d.ts +51 -0
  6. package/dist/types/src/backend.d.ts.map +1 -0
  7. package/dist/types/src/behavior.d.ts +35 -0
  8. package/dist/types/src/behavior.d.ts.map +1 -0
  9. package/dist/types/src/component.d.ts +160 -0
  10. package/dist/types/src/component.d.ts.map +1 -0
  11. package/dist/types/src/index.d.ts +58 -0
  12. package/dist/types/src/index.d.ts.map +1 -0
  13. package/dist/types/src/selector_query.d.ts +98 -0
  14. package/dist/types/src/selector_query.d.ts.map +1 -0
  15. package/dist/types/src/space.d.ts +369 -0
  16. package/dist/types/src/space.d.ts.map +1 -0
  17. package/dist/types/src/types.d.ts +77 -0
  18. package/dist/types/src/types.d.ts.map +1 -0
  19. package/dist/types/src/utils.d.ts +2 -0
  20. package/dist/types/src/utils.d.ts.map +1 -0
  21. package/dist/types/tests/base/env.d.ts +3 -0
  22. package/dist/types/tests/base/env.d.ts.map +1 -0
  23. package/dist/types/tests/data_update.test.d.ts +2 -0
  24. package/dist/types/tests/data_update.test.d.ts.map +1 -0
  25. package/dist/types/tests/env.test.d.ts +2 -0
  26. package/dist/types/tests/env.test.d.ts.map +1 -0
  27. package/dist/types/tests/selector.test.d.ts +2 -0
  28. package/dist/types/tests/selector.test.d.ts.map +1 -0
  29. package/dist/types/tests/space.test.d.ts +2 -0
  30. package/dist/types/tests/space.test.d.ts.map +1 -0
  31. package/dist/types/tests/trait_behavior.test.d.ts +2 -0
  32. package/dist/types/tests/trait_behavior.test.d.ts.map +1 -0
  33. package/jest.config.js +13 -0
  34. package/package.json +32 -0
  35. package/src/backend.ts +106 -0
  36. package/src/behavior.ts +101 -0
  37. package/src/component.ts +476 -0
  38. package/src/index.ts +82 -0
  39. package/src/selector_query.ts +356 -0
  40. package/src/space.ts +1514 -0
  41. package/src/types.ts +85 -0
  42. package/src/utils.ts +3 -0
  43. package/tests/base/env.ts +20 -0
  44. package/tests/data_update.test.ts +92 -0
  45. package/tests/env.test.ts +141 -0
  46. package/tests/selector.test.ts +407 -0
  47. package/tests/space.test.ts +953 -0
  48. package/tests/trait_behavior.test.ts +141 -0
  49. package/tsconfig.json +11 -0
  50. package/webpack.config.js +78 -0
@@ -0,0 +1,953 @@
1
+ import * as glassEasel from 'glass-easel'
2
+ import { tmpl } from './base/env'
3
+ import {
4
+ MiniProgramEnv,
5
+ StyleIsolation,
6
+ BehaviorConstructor,
7
+ ComponentConstructor,
8
+ types,
9
+ } from '../src'
10
+
11
+ const domHtml = (elem: glassEasel.Element): string => {
12
+ const domElem = elem.getBackendElement() as unknown as Element
13
+ return domElem.innerHTML
14
+ }
15
+
16
+ describe('define', () => {
17
+ test('define basic behaviors and components', () => {
18
+ const env = new MiniProgramEnv()
19
+ const codeSpace = env.createCodeSpace('', true)
20
+
21
+ codeSpace.addStyleSheet('app', 'app.css')
22
+ codeSpace.addStyleSheet('path/to/comp', 'path/to/comp.css')
23
+
24
+ codeSpace.addCompiledTemplate('path/to/comp', tmpl(`
25
+ <div class="ab">{{a}}-{{b}}</div>
26
+ `))
27
+
28
+ const beh = codeSpace.behavior()
29
+ .definition({
30
+ data: {
31
+ a: 123,
32
+ },
33
+ })
34
+ .register()
35
+
36
+ codeSpace.component('path/to/comp')
37
+ .definition({
38
+ behaviors: [beh],
39
+ properties: {
40
+ b: Number,
41
+ },
42
+ })
43
+ .register()
44
+
45
+ const ab = env.associateBackend()
46
+ ab.registerStyleSheetContent('app.css', '')
47
+ ab.registerStyleSheetContent('path/to/comp.css', '.ab { color: red }')
48
+ const root = ab.createRoot('body', codeSpace, 'path/to/comp?b=456')
49
+ expect(domHtml(root.getComponent())).toBe('<div class="ab">123-456</div>')
50
+ })
51
+
52
+ test('define basic behaviors and components with global vars', () => {
53
+ const env = new MiniProgramEnv()
54
+ const codeSpace = env.createCodeSpace('', true)
55
+ const callOrder = [] as number[]
56
+
57
+ codeSpace.addComponentStaticConfig('path/to/comp', {})
58
+
59
+ codeSpace.addCompiledTemplate('path/to/comp', tmpl(`
60
+ <div>{{a}}-{{b}}-{{c}}</div>
61
+ `))
62
+
63
+ const g = {} as { Behavior: BehaviorConstructor, Component: ComponentConstructor }
64
+ codeSpace.globalComponentEnv(g, 'path/to/comp', () => {
65
+ const Behavior = g.Behavior
66
+ const Component = g.Component
67
+
68
+ const beh = Behavior({
69
+ data: {
70
+ a: 123,
71
+ },
72
+ observers: {
73
+ a() {
74
+ callOrder.push(1)
75
+ },
76
+ },
77
+ })
78
+
79
+ Component({
80
+ options: {
81
+ propertyEarlyInit: true,
82
+ },
83
+ behaviors: [beh],
84
+ properties: {
85
+ b: Number,
86
+ },
87
+ data: () => ({
88
+ c: 789,
89
+ }),
90
+ observers: [{
91
+ fields: 'b',
92
+ observer() {
93
+ callOrder.push(2)
94
+ },
95
+ }],
96
+ created() {
97
+ callOrder.push(3)
98
+ },
99
+ attached() {
100
+ this.setData({
101
+ a: 321,
102
+ b: 654,
103
+ } as { b: number })
104
+ callOrder.push(4)
105
+ },
106
+ detached() {
107
+ callOrder.push(5)
108
+ },
109
+ moved() {
110
+ callOrder.push(6)
111
+ },
112
+ ready() {
113
+ callOrder.push(7)
114
+ },
115
+ lifetimes: {
116
+ invalid() { /* empty */ },
117
+ },
118
+ pageLifetimes: {
119
+ invalid() { /* empty */ },
120
+ },
121
+ relations: {
122
+ invalid: {
123
+ type: 'parent',
124
+ },
125
+ },
126
+ externalClasses: [],
127
+ })
128
+ })
129
+
130
+ const ab = env.associateBackend()
131
+ const root = ab.createRoot('body', codeSpace, 'path/to/comp?b=456')
132
+ expect(domHtml(root.getComponent())).toBe('<div>123-456-789</div>')
133
+ glassEasel.Element.pretendAttached(root.getComponent())
134
+ expect(domHtml(root.getComponent())).toBe('<div>321-654-789</div>')
135
+ root.getComponent().triggerLifetime('ready', [])
136
+ root.getComponent().triggerLifetime('moved', [])
137
+ glassEasel.Element.pretendDetached(root.getComponent())
138
+ expect(callOrder).toStrictEqual([2, 3, 1, 2, 4, 7, 6, 5])
139
+ })
140
+
141
+ test('define legacy pages', () => {
142
+ const env = new MiniProgramEnv()
143
+ const codeSpace = env.createCodeSpace('', true)
144
+ const callOrder = [] as number[]
145
+
146
+ codeSpace.addCompiledTemplate('path/to/comp', tmpl(`
147
+ <div>{{a}}-{{b}}</div>
148
+ `))
149
+
150
+ codeSpace.componentEnv('path/to/comp', ({ Behavior, Page }) => {
151
+ const beh = Behavior()
152
+ .property('a', String)
153
+ .lifetime('attached', function () {
154
+ expect(this.hasBehavior(beh)).toBe(true)
155
+ const self = this as unknown as {
156
+ myMethod: () => number,
157
+ myData: any,
158
+ }
159
+ expect(self.myMethod()).toBe(123)
160
+ expect(self.myData).toStrictEqual({ myField: 456 })
161
+ callOrder.push(1)
162
+ })
163
+ .register()
164
+
165
+ Page({
166
+ behaviors: [beh],
167
+ data: {
168
+ b: 'def',
169
+ },
170
+ myMethod() {
171
+ return 123
172
+ },
173
+ myData: {
174
+ myField: 456,
175
+ },
176
+ })
177
+ })
178
+
179
+ const ab = env.associateBackend()
180
+ const root = ab.createRoot('body', codeSpace, 'path/to/comp?a=abc')
181
+ glassEasel.Element.pretendAttached(root.getComponent())
182
+ expect(domHtml(root.getComponent())).toBe('<div>abc-def</div>')
183
+ expect(callOrder).toStrictEqual([1])
184
+ })
185
+
186
+ test('options generics', () => {
187
+ const env = new MiniProgramEnv()
188
+ const codeSpace = env.createCodeSpace('', true)
189
+
190
+ codeSpace.addComponentStaticConfig('comp/a', {
191
+ component: true,
192
+ generics: {
193
+ c: true,
194
+ },
195
+ })
196
+ codeSpace.addCompiledTemplate('comp/a', tmpl(`
197
+ <c />
198
+ `))
199
+ codeSpace.componentEnv('comp/a', ({ Component }) => {
200
+ Component().register()
201
+ })
202
+
203
+ codeSpace.addComponentStaticConfig('comp/b', {
204
+ component: true,
205
+ })
206
+ codeSpace.addCompiledTemplate('comp/b', tmpl(`
207
+ <span>B</span>
208
+ `))
209
+ codeSpace.componentEnv('comp/b', ({ Component }) => {
210
+ Component().register()
211
+ })
212
+
213
+ codeSpace.addComponentStaticConfig('path/to/comp', {
214
+ usingComponents: {
215
+ a: '/comp/a',
216
+ b: '/comp/b',
217
+ },
218
+ })
219
+ codeSpace.addCompiledTemplate('path/to/comp', tmpl(`
220
+ <a generic:c="b" />
221
+ `))
222
+ codeSpace.componentEnv('path/to/comp', ({ Component }) => {
223
+ Component().register()
224
+ })
225
+
226
+ const ab = env.associateBackend()
227
+ const root = ab.createRoot('body', codeSpace, 'path/to/comp')
228
+ expect(domHtml(root.getComponent())).toBe('<a><c><span>B</span></c></a>')
229
+ })
230
+
231
+ test('options placeholder', () => {
232
+ const env = new MiniProgramEnv()
233
+ const codeSpace = env.createCodeSpace('', true)
234
+
235
+ codeSpace.addComponentStaticConfig('comp/a', {
236
+ component: true,
237
+ })
238
+ codeSpace.addCompiledTemplate('comp/a', tmpl(`
239
+ <div>A</div>
240
+ `))
241
+ codeSpace.componentEnv('comp/a', ({ Component }) => {
242
+ Component().register()
243
+ })
244
+
245
+ codeSpace.addComponentStaticConfig('path/to/comp', {
246
+ usingComponents: {
247
+ a: '/comp/b',
248
+ },
249
+ placeholder: {
250
+ a: '/comp/a',
251
+ },
252
+ })
253
+ codeSpace.addCompiledTemplate('path/to/comp', tmpl(`
254
+ <a />
255
+ `))
256
+ codeSpace.componentEnv('path/to/comp', ({ Component }) => {
257
+ Component().register()
258
+ })
259
+
260
+ const ab = env.associateBackend()
261
+ const root = ab.createRoot('body', codeSpace, 'path/to/comp')
262
+ expect(domHtml(root.getComponent())).toBe('<a><div>A</div></a>')
263
+
264
+ codeSpace.addComponentStaticConfig('comp/b', {
265
+ component: true,
266
+ })
267
+ codeSpace.addCompiledTemplate('comp/b', tmpl(`
268
+ <span>B</span>
269
+ `))
270
+ codeSpace.componentEnv('comp/b', ({ Component }) => {
271
+ Component().register()
272
+ })
273
+
274
+ expect(domHtml(root.getComponent())).toBe('<a><span>B</span></a>')
275
+ })
276
+
277
+ test('options pureDataPattern (js)', () => {
278
+ const env = new MiniProgramEnv()
279
+ const codeSpace = env.createCodeSpace('', true)
280
+
281
+ codeSpace.addCompiledTemplate('path/to/comp', tmpl(`
282
+ <div>{{_a}}-{{b}}</div>
283
+ `))
284
+
285
+ codeSpace.componentEnv('path/to/comp', ({ Component }) => {
286
+ Component()
287
+ .options({
288
+ pureDataPattern: /^_/,
289
+ })
290
+ .data(() => ({
291
+ _a: 123,
292
+ b: 456,
293
+ }))
294
+ .register()
295
+ })
296
+
297
+ const ab = env.associateBackend()
298
+ const root = ab.createRoot('body', codeSpace, 'path/to/comp')
299
+ expect(domHtml(root.getComponent())).toBe('<div>-456</div>')
300
+ })
301
+
302
+ test('options pureDataPattern (json)', () => {
303
+ const env = new MiniProgramEnv()
304
+ const codeSpace = env.createCodeSpace('', true)
305
+
306
+ codeSpace.addComponentStaticConfig('path/to/comp', {
307
+ pureDataPattern: '^_',
308
+ })
309
+
310
+ codeSpace.addCompiledTemplate('path/to/comp', tmpl(`
311
+ <div>{{_a}}-{{b}}</div>
312
+ `))
313
+
314
+ codeSpace.componentEnv('path/to/comp', ({ Component }) => {
315
+ Component()
316
+ .options({
317
+ pureDataPattern: /^_/,
318
+ })
319
+ .data(() => ({
320
+ _a: 123,
321
+ b: 456,
322
+ }))
323
+ .register()
324
+ })
325
+
326
+ const ab = env.associateBackend()
327
+ const root = ab.createRoot('body', codeSpace, 'path/to/comp')
328
+ expect(domHtml(root.getComponent())).toBe('<div>-456</div>')
329
+ })
330
+
331
+ test('options addGlobalClass', () => {
332
+ const env = new MiniProgramEnv()
333
+ const codeSpace = env.createCodeSpace('', true)
334
+
335
+ codeSpace.addStyleSheet('child/comp', 'empty-style-sheet', 'child-comp')
336
+ codeSpace.addComponentStaticConfig('child/comp', {
337
+ component: true,
338
+ addGlobalClass: true,
339
+ })
340
+ codeSpace.addCompiledTemplate('child/comp', tmpl(`
341
+ <div class="def"></div>
342
+ `))
343
+ codeSpace.componentEnv('child/comp', ({ Component }) => {
344
+ Component()
345
+ .options({
346
+ virtualHost: true,
347
+ })
348
+ .register()
349
+ })
350
+
351
+ codeSpace.addComponentStaticConfig('path/to/comp', {
352
+ usingComponents: {
353
+ child: '/child/comp',
354
+ },
355
+ addGlobalClass: true,
356
+ })
357
+ codeSpace.addCompiledTemplate('path/to/comp', tmpl(`
358
+ <div class="abc">
359
+ <child />
360
+ </div>
361
+ `))
362
+ codeSpace.componentEnv('path/to/comp', ({ Component }) => {
363
+ Component().register()
364
+ })
365
+
366
+ const ab = env.associateBackend()
367
+ ab.registerStyleSheetContent('empty-style-sheet', '')
368
+ const root = ab.createRoot('body', codeSpace, 'path/to/comp')
369
+ expect(domHtml(root.getComponent())).toBe('<div class="abc"><div class="def child-comp--def"></div></div>')
370
+ })
371
+
372
+ test('options styleIsolation shared', () => {
373
+ const env = new MiniProgramEnv()
374
+ const codeSpace = env.createCodeSpace('', true)
375
+
376
+ codeSpace.addStyleSheet('child/comp', 'empty-style-sheet', 'child-comp')
377
+ codeSpace.addComponentStaticConfig('child/comp', {
378
+ component: true,
379
+ styleIsolation: StyleIsolation.Shared,
380
+ })
381
+ codeSpace.addCompiledTemplate('child/comp', tmpl(`
382
+ <div class="def"></div>
383
+ `))
384
+ codeSpace.componentEnv('child/comp', ({ Component }) => {
385
+ Component()
386
+ .options({
387
+ virtualHost: true,
388
+ })
389
+ .register()
390
+ })
391
+
392
+ codeSpace.addStyleSheet('path/to/comp', 'empty-style-sheet', 'comp')
393
+ codeSpace.addComponentStaticConfig('path/to/comp', {
394
+ usingComponents: {
395
+ child: '/child/comp',
396
+ },
397
+ styleIsolation: StyleIsolation.PageShared,
398
+ })
399
+ codeSpace.addCompiledTemplate('path/to/comp', tmpl(`
400
+ <div class="abc">
401
+ <child />
402
+ </div>
403
+ `))
404
+ codeSpace.componentEnv('path/to/comp', ({ Component }) => {
405
+ Component().register()
406
+ })
407
+
408
+ const ab = env.associateBackend()
409
+ ab.registerStyleSheetContent('empty-style-sheet', '')
410
+ const root = ab.createRoot('body', codeSpace, 'path/to/comp')
411
+ expect(domHtml(root.getComponent())).toBe('<div class="abc"><div class="def"></div></div>')
412
+ })
413
+
414
+ test('options styleIsolation apply-shared', () => {
415
+ const env = new MiniProgramEnv()
416
+ const codeSpace = env.createCodeSpace('', true)
417
+
418
+ codeSpace.addStyleSheet('child/comp', 'empty-style-sheet', 'child-comp')
419
+ codeSpace.addComponentStaticConfig('child/comp', {
420
+ component: true,
421
+ styleIsolation: StyleIsolation.ApplyShared,
422
+ })
423
+ codeSpace.addCompiledTemplate('child/comp', tmpl(`
424
+ <div class="def"></div>
425
+ `))
426
+ codeSpace.componentEnv('child/comp', ({ Component }) => {
427
+ Component()
428
+ .options({
429
+ virtualHost: true,
430
+ })
431
+ .register()
432
+ })
433
+
434
+ codeSpace.addStyleSheet('path/to/comp', 'empty-style-sheet', 'comp')
435
+ codeSpace.addComponentStaticConfig('path/to/comp', {
436
+ usingComponents: {
437
+ child: '/child/comp',
438
+ },
439
+ styleIsolation: StyleIsolation.PageApplyShared,
440
+ })
441
+ codeSpace.addCompiledTemplate('path/to/comp', tmpl(`
442
+ <div class="abc">
443
+ <child />
444
+ </div>
445
+ `))
446
+ codeSpace.componentEnv('path/to/comp', ({ Component }) => {
447
+ Component().register()
448
+ })
449
+
450
+ const ab = env.associateBackend()
451
+ ab.registerStyleSheetContent('empty-style-sheet', '')
452
+ const root = ab.createRoot('body', codeSpace, 'path/to/comp')
453
+ expect(domHtml(root.getComponent())).toBe('<div class="abc comp--abc"><div class="def child-comp--def"></div></div>')
454
+ })
455
+
456
+ test('options styleIsolation isolated', () => {
457
+ const env = new MiniProgramEnv()
458
+ const codeSpace = env.createCodeSpace('', true)
459
+
460
+ codeSpace.addStyleSheet('child/comp', 'empty-style-sheet', 'child-comp')
461
+ codeSpace.addComponentStaticConfig('child/comp', {
462
+ component: true,
463
+ styleIsolation: StyleIsolation.Isolated,
464
+ })
465
+ codeSpace.addCompiledTemplate('child/comp', tmpl(`
466
+ <div class="def"></div>
467
+ `))
468
+ codeSpace.componentEnv('child/comp', ({ Component }) => {
469
+ Component()
470
+ .options({
471
+ virtualHost: true,
472
+ })
473
+ .register()
474
+ })
475
+
476
+ codeSpace.addStyleSheet('path/to/comp', 'empty-style-sheet', 'comp')
477
+ codeSpace.addComponentStaticConfig('path/to/comp', {
478
+ usingComponents: {
479
+ child: '/child/comp',
480
+ },
481
+ styleIsolation: StyleIsolation.PageIsolated,
482
+ })
483
+ codeSpace.addCompiledTemplate('path/to/comp', tmpl(`
484
+ <div class="abc">
485
+ <child />
486
+ </div>
487
+ `))
488
+ codeSpace.componentEnv('path/to/comp', ({ Component }) => {
489
+ Component().register()
490
+ })
491
+
492
+ const ab = env.associateBackend()
493
+ ab.registerStyleSheetContent('empty-style-sheet', '')
494
+ const root = ab.createRoot('body', codeSpace, 'path/to/comp')
495
+ expect(domHtml(root.getComponent())).toBe('<div class="comp--abc"><div class="child-comp--def"></div></div>')
496
+ })
497
+
498
+ test('options dataDeepCopy', () => {
499
+ const env = new MiniProgramEnv()
500
+ const codeSpace = env.createCodeSpace('', true)
501
+
502
+ codeSpace.addComponentStaticConfig('path/to/comp', {})
503
+ codeSpace.addCompiledTemplate('path/to/comp', tmpl(''))
504
+ codeSpace.componentEnv('path/to/comp', ({ Component }) => {
505
+ Component({
506
+ options: {
507
+ dataDeepCopy: glassEasel.DeepCopyKind.None,
508
+ },
509
+ data: {
510
+ a: [1, 2, 3],
511
+ },
512
+ })
513
+ })
514
+
515
+ const ab = env.associateBackend()
516
+ const root = ab.createRoot('body', codeSpace, 'path/to/comp')
517
+ const a = [3, 2, 1]
518
+ root.getComponent().setData({
519
+ a,
520
+ })
521
+ expect(root.getComponent().data.a).toBe(a)
522
+ })
523
+
524
+ test('options propertyPassingDeepCopy', () => {
525
+ const env = new MiniProgramEnv()
526
+ const codeSpace = env.createCodeSpace('', true)
527
+ const callOrder = [] as number[]
528
+
529
+ codeSpace.addComponentStaticConfig('child/comp', {
530
+ component: true,
531
+ })
532
+ codeSpace.addCompiledTemplate('child/comp', tmpl(`
533
+ <div class="def"></div>
534
+ `))
535
+ // eslint-disable-next-line arrow-body-style
536
+ const childDef = codeSpace.componentEnv('child/comp', ({ Component }) => {
537
+ return Component()
538
+ .options({
539
+ virtualHost: true,
540
+ dataDeepCopy: glassEasel.DeepCopyKind.None,
541
+ propertyPassingDeepCopy: glassEasel.DeepCopyKind.None,
542
+ })
543
+ .property('p', Object)
544
+ .register()
545
+ })
546
+
547
+ codeSpace.addComponentStaticConfig('path/to/comp', {
548
+ usingComponents: {
549
+ child: '/child/comp',
550
+ },
551
+ styleIsolation: StyleIsolation.PageIsolated,
552
+ })
553
+ codeSpace.addCompiledTemplate('path/to/comp', tmpl(`
554
+ <child id="c" p="{{a}}" />
555
+ `))
556
+ codeSpace.componentEnv('path/to/comp', ({ Component }) => {
557
+ Component()
558
+ .options({
559
+ dataDeepCopy: glassEasel.DeepCopyKind.None,
560
+ propertyPassingDeepCopy: glassEasel.DeepCopyKind.None,
561
+ })
562
+ .data(() => ({
563
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
564
+ a: Object.create(Object.prototype, {
565
+ f: { enumerable: true, value: 123 },
566
+ __test: { enumerable: false, value: 456 },
567
+ }),
568
+ }))
569
+ .lifetime('attached', function () {
570
+ const child = this.selectComponent('#c', childDef)!
571
+ expect(child.data.p).toBe(this.data.a)
572
+ callOrder.push(1)
573
+ })
574
+ .register()
575
+ })
576
+
577
+ const ab = env.associateBackend()
578
+ const root = ab.createRoot('body', codeSpace, 'path/to/comp')
579
+ glassEasel.Element.pretendAttached(root.getComponent())
580
+ expect(callOrder).toStrictEqual([1])
581
+ })
582
+
583
+ test('definition filter', () => {
584
+ const env = new MiniProgramEnv()
585
+ const codeSpace = env.createCodeSpace('', true)
586
+
587
+ codeSpace.addCompiledTemplate('path/to/comp', tmpl(`
588
+ <div>{{a}}-{{b}}</div>
589
+ `))
590
+
591
+ const beh = codeSpace.behavior()
592
+ .data(() => ({
593
+ a: 123,
594
+ }))
595
+ .register()
596
+
597
+ const filterBeh = codeSpace.behavior()
598
+ .behavior(beh)
599
+ .definition({
600
+ definitionFilter: (def: types.GeneralComponentDefinition) => {
601
+ // eslint-disable-next-line no-param-reassign
602
+ def.data = { b: 456 }
603
+ },
604
+ })
605
+ .register()
606
+
607
+ codeSpace.component('path/to/comp')
608
+ .definition({
609
+ behaviors: [filterBeh],
610
+ })
611
+ .register()
612
+
613
+ const ab = env.associateBackend()
614
+ const root = ab.createRoot('body', codeSpace, 'path/to/comp')
615
+ expect(domHtml(root.getComponent())).toBe('<div>123-456</div>')
616
+ })
617
+
618
+ test('chaining behaviors', () => {
619
+ const env = new MiniProgramEnv()
620
+ const codeSpace = env.createCodeSpace('', true)
621
+
622
+ codeSpace.addCompiledTemplate('path/to/comp', tmpl(`
623
+ <div>{{a}}-{{b}}</div>
624
+ `))
625
+
626
+ const beh = codeSpace.behavior()
627
+ .data(() => ({
628
+ a: 123,
629
+ }))
630
+ .register()
631
+
632
+ codeSpace.component('path/to/comp')
633
+ .behavior(beh)
634
+ .data(() => ({
635
+ b: 456,
636
+ }))
637
+ .register()
638
+
639
+ const ab = env.associateBackend()
640
+ const root = ab.createRoot('body', codeSpace, 'path/to/comp')
641
+ expect(domHtml(root.getComponent())).toBe('<div>123-456</div>')
642
+ })
643
+
644
+ test('chaining filters', () => {
645
+ const env = new MiniProgramEnv()
646
+ const codeSpace = env.createCodeSpace('', true)
647
+
648
+ codeSpace.addCompiledTemplate('path/to/comp', tmpl(`
649
+ <div>{{a}}-{{b}}</div>
650
+ `))
651
+
652
+ type TAdd = { data: <T>(this: T) => T }
653
+ type TRemove = 'data' | 'property'
654
+ const beh = codeSpace.behavior()
655
+ .chainingFilter<TAdd, TRemove>((chain) => {
656
+ const oldData = chain.data.bind(chain)
657
+ const newData = function () {
658
+ oldData(() => ({
659
+ a: 123,
660
+ }))
661
+ }
662
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
663
+ return Object.create(chain, {
664
+ data: { value: newData },
665
+ })
666
+ })
667
+ .register()
668
+
669
+ codeSpace.component('path/to/comp')
670
+ .data(() => ({
671
+ b: 456,
672
+ }))
673
+ .behavior(beh)
674
+ .data()
675
+ .register()
676
+
677
+ const ab = env.associateBackend()
678
+ const root = ab.createRoot('body', codeSpace, 'path/to/comp')
679
+ expect(domHtml(root.getComponent())).toBe('<div>123-456</div>')
680
+ })
681
+
682
+ test('chaining external classes', () => {
683
+ const env = new MiniProgramEnv()
684
+ const codeSpace = env.createCodeSpace('', true)
685
+
686
+ codeSpace.addComponentStaticConfig('child/comp', {
687
+ component: true,
688
+ })
689
+ codeSpace.addCompiledTemplate('child/comp', tmpl(`
690
+ <div class="a-class"></div>
691
+ `))
692
+ codeSpace.componentEnv('child/comp', ({ Component }) => {
693
+ Component()
694
+ .options({
695
+ virtualHost: true,
696
+ })
697
+ .externalClasses(['a-class'])
698
+ .register()
699
+ })
700
+
701
+ codeSpace.addComponentStaticConfig('path/to/comp', {
702
+ usingComponents: {
703
+ child: '/child/comp',
704
+ },
705
+ })
706
+ codeSpace.addCompiledTemplate('path/to/comp', tmpl(`
707
+ <div class="abc">
708
+ <child a-class="def" />
709
+ </div>
710
+ `))
711
+ codeSpace.componentEnv('path/to/comp', ({ Component }) => {
712
+ Component().register()
713
+ })
714
+
715
+ const ab = env.associateBackend()
716
+ const root = ab.createRoot('body', codeSpace, 'path/to/comp')
717
+ expect(domHtml(root.getComponent())).toBe('<div class="abc"><div class="def"></div></div>')
718
+ })
719
+
720
+ test('chaining methods', () => {
721
+ const env = new MiniProgramEnv()
722
+ const codeSpace = env.createCodeSpace('', true)
723
+ const callOrder = [] as number[]
724
+
725
+ codeSpace.addComponentStaticConfig('child/comp', {
726
+ component: true,
727
+ })
728
+ // eslint-disable-next-line arrow-body-style
729
+ const childType = codeSpace.componentEnv('child/comp', ({ Component }) => {
730
+ return Component()
731
+ .methods({
732
+ childFn() {
733
+ return 123
734
+ },
735
+ })
736
+ .lifetime('attached', function () {
737
+ // eslint-disable-next-line no-use-before-define
738
+ expect(this.selectOwnerComponent(parentType)!.parentFn()).toBe(456)
739
+ callOrder.push(1)
740
+ })
741
+ .register()
742
+ })
743
+
744
+ codeSpace.addComponentStaticConfig('path/to/comp', {
745
+ usingComponents: {
746
+ child: '/child/comp',
747
+ },
748
+ })
749
+ codeSpace.addCompiledTemplate('path/to/comp', tmpl(`
750
+ <child id="c" />
751
+ `))
752
+ // eslint-disable-next-line arrow-body-style
753
+ const parentType = codeSpace.componentEnv('path/to/comp', ({ Component }) => {
754
+ return Component()
755
+ .methods({
756
+ parentFn() {
757
+ return 456
758
+ },
759
+ })
760
+ .lifetime('attached', function () {
761
+ expect(this.selectComponent('#c', childType)!.childFn()).toBe(123)
762
+ callOrder.push(2)
763
+ })
764
+ .register()
765
+ })
766
+
767
+ const ab = env.associateBackend()
768
+ const root = ab.createRoot('body', codeSpace, 'path/to/comp')
769
+ glassEasel.Element.pretendAttached(root.getComponent())
770
+ expect(callOrder).toStrictEqual([2, 1])
771
+ })
772
+
773
+ test('chaining observer', () => {
774
+ const env = new MiniProgramEnv()
775
+ const codeSpace = env.createCodeSpace('', true)
776
+
777
+ codeSpace.addComponentStaticConfig('child/comp', {
778
+ component: true,
779
+ })
780
+ codeSpace.addCompiledTemplate('child/comp', tmpl(`
781
+ <span>{{aa}}</span>
782
+ `))
783
+ codeSpace.componentEnv('child/comp', ({ Component }) => {
784
+ Component()
785
+ .options({
786
+ virtualHost: true,
787
+ })
788
+ .property('a', Number)
789
+ .data(() => ({
790
+ aa: 10,
791
+ }))
792
+ .observer('a', function () {
793
+ this.setData({
794
+ aa: this.data.a * 10,
795
+ })
796
+ })
797
+ .register()
798
+ })
799
+
800
+ codeSpace.addComponentStaticConfig('path/to/comp', {
801
+ usingComponents: {
802
+ child: '/child/comp',
803
+ },
804
+ })
805
+ codeSpace.addCompiledTemplate('path/to/comp', tmpl(`
806
+ <child a="{{bb}}" />
807
+ `))
808
+ codeSpace.componentEnv('path/to/comp', ({ Component }) => {
809
+ Component()
810
+ .data(() => ({
811
+ b: 1,
812
+ bb: 10,
813
+ }))
814
+ .observer('b', function () {
815
+ this.setData({
816
+ bb: this.data.b * 10,
817
+ })
818
+ })
819
+ .lifetime('attached', function () {
820
+ this.setData({ b: 2 })
821
+ })
822
+ .register()
823
+ })
824
+
825
+ const ab = env.associateBackend()
826
+ const root = ab.createRoot('body', codeSpace, 'path/to/comp')
827
+ expect(domHtml(root.getComponent())).toBe('<span>100</span>')
828
+ glassEasel.Element.pretendAttached(root.getComponent())
829
+ expect(domHtml(root.getComponent())).toBe('<span>200</span>')
830
+ })
831
+
832
+ test('chaining pageLifetime', () => {
833
+ const env = new MiniProgramEnv()
834
+ const codeSpace = env.createCodeSpace('', true)
835
+
836
+ codeSpace.addComponentStaticConfig('child/comp', {
837
+ component: true,
838
+ })
839
+ codeSpace.addCompiledTemplate('child/comp', tmpl(`
840
+ <span>{{a}}-{{b}}</span>
841
+ `))
842
+ codeSpace.componentEnv('child/comp', ({ Component }) => {
843
+ Component()
844
+ .options({
845
+ virtualHost: true,
846
+ })
847
+ .property('a', Number)
848
+ .data(() => ({
849
+ b: 0,
850
+ }))
851
+ .pageLifetime('show', function () {
852
+ this.setData({
853
+ b: 456,
854
+ })
855
+ })
856
+ .register()
857
+ })
858
+
859
+ codeSpace.addComponentStaticConfig('path/to/comp', {
860
+ usingComponents: {
861
+ child: '/child/comp',
862
+ },
863
+ })
864
+ codeSpace.addCompiledTemplate('path/to/comp', tmpl(`
865
+ <child a="{{a}}" />
866
+ `))
867
+ codeSpace.componentEnv('path/to/comp', ({ Component }) => {
868
+ Component()
869
+ .data(() => ({
870
+ a: 0,
871
+ }))
872
+ .pageLifetime('show', function (a: number) {
873
+ this.setData({ a })
874
+ })
875
+ .register()
876
+ })
877
+
878
+ const ab = env.associateBackend()
879
+ const root = ab.createRoot('body', codeSpace, 'path/to/comp')
880
+ expect(domHtml(root.getComponent())).toBe('<span>0-0</span>')
881
+ root.getComponent().triggerPageLifetime('show', [123])
882
+ expect(domHtml(root.getComponent())).toBe('<span>123-456</span>')
883
+ })
884
+
885
+ test('chaining relation', () => {
886
+ const env = new MiniProgramEnv()
887
+ const codeSpace = env.createCodeSpace('', true)
888
+
889
+ codeSpace.addComponentStaticConfig('child/list', {
890
+ component: true,
891
+ })
892
+ codeSpace.addCompiledTemplate('child/list', tmpl(`
893
+ <div>{{count}}</div><slot />
894
+ `))
895
+ // eslint-disable-next-line arrow-body-style
896
+ const listDef = codeSpace.componentEnv('child/list', ({ Component }) => {
897
+ return Component()
898
+ .data(() => ({
899
+ count: 0,
900
+ }))
901
+ .relation('item', {
902
+ type: 'child',
903
+ linked(target) {
904
+ // eslint-disable-next-line no-use-before-define
905
+ expect(target.asInstanceOf(itemDef)).not.toBe(null)
906
+ this.setData({
907
+ count: this.getRelationNodes('item').length,
908
+ })
909
+ },
910
+ })
911
+ .register()
912
+ })
913
+
914
+ codeSpace.addComponentStaticConfig('child/item', {
915
+ component: true,
916
+ })
917
+ // eslint-disable-next-line arrow-body-style
918
+ const itemDef = codeSpace.componentEnv('child/item', ({ Component }) => {
919
+ return Component()
920
+ .data(() => ({
921
+ count: 0,
922
+ }))
923
+ .init(({ relation }) => {
924
+ relation({
925
+ type: 'parent',
926
+ target: listDef,
927
+ })
928
+ })
929
+ .register()
930
+ })
931
+
932
+ codeSpace.addComponentStaticConfig('path/to/comp', {
933
+ usingComponents: {
934
+ list: '/child/list',
935
+ item: '/child/item',
936
+ },
937
+ })
938
+ codeSpace.addCompiledTemplate('path/to/comp', tmpl(`
939
+ <list>
940
+ <item />
941
+ <item />
942
+ </list>
943
+ `))
944
+ codeSpace.componentEnv('path/to/comp', ({ Component }) => {
945
+ Component().register()
946
+ })
947
+
948
+ const ab = env.associateBackend()
949
+ const root = ab.createRoot('body', codeSpace, 'path/to/comp')
950
+ glassEasel.Element.pretendAttached(root.getComponent())
951
+ expect(domHtml(root.getComponent())).toBe('<list><div>2</div><item></item><item></item></list>')
952
+ })
953
+ })