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,1309 @@
1
+ /* eslint-disable @typescript-eslint/no-unsafe-return */
2
+
3
+ import * as backend from './backend/backend_protocol'
4
+ import * as composedBackend from './backend/composed_backend_protocol'
5
+ import * as domlikeBackend from './backend/domlike_backend_protocol'
6
+ import {
7
+ FuncArr,
8
+ GeneralFuncType,
9
+ triggerWarning,
10
+ } from './func_arr'
11
+ import {
12
+ Element,
13
+ } from './element'
14
+ import {
15
+ globalOptions,
16
+ normalizeComponentOptions,
17
+ NormalizedComponentOptions,
18
+ getDefaultComponentSpace,
19
+ getDefaultBackendContext,
20
+ } from './global_options'
21
+ import {
22
+ ShadowRoot,
23
+ } from './shadow_root'
24
+ import {
25
+ ComponentInstance,
26
+ ComponentParams,
27
+ DataList,
28
+ PropertyList,
29
+ MethodList,
30
+ GeneralComponentInstance,
31
+ DataWithPropertyValues,
32
+ RelationParams,
33
+ TraitRelationParams,
34
+ ComponentMethod,
35
+ TaggedMethod,
36
+ METHOD_TAG,
37
+ DeepReadonly,
38
+ GetFromDataPath,
39
+ SetDataSetter,
40
+ } from './component_params'
41
+ import {
42
+ Behavior,
43
+ GeneralBehavior,
44
+ ComponentDefinitionWithPlaceholder,
45
+ RelationHandler,
46
+ normalizeRelation,
47
+ BuilderContext,
48
+ } from './behavior'
49
+ import {
50
+ ComponentSpace,
51
+ } from './component_space'
52
+ import {
53
+ simpleDeepCopy,
54
+ } from './data_utils'
55
+ import {
56
+ DataGroup,
57
+ DataGroupObserverTree,
58
+ DataValue,
59
+ DeepCopyStrategy,
60
+ getDeepCopyStrategy,
61
+ } from './data_proxy'
62
+ import {
63
+ Relation,
64
+ generateRelationDefinitionGroup,
65
+ RelationDefinitionGroup,
66
+ } from './relation'
67
+ import {
68
+ Template,
69
+ TemplateEngine,
70
+ } from './template_engine'
71
+ import {
72
+ ClassList,
73
+ } from './class_list'
74
+ import {
75
+ GeneralBackendContext,
76
+ GeneralBackendElement,
77
+ } from './node'
78
+ import {
79
+ DataPath,
80
+ parseSinglePath,
81
+ parseMultiPaths,
82
+ } from './data_path'
83
+ import {
84
+ ExternalShadowRoot,
85
+ } from './external_shadow_tree'
86
+ import {
87
+ BM,
88
+ BackendMode,
89
+ } from './backend/mode'
90
+ import {
91
+ EventListener,
92
+ } from './event'
93
+ import { TraitBehavior, TraitGroup } from './trait_behaviors'
94
+
95
+ export const convertGenerics = (
96
+ compDef: GeneralComponentDefinition,
97
+ space: ComponentSpace,
98
+ owner?: GeneralComponent,
99
+ genericTargets?: { [key: string]: string | ComponentDefinitionWithPlaceholder },
100
+ ): { [key: string]: ComponentDefinitionWithPlaceholder } | null => {
101
+ const hostUsing = owner?._$behavior._$using
102
+ const hostGenericImpls = owner?._$genericImpls
103
+ if (!compDef._$detail) compDef.prepare()
104
+ const childBeh = compDef.behavior
105
+ let genericImpls: { [key: string]: ComponentDefinitionWithPlaceholder } | null
106
+ const generics = childBeh._$generics
107
+ if (generics) {
108
+ const genericDefaults = childBeh._$genericDefaults!
109
+ genericImpls = Object.create(null) as { [key: string]: ComponentDefinitionWithPlaceholder }
110
+ for (let i = 0; i < generics.length; i += 1) {
111
+ const key = generics[i]!
112
+ if (genericTargets && Object.prototype.hasOwnProperty.call(genericTargets, key)) {
113
+ const target = genericTargets[key]!
114
+ if (typeof target === 'string') {
115
+ if (hostUsing?.[target]) {
116
+ genericImpls[key] = hostUsing[target]!
117
+ } else if (hostGenericImpls && hostGenericImpls[target]) {
118
+ genericImpls[key] = hostGenericImpls[target]!
119
+ } else {
120
+ const comp = space.getComponentByUrlWithoutDefault(target, '')
121
+ if (comp) {
122
+ genericImpls[key] = {
123
+ final: comp,
124
+ placeholder: null,
125
+ waiting: null,
126
+ }
127
+ } else {
128
+ triggerWarning(`Generic "${key}" value "${target}" is not valid (on component "${compDef.is}").`)
129
+ const defaultComp = space.getDefaultComponent()
130
+ if (!defaultComp) {
131
+ throw new Error(`Cannot find default component for generic "${key}" (on component "${compDef.is}")`)
132
+ }
133
+ genericImpls[key] = {
134
+ final: defaultComp,
135
+ placeholder: null,
136
+ waiting: null,
137
+ }
138
+ }
139
+ }
140
+ } else {
141
+ genericImpls[key] = target
142
+ }
143
+ } else {
144
+ const defaultComp = genericDefaults[key] || space.getDefaultComponent()
145
+ if (!defaultComp) {
146
+ throw new Error(`Cannot find default component for generic "${key}" (on component "${compDef.is}")`)
147
+ }
148
+ genericImpls[key] = {
149
+ final: defaultComp,
150
+ placeholder: null,
151
+ waiting: null,
152
+ }
153
+ }
154
+ }
155
+ } else {
156
+ genericImpls = null
157
+ }
158
+ return genericImpls
159
+ }
160
+
161
+ export const resolvePlaceholder = (
162
+ placeholder: string,
163
+ space: ComponentSpace,
164
+ behavior: GeneralBehavior,
165
+ genericImpls: { [key: string]: ComponentDefinitionWithPlaceholder } | null,
166
+ ): GeneralComponentDefinition => {
167
+ const using = behavior._$using
168
+ const usingTarget = using[placeholder] || (genericImpls && genericImpls[placeholder])
169
+ let ret: GeneralComponentDefinition | null = null
170
+ if (usingTarget) {
171
+ if (usingTarget.placeholder === null) {
172
+ ret = usingTarget.final
173
+ } else {
174
+ triggerWarning(`Placeholder on generic implementation is not valid (on component "${behavior.is}")`)
175
+ }
176
+ }
177
+ if (ret) return ret
178
+ const defaultComp = space.getDefaultComponent()
179
+ if (!defaultComp) {
180
+ throw new Error(`Cannot find default component for placeholder target "${placeholder}" (on component "${behavior.is}")`)
181
+ }
182
+ return defaultComp
183
+ }
184
+
185
+ export type Lifetimes = {
186
+ created: () => void,
187
+ attached: () => void,
188
+ moved: () => void,
189
+ detached: () => void,
190
+ ready: () => void,
191
+ }
192
+
193
+ export type LifetimeFuncs = {
194
+ [name in keyof Lifetimes]?: FuncArr<Lifetimes[name]>
195
+ } & Record<string, FuncArr<GeneralFuncType>>
196
+
197
+ export type PageLifetimeFuncs = {
198
+ [name: string]: FuncArr<GeneralFuncType>,
199
+ }
200
+
201
+ type ComponentDefinitionDetail<
202
+ TData extends DataList,
203
+ TProperty extends PropertyList,
204
+ TMethod extends MethodList,
205
+ > = {
206
+ proto: ComponentInstProto<TData, TProperty, TMethod>
207
+ template: Template
208
+ dataGroupObserverTree: DataGroupObserverTree
209
+ dataDeepCopy: DeepCopyStrategy
210
+ propertyPassingDeepCopy: DeepCopyStrategy
211
+ relationDefinitionGroup: RelationDefinitionGroup | null
212
+ }
213
+
214
+ export class ComponentDefinition<
215
+ TData extends DataList,
216
+ TProperty extends PropertyList,
217
+ TMethod extends MethodList,
218
+ > {
219
+ is: string
220
+ behavior: Behavior<TData, TProperty, TMethod, any>
221
+ /** @internal */
222
+ _$detail: ComponentDefinitionDetail<TData, TProperty, TMethod> | null
223
+ /** @internal */
224
+ _$options: NormalizedComponentOptions
225
+ /** @internal */
226
+ private _$templateEngine: TemplateEngine
227
+
228
+ /** @internal */
229
+ constructor(
230
+ behavior: Behavior<TData, TProperty, TMethod, any>,
231
+ ) {
232
+ this.behavior = behavior
233
+ this.is = this.behavior.is
234
+ this._$detail = null
235
+ this._$options = normalizeComponentOptions(
236
+ behavior._$options,
237
+ behavior.ownerSpace.getComponentOptions(),
238
+ )
239
+ const templateEngine = this._$options.templateEngine
240
+ this._$templateEngine = templateEngine
241
+ }
242
+
243
+ general(): GeneralComponentDefinition {
244
+ return this as unknown as GeneralComponentDefinition
245
+ }
246
+
247
+ /** Get the normalized component options */
248
+ getComponentOptions(): NormalizedComponentOptions {
249
+ return this._$options
250
+ }
251
+
252
+ /**
253
+ * List all component dependencies (recursively)
254
+ *
255
+ * This method will prepare the underlying behavior.
256
+ * The caller component is not included in the result.
257
+ */
258
+ getComponentDependencies(): Set<GeneralComponentDefinition> {
259
+ return this.behavior.getComponentDependencies()
260
+ }
261
+
262
+ isPrepared(): boolean {
263
+ return !!this._$detail
264
+ }
265
+
266
+ prepare() {
267
+ if (this._$detail) return
268
+ this.behavior.prepare()
269
+ const behavior = this.behavior
270
+ const options = this._$options
271
+ const propSetters = {} as {
272
+ [key: string]: {
273
+ enumerable: boolean,
274
+ get: (this: Component<TData, TProperty, TMethod>) => unknown,
275
+ set: (this: Component<TData, TProperty, TMethod>, v: unknown) => void,
276
+ } | {
277
+ enumerable: boolean,
278
+ value: (...args: unknown[]) => unknown,
279
+ }
280
+ }
281
+
282
+ // add properties to component prototype if needed
283
+ if (options.writeFieldsToNode) {
284
+ const keys = Object.keys(behavior._$propertyMap)
285
+ for (let i = 0; i < keys.length; i += 1) {
286
+ const propName = keys[i]!
287
+ propSetters[propName] = {
288
+ enumerable: true,
289
+ get() {
290
+ return this._$dataGroup.data[propName]
291
+ },
292
+ set(v: DataValue) {
293
+ const dataGroup = this._$dataGroup
294
+ dataGroup.replaceDataOnPath([propName], v)
295
+ dataGroup.applyDataUpdates()
296
+ },
297
+ }
298
+ }
299
+ const methodKeys = Object.keys(behavior._$methodMap)
300
+ for (let i = 0; i < methodKeys.length; i += 1) {
301
+ const methodName = methodKeys[i]!
302
+ propSetters[methodName] = {
303
+ enumerable: true,
304
+ value: behavior._$methodMap[methodName]!,
305
+ }
306
+ }
307
+ }
308
+
309
+ // create prototype
310
+ const protoFunc = function ComponentInst() { /* empty */ }
311
+ protoFunc.prototype = Object.create(Component.prototype, propSetters) as
312
+ ComponentInstProto<TData, TProperty, TMethod>
313
+ const proto = protoFunc.prototype
314
+ proto._$behavior = behavior
315
+ proto._$definition = this
316
+ proto._$methodMap = behavior._$methodMap
317
+
318
+ // init other helpers
319
+ const dataGroupObserverTree = behavior._$generateObserverTree()
320
+ proto._$lifetimeFuncs = behavior._$getAllLifetimeFuncs()
321
+ proto._$pageLifetimeFuncs = behavior._$getAllPageLifetimeFuncs()
322
+ const relationDefinitionGroup = generateRelationDefinitionGroup(behavior._$relationMap)
323
+ const dataDeepCopy = getDeepCopyStrategy(options.dataDeepCopy)
324
+ const propertyPassingDeepCopy = getDeepCopyStrategy(options.propertyPassingDeepCopy)
325
+
326
+ // call template engine
327
+ const template = this._$templateEngine.create(behavior as unknown as GeneralBehavior, options)
328
+
329
+ this._$detail = {
330
+ proto,
331
+ template,
332
+ dataGroupObserverTree,
333
+ dataDeepCopy,
334
+ propertyPassingDeepCopy,
335
+ relationDefinitionGroup,
336
+ }
337
+ }
338
+ }
339
+
340
+ let componentInstanceIdInc = 1
341
+
342
+ /**
343
+ * A node that has a shadow tree attached to it
344
+ */
345
+ export class Component<
346
+ TData extends DataList,
347
+ TProperty extends PropertyList,
348
+ TMethod extends MethodList,
349
+ > extends Element {
350
+ /** @internal */
351
+ _$behavior: Behavior<TData, TProperty, TMethod, any>
352
+ /** @internal */
353
+ _$definition: ComponentDefinition<TData, TProperty, TMethod>
354
+ /** @internal */
355
+ _$lifetimeFuncs: LifetimeFuncs
356
+ /** @internal */
357
+ _$pageLifetimeFuncs: PageLifetimeFuncs
358
+ /** @internal */
359
+ _$methodMap: MethodList
360
+ /** @internal */
361
+ _$genericImpls: { [name: string]: ComponentDefinitionWithPlaceholder } | null
362
+ /** @internal */
363
+ _$dataGroup: DataGroup<TData, TProperty, TMethod>
364
+ /** @internal */
365
+ _$external: boolean
366
+ shadowRoot: ShadowRoot | ExternalShadowRoot
367
+ /** @internal */
368
+ _$relation: Relation | null
369
+ /** @internal */
370
+ _$idPrefix: string
371
+ /** @internal */
372
+ _$componentInstanceId: number | undefined
373
+ tagName: string
374
+ /** @internal */
375
+ private _$traitGroup: TraitGroup
376
+ /** @internal */
377
+ private _$methodCaller: ComponentInstance<TData, TProperty, TMethod>
378
+
379
+ constructor() {
380
+ throw new Error('Element cannot be constructed directly')
381
+ // eslint-disable-next-line no-unreachable
382
+ super()
383
+ }
384
+
385
+ general(): GeneralComponent {
386
+ return this as unknown as GeneralComponent
387
+ }
388
+
389
+ /**
390
+ * Cast a general component node to the instance of the specified component
391
+ *
392
+ * Returns `null` if the component node is not the instance of the specified component.
393
+ */
394
+ override asInstanceOf<
395
+ UData extends DataList,
396
+ UProperty extends PropertyList,
397
+ UMethod extends MethodList,
398
+ >(
399
+ componentDefinition: ComponentDefinition<UData, UProperty, UMethod>,
400
+ ): ComponentInstance<UData, UProperty, UMethod> | null {
401
+ if (this._$behavior as any !== componentDefinition.behavior) {
402
+ return null
403
+ }
404
+ return this as unknown as ComponentInstance<UData, UProperty, UMethod>
405
+ }
406
+
407
+ static register<
408
+ TData extends DataList,
409
+ TProperty extends PropertyList,
410
+ TMethod extends MethodList,
411
+ >(
412
+ def: ComponentParams<TData, TProperty, TMethod> &
413
+ ThisType<ComponentInstance<TData, TProperty, TMethod>>,
414
+ space?: ComponentSpace,
415
+ ): ComponentDefinition<TData, TProperty, TMethod> {
416
+ return (space || getDefaultComponentSpace()).defineComponent(def)
417
+ }
418
+
419
+ /** @internal */
420
+ static _$tagMethod<Fn extends ComponentMethod>(func: Fn): TaggedMethod<Fn> {
421
+ const taggedMethod = func as unknown as TaggedMethod<Fn>
422
+ (taggedMethod as unknown as { [tag: symbol]: true })[METHOD_TAG] = true
423
+ return taggedMethod
424
+ }
425
+
426
+ /** @internal */
427
+ static _$isTaggedMethod(func: unknown): func is TaggedMethod<ComponentMethod> {
428
+ return typeof func === 'function' && !!(func as unknown as { [tag: symbol]: true })[METHOD_TAG]
429
+ }
430
+
431
+ /** @internal */
432
+ static _$advancedCreate<
433
+ TData extends DataList,
434
+ TProperty extends PropertyList,
435
+ TMethod extends MethodList,
436
+ >(
437
+ tagName: string,
438
+ def: ComponentDefinition<TData, TProperty, TMethod>,
439
+ owner: ShadowRoot | null,
440
+ backendContext: GeneralBackendContext | null,
441
+ genericImpls: { [name: string]: ComponentDefinitionWithPlaceholder } | null,
442
+ placeholderHandler: (() => void) | undefined,
443
+ initPropValues?: (comp: ComponentInstance<TData, TProperty, TMethod>) => void,
444
+ ): ComponentInstance<TData, TProperty, TMethod> {
445
+ if (!def._$detail) def.prepare()
446
+ const {
447
+ proto,
448
+ template,
449
+ dataDeepCopy,
450
+ propertyPassingDeepCopy,
451
+ relationDefinitionGroup,
452
+ } = def._$detail!
453
+ let dataGroupObserverTree = def._$detail!.dataGroupObserverTree
454
+ const options = def._$options
455
+ const behavior = def.behavior
456
+ const nodeTreeContext: GeneralBackendContext = owner
457
+ ? owner._$nodeTreeContext
458
+ : backendContext || globalOptions.backendContext || getDefaultBackendContext()
459
+ const external = options.externalComponent
460
+ const propEarlyInit = options.propertyEarlyInit
461
+ const writeExtraInfoToAttr = globalOptions.writeExtraInfoToAttr
462
+
463
+ // initialize component instance object
464
+ const comp = Object.create(proto) as
465
+ ComponentInstance<TData, TProperty, TMethod>
466
+ comp._$genericImpls = genericImpls
467
+ comp._$placeholderHandler = placeholderHandler
468
+ comp._$external = external
469
+ comp.tagName = tagName
470
+ comp._$methodCaller = comp
471
+
472
+ // create backend element
473
+ let backendElement: GeneralBackendElement | null
474
+ if (options.virtualHost) {
475
+ backendElement = null
476
+ comp._$initialize(true, null, owner, nodeTreeContext)
477
+ if (BM.SHADOW || (BM.DYNAMIC && nodeTreeContext.mode === BackendMode.Shadow)) {
478
+ if (owner) {
479
+ const backend = owner._$backendShadowRoot
480
+ backendElement = backend?.createComponent(tagName, true) || null
481
+ } else {
482
+ const sr = (nodeTreeContext as backend.Context).getRootNode().getShadowRoot()
483
+ if (!sr) throw new Error('Failed getting backend shadow tree')
484
+ backendElement = sr.createComponent(tagName, false) || null
485
+ }
486
+ }
487
+ } else if (owner) {
488
+ if (BM.DOMLIKE || (BM.DYNAMIC && nodeTreeContext.mode === BackendMode.Domlike)) {
489
+ backendElement = (owner._$nodeTreeContext as domlikeBackend.Context)
490
+ .document.createElement(tagName)
491
+ } else if (BM.SHADOW || (BM.DYNAMIC && nodeTreeContext.mode === BackendMode.Shadow)) {
492
+ const backend = owner._$backendShadowRoot
493
+ backendElement = backend?.createComponent(tagName, false) || null
494
+ } else {
495
+ const backend = owner._$nodeTreeContext as composedBackend.Context
496
+ backendElement = backend.createElement(tagName)
497
+ }
498
+ comp._$initialize(false, backendElement, owner, nodeTreeContext)
499
+ } else {
500
+ if (BM.DOMLIKE || (BM.DYNAMIC && nodeTreeContext.mode === BackendMode.Domlike)) {
501
+ backendElement = (nodeTreeContext as domlikeBackend.Context)
502
+ .document.createElement(tagName)
503
+ } else if (BM.SHADOW || (BM.DYNAMIC && nodeTreeContext.mode === BackendMode.Shadow)) {
504
+ const sr = (nodeTreeContext as backend.Context).getRootNode().getShadowRoot()
505
+ if (!sr) throw new Error('Failed getting backend shadow tree')
506
+ backendElement = sr.createComponent(tagName, false) || null
507
+ } else {
508
+ backendElement = (nodeTreeContext as composedBackend.Context).createElement(tagName) || null
509
+ }
510
+ comp._$initialize(false, backendElement, owner, nodeTreeContext)
511
+ }
512
+
513
+ // init class list
514
+ const externalClassAlias = {} as { [externalName: string]: string[] | null }
515
+ if (behavior._$externalClasses) {
516
+ const externalClasses = behavior._$externalClasses
517
+ for (let i = 0; i < externalClasses.length; i += 1) {
518
+ externalClassAlias[externalClasses[i]!] = null
519
+ }
520
+ }
521
+ comp.classList = new ClassList(comp, externalClassAlias)
522
+ if (owner && backendElement) {
523
+ const styleScope = owner.getHostNode()._$definition._$options.styleScope
524
+ if (styleScope) {
525
+ if (!(BM.DOMLIKE || (BM.DYNAMIC && nodeTreeContext.mode === BackendMode.Domlike))) {
526
+ (backendElement as backend.Element | composedBackend.Element).setStyleScope(styleScope)
527
+ }
528
+ }
529
+ if (writeExtraInfoToAttr) {
530
+ const prefix = owner.getHostNode()
531
+ ._$behavior.ownerSpace?.styleScopeManager.queryName(styleScope)
532
+ if (prefix) {
533
+ backendElement.setAttribute('exparser:info-class-prefix', `${prefix}--`)
534
+ }
535
+ }
536
+ }
537
+
538
+ // associate in backend
539
+ if (!(BM.DOMLIKE || (BM.DYNAMIC && nodeTreeContext.mode === BackendMode.Domlike))) {
540
+ if (backendElement) {
541
+ (backendElement as backend.Element | composedBackend.Element).associateValue(comp)
542
+ }
543
+ }
544
+
545
+ // write attr
546
+ if (writeExtraInfoToAttr && backendElement) {
547
+ const componentInstanceId = componentInstanceIdInc
548
+ componentInstanceIdInc += 1
549
+ comp._$componentInstanceId = componentInstanceId
550
+ backendElement.setAttribute('exparser:info-component-id', componentInstanceId)
551
+ }
552
+ comp._$idPrefix = options.idPrefixGenerator ? options.idPrefixGenerator.call(comp as unknown as GeneralComponentInstance) : ''
553
+
554
+ // combine initial data
555
+ const staticData = behavior._$staticData
556
+ const dataGenFuncs = behavior._$data
557
+ let data: DataList
558
+ if (staticData === undefined) {
559
+ if (dataGenFuncs.length === 1) {
560
+ const f = dataGenFuncs[0]!
561
+ data = f()
562
+ } else {
563
+ data = {}
564
+ for (let i = 0; i < dataGenFuncs.length; i += 1) {
565
+ const f = dataGenFuncs[i]!
566
+ Object.assign(data, f())
567
+ }
568
+ }
569
+ } else {
570
+ data = simpleDeepCopy(staticData)
571
+ for (let i = 0; i < dataGenFuncs.length; i += 1) {
572
+ const f = dataGenFuncs[i]!
573
+ Object.assign(data, f())
574
+ }
575
+ }
576
+
577
+ // init relations
578
+ const relation = comp._$relation = new Relation(
579
+ comp as unknown as GeneralComponentInstance,
580
+ relationDefinitionGroup,
581
+ )
582
+
583
+ // init trait group
584
+ comp._$traitGroup = new TraitGroup()
585
+ const traitBehaviors = behavior._$traitBehaviors
586
+ if (traitBehaviors !== undefined) {
587
+ for (let i = 0; i < traitBehaviors.length; i += 1) {
588
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
589
+ const { traitBehavior, impl } = traitBehaviors[i]!
590
+ comp._$traitGroup.implement(traitBehavior, impl)
591
+ }
592
+ }
593
+
594
+ // call method caller init
595
+ if (behavior._$methodCallerInit) {
596
+ const methodCaller = behavior._$methodCallerInit.call(comp)
597
+ comp._$methodCaller = methodCaller
598
+ }
599
+
600
+ // call init functions
601
+ let initDone = false
602
+ function relationInit(def: RelationParams): RelationHandler<unknown, never>
603
+ function relationInit<TOut extends { [x: string]: unknown }>(
604
+ def: TraitRelationParams<TOut>,
605
+ ): RelationHandler<unknown, TOut>
606
+ function relationInit<TOut extends { [x: string]: unknown }>(
607
+ def: RelationParams | TraitRelationParams<TOut>,
608
+ ): RelationHandler<unknown, unknown> {
609
+ if (initDone) throw new Error('Cannot execute init-time functions after initialization')
610
+ const target = def.target
611
+ const normalizedRel = normalizeRelation(behavior.is, 'undefined', def)
612
+ let key: symbol
613
+ if (normalizedRel) {
614
+ key = relation.add(normalizedRel)
615
+ } else {
616
+ key = Symbol('invalid')
617
+ }
618
+ const list = () => {
619
+ const targetNodes = relation.getLinkedTargets(key)
620
+ return targetNodes.map((x) => x.getMethodCaller())
621
+ }
622
+ const listAsTrait = target instanceof TraitBehavior ? () => {
623
+ const targetNodes = relation.getLinkedTargets(key)
624
+ return targetNodes.map((x: GeneralComponent) => x.traitBehavior(target))
625
+ } : undefined
626
+ return { list, listAsTrait } as any
627
+ }
628
+ if (behavior._$init.length > 0) {
629
+ let cowObserver = true
630
+ let cowLifetime = true
631
+ let cowPageLifetime = true
632
+ let cowMethodMap = true
633
+ const methodCaller = comp.getMethodCaller()
634
+ const builderContext: BuilderContext<any, any, any> = {
635
+ self: methodCaller,
636
+ data,
637
+ setData: comp.setData.bind(comp) as (newData: { [x: string]: unknown }) => void,
638
+ implement: <TIn extends { [x: string]: unknown }>(
639
+ traitBehavior: TraitBehavior<TIn, { [x: string]: unknown }>,
640
+ impl: TIn,
641
+ ): void => {
642
+ if (initDone) throw new Error('Cannot execute init-time functions after initialization')
643
+ comp._$traitGroup.implement(traitBehavior, impl)
644
+ },
645
+ relation: relationInit,
646
+ observer: (dataPaths: string | readonly string[], func: (...args: any[]) => void): void => {
647
+ if (initDone) throw new Error('Cannot execute init-time functions after initialization')
648
+ if (cowObserver) {
649
+ cowObserver = false
650
+ dataGroupObserverTree = dataGroupObserverTree.cloneSub()
651
+ }
652
+ dataGroupObserverTree.addObserver(func, parseMultiPaths(dataPaths as string | string[]))
653
+ },
654
+ lifetime: (name: string, func: (...args: unknown[]) => void): void => {
655
+ if (initDone) throw new Error('Cannot execute init-time functions after initialization')
656
+ if (cowLifetime) {
657
+ cowLifetime = false
658
+ comp._$lifetimeFuncs = behavior._$getAllLifetimeFuncs()
659
+ }
660
+ const fag = comp._$lifetimeFuncs
661
+ if (fag[name]) {
662
+ fag[name]!.add(func)
663
+ } else {
664
+ const fa = fag[name] = new FuncArr()
665
+ fa.add(func)
666
+ }
667
+ },
668
+ pageLifetime: (name: string, func: (...args: unknown[]) => void): void => {
669
+ if (initDone) throw new Error('Cannot execute init-time functions after initialization')
670
+ if (cowPageLifetime) {
671
+ cowPageLifetime = false
672
+ comp._$pageLifetimeFuncs = behavior._$getAllPageLifetimeFuncs()
673
+ }
674
+ const fag = comp._$pageLifetimeFuncs
675
+ if (fag[name]) {
676
+ fag[name]!.add(func)
677
+ } else {
678
+ const fa = fag[name] = new FuncArr()
679
+ fa.add(func)
680
+ }
681
+ },
682
+ method: <Fn extends ComponentMethod>(func: Fn) => Component._$tagMethod(func),
683
+ listener: <T>(func: EventListener<T>) => Component._$tagMethod(func),
684
+ }
685
+ const initFuncs = behavior._$init
686
+ for (let i = 0; i < initFuncs.length; i += 1) {
687
+ const init = initFuncs[i]!
688
+ const exported = init.call(methodCaller, builderContext) as
689
+ { [x: string]: unknown } | undefined
690
+ if (exported) {
691
+ const exportedKeys = Object.keys(exported)
692
+ for (let j = 0; j < exportedKeys.length; j += 1) {
693
+ const exportedKey = exportedKeys[j]!
694
+ const exportItem: unknown = exported[exportedKey]
695
+ if (Component._$isTaggedMethod(exportItem)) {
696
+ if (cowMethodMap) {
697
+ cowMethodMap = false
698
+ comp._$methodMap = Object.create(comp._$methodMap) as MethodList
699
+ }
700
+ comp._$methodMap[exportedKey] = exportItem
701
+ }
702
+ }
703
+ }
704
+ }
705
+ }
706
+ initDone = true
707
+
708
+ // init data
709
+ const tmplInst = template.createInstance(
710
+ comp as unknown as GeneralComponentInstance,
711
+ )
712
+ const shadowRoot = tmplInst.shadowRoot
713
+ comp.shadowRoot = shadowRoot
714
+ const dataGroup = new DataGroup(
715
+ comp,
716
+ data as DataWithPropertyValues<TData, TProperty>,
717
+ options.pureDataPattern || null,
718
+ dataDeepCopy,
719
+ propertyPassingDeepCopy,
720
+ options.reflectToAttributes,
721
+ dataGroupObserverTree,
722
+ )
723
+ comp._$dataGroup = dataGroup
724
+
725
+ // init template with init data
726
+ if (propEarlyInit && initPropValues !== undefined) initPropValues(comp)
727
+ tmplInst.initValues(
728
+ dataGroup.innerData || dataGroup.data,
729
+ )
730
+ dataGroup.setUpdateListener(
731
+ tmplInst.updateValues.bind(tmplInst),
732
+ )
733
+
734
+ // bind behavior listeners
735
+ const listeners = behavior._$listeners
736
+ if (listeners !== undefined) {
737
+ for (let i = 0; i < listeners.length; i += 1) {
738
+ const { id, ev, listener: gf } = listeners[i]!
739
+ const listener = gf as EventListener<any>
740
+ if (id === 'this') {
741
+ comp.addListener(ev, (ev) => listener.call(comp._$methodCaller, ev))
742
+ } else if (!external) {
743
+ const sr = shadowRoot as ShadowRoot
744
+ const elem = id ? sr.getElementById(id) : sr
745
+ if (elem) {
746
+ elem.addListener(ev, (ev) => listener.call(comp._$methodCaller, ev))
747
+ }
748
+ } else {
749
+ const sr = shadowRoot as ExternalShadowRoot
750
+ const elem = id ? sr.getIdMap()[id] : sr.root
751
+ if (elem) {
752
+ sr.setListener(elem, ev, (ev) => listener.call(comp._$methodCaller, ev))
753
+ }
754
+ }
755
+ }
756
+ }
757
+
758
+ // trigger created lifetimes
759
+ comp._$lifetimeFuncs.created?.call(
760
+ comp._$methodCaller as any,
761
+ [],
762
+ comp as unknown as GeneralComponent,
763
+ )
764
+ if (!propEarlyInit && initPropValues !== undefined) initPropValues(comp)
765
+
766
+ return comp
767
+ }
768
+
769
+ static createWithGenericsAndContext<
770
+ TData extends DataList,
771
+ TProperty extends PropertyList,
772
+ TMethod extends MethodList,
773
+ >(
774
+ tagName: string | ComponentDefinition<TData, TProperty, TMethod>,
775
+ componentDefinition: ComponentDefinition<TData, TProperty, TMethod> | null,
776
+ genericTargets: { [name: string]: GeneralComponentDefinition } | null,
777
+ backendContext: GeneralBackendContext | null,
778
+ initPropValues?: (comp: ComponentInstance<TData, TProperty, TMethod>) => void,
779
+ ): ComponentInstance<TData, TProperty, TMethod> {
780
+ const collectGenericImpls = (def: GeneralComponentDefinition) => {
781
+ const space = def.behavior.ownerSpace
782
+ let genericImpls: { [key: string]: ComponentDefinitionWithPlaceholder } | undefined
783
+ if (genericTargets) {
784
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
785
+ genericImpls = Object.create(null)
786
+ Object.entries(genericTargets).forEach(([key, g]) => {
787
+ genericImpls![key] = {
788
+ final: g,
789
+ placeholder: null,
790
+ waiting: null,
791
+ }
792
+ })
793
+ }
794
+ return convertGenerics(def, space, undefined, genericImpls)
795
+ }
796
+ if (componentDefinition) {
797
+ return Component._$advancedCreate(
798
+ String(tagName),
799
+ componentDefinition,
800
+ null,
801
+ backendContext,
802
+ collectGenericImpls(componentDefinition as unknown as GeneralComponentDefinition),
803
+ undefined,
804
+ initPropValues,
805
+ )
806
+ }
807
+ if (tagName instanceof ComponentDefinition) {
808
+ return Component._$advancedCreate(
809
+ tagName.is,
810
+ tagName,
811
+ null,
812
+ backendContext,
813
+ collectGenericImpls(tagName as unknown as GeneralComponentDefinition),
814
+ undefined,
815
+ )
816
+ }
817
+ const compDef = getDefaultComponentSpace().getComponentByUrl(tagName, '')
818
+ return Component._$advancedCreate(
819
+ tagName,
820
+ compDef,
821
+ null,
822
+ backendContext,
823
+ collectGenericImpls(compDef),
824
+ undefined,
825
+ ) as unknown as ComponentInstance<TData, TProperty, TMethod>
826
+ }
827
+
828
+ static createWithGenerics<
829
+ TData extends DataList,
830
+ TProperty extends PropertyList,
831
+ TMethod extends MethodList,
832
+ >(
833
+ tagName: string | ComponentDefinition<TData, TProperty, TMethod>,
834
+ componentDefinition: ComponentDefinition<TData, TProperty, TMethod> | null,
835
+ genericImpls: { [name: string]: GeneralComponentDefinition } | null,
836
+ initPropValues?: (comp: ComponentInstance<TData, TProperty, TMethod>) => void,
837
+ ): ComponentInstance<TData, TProperty, TMethod> {
838
+ return Component.createWithGenericsAndContext(
839
+ tagName,
840
+ componentDefinition,
841
+ genericImpls,
842
+ null,
843
+ initPropValues,
844
+ )
845
+ }
846
+
847
+ static createWithContext<
848
+ TData extends DataList,
849
+ TProperty extends PropertyList,
850
+ TMethod extends MethodList,
851
+ >(
852
+ tagName: string | ComponentDefinition<TData, TProperty, TMethod>,
853
+ componentDefinition: ComponentDefinition<TData, TProperty, TMethod> | null,
854
+ backendContext: GeneralBackendContext | null,
855
+ initPropValues?: (comp: ComponentInstance<TData, TProperty, TMethod>) => void,
856
+ ): ComponentInstance<TData, TProperty, TMethod> {
857
+ return Component.createWithGenericsAndContext(
858
+ tagName,
859
+ componentDefinition,
860
+ null,
861
+ backendContext,
862
+ initPropValues,
863
+ )
864
+ }
865
+
866
+ static create<
867
+ TData extends DataList,
868
+ TProperty extends PropertyList,
869
+ TMethod extends MethodList,
870
+ >(
871
+ tagName: string | ComponentDefinition<TData, TProperty, TMethod>,
872
+ componentDefinition: ComponentDefinition<TData, TProperty, TMethod> | null,
873
+ initPropValues?: (comp: ComponentInstance<TData, TProperty, TMethod>) => void,
874
+ ): ComponentInstance<TData, TProperty, TMethod> {
875
+ return Component.createWithGenericsAndContext(
876
+ tagName,
877
+ componentDefinition,
878
+ null,
879
+ null,
880
+ initPropValues,
881
+ )
882
+ }
883
+
884
+ get is(): string {
885
+ return this._$definition.is
886
+ }
887
+
888
+ get properties(): DeepReadonly<DataWithPropertyValues<TData, TProperty>> {
889
+ return this._$dataGroup.data as any
890
+ }
891
+
892
+ get data(): DeepReadonly<DataWithPropertyValues<TData, TProperty>> {
893
+ return this._$dataGroup.data as any
894
+ }
895
+
896
+ set data(newData: Partial<DataWithPropertyValues<TData, TProperty>>) {
897
+ const dataGroup = this._$dataGroup
898
+ Object.entries(newData).forEach(([key, value]) => dataGroup.replaceDataOnPath([key], value))
899
+ dataGroup.applyDataUpdates()
900
+ }
901
+
902
+ get $(): { [id: string]: Element } | { [id: string]: GeneralBackendElement } {
903
+ if (this._$external) {
904
+ return (this.shadowRoot as ExternalShadowRoot).getIdMap()
905
+ }
906
+ return (this.shadowRoot as ShadowRoot)._$getIdMap()
907
+ }
908
+
909
+ /**
910
+ * Returns the shadow root element
911
+ *
912
+ * Returns `null` for external components.
913
+ */
914
+ getShadowRoot(): ShadowRoot | null {
915
+ if (this._$external) {
916
+ return null
917
+ }
918
+ return this.shadowRoot as ShadowRoot
919
+ }
920
+
921
+ static listProperties<
922
+ TData extends DataList,
923
+ TProperty extends PropertyList,
924
+ TMethod extends MethodList,
925
+ >(
926
+ comp: ComponentInstance<TData, TProperty, TMethod>,
927
+ ): string[] {
928
+ return Object.keys(comp._$behavior._$propertyMap)
929
+ }
930
+
931
+ static hasProperty<
932
+ TData extends DataList,
933
+ TProperty extends PropertyList,
934
+ TMethod extends MethodList,
935
+ >(comp: Component<TData, TProperty, TMethod>, propName: string): boolean {
936
+ return !!comp._$behavior._$propertyMap[propName]
937
+ }
938
+
939
+ /** List methods by the component definition (backward compatibility) */
940
+ static getMethodsFromDef<
941
+ TData extends DataList,
942
+ TProperty extends PropertyList,
943
+ TMethod extends MethodList,
944
+ >(
945
+ compDef: ComponentDefinition<TData, TProperty, TMethod>,
946
+ ): { [name: string]: GeneralFuncType } {
947
+ return compDef.behavior._$methodMap
948
+ }
949
+
950
+ /** Get a method */
951
+ static getMethod<
952
+ TData extends DataList,
953
+ TProperty extends PropertyList,
954
+ TMethod extends MethodList,
955
+ >(
956
+ comp: Component<TData, TProperty, TMethod>,
957
+ methodName: string,
958
+ ): GeneralFuncType | undefined {
959
+ return comp._$behavior._$methodMap[methodName]
960
+ }
961
+
962
+ /**
963
+ * Get the corresponding component definition
964
+ */
965
+ getComponentDefinition(): ComponentDefinition<TData, TProperty, TMethod> {
966
+ return this._$definition
967
+ }
968
+
969
+ /**
970
+ * Get the options of the component
971
+ */
972
+ getComponentOptions(): NormalizedComponentOptions {
973
+ return this._$definition._$options
974
+ }
975
+
976
+ /**
977
+ * Check whether the `other` behavior is a dependent behavior or a implemented trait behavior
978
+ */
979
+ hasBehavior(other: string | GeneralBehavior | TraitBehavior<any, any>): boolean {
980
+ if (other instanceof TraitBehavior) {
981
+ return this._$traitGroup.get(other) !== undefined
982
+ }
983
+ return this._$behavior.hasBehavior(other)
984
+ }
985
+
986
+ /** Get the root behavior of the component */
987
+ getRootBehavior(): Behavior<TData, TProperty, TMethod, any> {
988
+ return this._$behavior
989
+ }
990
+
991
+ /**
992
+ * Get the trait behavior implementation of the component
993
+ *
994
+ * Returns `undefined` if the specified trait behavior is not implemented.
995
+ */
996
+ traitBehavior<TOut extends { [x: string]: any }>(
997
+ traitBehavior: TraitBehavior<any, TOut>,
998
+ ): TOut | undefined {
999
+ return this._$traitGroup.get(traitBehavior)
1000
+ }
1001
+
1002
+ /**
1003
+ * Set the caller (a.k.a. `this` ) of event callbacks and life-time callbacks
1004
+ *
1005
+ * By default, the caller is the component instance itself.
1006
+ * Use this method to override this behavior.
1007
+ */
1008
+ setMethodCaller(caller: ComponentInstance<TData, TProperty, TMethod>) {
1009
+ this._$methodCaller = caller
1010
+ }
1011
+
1012
+ /**
1013
+ * Get the current caller set by `setMethodCaller`
1014
+ */
1015
+ getMethodCaller(): ComponentInstance<TData, TProperty, TMethod> {
1016
+ return this._$methodCaller
1017
+ }
1018
+
1019
+ /**
1020
+ * Triggers a life-time callback on an element
1021
+ *
1022
+ * Normally external life-times should only be triggered by template engine.
1023
+ * Most cases should take a common method instead.
1024
+ */
1025
+ triggerLifetime(name: string, args: Parameters<GeneralFuncType>) {
1026
+ const f = this._$lifetimeFuncs[name]
1027
+ if (f) f.call(this._$methodCaller as any, args)
1028
+ }
1029
+
1030
+ /**
1031
+ * @internal
1032
+ * @deprecated Rename to `triggerLifetime`
1033
+ */
1034
+ triggerLifeTime(name: string, args: Parameters<GeneralFuncType>) {
1035
+ return this.triggerLifetime(name, args)
1036
+ }
1037
+
1038
+ /**
1039
+ * Triggers a page-life-time callback on an element
1040
+ */
1041
+ triggerPageLifetime(name: string, args: Parameters<GeneralFuncType>) {
1042
+ const rec = (node: Element) => {
1043
+ if (node instanceof Component) {
1044
+ if (node._$pageLifetimeFuncs) {
1045
+ const f = node._$pageLifetimeFuncs[name]
1046
+ if (f) f.call(node._$methodCaller, args)
1047
+ }
1048
+ if (!node._$external) rec(node.shadowRoot as ShadowRoot)
1049
+ }
1050
+ const children = node.childNodes
1051
+ for (let i = 0; i < children.length; i += 1) {
1052
+ const child = children[i]
1053
+ if (child instanceof Element) {
1054
+ rec(child)
1055
+ }
1056
+ }
1057
+ }
1058
+ rec(this)
1059
+ }
1060
+
1061
+ /**
1062
+ * @internal
1063
+ * @deprecated Rename to `triggerPageLifetime`
1064
+ */
1065
+ triggerPageLifeTime(name: string, args: Parameters<GeneralFuncType>) {
1066
+ return this.triggerPageLifetime(name, args)
1067
+ }
1068
+
1069
+ /**
1070
+ * Get the target elements of a relation
1071
+ */
1072
+ getRelationNodes(relationKey: string): GeneralComponent[] {
1073
+ return this._$relation?.getLinkedTargets(relationKey) || ([] as GeneralComponent[])
1074
+ }
1075
+
1076
+ /** Check the existence of an external class */
1077
+ hasExternalClass(name: string): boolean {
1078
+ return (this.classList as ClassList)._$hasAlias(name)
1079
+ }
1080
+
1081
+ /** Update an external class value */
1082
+ setExternalClass(name: string, target: string) {
1083
+ const cl = (this.classList as ClassList)
1084
+ cl._$setAlias(name, target)
1085
+ cl._$spreadAliasUpdate()
1086
+ }
1087
+
1088
+ /** Schedule an update for an external class value */
1089
+ scheduleExternalClassChange(name: string, target: string) {
1090
+ const cl = (this.classList as ClassList)
1091
+ cl._$setAlias(name, target)
1092
+ }
1093
+
1094
+ /** Update multiple external class values */
1095
+ applyExternalClassChanges() {
1096
+ (this.classList as ClassList)._$spreadAliasUpdate()
1097
+ }
1098
+
1099
+ /** Check a field is excluded by pureDataPattern or not */
1100
+ isInnerDataExcluded(fieldName: string): boolean {
1101
+ return this._$definition._$options.pureDataPattern?.test(fieldName) || false
1102
+ }
1103
+
1104
+ static getInnerData<
1105
+ TData extends DataList,
1106
+ TProperty extends PropertyList,
1107
+ TMethod extends MethodList,
1108
+ >(
1109
+ comp: Component<TData, TProperty, TMethod>,
1110
+ ): { [key: string]: DataValue } | null {
1111
+ return comp._$dataGroup.innerData
1112
+ }
1113
+
1114
+ static getDataProxy<
1115
+ TData extends DataList,
1116
+ TProperty extends PropertyList,
1117
+ TMethod extends MethodList,
1118
+ >(
1119
+ comp: Component<TData, TProperty, TMethod>,
1120
+ ): DataGroup<TData, TProperty, TMethod> {
1121
+ return comp._$dataGroup
1122
+ }
1123
+
1124
+ static replaceWholeData<
1125
+ TData extends DataList,
1126
+ TProperty extends PropertyList,
1127
+ TMethod extends MethodList,
1128
+ >(
1129
+ comp: Component<TData, TProperty, TMethod>,
1130
+ newData: DataWithPropertyValues<TData, TProperty>,
1131
+ ) {
1132
+ comp._$dataGroup.replaceWholeData(newData)
1133
+ }
1134
+
1135
+ /**
1136
+ * Schedule a data update on a single specified path
1137
+ *
1138
+ * The data update will not be applied until next `setData` or `applyDataUpdates` call.
1139
+ * All data observers will not be triggered immediately before applied.
1140
+ * Reads of the data will get the unchanged value before applied.
1141
+ */
1142
+ replaceDataOnPath<
1143
+ T extends DataPath,
1144
+ >(
1145
+ path: readonly [...T],
1146
+ data: GetFromDataPath<DataWithPropertyValues<TData, TProperty>, T>,
1147
+ ): void;
1148
+ replaceDataOnPath(path: DataPath, data: unknown) {
1149
+ const dataProxy = this._$dataGroup
1150
+ if (dataProxy === undefined) {
1151
+ throw new Error('Cannot update data before component created')
1152
+ }
1153
+ dataProxy.replaceDataOnPath(path, data)
1154
+ }
1155
+
1156
+ /**
1157
+ * Schedule an array update
1158
+ *
1159
+ * The behavior is like `Array.prototype.slice` .
1160
+ * Break the array before the `index`-th item, delete `del` items, and insert some items here.
1161
+ * If `index` is undefined, negative, or larger than the length of the array,
1162
+ * no items will be deleted and new items will be appended to the end of the array.
1163
+ * The data update will not be applied until next `setData` or `applyDataUpdates` call.
1164
+ * All data observers will not be triggered immediately before applied.
1165
+ * Reads of the data will get the unchanged value before applied.
1166
+ */
1167
+ spliceArrayDataOnPath<
1168
+ T extends DataPath,
1169
+ >(
1170
+ path: readonly [...T],
1171
+ index: GetFromDataPath<
1172
+ DataWithPropertyValues<TData, TProperty>,
1173
+ T
1174
+ > extends any[] ? number | undefined : never,
1175
+ del: GetFromDataPath<
1176
+ DataWithPropertyValues<TData, TProperty>,
1177
+ T
1178
+ > extends any[] ? number | undefined : never,
1179
+ inserts: GetFromDataPath<
1180
+ DataWithPropertyValues<TData, TProperty>,
1181
+ T
1182
+ > extends (infer I)[] ? I[] : never
1183
+ ): void;
1184
+ spliceArrayDataOnPath(
1185
+ path: DataPath,
1186
+ index: number | undefined,
1187
+ del: number | undefined,
1188
+ inserts: unknown[],
1189
+ ) {
1190
+ const dataProxy = this._$dataGroup
1191
+ if (dataProxy === undefined) {
1192
+ throw new Error('Cannot update data before component created')
1193
+ }
1194
+ dataProxy.spliceArrayDataOnPath(path, index, del, inserts)
1195
+ }
1196
+
1197
+ /**
1198
+ * Check whether there are pending changes or not
1199
+ */
1200
+ hasPendingChanges(): boolean {
1201
+ const dataProxy = this._$dataGroup
1202
+ if (dataProxy === undefined) return false
1203
+ return dataProxy.getChanges().length > 0
1204
+ }
1205
+
1206
+ /**
1207
+ * Apply all scheduled updates immediately
1208
+ *
1209
+ * Inside observers, it is generally not .
1210
+ */
1211
+ applyDataUpdates() {
1212
+ const dataProxy = this._$dataGroup
1213
+ if (dataProxy === undefined) {
1214
+ throw new Error('Cannot update data before component created')
1215
+ }
1216
+ dataProxy.applyDataUpdates()
1217
+ }
1218
+
1219
+ /**
1220
+ * Pending all data updates in the callback, and apply updates after callback returns
1221
+ *
1222
+ * This function helps grouping several `replaceDataOnPath` or `spliceArrayDataOnPath` calls,
1223
+ * and then apply them at the end of the callback.
1224
+ * `setData` and `applyDataUpdates` calls inside the callback still apply updates immediately.
1225
+ */
1226
+ groupUpdates<T>(callback: () => T): T {
1227
+ const dataProxy = this._$dataGroup
1228
+ if (dataProxy === undefined) {
1229
+ throw new Error('Cannot update data before component created')
1230
+ }
1231
+ const ret = callback()
1232
+ dataProxy.applyDataUpdates()
1233
+ return ret
1234
+ }
1235
+
1236
+ /**
1237
+ * Schedule a classic data updates
1238
+ *
1239
+ * The data update will not be applied until next `setData` or `applyDataUpdates` call.
1240
+ * When called inside observers, the data update will be applied when observer ends.
1241
+ * All data observers will not be triggered immediately before applied.
1242
+ * Reads of the data will get the unchanged value before applied.
1243
+ */
1244
+ updateData(newData: Partial<SetDataSetter<DataWithPropertyValues<TData, TProperty>>>): void
1245
+ updateData(newData: Record<string, any>): void {
1246
+ const dataProxy = this._$dataGroup
1247
+ if (dataProxy === undefined) {
1248
+ throw new Error('Cannot update data before component created')
1249
+ }
1250
+ const keys = Object.keys(newData)
1251
+ for (let i = 0; i < keys.length; i += 1) {
1252
+ const key = keys[i]!
1253
+ const p = parseSinglePath(key)
1254
+ if (p) {
1255
+ dataProxy.replaceDataOnPath(p, newData[key])
1256
+ }
1257
+ }
1258
+ }
1259
+
1260
+ /**
1261
+ * Do a classic data updates
1262
+ *
1263
+ * This method apply updates immediately, so there is no async callback.
1264
+ * When called inside observers, the data update will not be applied to templates.
1265
+ * Inside observers, it is recommended to use `updateData` instead.
1266
+ */
1267
+ setData(newData: Partial<SetDataSetter<DataWithPropertyValues<TData, TProperty>>>): void
1268
+ setData(newData: Record<string, any>): void {
1269
+ const dataProxy = this._$dataGroup
1270
+ if (dataProxy === undefined) {
1271
+ throw new Error('Cannot update data before component created')
1272
+ }
1273
+ const keys = Object.keys(newData)
1274
+ for (let i = 0; i < keys.length; i += 1) {
1275
+ const key = keys[i]!
1276
+ const p = parseSinglePath(key)
1277
+ if (p) {
1278
+ dataProxy.replaceDataOnPath(p, newData[key])
1279
+ }
1280
+ }
1281
+ dataProxy.applyDataUpdates()
1282
+ }
1283
+ }
1284
+
1285
+ export type GeneralComponentDefinition = ComponentDefinition<
1286
+ Record<string, any>,
1287
+ Record<string, any>,
1288
+ Record<string, any>
1289
+ >
1290
+
1291
+ export type GeneralComponent = Component<
1292
+ Record<string, any>,
1293
+ Record<string, any>,
1294
+ Record<string, any>
1295
+ >
1296
+
1297
+ type ComponentInstProto<
1298
+ TData extends DataList,
1299
+ TProperty extends PropertyList,
1300
+ TMethod extends MethodList,
1301
+ > = Component<TData, TProperty, TMethod> & {
1302
+ _$behavior: Behavior<TData, TProperty, TMethod, any>
1303
+ _$definition: ComponentDefinition<TData, TProperty, TMethod>
1304
+ _$lifetimeFuncs: LifetimeFuncs
1305
+ _$pageLifetimeFuncs: PageLifetimeFuncs
1306
+ _$methodMap: MethodList
1307
+ } & {
1308
+ [key: string]: any
1309
+ }