glass-easel 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 (237) hide show
  1. package/README.md +40 -0
  2. package/dist/glass_easel.all.d.ts +1 -0
  3. package/dist/glass_easel.all.js +2 -0
  4. package/dist/glass_easel.all.js.map +1 -0
  5. package/dist/glass_easel.domlike.global.d.ts +1 -0
  6. package/dist/glass_easel.domlike.global.js +2 -0
  7. package/dist/glass_easel.domlike.global.js.map +1 -0
  8. package/dist/index.d.ts +1 -0
  9. package/dist/index.js +1 -0
  10. package/dist/types/src/backend/backend_protocol.d.ts +119 -0
  11. package/dist/types/src/backend/backend_protocol.d.ts.map +1 -0
  12. package/dist/types/src/backend/composed_backend_protocol.d.ts +90 -0
  13. package/dist/types/src/backend/composed_backend_protocol.d.ts.map +1 -0
  14. package/dist/types/src/backend/domlike_backend_protocol.d.ts +76 -0
  15. package/dist/types/src/backend/domlike_backend_protocol.d.ts.map +1 -0
  16. package/dist/types/src/backend/mode.d.ts +46 -0
  17. package/dist/types/src/backend/mode.d.ts.map +1 -0
  18. package/dist/types/src/backend/suggested_backend_protocol.d.ts +30 -0
  19. package/dist/types/src/backend/suggested_backend_protocol.d.ts.map +1 -0
  20. package/dist/types/src/behavior.d.ts +428 -0
  21. package/dist/types/src/behavior.d.ts.map +1 -0
  22. package/dist/types/src/class_list.d.ts +79 -0
  23. package/dist/types/src/class_list.d.ts.map +1 -0
  24. package/dist/types/src/component.d.ts +291 -0
  25. package/dist/types/src/component.d.ts.map +1 -0
  26. package/dist/types/src/component_params.d.ts +239 -0
  27. package/dist/types/src/component_params.d.ts.map +1 -0
  28. package/dist/types/src/component_space.d.ts +164 -0
  29. package/dist/types/src/component_space.d.ts.map +1 -0
  30. package/dist/types/src/data_path.d.ts +5 -0
  31. package/dist/types/src/data_path.d.ts.map +1 -0
  32. package/dist/types/src/data_proxy.d.ts +107 -0
  33. package/dist/types/src/data_proxy.d.ts.map +1 -0
  34. package/dist/types/src/data_utils.d.ts +3 -0
  35. package/dist/types/src/data_utils.d.ts.map +1 -0
  36. package/dist/types/src/element.d.ts +275 -0
  37. package/dist/types/src/element.d.ts.map +1 -0
  38. package/dist/types/src/element_iterator.d.ts +43 -0
  39. package/dist/types/src/element_iterator.d.ts.map +1 -0
  40. package/dist/types/src/event.d.ts +104 -0
  41. package/dist/types/src/event.d.ts.map +1 -0
  42. package/dist/types/src/external_shadow_tree.d.ts +20 -0
  43. package/dist/types/src/external_shadow_tree.d.ts.map +1 -0
  44. package/dist/types/src/func_arr.d.ts +39 -0
  45. package/dist/types/src/func_arr.d.ts.map +1 -0
  46. package/dist/types/src/global_options.d.ts +111 -0
  47. package/dist/types/src/global_options.d.ts.map +1 -0
  48. package/dist/types/src/index.d.ts +43 -0
  49. package/dist/types/src/index.d.ts.map +1 -0
  50. package/dist/types/src/mutation_observer.d.ts +79 -0
  51. package/dist/types/src/mutation_observer.d.ts.map +1 -0
  52. package/dist/types/src/native_node.d.ts +8 -0
  53. package/dist/types/src/native_node.d.ts.map +1 -0
  54. package/dist/types/src/node.d.ts +49 -0
  55. package/dist/types/src/node.d.ts.map +1 -0
  56. package/dist/types/src/relation.d.ts +47 -0
  57. package/dist/types/src/relation.d.ts.map +1 -0
  58. package/dist/types/src/render.d.ts +3 -0
  59. package/dist/types/src/render.d.ts.map +1 -0
  60. package/dist/types/src/selector.d.ts +32 -0
  61. package/dist/types/src/selector.d.ts.map +1 -0
  62. package/dist/types/src/shadow_root.d.ts +136 -0
  63. package/dist/types/src/shadow_root.d.ts.map +1 -0
  64. package/dist/types/src/template_engine.d.ts +18 -0
  65. package/dist/types/src/template_engine.d.ts.map +1 -0
  66. package/dist/types/src/text_node.d.ts +32 -0
  67. package/dist/types/src/text_node.d.ts.map +1 -0
  68. package/dist/types/src/tmpl/index.d.ts +18 -0
  69. package/dist/types/src/tmpl/index.d.ts.map +1 -0
  70. package/dist/types/src/tmpl/native_rendering.d.ts +45 -0
  71. package/dist/types/src/tmpl/native_rendering.d.ts.map +1 -0
  72. package/dist/types/src/tmpl/proc_gen_wrapper.d.ts +80 -0
  73. package/dist/types/src/tmpl/proc_gen_wrapper.d.ts.map +1 -0
  74. package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts +50 -0
  75. package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts.map +1 -0
  76. package/dist/types/src/tmpl/range_list_diff.d.ts +19 -0
  77. package/dist/types/src/tmpl/range_list_diff.d.ts.map +1 -0
  78. package/dist/types/src/trait_behaviors.d.ts +38 -0
  79. package/dist/types/src/trait_behaviors.d.ts.map +1 -0
  80. package/dist/types/src/virtual_node.d.ts +10 -0
  81. package/dist/types/src/virtual_node.d.ts.map +1 -0
  82. package/dist/types/tests/backend/domlike.test.d.ts +2 -0
  83. package/dist/types/tests/backend/domlike.test.d.ts.map +1 -0
  84. package/dist/types/tests/base/env.d.ts +29 -0
  85. package/dist/types/tests/base/env.d.ts.map +1 -0
  86. package/dist/types/tests/base/match.d.ts +9 -0
  87. package/dist/types/tests/base/match.d.ts.map +1 -0
  88. package/dist/types/tests/core/backend.test.d.ts +2 -0
  89. package/dist/types/tests/core/backend.test.d.ts.map +1 -0
  90. package/dist/types/tests/core/behavior.test.d.ts +2 -0
  91. package/dist/types/tests/core/behavior.test.d.ts.map +1 -0
  92. package/dist/types/tests/core/component_space.test.d.ts +2 -0
  93. package/dist/types/tests/core/component_space.test.d.ts.map +1 -0
  94. package/dist/types/tests/core/data_update.test.d.ts +2 -0
  95. package/dist/types/tests/core/data_update.test.d.ts.map +1 -0
  96. package/dist/types/tests/core/misc.test.d.ts +2 -0
  97. package/dist/types/tests/core/misc.test.d.ts.map +1 -0
  98. package/dist/types/tests/core/placeholder.test.d.ts +2 -0
  99. package/dist/types/tests/core/placeholder.test.d.ts.map +1 -0
  100. package/dist/types/tests/core/slot.test.d.ts +2 -0
  101. package/dist/types/tests/core/slot.test.d.ts.map +1 -0
  102. package/dist/types/tests/core/trait_behaviors.test.d.ts +2 -0
  103. package/dist/types/tests/core/trait_behaviors.test.d.ts.map +1 -0
  104. package/dist/types/tests/tmpl/binding_map.test.d.ts +2 -0
  105. package/dist/types/tests/tmpl/binding_map.test.d.ts.map +1 -0
  106. package/dist/types/tests/tmpl/event.test.d.ts +2 -0
  107. package/dist/types/tests/tmpl/event.test.d.ts.map +1 -0
  108. package/dist/types/tests/tmpl/expression.test.d.ts +2 -0
  109. package/dist/types/tests/tmpl/expression.test.d.ts.map +1 -0
  110. package/dist/types/tests/tmpl/lvalue.test.d.ts +2 -0
  111. package/dist/types/tests/tmpl/lvalue.test.d.ts.map +1 -0
  112. package/dist/types/tests/tmpl/native_rendering.test.d.ts +2 -0
  113. package/dist/types/tests/tmpl/native_rendering.test.d.ts.map +1 -0
  114. package/dist/types/tests/tmpl/structure.test.d.ts +2 -0
  115. package/dist/types/tests/tmpl/structure.test.d.ts.map +1 -0
  116. package/dist/types/tests/types/chaining.test.d.ts +2 -0
  117. package/dist/types/tests/types/chaining.test.d.ts.map +1 -0
  118. package/dist/types/tests/types/createElement.test.d.ts +2 -0
  119. package/dist/types/tests/types/createElement.test.d.ts.map +1 -0
  120. package/dist/types/tests/types/definition.test.d.ts +2 -0
  121. package/dist/types/tests/types/definition.test.d.ts.map +1 -0
  122. package/guide/zh_CN/advanced/binding_map_update.md +32 -0
  123. package/guide/zh_CN/advanced/build_args.md +28 -0
  124. package/guide/zh_CN/advanced/component_filter.md +70 -0
  125. package/guide/zh_CN/advanced/component_space.md +124 -0
  126. package/guide/zh_CN/advanced/custom_backend.md +53 -0
  127. package/guide/zh_CN/advanced/error_listener.md +32 -0
  128. package/guide/zh_CN/advanced/external_component.md +73 -0
  129. package/guide/zh_CN/advanced/template_engine.md +61 -0
  130. package/guide/zh_CN/appendix/backend_protocol.md +501 -0
  131. package/guide/zh_CN/appendix/list_diff_algorithm.md +406 -0
  132. package/guide/zh_CN/basic/beginning.md +94 -0
  133. package/guide/zh_CN/basic/component.md +156 -0
  134. package/guide/zh_CN/basic/event.md +169 -0
  135. package/guide/zh_CN/basic/lifetime.md +66 -0
  136. package/guide/zh_CN/basic/method.md +62 -0
  137. package/guide/zh_CN/basic/template.md +135 -0
  138. package/guide/zh_CN/data_management/advanced_update.md +170 -0
  139. package/guide/zh_CN/data_management/data_deep_copy.md +157 -0
  140. package/guide/zh_CN/data_management/data_observer.md +154 -0
  141. package/guide/zh_CN/data_management/property_early_init.md +31 -0
  142. package/guide/zh_CN/data_management/pure_data_pattern.md +21 -0
  143. package/guide/zh_CN/index.md +93 -0
  144. package/guide/zh_CN/interaction/behavior.md +52 -0
  145. package/guide/zh_CN/interaction/component_path.md +37 -0
  146. package/guide/zh_CN/interaction/generic.md +73 -0
  147. package/guide/zh_CN/interaction/placeholder.md +40 -0
  148. package/guide/zh_CN/interaction/relation.md +151 -0
  149. package/guide/zh_CN/interaction/slot.md +137 -0
  150. package/guide/zh_CN/interaction/template_import.md +94 -0
  151. package/guide/zh_CN/interaction/trait_behavior.md +117 -0
  152. package/guide/zh_CN/styling/external_class.md +46 -0
  153. package/guide/zh_CN/styling/style_isolation.md +54 -0
  154. package/guide/zh_CN/styling/virtual_host.md +52 -0
  155. package/guide/zh_CN/tree/element_iterator.md +54 -0
  156. package/guide/zh_CN/tree/mutation_observer.md +52 -0
  157. package/guide/zh_CN/tree/node_tree.md +142 -0
  158. package/guide/zh_CN/tree/node_tree_modification.md +78 -0
  159. package/guide/zh_CN/tree/selector.md +66 -0
  160. package/jest.config.js +6 -0
  161. package/jest.dts.config.js +9 -0
  162. package/jest.unit.config.js +14 -0
  163. package/package.json +28 -0
  164. package/src/backend/backend_protocol.ts +313 -0
  165. package/src/backend/composed_backend_protocol.ts +252 -0
  166. package/src/backend/domlike_backend_protocol.ts +370 -0
  167. package/src/backend/mode.ts +51 -0
  168. package/src/backend/suggested_backend_protocol.ts +83 -0
  169. package/src/behavior.ts +1655 -0
  170. package/src/bootstrap_dom_dev.js +22 -0
  171. package/src/class_list.ts +376 -0
  172. package/src/component.ts +1309 -0
  173. package/src/component_params.ts +461 -0
  174. package/src/component_space.ts +547 -0
  175. package/src/data_path.ts +225 -0
  176. package/src/data_proxy.ts +670 -0
  177. package/src/data_utils.ts +50 -0
  178. package/src/element.ts +1966 -0
  179. package/src/element_iterator.ts +158 -0
  180. package/src/event.ts +401 -0
  181. package/src/external_shadow_tree.ts +27 -0
  182. package/src/func_arr.ts +198 -0
  183. package/src/global_options.ts +242 -0
  184. package/src/index.ts +187 -0
  185. package/src/mutation_observer.ts +252 -0
  186. package/src/native_node.ts +74 -0
  187. package/src/node.ts +174 -0
  188. package/src/relation.ts +380 -0
  189. package/src/render.ts +25 -0
  190. package/src/selector.ts +218 -0
  191. package/src/shadow_root.ts +766 -0
  192. package/src/template_engine.ts +45 -0
  193. package/src/text_node.ts +149 -0
  194. package/src/tmpl/index.ts +199 -0
  195. package/src/tmpl/native_rendering.ts +175 -0
  196. package/src/tmpl/proc_gen_wrapper.ts +954 -0
  197. package/src/tmpl/proc_gen_wrapper_dom.ts +230 -0
  198. package/src/tmpl/range_list_diff.ts +443 -0
  199. package/src/trait_behaviors.ts +51 -0
  200. package/src/virtual_node.ts +51 -0
  201. package/tests/backend/domlike.test.ts +254 -0
  202. package/tests/base/env.ts +78 -0
  203. package/tests/base/match.ts +185 -0
  204. package/tests/core/backend.test.ts +144 -0
  205. package/tests/core/behavior.test.ts +546 -0
  206. package/tests/core/component_space.test.ts +212 -0
  207. package/tests/core/data_update.test.ts +461 -0
  208. package/tests/core/misc.test.ts +339 -0
  209. package/tests/core/placeholder.test.ts +180 -0
  210. package/tests/core/slot.test.ts +1495 -0
  211. package/tests/core/trait_behaviors.test.ts +153 -0
  212. package/tests/legacy/README.md +3 -0
  213. package/tests/legacy/behavior.test.js +293 -0
  214. package/tests/legacy/component.test.js +1247 -0
  215. package/tests/legacy/data_path.test.js +149 -0
  216. package/tests/legacy/data_proxy.test.js +759 -0
  217. package/tests/legacy/element_iterator.test.js +148 -0
  218. package/tests/legacy/event.test.js +849 -0
  219. package/tests/legacy/external.test.js +510 -0
  220. package/tests/legacy/extra_info.test.js +109 -0
  221. package/tests/legacy/generics.test.js +176 -0
  222. package/tests/legacy/mutation_observer.test.js +210 -0
  223. package/tests/legacy/relation.test.js +517 -0
  224. package/tests/legacy/selector.test.js +263 -0
  225. package/tests/legacy/slot.test.js +915 -0
  226. package/tests/legacy/virtual.test.js +394 -0
  227. package/tests/tmpl/binding_map.test.ts +208 -0
  228. package/tests/tmpl/event.test.ts +206 -0
  229. package/tests/tmpl/expression.test.ts +429 -0
  230. package/tests/tmpl/lvalue.test.ts +160 -0
  231. package/tests/tmpl/native_rendering.test.ts +155 -0
  232. package/tests/tmpl/structure.test.ts +998 -0
  233. package/tests/types/chaining.test.ts +614 -0
  234. package/tests/types/createElement.test.ts +82 -0
  235. package/tests/types/definition.test.ts +442 -0
  236. package/tsconfig.json +11 -0
  237. package/webpack.config.js +270 -0
