glass-easel 0.2.0 → 0.3.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.
- package/.eslintignore +4 -0
- package/dist/glass_easel.all.js +2 -2
- package/dist/glass_easel.all.js.map +1 -1
- package/dist/glass_easel.d.ts +2546 -0
- package/dist/glass_easel.domlike.global.js +2 -2
- package/dist/glass_easel.domlike.global.js.map +1 -1
- package/guide/zh_CN/appendix/backend_protocol.md +164 -74
- package/jest.unit.config.js +7 -4
- package/package.json +7 -5
- package/rollup.config.ts +101 -0
- package/src/backend/backend_protocol.ts +26 -345
- package/src/backend/composed_backend_protocol.ts +10 -264
- package/src/backend/current_window_backend_context.ts +478 -0
- package/src/backend/domlike_backend_protocol.ts +9 -498
- package/src/backend/empty_backend.ts +265 -0
- package/src/backend/empty_composed_backend.ts +245 -0
- package/src/backend/index.ts +18 -0
- package/src/backend/suggested_backend_protocol.ts +62 -11
- package/src/behavior.ts +131 -442
- package/src/class_list.ts +328 -222
- package/src/component.ts +349 -184
- package/src/component_params.ts +54 -25
- package/src/component_space.ts +36 -15
- package/src/data_path.ts +22 -34
- package/src/data_proxy.ts +334 -27
- package/src/devtool.ts +89 -0
- package/src/element.ts +667 -285
- package/src/element_iterator.ts +9 -4
- package/src/event.ts +39 -20
- package/src/external_shadow_tree.ts +2 -2
- package/src/func_arr.ts +55 -101
- package/src/global_options.ts +18 -42
- package/src/index.ts +72 -73
- package/src/mutation_observer.ts +10 -7
- package/src/native_node.ts +79 -35
- package/src/node.ts +23 -30
- package/src/relation.ts +101 -12
- package/src/render.ts +5 -3
- package/src/selector.ts +9 -7
- package/src/shadow_root.ts +96 -240
- package/src/template_engine.ts +10 -7
- package/src/text_node.ts +43 -19
- package/src/tmpl/index.ts +38 -30
- package/src/tmpl/native_rendering.ts +14 -21
- package/src/tmpl/proc_gen_wrapper.ts +189 -151
- package/src/tmpl/proc_gen_wrapper_dom.ts +10 -8
- package/src/tmpl/range_list_diff.ts +30 -9
- package/src/trait_behaviors.ts +1 -1
- package/src/type_symbol.ts +36 -0
- package/src/virtual_node.ts +26 -13
- package/src/warning.ts +119 -0
- package/tests/base/composed_backend.ts +143 -142
- package/tests/base/env.ts +76 -3
- package/tests/base/match.ts +24 -22
- package/tests/base/shadow_backend.ts +917 -0
- package/tests/core/backend.test.ts +53 -1
- package/tests/core/behavior.test.ts +1 -1
- package/tests/core/data_update.test.ts +135 -0
- package/tests/core/misc.test.ts +91 -21
- package/tests/core/placeholder.test.ts +66 -25
- package/tests/core/slot.test.ts +161 -23
- package/tests/legacy/component.test.js +152 -78
- package/tests/legacy/data_path.test.js +19 -19
- package/tests/legacy/data_proxy.test.js +14 -7
- package/tests/legacy/external.test.js +8 -8
- package/tests/legacy/mutation_observer.test.js +7 -5
- package/tests/legacy/slot.test.js +2 -3
- package/tests/legacy/virtual.test.js +258 -25
- package/tests/tmpl/binding_map.test.ts +201 -195
- package/tests/tmpl/event.test.ts +138 -23
- package/tests/tmpl/expression.test.ts +15 -15
- package/tests/tmpl/lvalue.test.ts +101 -0
- package/tests/tmpl/structure.test.ts +486 -43
- package/tests/types/chaining.test.ts +27 -30
- package/tests/types/createElement.test.ts +5 -4
- package/tests/types/definition.test.ts +11 -14
- package/tsconfig.json +1 -3
- package/dist/glass_easel.all.d.ts +0 -1
- package/dist/glass_easel.domlike.global.d.ts +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/types/src/backend/backend_protocol.d.ts +0 -141
- package/dist/types/src/backend/backend_protocol.d.ts.map +0 -1
- package/dist/types/src/backend/composed_backend_protocol.d.ts +0 -102
- package/dist/types/src/backend/composed_backend_protocol.d.ts.map +0 -1
- package/dist/types/src/backend/domlike_backend_protocol.d.ts +0 -100
- package/dist/types/src/backend/domlike_backend_protocol.d.ts.map +0 -1
- package/dist/types/src/backend/mode.d.ts +0 -65
- package/dist/types/src/backend/mode.d.ts.map +0 -1
- package/dist/types/src/backend/suggested_backend_protocol.d.ts +0 -30
- package/dist/types/src/backend/suggested_backend_protocol.d.ts.map +0 -1
- package/dist/types/src/behavior.d.ts +0 -434
- package/dist/types/src/behavior.d.ts.map +0 -1
- package/dist/types/src/class_list.d.ts +0 -83
- package/dist/types/src/class_list.d.ts.map +0 -1
- package/dist/types/src/component.d.ts +0 -325
- package/dist/types/src/component.d.ts.map +0 -1
- package/dist/types/src/component_params.d.ts +0 -236
- package/dist/types/src/component_params.d.ts.map +0 -1
- package/dist/types/src/component_space.d.ts +0 -211
- package/dist/types/src/component_space.d.ts.map +0 -1
- package/dist/types/src/data_path.d.ts +0 -5
- package/dist/types/src/data_path.d.ts.map +0 -1
- package/dist/types/src/data_proxy.d.ts +0 -107
- package/dist/types/src/data_proxy.d.ts.map +0 -1
- package/dist/types/src/data_utils.d.ts +0 -3
- package/dist/types/src/data_utils.d.ts.map +0 -1
- package/dist/types/src/element.d.ts +0 -365
- package/dist/types/src/element.d.ts.map +0 -1
- package/dist/types/src/element_iterator.d.ts +0 -43
- package/dist/types/src/element_iterator.d.ts.map +0 -1
- package/dist/types/src/event.d.ts +0 -105
- package/dist/types/src/event.d.ts.map +0 -1
- package/dist/types/src/external_shadow_tree.d.ts +0 -20
- package/dist/types/src/external_shadow_tree.d.ts.map +0 -1
- package/dist/types/src/func_arr.d.ts +0 -39
- package/dist/types/src/func_arr.d.ts.map +0 -1
- package/dist/types/src/global_options.d.ts +0 -120
- package/dist/types/src/global_options.d.ts.map +0 -1
- package/dist/types/src/index.d.ts +0 -43
- package/dist/types/src/index.d.ts.map +0 -1
- package/dist/types/src/mutation_observer.d.ts +0 -79
- package/dist/types/src/mutation_observer.d.ts.map +0 -1
- package/dist/types/src/native_node.d.ts +0 -11
- package/dist/types/src/native_node.d.ts.map +0 -1
- package/dist/types/src/node.d.ts +0 -48
- package/dist/types/src/node.d.ts.map +0 -1
- package/dist/types/src/relation.d.ts +0 -46
- package/dist/types/src/relation.d.ts.map +0 -1
- package/dist/types/src/render.d.ts +0 -3
- package/dist/types/src/render.d.ts.map +0 -1
- package/dist/types/src/selector.d.ts +0 -32
- package/dist/types/src/selector.d.ts.map +0 -1
- package/dist/types/src/shadow_root.d.ts +0 -174
- package/dist/types/src/shadow_root.d.ts.map +0 -1
- package/dist/types/src/template_engine.d.ts +0 -56
- package/dist/types/src/template_engine.d.ts.map +0 -1
- package/dist/types/src/text_node.d.ts +0 -44
- package/dist/types/src/text_node.d.ts.map +0 -1
- package/dist/types/src/tmpl/index.d.ts +0 -19
- package/dist/types/src/tmpl/index.d.ts.map +0 -1
- package/dist/types/src/tmpl/native_rendering.d.ts +0 -45
- package/dist/types/src/tmpl/native_rendering.d.ts.map +0 -1
- package/dist/types/src/tmpl/proc_gen_wrapper.d.ts +0 -89
- package/dist/types/src/tmpl/proc_gen_wrapper.d.ts.map +0 -1
- package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts +0 -50
- package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts.map +0 -1
- package/dist/types/src/tmpl/range_list_diff.d.ts +0 -19
- package/dist/types/src/tmpl/range_list_diff.d.ts.map +0 -1
- package/dist/types/src/trait_behaviors.d.ts +0 -38
- package/dist/types/src/trait_behaviors.d.ts.map +0 -1
- package/dist/types/src/virtual_node.d.ts +0 -10
- package/dist/types/src/virtual_node.d.ts.map +0 -1
- package/dist/types/tests/backend/domlike.test.d.ts +0 -2
- package/dist/types/tests/backend/domlike.test.d.ts.map +0 -1
- package/dist/types/tests/base/composed_backend.d.ts +0 -123
- package/dist/types/tests/base/composed_backend.d.ts.map +0 -1
- package/dist/types/tests/base/env.d.ts +0 -30
- package/dist/types/tests/base/env.d.ts.map +0 -1
- package/dist/types/tests/base/match.d.ts +0 -9
- package/dist/types/tests/base/match.d.ts.map +0 -1
- package/dist/types/tests/core/backend.test.d.ts +0 -2
- package/dist/types/tests/core/backend.test.d.ts.map +0 -1
- package/dist/types/tests/core/behavior.test.d.ts +0 -2
- package/dist/types/tests/core/behavior.test.d.ts.map +0 -1
- package/dist/types/tests/core/component_space.test.d.ts +0 -2
- package/dist/types/tests/core/component_space.test.d.ts.map +0 -1
- package/dist/types/tests/core/data_update.test.d.ts +0 -2
- package/dist/types/tests/core/data_update.test.d.ts.map +0 -1
- package/dist/types/tests/core/misc.test.d.ts +0 -2
- package/dist/types/tests/core/misc.test.d.ts.map +0 -1
- package/dist/types/tests/core/placeholder.test.d.ts +0 -2
- package/dist/types/tests/core/placeholder.test.d.ts.map +0 -1
- package/dist/types/tests/core/slot.test.d.ts +0 -2
- package/dist/types/tests/core/slot.test.d.ts.map +0 -1
- package/dist/types/tests/core/trait_behaviors.test.d.ts +0 -2
- package/dist/types/tests/core/trait_behaviors.test.d.ts.map +0 -1
- package/dist/types/tests/tmpl/binding_map.test.d.ts +0 -2
- package/dist/types/tests/tmpl/binding_map.test.d.ts.map +0 -1
- package/dist/types/tests/tmpl/event.test.d.ts +0 -2
- package/dist/types/tests/tmpl/event.test.d.ts.map +0 -1
- package/dist/types/tests/tmpl/expression.test.d.ts +0 -2
- package/dist/types/tests/tmpl/expression.test.d.ts.map +0 -1
- package/dist/types/tests/tmpl/lvalue.test.d.ts +0 -2
- package/dist/types/tests/tmpl/lvalue.test.d.ts.map +0 -1
- package/dist/types/tests/tmpl/native_rendering.test.d.ts +0 -2
- package/dist/types/tests/tmpl/native_rendering.test.d.ts.map +0 -1
- package/dist/types/tests/tmpl/structure.test.d.ts +0 -2
- package/dist/types/tests/tmpl/structure.test.d.ts.map +0 -1
- package/dist/types/tests/types/chaining.test.d.ts +0 -2
- package/dist/types/tests/types/chaining.test.d.ts.map +0 -1
- package/dist/types/tests/types/createElement.test.d.ts +0 -2
- package/dist/types/tests/types/createElement.test.d.ts.map +0 -1
- package/dist/types/tests/types/definition.test.d.ts +0 -2
- package/dist/types/tests/types/definition.test.d.ts.map +0 -1
- package/webpack.config.js +0 -275
- /package/src/backend/{mode.ts → shared.ts} +0 -0
package/src/data_proxy.ts
CHANGED
|
@@ -1,21 +1,303 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { type GeneralComponent } from './component'
|
|
2
|
+
import {
|
|
3
|
+
type ComponentInstance,
|
|
4
|
+
type DataList,
|
|
5
|
+
type DataWithPropertyValues,
|
|
6
|
+
type MethodList,
|
|
7
|
+
type PropertyList,
|
|
8
|
+
} from './component_params'
|
|
9
|
+
import { type DataPath, type MultiPaths } from './data_path'
|
|
3
10
|
import { deepCopy, simpleDeepCopy } from './data_utils'
|
|
4
|
-
import {
|
|
11
|
+
import { safeCallback } from './func_arr'
|
|
5
12
|
import { DeepCopyKind } from './global_options'
|
|
6
13
|
import { MutationObserverTarget } from './mutation_observer'
|
|
7
|
-
import {
|
|
8
|
-
DataList,
|
|
9
|
-
PropertyList,
|
|
10
|
-
MethodList,
|
|
11
|
-
ComponentInstance,
|
|
12
|
-
DataWithPropertyValues,
|
|
13
|
-
} from './component_params'
|
|
14
|
-
import { GeneralComponent } from './component'
|
|
14
|
+
import { triggerWarning } from './warning'
|
|
15
15
|
|
|
16
16
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
17
17
|
const hasOwnProperty = Object.prototype.hasOwnProperty
|
|
18
18
|
|
|
19
|
+
export const enum NormalizedPropertyType {
|
|
20
|
+
Invalid = 'invalid',
|
|
21
|
+
Any = 'any',
|
|
22
|
+
String = 'string',
|
|
23
|
+
Number = 'number',
|
|
24
|
+
Boolean = 'boolean',
|
|
25
|
+
Object = 'object',
|
|
26
|
+
Array = 'array',
|
|
27
|
+
Function = 'function',
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type PropertyDefinition = {
|
|
31
|
+
type: NormalizedPropertyType
|
|
32
|
+
optionalTypes: NormalizedPropertyType[] | null
|
|
33
|
+
value: unknown
|
|
34
|
+
default: (() => unknown) | undefined
|
|
35
|
+
observer: ((newValue: unknown, oldValue: unknown) => void) | null
|
|
36
|
+
comparer: ((newValue: unknown, oldValue: unknown) => boolean) | null
|
|
37
|
+
reflectIdPrefix: boolean
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const shallowMerge = (dest: { [key: string]: unknown }, src: { [key: string]: unknown }) => {
|
|
41
|
+
const keys = Object.keys(src)
|
|
42
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
43
|
+
const key = keys[i]!
|
|
44
|
+
if (Object.prototype.hasOwnProperty.call(dest, key)) {
|
|
45
|
+
if (key[0] === '_') {
|
|
46
|
+
triggerWarning(`data field "${key}" from different behaviors is overriding or merging.`)
|
|
47
|
+
}
|
|
48
|
+
if (
|
|
49
|
+
typeof dest[key] === 'object' &&
|
|
50
|
+
typeof src[key] === 'object' &&
|
|
51
|
+
src[key] !== null &&
|
|
52
|
+
!Array.isArray(src[key])
|
|
53
|
+
) {
|
|
54
|
+
if (Array.isArray(dest[key])) {
|
|
55
|
+
dest[key] = (dest[key] as DataValue[]).slice()
|
|
56
|
+
} else {
|
|
57
|
+
const oldDest = dest[key] as { [key: string]: DataValue }
|
|
58
|
+
const newDest = {} as { [key: string]: DataValue }
|
|
59
|
+
const subKeys = Object.keys(oldDest)
|
|
60
|
+
for (let i = 0; i < subKeys.length; i += 1) {
|
|
61
|
+
const subKey = subKeys[i]!
|
|
62
|
+
newDest[subKey] = oldDest[subKey]
|
|
63
|
+
}
|
|
64
|
+
dest[key] = newDest
|
|
65
|
+
}
|
|
66
|
+
shallowMerge(
|
|
67
|
+
dest[key] as { [key: string]: unknown },
|
|
68
|
+
src[key] as { [key: string]: unknown },
|
|
69
|
+
)
|
|
70
|
+
} else {
|
|
71
|
+
dest[key] = src[key]
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
dest[key] = src[key]
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export const normalizePropertyTypeShortHand = (propDef: unknown): PropertyDefinition | null => {
|
|
80
|
+
if (propDef === NormalizedPropertyType.String || propDef === String) {
|
|
81
|
+
return {
|
|
82
|
+
type: NormalizedPropertyType.String,
|
|
83
|
+
optionalTypes: null,
|
|
84
|
+
value: '',
|
|
85
|
+
default: undefined,
|
|
86
|
+
observer: null,
|
|
87
|
+
comparer: null,
|
|
88
|
+
reflectIdPrefix: false,
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (propDef === NormalizedPropertyType.Number || propDef === Number) {
|
|
92
|
+
return {
|
|
93
|
+
type: NormalizedPropertyType.Number,
|
|
94
|
+
optionalTypes: null,
|
|
95
|
+
value: 0,
|
|
96
|
+
default: undefined,
|
|
97
|
+
observer: null,
|
|
98
|
+
comparer: null,
|
|
99
|
+
reflectIdPrefix: false,
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (propDef === NormalizedPropertyType.Boolean || propDef === Boolean) {
|
|
103
|
+
return {
|
|
104
|
+
type: NormalizedPropertyType.Boolean,
|
|
105
|
+
optionalTypes: null,
|
|
106
|
+
value: false,
|
|
107
|
+
default: undefined,
|
|
108
|
+
observer: null,
|
|
109
|
+
comparer: null,
|
|
110
|
+
reflectIdPrefix: false,
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (propDef === NormalizedPropertyType.Object || propDef === Object) {
|
|
114
|
+
return {
|
|
115
|
+
type: NormalizedPropertyType.Object,
|
|
116
|
+
optionalTypes: null,
|
|
117
|
+
value: null,
|
|
118
|
+
default: undefined,
|
|
119
|
+
observer: null,
|
|
120
|
+
comparer: null,
|
|
121
|
+
reflectIdPrefix: false,
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (propDef === NormalizedPropertyType.Array || propDef === Array) {
|
|
125
|
+
return {
|
|
126
|
+
type: NormalizedPropertyType.Array,
|
|
127
|
+
optionalTypes: null,
|
|
128
|
+
value: [],
|
|
129
|
+
default: undefined,
|
|
130
|
+
observer: null,
|
|
131
|
+
comparer: null,
|
|
132
|
+
reflectIdPrefix: false,
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (propDef === NormalizedPropertyType.Function || propDef === Function) {
|
|
136
|
+
return {
|
|
137
|
+
type: NormalizedPropertyType.Function,
|
|
138
|
+
optionalTypes: null,
|
|
139
|
+
value() {
|
|
140
|
+
/* empty */
|
|
141
|
+
},
|
|
142
|
+
default: undefined,
|
|
143
|
+
observer: null,
|
|
144
|
+
comparer: null,
|
|
145
|
+
reflectIdPrefix: false,
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (propDef === NormalizedPropertyType.Any || propDef === null || propDef === undefined) {
|
|
149
|
+
return {
|
|
150
|
+
type: NormalizedPropertyType.Any,
|
|
151
|
+
optionalTypes: null,
|
|
152
|
+
value: null,
|
|
153
|
+
default: undefined,
|
|
154
|
+
observer: null,
|
|
155
|
+
comparer: null,
|
|
156
|
+
reflectIdPrefix: false,
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return null
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export const normalizePropertyType = (t: unknown): NormalizedPropertyType => {
|
|
163
|
+
if (t === NormalizedPropertyType.String || t === String) {
|
|
164
|
+
return NormalizedPropertyType.String
|
|
165
|
+
}
|
|
166
|
+
if (t === NormalizedPropertyType.Number || t === Number) {
|
|
167
|
+
return NormalizedPropertyType.Number
|
|
168
|
+
}
|
|
169
|
+
if (t === NormalizedPropertyType.Boolean || t === Boolean) {
|
|
170
|
+
return NormalizedPropertyType.Boolean
|
|
171
|
+
}
|
|
172
|
+
if (t === NormalizedPropertyType.Object || t === Object) {
|
|
173
|
+
return NormalizedPropertyType.Object
|
|
174
|
+
}
|
|
175
|
+
if (t === NormalizedPropertyType.Array || t === Array) {
|
|
176
|
+
return NormalizedPropertyType.Array
|
|
177
|
+
}
|
|
178
|
+
if (t === NormalizedPropertyType.Function || t === Function) {
|
|
179
|
+
return NormalizedPropertyType.Function
|
|
180
|
+
}
|
|
181
|
+
if (t === NormalizedPropertyType.Any || t === null || t === undefined) {
|
|
182
|
+
return NormalizedPropertyType.Any
|
|
183
|
+
}
|
|
184
|
+
return NormalizedPropertyType.Invalid
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export const convertValueToType = (
|
|
188
|
+
value: unknown,
|
|
189
|
+
propName: string,
|
|
190
|
+
prop: PropertyDefinition,
|
|
191
|
+
component: GeneralComponent | null,
|
|
192
|
+
): unknown => {
|
|
193
|
+
const type = prop.type
|
|
194
|
+
const defaultFn =
|
|
195
|
+
prop.default === undefined
|
|
196
|
+
? undefined
|
|
197
|
+
: () =>
|
|
198
|
+
safeCallback(
|
|
199
|
+
`Property "${propName}" Default`,
|
|
200
|
+
prop.default!,
|
|
201
|
+
null,
|
|
202
|
+
[],
|
|
203
|
+
component || undefined,
|
|
204
|
+
)
|
|
205
|
+
// try match optional types
|
|
206
|
+
const optionalTypes = prop.optionalTypes
|
|
207
|
+
if (optionalTypes) {
|
|
208
|
+
for (let i = 0; i < optionalTypes.length; i += 1) {
|
|
209
|
+
if (matchTypeWithValue(optionalTypes[i]!, value)) {
|
|
210
|
+
return value
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// for string
|
|
215
|
+
if (type === NormalizedPropertyType.String) {
|
|
216
|
+
if (value === null || value === undefined) {
|
|
217
|
+
triggerWarning(
|
|
218
|
+
`property "${propName}" received type-incompatible value: expected <String> but get null value. Used default value instead.`,
|
|
219
|
+
)
|
|
220
|
+
return defaultFn === undefined ? '' : defaultFn()
|
|
221
|
+
}
|
|
222
|
+
if (typeof value === 'object') {
|
|
223
|
+
triggerWarning(
|
|
224
|
+
`property "${propName}" received type-incompatible value: expected <String> but got object-typed value. Force converted.`,
|
|
225
|
+
)
|
|
226
|
+
}
|
|
227
|
+
return String(value)
|
|
228
|
+
}
|
|
229
|
+
// for number
|
|
230
|
+
if (type === NormalizedPropertyType.Number) {
|
|
231
|
+
// eslint-disable-next-line no-restricted-globals
|
|
232
|
+
if (isFinite(value as number)) return Number(value)
|
|
233
|
+
if (typeof value === 'number') {
|
|
234
|
+
triggerWarning(
|
|
235
|
+
`property "${propName}" received type-incompatible value: expected <Number> but got NaN or Infinity. Used default value instead.`,
|
|
236
|
+
)
|
|
237
|
+
} else {
|
|
238
|
+
triggerWarning(
|
|
239
|
+
`property "${propName}" received type-incompatible value: expected <Number> but got non-number value. Used default value instead.`,
|
|
240
|
+
)
|
|
241
|
+
}
|
|
242
|
+
return defaultFn === undefined ? 0 : defaultFn()
|
|
243
|
+
}
|
|
244
|
+
// for boolean
|
|
245
|
+
if (type === NormalizedPropertyType.Boolean) {
|
|
246
|
+
return !!value
|
|
247
|
+
}
|
|
248
|
+
// for array
|
|
249
|
+
if (type === NormalizedPropertyType.Array) {
|
|
250
|
+
if (Array.isArray(value)) return value as unknown
|
|
251
|
+
triggerWarning(
|
|
252
|
+
`property "${propName}" received type-incompatible value: expected <Array> but got non-array value. Used default value instead.`,
|
|
253
|
+
)
|
|
254
|
+
return defaultFn === undefined ? [] : defaultFn()
|
|
255
|
+
}
|
|
256
|
+
// for object
|
|
257
|
+
if (type === NormalizedPropertyType.Object) {
|
|
258
|
+
if (typeof value === 'object') return value
|
|
259
|
+
triggerWarning(
|
|
260
|
+
`property "${propName}" received type-incompatible value: expected <Object> but got non-object value. Used default value instead.`,
|
|
261
|
+
)
|
|
262
|
+
return defaultFn === undefined ? null : defaultFn()
|
|
263
|
+
}
|
|
264
|
+
// for function
|
|
265
|
+
if (type === NormalizedPropertyType.Function) {
|
|
266
|
+
if (typeof value === 'function') return value
|
|
267
|
+
triggerWarning(
|
|
268
|
+
`property "${propName}" received type-incompatible value: expected <Function> but got non-function value. Used default value instead.`,
|
|
269
|
+
)
|
|
270
|
+
// eslint-disable-next-line func-names
|
|
271
|
+
return defaultFn === undefined
|
|
272
|
+
? function () {
|
|
273
|
+
/* empty */
|
|
274
|
+
}
|
|
275
|
+
: defaultFn()
|
|
276
|
+
}
|
|
277
|
+
// for any-typed, just return the value and avoid undefined
|
|
278
|
+
if (value === undefined) return defaultFn === undefined ? null : defaultFn()
|
|
279
|
+
return value
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export const matchTypeWithValue = (type: NormalizedPropertyType, value: any) => {
|
|
283
|
+
if (type === NormalizedPropertyType.String) {
|
|
284
|
+
if (typeof value !== 'string') return false
|
|
285
|
+
} else if (type === NormalizedPropertyType.Number) {
|
|
286
|
+
if (!Number.isFinite(value)) return false
|
|
287
|
+
} else if (type === NormalizedPropertyType.Boolean) {
|
|
288
|
+
if (typeof value !== 'boolean') return false
|
|
289
|
+
} else if (type === NormalizedPropertyType.Object) {
|
|
290
|
+
if (typeof value !== 'object' || Array.isArray(value)) return false
|
|
291
|
+
} else if (type === NormalizedPropertyType.Array) {
|
|
292
|
+
if (typeof value !== 'object' || !Array.isArray(value)) return false
|
|
293
|
+
} else if (type === NormalizedPropertyType.Function) {
|
|
294
|
+
if (typeof value !== 'function') return false
|
|
295
|
+
} else if (value === undefined) {
|
|
296
|
+
return false
|
|
297
|
+
}
|
|
298
|
+
return true
|
|
299
|
+
}
|
|
300
|
+
|
|
19
301
|
export const enum DeepCopyStrategy {
|
|
20
302
|
None,
|
|
21
303
|
Simple,
|
|
@@ -28,7 +310,8 @@ export type DataObserver = (...values: unknown[]) => void
|
|
|
28
310
|
|
|
29
311
|
export type DataChange = DataReplace | DataSplice
|
|
30
312
|
// for replace
|
|
31
|
-
export type DataReplace = [DataPath, DataValue,
|
|
313
|
+
export type DataReplace = [DataPath, DataValue, RequireComparer, undefined]
|
|
314
|
+
export type RequireComparer = true | undefined
|
|
32
315
|
// for splice, numbers are index, removal count
|
|
33
316
|
export type DataSplice = [DataPath, DataValue[], number, number]
|
|
34
317
|
|
|
@@ -346,7 +629,7 @@ export class DataGroup<
|
|
|
346
629
|
data = simpleDeepCopy(newData)
|
|
347
630
|
}
|
|
348
631
|
}
|
|
349
|
-
this._$pendingChanges.push([[propName], data,
|
|
632
|
+
this._$pendingChanges.push([[propName], data, true, undefined])
|
|
350
633
|
return true
|
|
351
634
|
}
|
|
352
635
|
|
|
@@ -412,8 +695,8 @@ export class DataGroup<
|
|
|
412
695
|
// apply changes and collect changing information
|
|
413
696
|
for (let i = 0; i < changes.length; i += 1) {
|
|
414
697
|
const change = changes[i]!
|
|
415
|
-
const [path, newData,
|
|
416
|
-
const isSplice =
|
|
698
|
+
const [path, newData, maybeSpliceIndex, maybeSpliceDel] = change
|
|
699
|
+
const isSplice = maybeSpliceDel !== undefined
|
|
417
700
|
const propName = String(path[0])
|
|
418
701
|
const excluded = pureDataPattern ? pureDataPattern.test(propName) : false
|
|
419
702
|
const prop: PropertyDefinition | undefined = propFields[propName]
|
|
@@ -426,10 +709,11 @@ export class DataGroup<
|
|
|
426
709
|
if (isSplice) {
|
|
427
710
|
if (Array.isArray(oldData)) {
|
|
428
711
|
const c = change as DataSplice
|
|
712
|
+
const spliceIndex = maybeSpliceIndex as number
|
|
429
713
|
normalizedSpliceIndex =
|
|
430
|
-
spliceIndex
|
|
714
|
+
spliceIndex >= 0 && spliceIndex < oldData.length ? spliceIndex : oldData.length
|
|
431
715
|
c[2] = normalizedSpliceIndex
|
|
432
|
-
oldData.splice(normalizedSpliceIndex,
|
|
716
|
+
oldData.splice(normalizedSpliceIndex, maybeSpliceDel, ...(newData as typeof oldData))
|
|
433
717
|
} else {
|
|
434
718
|
triggerWarning(
|
|
435
719
|
`An array splice change cannot be applied to a non-array value (on path "${path.join(
|
|
@@ -439,7 +723,12 @@ export class DataGroup<
|
|
|
439
723
|
}
|
|
440
724
|
filteredData = oldData
|
|
441
725
|
} else {
|
|
442
|
-
filteredData = convertValueToType(
|
|
726
|
+
filteredData = convertValueToType(
|
|
727
|
+
newData,
|
|
728
|
+
propName,
|
|
729
|
+
prop,
|
|
730
|
+
this._$comp as GeneralComponent | null,
|
|
731
|
+
)
|
|
443
732
|
}
|
|
444
733
|
if (!excluded) {
|
|
445
734
|
if (this.innerData) {
|
|
@@ -454,7 +743,11 @@ export class DataGroup<
|
|
|
454
743
|
} else {
|
|
455
744
|
change[1] = inserts = simpleDeepCopy(newData as unknown[])
|
|
456
745
|
}
|
|
457
|
-
;(innerNewData as DataValue[]).splice(
|
|
746
|
+
;(innerNewData as DataValue[]).splice(
|
|
747
|
+
normalizedSpliceIndex,
|
|
748
|
+
maybeSpliceDel!,
|
|
749
|
+
...inserts,
|
|
750
|
+
)
|
|
458
751
|
} else if (dataDeepCopy === DeepCopyStrategy.SimpleWithRecursion) {
|
|
459
752
|
change[1] = innerNewData = deepCopy(filteredData, true)
|
|
460
753
|
} else {
|
|
@@ -489,16 +782,25 @@ export class DataGroup<
|
|
|
489
782
|
}
|
|
490
783
|
}
|
|
491
784
|
}
|
|
492
|
-
|
|
493
|
-
|
|
785
|
+
let comparerResult: boolean
|
|
786
|
+
if (!isSplice && maybeSpliceIndex === true) {
|
|
787
|
+
if (prop.comparer) {
|
|
788
|
+
change[2] = undefined
|
|
789
|
+
comparerResult = !!safeCallback(
|
|
494
790
|
'Property Comparer',
|
|
495
791
|
prop.comparer,
|
|
496
792
|
comp!,
|
|
497
793
|
[newData, oldData],
|
|
498
794
|
comp?.general(),
|
|
499
795
|
)
|
|
500
|
-
|
|
501
|
-
|
|
796
|
+
} else {
|
|
797
|
+
comparerResult = oldData !== filteredData
|
|
798
|
+
}
|
|
799
|
+
changed = comparerResult
|
|
800
|
+
} else {
|
|
801
|
+
comparerResult = oldData !== filteredData
|
|
802
|
+
}
|
|
803
|
+
if (!excluded && comparerResult) {
|
|
502
804
|
propChanges.push({
|
|
503
805
|
propName,
|
|
504
806
|
prop,
|
|
@@ -540,10 +842,11 @@ export class DataGroup<
|
|
|
540
842
|
const oldData = (curData as DataList)[curSlice as string]
|
|
541
843
|
if (Array.isArray(oldData)) {
|
|
542
844
|
const c = change as DataSplice
|
|
845
|
+
const spliceIndex = maybeSpliceIndex as number
|
|
543
846
|
normalizedSpliceIndex =
|
|
544
|
-
spliceIndex
|
|
847
|
+
spliceIndex >= 0 && spliceIndex < oldData.length ? spliceIndex : oldData.length
|
|
545
848
|
c[2] = normalizedSpliceIndex
|
|
546
|
-
oldData.splice(normalizedSpliceIndex,
|
|
849
|
+
oldData.splice(normalizedSpliceIndex, maybeSpliceDel, ...(newData as typeof oldData))
|
|
547
850
|
} else {
|
|
548
851
|
triggerWarning(
|
|
549
852
|
`An array splice change cannot be applied to a non-array value (on path "${path.join(
|
|
@@ -594,7 +897,11 @@ export class DataGroup<
|
|
|
594
897
|
} else {
|
|
595
898
|
change[1] = inserts = simpleDeepCopy(newData as unknown[])
|
|
596
899
|
}
|
|
597
|
-
;(innerNewData as DataValue[]).splice(
|
|
900
|
+
;(innerNewData as DataValue[]).splice(
|
|
901
|
+
normalizedSpliceIndex,
|
|
902
|
+
maybeSpliceDel!,
|
|
903
|
+
...inserts,
|
|
904
|
+
)
|
|
598
905
|
} else if (dataDeepCopy === DeepCopyStrategy.SimpleWithRecursion) {
|
|
599
906
|
change[1] = innerNewData = deepCopy(newData, true)
|
|
600
907
|
} else {
|
|
@@ -650,7 +957,7 @@ export class DataGroup<
|
|
|
650
957
|
prop.observer,
|
|
651
958
|
comp.getMethodCaller() as any,
|
|
652
959
|
[newValue, oldValue],
|
|
653
|
-
comp
|
|
960
|
+
comp,
|
|
654
961
|
)
|
|
655
962
|
}
|
|
656
963
|
if (comp._$mutationObserverTarget) {
|
package/src/devtool.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { type AnyComponent, type GeneralComponent } from './component'
|
|
2
|
+
import { ENV, globalOptions } from './global_options'
|
|
3
|
+
|
|
4
|
+
export type DevtoolInterface = {
|
|
5
|
+
now: () => number
|
|
6
|
+
addTimelineEvent: (time: number, type: string, data?: Record<string, unknown>) => void
|
|
7
|
+
addTimelineComponentEvent: (
|
|
8
|
+
time: number,
|
|
9
|
+
type: string,
|
|
10
|
+
component: GeneralComponent,
|
|
11
|
+
data?: Record<string, unknown>,
|
|
12
|
+
) => void
|
|
13
|
+
addTimelinePerformanceMeasureStart: (
|
|
14
|
+
time: number,
|
|
15
|
+
type: string,
|
|
16
|
+
component: GeneralComponent | string | null,
|
|
17
|
+
data?: Record<string, unknown>,
|
|
18
|
+
) => void
|
|
19
|
+
addTimelinePerformanceMeasureEnd: (time: number) => void
|
|
20
|
+
addTimelineBackendWaterfall: (
|
|
21
|
+
type: string,
|
|
22
|
+
times: [
|
|
23
|
+
number, // pending time
|
|
24
|
+
number, // start time
|
|
25
|
+
number, // end time
|
|
26
|
+
],
|
|
27
|
+
data?: Record<string, unknown>,
|
|
28
|
+
) => void
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let defaultDevtools: DevtoolInterface | null | undefined
|
|
32
|
+
|
|
33
|
+
export const getDevtool = (): DevtoolInterface | null | undefined => {
|
|
34
|
+
if (!ENV.DEV) return null
|
|
35
|
+
if (defaultDevtools === undefined) {
|
|
36
|
+
defaultDevtools =
|
|
37
|
+
globalOptions.devtool ||
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
39
|
+
((globalThis as any).__glass_easel_devtool__ as DevtoolInterface | undefined)
|
|
40
|
+
}
|
|
41
|
+
return defaultDevtools
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const performanceMeasureStart = (
|
|
45
|
+
type: string,
|
|
46
|
+
comp: AnyComponent | null = null,
|
|
47
|
+
data?: Record<string, unknown>,
|
|
48
|
+
) => {
|
|
49
|
+
getDevtool()?.addTimelinePerformanceMeasureStart(getDevtool()!.now(), type, comp, data)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const performanceMeasureEnd = () => {
|
|
53
|
+
getDevtool()?.addTimelinePerformanceMeasureEnd(getDevtool()!.now())
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const performanceMeasureRenderWaterfall = (
|
|
57
|
+
type: string,
|
|
58
|
+
waterfallType: string,
|
|
59
|
+
comp: AnyComponent,
|
|
60
|
+
render: () => void,
|
|
61
|
+
) => {
|
|
62
|
+
const devtool = getDevtool()
|
|
63
|
+
if (!devtool) {
|
|
64
|
+
render()
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const pendingTimestamp = devtool.now()
|
|
69
|
+
const nodeTreeContext = comp.getBackendContext()
|
|
70
|
+
if (nodeTreeContext) {
|
|
71
|
+
const measureId = nodeTreeContext.performanceTraceStart?.()
|
|
72
|
+
performanceMeasureStart(type, comp)
|
|
73
|
+
render()
|
|
74
|
+
performanceMeasureEnd()
|
|
75
|
+
nodeTreeContext.performanceTraceEnd?.(measureId!, ({ startTimestamp, endTimestamp }) => {
|
|
76
|
+
devtool.addTimelineBackendWaterfall(waterfallType, [
|
|
77
|
+
pendingTimestamp,
|
|
78
|
+
startTimestamp,
|
|
79
|
+
endTimestamp,
|
|
80
|
+
])
|
|
81
|
+
})
|
|
82
|
+
} else {
|
|
83
|
+
render()
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export const addTimelineEvent = (type: string, data?: Record<string, unknown>) => {
|
|
88
|
+
getDevtool()?.addTimelineEvent(getDevtool()!.now(), type, data)
|
|
89
|
+
}
|