@@ -0,0 +1,144 @@
1
+ import {
2
+ domBackend,
3
+ shadowBackend,
4
+ composedBackend,
5
+ tmpl,
6
+ } from '../base/env'
7
+ import * as glassEasel from '../../src'
8
+
9
+ const componentSpace = new glassEasel.ComponentSpace()
10
+ componentSpace.updateComponentOptions({
11
+ writeFieldsToNode: true,
12
+ writeIdToDOM: true,
13
+ })
14
+ componentSpace.defineComponent({
15
+ is: '',
16
+ })
17
+
18
+ const forEachBackend = async (
19
+ f: (
20
+ context: glassEasel.composedBackend.Context
21
+ | glassEasel.backend.Context
22
+ | glassEasel.domlikeBackend.Context
23
+ ) => Promise<void>,
24
+ ) => {
25
+ await Promise.all([
26
+ f(domBackend),
27
+ f(shadowBackend),
28
+ f(composedBackend),
29
+ ])
30
+ }
31
+
32
+ describe('backend', () => {
33
+ test('support render callback', async () => {
34
+ const compDef = componentSpace.defineComponent({})
35
+ await forEachBackend((context) => {
36
+ const comp = glassEasel.Component.createWithContext('root', compDef.general(), context)
37
+ const callOrder: number[] = []
38
+ return new Promise((resolve) => {
39
+ const done = () => {
40
+ expect(callOrder).toStrictEqual([1, 2, 3, 4, 5])
41
+ resolve()
42
+ }
43
+ callOrder.push(1)
44
+ glassEasel.triggerRender(comp, () => {
45
+ callOrder.push(3)
46
+ glassEasel.triggerRender(comp, () => {
47
+ callOrder.push(5)
48
+ done()
49
+ })
50
+ })
51
+ callOrder.push(2)
52
+ glassEasel.triggerRender(comp, () => {
53
+ callOrder.push(4)
54
+ })
55
+ })
56
+ })
57
+ })
58
+
59
+ test('support basic context env methods', async () => {
60
+ await forEachBackend((context) => {
61
+ expect(typeof context.destroy).toBe('function')
62
+ expect(typeof context.getWindowWidth()).toBe('number')
63
+ expect(typeof context.getWindowHeight()).toBe('number')
64
+ expect(typeof context.getDevicePixelRatio()).toBe('number')
65
+ expect(typeof context.getTheme()).toBe('string')
66
+ expect(typeof context.onEvent).toBe('function')
67
+ return Promise.resolve()
68
+ })
69
+ })
70
+
71
+ test('support basic context style-sheet methods', async () => {
72
+ await forEachBackend((context) => {
73
+ expect(typeof context.registerStyleSheetContent).toBe('function')
74
+ expect(typeof context.appendStyleSheetPath).toBe('function')
75
+ expect(typeof context.disableStyleSheet).toBe('function')
76
+ if (context === domBackend) {
77
+ const document = context.document as unknown as Element
78
+ const styleText = '.a { color: red }'
79
+ context.registerStyleSheetContent('/backend/test/a', styleText)
80
+ const index = context.appendStyleSheetPath('/backend/test/a', 0)
81
+ try { context.appendStyleSheetPath('/backend/test/a-invalid', 0) } catch (e) { /* empty */ }
82
+ expect((document.querySelector('style[wx-style-scope]') as HTMLStyleElement).innerText).toBe(styleText)
83
+ context.disableStyleSheet(index)
84
+ expect(document.querySelector('style[wx-style-scope]')).toBe(null)
85
+ }
86
+ return Promise.resolve()
87
+ })
88
+ })
89
+
90
+ test('prevent some node from direct construction', () => {
91
+ let elem: glassEasel.Node | null = null
92
+ try {
93
+ elem = new glassEasel.Element()
94
+ } catch (e) { /* empty */ }
95
+ try {
96
+ elem = new glassEasel.VirtualNode()
97
+ } catch (e) { /* empty */ }
98
+ try {
99
+ elem = new glassEasel.ShadowRoot()
100
+ } catch (e) { /* empty */ }
101
+ try {
102
+ elem = new glassEasel.NativeNode()
103
+ } catch (e) { /* empty */ }
104
+ try {
105
+ elem = new glassEasel.Component()
106
+ } catch (e) { /* empty */ }
107
+ expect(elem).toBe(null)
108
+ })
109
+
110
+ test('auto backend element destroy', () => {
111
+ const compDef = componentSpace.defineComponent({
112
+ template: tmpl(`
113
+ <div wx:if="{{text}}">{{text}}</div>
114
+ `),
115
+ })
116
+ const elem = glassEasel.Component.createWithContext('root', compDef.general(), composedBackend)
117
+ elem.destroyBackendElementOnDetach()
118
+ elem.setData({
119
+ text: '123',
120
+ })
121
+ const virtualNode = elem.getShadowRoot()!.childNodes[0]! as glassEasel.VirtualNode
122
+ const nativeNode = virtualNode.childNodes[0]! as glassEasel.NativeNode
123
+ const textNode = nativeNode.childNodes[0]! as glassEasel.TextNode
124
+ glassEasel.Element.pretendAttached(elem)
125
+ expect(virtualNode.$$).toBe(null)
126
+ expect(nativeNode.$$).toBeInstanceOf(glassEasel.composedBackend.EmptyComposedBackendElement)
127
+ expect(textNode.$$).toBeInstanceOf(glassEasel.composedBackend.EmptyComposedBackendElement)
128
+ elem.setData({
129
+ text: '456',
130
+ })
131
+ expect(virtualNode.$$).toBe(null)
132
+ expect(nativeNode.$$).toBeInstanceOf(glassEasel.composedBackend.EmptyComposedBackendElement)
133
+ expect(textNode.$$).toBeInstanceOf(glassEasel.composedBackend.EmptyComposedBackendElement)
134
+ elem.setData({
135
+ text: '',
136
+ })
137
+ expect(virtualNode.$$).toBe(null)
138
+ expect(nativeNode.$$).toBe(null)
139
+ expect(textNode.$$).toBe(null)
140
+ expect(elem.$$).toBeInstanceOf(glassEasel.composedBackend.EmptyComposedBackendElement)
141
+ glassEasel.Element.pretendDetached(elem)
142
+ expect(elem.$$).toBe(null)
143
+ })
144
+ })
@@ -0,0 +1,546 @@
1
+ import {
2
+ domBackend,
3
+ execWithWarn,
4
+ tmpl,
5
+ } from '../base/env'
6
+ import * as glassEasel from '../../src'
7
+
8
+ const componentSpace = new glassEasel.ComponentSpace()
9
+ componentSpace.updateComponentOptions({
10
+ writeFieldsToNode: true,
11
+ })
12
+ componentSpace.defineComponent({
13
+ is: '',
14
+ })
15
+
16
+ const domHtml = (elem: glassEasel.Element): string => {
17
+ const domElem = elem.getBackendElement() as unknown as Element
18
+ return domElem.innerHTML
19
+ }
20
+
21
+ describe('chaining-form interface', () => {
22
+ test('chaining options and template', () => {
23
+ const beh = componentSpace.define()
24
+ .options({
25
+ writeIdToDOM: false,
26
+ })
27
+ .template(tmpl(`
28
+ <div></div>
29
+ `))
30
+ .registerBehavior()
31
+ const compDef = componentSpace.define()
32
+ .options({
33
+ writeIdToDOM: true,
34
+ })
35
+ .template(tmpl(`
36
+ <div id="{{a}}"></div>
37
+ `))
38
+ .behavior(beh)
39
+ .data(() => ({
40
+ a: 'abc',
41
+ }))
42
+ .registerComponent()
43
+ const elem = glassEasel.Component.createWithContext('root', compDef, domBackend)
44
+ expect(domHtml(elem)).toBe('<div id="abc"></div>')
45
+ })
46
+
47
+ test('chaining using and generics', () => {
48
+ const child = componentSpace.define()
49
+ .options({
50
+ virtualHost: true,
51
+ })
52
+ .externalClasses(['a-class', 'b-class'])
53
+ .template(tmpl(`
54
+ <span></span>
55
+ `))
56
+ .registerComponent()
57
+ const beh = componentSpace.define()
58
+ .usingComponents({
59
+ 'invalid-comp': child,
60
+ })
61
+ .generics({
62
+ 'invalid-gen': true,
63
+ })
64
+ .registerBehavior()
65
+ const compDef = componentSpace.define()
66
+ .behavior(beh)
67
+ .usingComponents({
68
+ 'comp-a': child,
69
+ })
70
+ .usingComponents({
71
+ 'comp-b': child,
72
+ })
73
+ .generics({
74
+ 'gen-a': true,
75
+ })
76
+ .generics({
77
+ 'gen-b': {
78
+ default: 'comp-b',
79
+ },
80
+ })
81
+ .template(tmpl(`
82
+ <comp-a />
83
+ <comp-b />
84
+ <gen-a />
85
+ <gen-b />
86
+ <invalid-comp />
87
+ <invalid-gen />
88
+ `))
89
+ .registerComponent()
90
+ const elem = glassEasel.Component.createWithGenericsAndContext(
91
+ 'root',
92
+ compDef,
93
+ {
94
+ 'gen-a': child,
95
+ 'gen-b': child,
96
+ 'invalid-gen': child,
97
+ },
98
+ domBackend,
99
+ )
100
+ expect(domHtml(elem)).toBe('<span></span><span></span><span></span><span></span><invalid-comp></invalid-comp><invalid-gen></invalid-gen>')
101
+ })
102
+
103
+ test('chaining external classes', () => {
104
+ const beh = componentSpace.define()
105
+ .externalClasses(['invalid'])
106
+ .registerBehavior()
107
+ const child = componentSpace.define()
108
+ .behavior(beh)
109
+ .externalClasses(['a-class', 'b-class'])
110
+ .template(tmpl(`
111
+ <div class="invalid a-class b-class"></div>
112
+ `))
113
+ .registerComponent()
114
+ const compDef = componentSpace.define()
115
+ .usingComponents({
116
+ child,
117
+ })
118
+ .template(tmpl(`
119
+ <child invalid="i" a-class="a" b-class="b" />
120
+ `))
121
+ .registerComponent()
122
+ const elem = glassEasel.Component.createWithContext('root', compDef, domBackend)
123
+ expect(domHtml(elem)).toBe('<child><div class="invalid a b"></div></child>')
124
+ })
125
+
126
+ test('chaining data and observers', () => {
127
+ const callOrder: number[] = []
128
+ const beh = componentSpace.define()
129
+ .data(() => ({
130
+ a: 123,
131
+ a2: 456,
132
+ }))
133
+ .observer('a', function () {
134
+ callOrder.push(1)
135
+ this.setData({
136
+ a2: this.data.a * 2,
137
+ })
138
+ })
139
+ .registerBehavior()
140
+ const compDef = componentSpace.define()
141
+ .behavior(beh)
142
+ .data(() => ({
143
+ b: 'abc',
144
+ b2: '',
145
+ b3: '',
146
+ c: 'ccc',
147
+ }))
148
+ .init(({ data, setData, observer }) => {
149
+ observer('b', () => {
150
+ callOrder.push(3)
151
+ setData({
152
+ b3: `${data.b}3`,
153
+ })
154
+ let catched = false
155
+ try { observer('b', () => undefined) } catch { catched = true }
156
+ expect(catched).toBe(true)
157
+ })
158
+
159
+ observer(['b', 'c'], () => {
160
+ callOrder.push(4)
161
+ })
162
+ })
163
+ .definition({
164
+ observers: {
165
+ b() {
166
+ callOrder.push(2)
167
+ this.setData({
168
+ b2: `${this.data.b}2`,
169
+ })
170
+ },
171
+ },
172
+ })
173
+ .registerComponent()
174
+ const elem = glassEasel.Component.createWithContext('root', compDef, domBackend)
175
+ expect(elem.data).toStrictEqual({
176
+ a: 123,
177
+ a2: 456,
178
+ b: 'abc',
179
+ b2: '',
180
+ b3: '',
181
+ c: 'ccc',
182
+ })
183
+ elem.setData({
184
+ a: 234,
185
+ b: 'def',
186
+ c: '',
187
+ })
188
+ expect(callOrder).toStrictEqual([1, 2, 3, 4])
189
+ expect(elem.data).toStrictEqual({
190
+ a: 234,
191
+ a2: 468,
192
+ b: 'def',
193
+ b2: 'def2',
194
+ b3: 'def3',
195
+ c: '',
196
+ })
197
+ })
198
+
199
+ test('chaining properties', () => {
200
+ const callOrder: number[] = []
201
+ const beh = componentSpace.define()
202
+ .property('propA', {
203
+ type: Number,
204
+ value: 123,
205
+ default: () => 456,
206
+ })
207
+ .observer('propA', () => {
208
+ callOrder.push(1)
209
+ })
210
+ .registerBehavior()
211
+ const compDef = componentSpace.define()
212
+ .behavior(beh)
213
+ .property('propB', String)
214
+ .definition({
215
+ properties: {
216
+ propC: {
217
+ default: () => 789,
218
+ },
219
+ },
220
+ observers: {
221
+ propA() {
222
+ callOrder.push(2)
223
+ },
224
+ },
225
+ })
226
+ .init(({ observer }) => {
227
+ observer('propB', () => {
228
+ callOrder.push(3)
229
+ })
230
+ })
231
+ .registerComponent()
232
+ const elem = glassEasel.Component.createWithContext('root', compDef, domBackend)
233
+ expect(elem.data).toStrictEqual({ propA: 456, propB: '', propC: 789 })
234
+ execWithWarn(1, () => {
235
+ elem.setData({
236
+ propA: 'abc' as unknown as number,
237
+ propB: 'def',
238
+ propC: undefined,
239
+ })
240
+ })
241
+ expect(callOrder).toStrictEqual([1, 2, 3])
242
+ expect(elem.data).toStrictEqual({ propA: 456, propB: 'def', propC: 789 })
243
+ })
244
+
245
+ test('chaining methods', () => {
246
+ const beh = componentSpace.define()
247
+ .data(() => ({
248
+ a1: '',
249
+ }))
250
+ .methods({
251
+ a1(s: string) {
252
+ this.setData({
253
+ a1: s,
254
+ })
255
+ },
256
+ })
257
+ .registerBehavior()
258
+ const compDef = componentSpace.define()
259
+ .template(tmpl(`
260
+ <div id="a" bind:customEv="cev" bind:customEv2="cev2">{{a1}}-{{a2}}-{{a3}}</div>
261
+ `))
262
+ .behavior(beh)
263
+ .definition({
264
+ data: {
265
+ a2: '',
266
+ },
267
+ methods: {
268
+ a2(s: string) {
269
+ this.setData({
270
+ a2: s,
271
+ })
272
+ },
273
+ },
274
+ })
275
+ .data(() => ({
276
+ a3: '',
277
+ }))
278
+ .init(({
279
+ setData,
280
+ method,
281
+ lifetime,
282
+ listener,
283
+ }) => {
284
+ const cev = method((s: glassEasel.Event<{ detailStr: string }>) => {
285
+ setData({ a3: s.detail.detailStr })
286
+ })
287
+ const cev2 = listener<{ detailStr: string }>((s) => {
288
+ setData({ a3: s.detail.detailStr })
289
+ })
290
+ lifetime('created', () => {
291
+ let catched = false
292
+ try { method(() => undefined) } catch { catched = true }
293
+ try { listener(() => undefined) } catch { catched = true }
294
+ expect(catched).toBe(false)
295
+ })
296
+
297
+ return {
298
+ cev,
299
+ cev2,
300
+ }
301
+ })
302
+ .registerComponent()
303
+ const elem = glassEasel.Component.createWithContext('root', compDef, domBackend)
304
+ expect(domHtml(elem)).toBe('<div>--</div>')
305
+ elem.a1('b1')
306
+ expect(domHtml(elem)).toBe('<div>b1--</div>')
307
+ elem.a2('b2')
308
+ expect(domHtml(elem)).toBe('<div>b1-b2-</div>')
309
+ elem.getShadowRoot()!.getElementById('a')!.asNativeNode()?.triggerEvent('customEv', { detailStr: 'b3' })
310
+ expect(domHtml(elem)).toBe('<div>b1-b2-b3</div>')
311
+ elem.getShadowRoot()!.getElementById('a')!.asNativeNode()?.triggerEvent('customEv2', { detailStr: 'b33' })
312
+ expect(domHtml(elem)).toBe('<div>b1-b2-b33</div>')
313
+ })
314
+
315
+ test('chaining lifetimes', () => {
316
+ const callOrder: number[] = []
317
+ const beh = componentSpace.define()
318
+ .data(() => ({
319
+ a: 0,
320
+ }))
321
+ .lifetime('created', function () {
322
+ callOrder.push(1)
323
+ this.setData({ a: 1 })
324
+ })
325
+ .registerBehavior()
326
+ const compDef = componentSpace.define()
327
+ .template(tmpl(`
328
+ <div>{{a}}-{{b}}-{{c}}</div>
329
+ `))
330
+ .behavior(beh)
331
+ .data(() => ({
332
+ b: 0,
333
+ }))
334
+ .definition({
335
+ lifetimes: {
336
+ created() {
337
+ callOrder.push(2)
338
+ this.setData({ b: 2 })
339
+ },
340
+ },
341
+ })
342
+ .data(() => ({
343
+ c: 0,
344
+ }))
345
+ .init(({ data, setData, lifetime }) => {
346
+ lifetime('created', () => {
347
+ callOrder.push(3)
348
+ setData({ c: 3 })
349
+ expect(data.c).toBe(3)
350
+ })
351
+ lifetime('attached', () => {
352
+ callOrder.push(-1)
353
+ })
354
+ expect(data.c).toBe(0)
355
+ lifetime('created', () => {
356
+ let catched = false
357
+ try { lifetime('attached', () => { callOrder.push(-100) }) } catch { catched = true }
358
+ expect(catched).toBe(true)
359
+ })
360
+ })
361
+ .registerComponent()
362
+ const elem = glassEasel.Component.createWithContext('root', compDef, domBackend)
363
+ expect(callOrder).toStrictEqual([1, 2, 3])
364
+ expect(elem.data).toStrictEqual({ a: 1, b: 2, c: 3 })
365
+ glassEasel.Element.pretendAttached(elem)
366
+ expect(callOrder).toStrictEqual([1, 2, 3, -1])
367
+ expect(domHtml(elem)).toBe('<div>1-2-3</div>')
368
+ })
369
+
370
+ test('chaining page-lifetimes', () => {
371
+ const callOrder: number[] = []
372
+ const beh = componentSpace.define()
373
+ .data(() => ({
374
+ a: 0,
375
+ }))
376
+ .pageLifetime('show', function (opt: { inc: number }) {
377
+ callOrder.push(opt.inc)
378
+ this.setData({ a: opt.inc })
379
+ const r = opt
380
+ r.inc += 1
381
+ })
382
+ .registerBehavior()
383
+ const compDef = componentSpace.define()
384
+ .template(tmpl(`
385
+ <div>{{a}}-{{b}}-{{c}}</div>
386
+ `))
387
+ .behavior(beh)
388
+ .data(() => ({
389
+ b: 0,
390
+ }))
391
+ .definition({
392
+ pageLifetimes: {
393
+ show(opt: { inc: number }) {
394
+ callOrder.push(opt.inc)
395
+ this.setData({ b: opt.inc * 10 })
396
+ const r = opt
397
+ r.inc += 1
398
+ },
399
+ },
400
+ })
401
+ .data(() => ({
402
+ c: 0,
403
+ }))
404
+ .init(({
405
+ data,
406
+ setData,
407
+ pageLifetime,
408
+ lifetime,
409
+ }) => {
410
+ pageLifetime('show', (opt: { inc: number }) => {
411
+ callOrder.push(opt.inc)
412
+ setData({ c: opt.inc * 100 })
413
+ const r = opt
414
+ r.inc += 1
415
+ expect(data.c).toBe(300)
416
+ })
417
+ pageLifetime('hide', () => {
418
+ callOrder.push(-1)
419
+ })
420
+ expect(data.c).toBe(0)
421
+ lifetime('created', () => {
422
+ let catched = false
423
+ try { pageLifetime('hide', () => { callOrder.push(-100) }) } catch { catched = true }
424
+ expect(catched).toBe(true)
425
+ })
426
+ })
427
+ .registerComponent()
428
+ const elem = glassEasel.Component.createWithContext('root', compDef, domBackend)
429
+ expect(domHtml(elem)).toBe('<div>0-0-0</div>')
430
+ elem.triggerPageLifetime('show', [{ inc: 1 }])
431
+ expect(callOrder).toStrictEqual([1, 2, 3])
432
+ expect(elem.data).toStrictEqual({ a: 1, b: 20, c: 300 })
433
+ expect(domHtml(elem)).toBe('<div>1-20-300</div>')
434
+ elem.triggerPageLifetime('hide', [])
435
+ expect(callOrder).toStrictEqual([1, 2, 3, -1])
436
+ })
437
+
438
+ test('chaining init and methodCallerInit', () => {
439
+ const callOrder: number[] = []
440
+ const beh = componentSpace.define()
441
+ .init(() => {
442
+ callOrder.push(1)
443
+ })
444
+ .registerBehavior()
445
+ const compDef = componentSpace.define()
446
+ .init(() => {
447
+ callOrder.push(2)
448
+ })
449
+ .behavior(beh)
450
+ .methodCallerInit(function () {
451
+ callOrder.push(3)
452
+ return this
453
+ })
454
+ .registerComponent()
455
+ glassEasel.Component.createWithContext('root', compDef, domBackend)
456
+ expect(callOrder).toStrictEqual([3, 1, 2])
457
+ })
458
+
459
+ test('chaining relations', () => {
460
+ const eventArr: number[] = []
461
+ const parentDef = componentSpace.define('parent-comp')
462
+ .relation('child', {
463
+ type: 'child',
464
+ target: 'child-comp',
465
+ linked() {
466
+ eventArr.push(1)
467
+ this.getRelationNodes('child').forEach((c, index) => {
468
+ // eslint-disable-next-line no-use-before-define
469
+ const cc = c.asInstanceOf(childDef)!
470
+ cc.setIndex(index)
471
+ })
472
+ },
473
+ })
474
+ .registerComponent()
475
+ const childDef = componentSpace.define('child-comp')
476
+ .template(tmpl('{{index}}'))
477
+ .data(() => ({
478
+ index: '',
479
+ }))
480
+ .methods({
481
+ setIndex(index: number) {
482
+ this.setData({
483
+ index: String.fromCharCode(index + 'A'.charCodeAt(0)),
484
+ })
485
+ },
486
+ })
487
+ .init(({ relation, lifetime }) => {
488
+ relation({
489
+ type: 'parent',
490
+ target: 'parent-comp',
491
+ linked() {
492
+ eventArr.push(2)
493
+ },
494
+ })
495
+ lifetime('created', () => {
496
+ let catched = false
497
+ try { relation({ type: 'child' }) } catch { catched = true }
498
+ expect(catched).toBe(true)
499
+ })
500
+ })
501
+ .registerComponent()
502
+ const compDef = componentSpace.define()
503
+ .usingComponents({
504
+ parent: parentDef,
505
+ child: childDef,
506
+ })
507
+ .template(tmpl(`
508
+ <parent>
509
+ <child wx:for="{{list}}" />
510
+ </parent>
511
+ `))
512
+ .data(() => ({
513
+ list: [1, 2, 3],
514
+ }))
515
+ .registerComponent()
516
+ const comp = glassEasel.Component.createWithContext('root', compDef, domBackend)
517
+ glassEasel.Element.pretendAttached(comp)
518
+ expect(eventArr).toStrictEqual([1, 2, 1, 2, 1, 2])
519
+ expect(domHtml(comp)).toBe('<parent><child>A</child><child>B</child><child>C</child></parent>')
520
+ })
521
+
522
+ test('chaining filter', () => {
523
+ const beh = componentSpace.define()
524
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
525
+ .chainingFilter<{ myData<T>(this: T): T }, never>((chain) => Object.create(chain, {
526
+ myData: {
527
+ value() {
528
+ return chain.data(() => ({
529
+ a: 123,
530
+ }))
531
+ },
532
+ },
533
+ }))
534
+ .registerBehavior()
535
+ const compDef = componentSpace.define()
536
+ .behavior(beh)
537
+ .data(() => ({ b: '233' }))
538
+ .myData()
539
+ .template(tmpl(`
540
+ <div>{{a}}</div>
541
+ `))
542
+ .registerComponent()
543
+ const elem = glassEasel.Component.createWithContext('root', compDef, domBackend)
544
+ expect(domHtml(elem)).toBe('<div>123</div>')
545
+ })
546
+ })