glass-easel-miniprogram-adapter 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -0
- package/dist/glass_easel_miniprogram_adapter.d.ts +1 -0
- package/dist/glass_easel_miniprogram_adapter.js +2 -0
- package/dist/glass_easel_miniprogram_adapter.js.map +1 -0
- package/dist/types/src/backend.d.ts +51 -0
- package/dist/types/src/backend.d.ts.map +1 -0
- package/dist/types/src/behavior.d.ts +35 -0
- package/dist/types/src/behavior.d.ts.map +1 -0
- package/dist/types/src/component.d.ts +160 -0
- package/dist/types/src/component.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +58 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/selector_query.d.ts +98 -0
- package/dist/types/src/selector_query.d.ts.map +1 -0
- package/dist/types/src/space.d.ts +369 -0
- package/dist/types/src/space.d.ts.map +1 -0
- package/dist/types/src/types.d.ts +77 -0
- package/dist/types/src/types.d.ts.map +1 -0
- package/dist/types/src/utils.d.ts +2 -0
- package/dist/types/src/utils.d.ts.map +1 -0
- package/dist/types/tests/base/env.d.ts +3 -0
- package/dist/types/tests/base/env.d.ts.map +1 -0
- package/dist/types/tests/data_update.test.d.ts +2 -0
- package/dist/types/tests/data_update.test.d.ts.map +1 -0
- package/dist/types/tests/env.test.d.ts +2 -0
- package/dist/types/tests/env.test.d.ts.map +1 -0
- package/dist/types/tests/selector.test.d.ts +2 -0
- package/dist/types/tests/selector.test.d.ts.map +1 -0
- package/dist/types/tests/space.test.d.ts +2 -0
- package/dist/types/tests/space.test.d.ts.map +1 -0
- package/dist/types/tests/trait_behavior.test.d.ts +2 -0
- package/dist/types/tests/trait_behavior.test.d.ts.map +1 -0
- package/jest.config.js +13 -0
- package/package.json +32 -0
- package/src/backend.ts +106 -0
- package/src/behavior.ts +101 -0
- package/src/component.ts +476 -0
- package/src/index.ts +82 -0
- package/src/selector_query.ts +356 -0
- package/src/space.ts +1514 -0
- package/src/types.ts +85 -0
- package/src/utils.ts +3 -0
- package/tests/base/env.ts +20 -0
- package/tests/data_update.test.ts +92 -0
- package/tests/env.test.ts +141 -0
- package/tests/selector.test.ts +407 -0
- package/tests/space.test.ts +953 -0
- package/tests/trait_behavior.test.ts +141 -0
- package/tsconfig.json +11 -0
- package/webpack.config.js +78 -0
package/src/space.ts
ADDED
|
@@ -0,0 +1,1514 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
2
|
+
|
|
3
|
+
import * as glassEasel from 'glass-easel'
|
|
4
|
+
import { MiniProgramEnv } from '.'
|
|
5
|
+
import {
|
|
6
|
+
ComponentStaticConfig,
|
|
7
|
+
ComponentDefinitionOptions,
|
|
8
|
+
StyleIsolation,
|
|
9
|
+
BehaviorDefinition,
|
|
10
|
+
ComponentDefinition,
|
|
11
|
+
PageDefinition,
|
|
12
|
+
utils as typeUtils,
|
|
13
|
+
} from './types'
|
|
14
|
+
import {
|
|
15
|
+
guid,
|
|
16
|
+
} from './utils'
|
|
17
|
+
import {
|
|
18
|
+
Behavior,
|
|
19
|
+
ComponentType,
|
|
20
|
+
DefinitionFilter,
|
|
21
|
+
GeneralBehavior,
|
|
22
|
+
TraitBehavior,
|
|
23
|
+
} from './behavior'
|
|
24
|
+
import {
|
|
25
|
+
AllData,
|
|
26
|
+
Component,
|
|
27
|
+
ComponentProto,
|
|
28
|
+
GeneralComponent,
|
|
29
|
+
} from './component'
|
|
30
|
+
|
|
31
|
+
// The page constructor
|
|
32
|
+
export interface PageConstructor {
|
|
33
|
+
<
|
|
34
|
+
TData extends DataList,
|
|
35
|
+
TNewExtraFields extends { [k: PropertyKey]: any },
|
|
36
|
+
>(
|
|
37
|
+
definition: PageDefinition<
|
|
38
|
+
TData,
|
|
39
|
+
TNewExtraFields
|
|
40
|
+
> & ThisType<Component<TData, Empty, TNewExtraFields, undefined>>,
|
|
41
|
+
): void
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// The component constructor
|
|
45
|
+
export interface ComponentConstructor {
|
|
46
|
+
(): ComponentBuilder
|
|
47
|
+
<
|
|
48
|
+
TData extends DataList,
|
|
49
|
+
TProperty extends PropertyList,
|
|
50
|
+
TMethod extends MethodList,
|
|
51
|
+
TComponentExport,
|
|
52
|
+
>(
|
|
53
|
+
definition: ComponentDefinition<
|
|
54
|
+
TData,
|
|
55
|
+
TProperty,
|
|
56
|
+
TMethod,
|
|
57
|
+
TComponentExport
|
|
58
|
+
> & ThisType<Component<TData, TProperty, TMethod, TComponentExport>>,
|
|
59
|
+
): void
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// The behavior constructor
|
|
63
|
+
export interface BehaviorConstructor {
|
|
64
|
+
(): BehaviorBuilder
|
|
65
|
+
<
|
|
66
|
+
TData extends DataList,
|
|
67
|
+
TProperty extends PropertyList,
|
|
68
|
+
TMethod extends MethodList,
|
|
69
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
70
|
+
TComponentExport,
|
|
71
|
+
>(
|
|
72
|
+
definition: BehaviorDefinition<
|
|
73
|
+
TData,
|
|
74
|
+
TProperty,
|
|
75
|
+
TMethod
|
|
76
|
+
>,
|
|
77
|
+
): Behavior<TData, TProperty, TMethod, never>
|
|
78
|
+
trait<TIn extends { [key: string]: any }>(): TraitBehavior<TIn, TIn>
|
|
79
|
+
trait<
|
|
80
|
+
TIn extends { [key: string]: any },
|
|
81
|
+
TOut extends { [key: string]: any }
|
|
82
|
+
>(trans: (impl: TIn) => TOut): TraitBehavior<TIn, TOut>
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* The component registration environment */
|
|
86
|
+
export interface ComponentEnv {
|
|
87
|
+
Page: PageConstructor,
|
|
88
|
+
Component: ComponentConstructor,
|
|
89
|
+
Behavior: BehaviorConstructor,
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
type Empty = typeUtils.Empty
|
|
93
|
+
type DataList = typeUtils.DataList
|
|
94
|
+
type PropertyList = typeUtils.PropertyList
|
|
95
|
+
type PropertyType = typeUtils.PropertyType
|
|
96
|
+
type PropertyTypeToValueType<T extends PropertyType> = typeUtils.PropertyTypeToValueType<T>
|
|
97
|
+
type MethodList = typeUtils.MethodList
|
|
98
|
+
type ChainingFilterType = typeUtils.ChainingFilterType
|
|
99
|
+
type ComponentMethod = typeUtils.ComponentMethod
|
|
100
|
+
type TaggedMethod<Fn extends ComponentMethod> = typeUtils.TaggedMethod<Fn>
|
|
101
|
+
type ChainingFilterFunc<
|
|
102
|
+
TAddedFields extends { [key: string]: any },
|
|
103
|
+
TRemovedFields extends string = never
|
|
104
|
+
> = typeUtils.ChainingFilterFunc<TAddedFields, TRemovedFields>
|
|
105
|
+
|
|
106
|
+
export interface RelationHandler<TTarget, TOut> {
|
|
107
|
+
list(): TTarget[]
|
|
108
|
+
listAsTrait: TOut extends never
|
|
109
|
+
? undefined
|
|
110
|
+
: () => TOut[]
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export type TraitRelationParams<TOut extends { [key: string]: any }> = {
|
|
114
|
+
target: TraitBehavior<any, TOut>;
|
|
115
|
+
type:
|
|
116
|
+
| 'ancestor'
|
|
117
|
+
| 'descendant'
|
|
118
|
+
| 'parent'
|
|
119
|
+
| 'child'
|
|
120
|
+
| 'parent-common-node'
|
|
121
|
+
| 'child-common-node';
|
|
122
|
+
linked?: (target: GeneralComponent) => void;
|
|
123
|
+
linkChanged?: (target: GeneralComponent) => void;
|
|
124
|
+
unlinked?: (target: GeneralComponent) => void;
|
|
125
|
+
linkFailed?: (target: GeneralComponent) => void;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export type RelationParams = {
|
|
129
|
+
target?: string | ComponentType<any, any, any, any> | GeneralBehavior | TraitBehavior<any>;
|
|
130
|
+
type: 'ancestor' | 'descendant' | 'parent' | 'child' | 'parent-common-node' | 'child-common-node';
|
|
131
|
+
linked?: (target: GeneralComponent) => void;
|
|
132
|
+
linkChanged?: (target: GeneralComponent) => void;
|
|
133
|
+
unlinked?: (target: GeneralComponent) => void;
|
|
134
|
+
linkFailed?: (target: GeneralComponent) => void;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export type Lifetimes = {
|
|
138
|
+
created: () => void,
|
|
139
|
+
attached: () => void,
|
|
140
|
+
moved: () => void,
|
|
141
|
+
detached: () => void,
|
|
142
|
+
ready: () => void,
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export interface BuilderContext<
|
|
146
|
+
TPrevData extends DataList,
|
|
147
|
+
TProperty extends PropertyList,
|
|
148
|
+
TMethodCaller
|
|
149
|
+
> extends ThisType<TMethodCaller> {
|
|
150
|
+
self: TMethodCaller;
|
|
151
|
+
data: typeUtils.DeepReadonly<typeUtils.DataWithPropertyValues<TPrevData, TProperty>>;
|
|
152
|
+
setData: (
|
|
153
|
+
newData: Partial<typeUtils.SetDataSetter<TPrevData>>, callback?: () => void,
|
|
154
|
+
) => void;
|
|
155
|
+
implement: <TIn extends { [x: string]: any }>(
|
|
156
|
+
traitBehavior: TraitBehavior<TIn, any>,
|
|
157
|
+
impl: TIn
|
|
158
|
+
) => void;
|
|
159
|
+
relation<TOut extends { [key: string]: any }>
|
|
160
|
+
(def: TraitRelationParams<TOut> & ThisType<TMethodCaller>): RelationHandler<any, TOut>
|
|
161
|
+
relation(def: RelationParams & ThisType<TMethodCaller>): RelationHandler<any, never>
|
|
162
|
+
observer<
|
|
163
|
+
P extends typeUtils.ObserverDataPathStrings<
|
|
164
|
+
typeUtils.DataWithPropertyValues<TPrevData, TProperty>
|
|
165
|
+
>,
|
|
166
|
+
V = typeUtils.DeepReadonly<
|
|
167
|
+
typeUtils. GetFromObserverPathString<typeUtils.DataWithPropertyValues<TPrevData, TProperty>, P>
|
|
168
|
+
>
|
|
169
|
+
>(
|
|
170
|
+
paths: P,
|
|
171
|
+
func: (newValue: V) => void,
|
|
172
|
+
): void;
|
|
173
|
+
observer<
|
|
174
|
+
P extends typeUtils.ObserverDataPathStrings<
|
|
175
|
+
typeUtils.DataWithPropertyValues<TPrevData, TProperty>
|
|
176
|
+
>[],
|
|
177
|
+
V = {
|
|
178
|
+
[K in keyof P]: typeUtils.DeepReadonly<
|
|
179
|
+
typeUtils.GetFromObserverPathString<
|
|
180
|
+
typeUtils.DataWithPropertyValues<TPrevData, TProperty>,
|
|
181
|
+
P[K]
|
|
182
|
+
>
|
|
183
|
+
>
|
|
184
|
+
}
|
|
185
|
+
>(
|
|
186
|
+
paths: readonly [...P],
|
|
187
|
+
func: (...newValues: V extends any[] ? V : never) => void,
|
|
188
|
+
): void;
|
|
189
|
+
lifetime: <L extends keyof Lifetimes>(name: L, func: Lifetimes[L]) => void;
|
|
190
|
+
pageLifetime: (name: string, func: (...args: any[]) => void) => void;
|
|
191
|
+
method: <Fn extends ComponentMethod>(func: Fn) => TaggedMethod<Fn>;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* A component space with mini-program code manager
|
|
196
|
+
*/
|
|
197
|
+
export class CodeSpace {
|
|
198
|
+
/** @internal */
|
|
199
|
+
_$env: MiniProgramEnv
|
|
200
|
+
private _$isMainSpace: boolean
|
|
201
|
+
private space: glassEasel.ComponentSpace
|
|
202
|
+
private styleScopeManager: glassEasel.StyleScopeManager
|
|
203
|
+
private staticConfigMap: { [path: string]: ComponentStaticConfig }
|
|
204
|
+
private styleSheetMap: { [path: string]: { url: string, styleScopeName: string | undefined } }
|
|
205
|
+
private compiledTemplateMap: { [path: string]: glassEasel.template.ComponentTemplate }
|
|
206
|
+
private waitingAliasMap: { [is: string]: string[] }
|
|
207
|
+
/** @internal */
|
|
208
|
+
_$sharedStyleScope: glassEasel.StyleScopeId
|
|
209
|
+
/** @internal */
|
|
210
|
+
_$styleIsolationMap: { [path: string]: StyleIsolation }
|
|
211
|
+
/** @internal */
|
|
212
|
+
_$overallBehavior: glassEasel.GeneralBehavior | null = null
|
|
213
|
+
|
|
214
|
+
/** @internal */
|
|
215
|
+
constructor(
|
|
216
|
+
env: MiniProgramEnv,
|
|
217
|
+
isMainSpace: boolean,
|
|
218
|
+
publicComponents: { [alias: string]: string },
|
|
219
|
+
globalCodeSpace?: CodeSpace,
|
|
220
|
+
) {
|
|
221
|
+
this._$env = env
|
|
222
|
+
this._$isMainSpace = isMainSpace
|
|
223
|
+
this.space = new glassEasel.ComponentSpace(
|
|
224
|
+
'',
|
|
225
|
+
globalCodeSpace?.space,
|
|
226
|
+
globalCodeSpace?.space.styleScopeManager,
|
|
227
|
+
)
|
|
228
|
+
this.styleScopeManager = this.space.styleScopeManager
|
|
229
|
+
this.staticConfigMap = Object.create(null) as { [path: string]: ComponentStaticConfig }
|
|
230
|
+
this.styleSheetMap = Object.create(null) as
|
|
231
|
+
{ [path: string]: { url: string, styleScopeName: string } }
|
|
232
|
+
this.compiledTemplateMap = Object.create(null) as
|
|
233
|
+
{ [path: string]: glassEasel.template.ComponentTemplate }
|
|
234
|
+
this.waitingAliasMap = Object.create(null) as { [path: string]: string[] }
|
|
235
|
+
Object.keys(publicComponents).forEach((alias) => {
|
|
236
|
+
const is = publicComponents[alias]!
|
|
237
|
+
if (this.waitingAliasMap[is]) this.waitingAliasMap[is]!.push(alias)
|
|
238
|
+
else this.waitingAliasMap[is] = [alias]
|
|
239
|
+
})
|
|
240
|
+
this._$sharedStyleScope = this.styleScopeManager.register('')
|
|
241
|
+
this._$styleIsolationMap = Object.create(null) as { [path: string]: StyleIsolation }
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
isMainSpace(): boolean {
|
|
245
|
+
return this._$isMainSpace
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Get the underlying component space
|
|
250
|
+
*/
|
|
251
|
+
getComponentSpace(): glassEasel.ComponentSpace {
|
|
252
|
+
return this.space
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Add a behavior for all components
|
|
257
|
+
*
|
|
258
|
+
* Must be called before any component registration so that the component will use this behavior.
|
|
259
|
+
* Set to `null` to disable this behavior.
|
|
260
|
+
*/
|
|
261
|
+
setOverallBehavior(behavior: glassEasel.GeneralBehavior) {
|
|
262
|
+
this._$overallBehavior = behavior
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Import another component space as a plugin (must be in the same environment)
|
|
267
|
+
*
|
|
268
|
+
* Components from the imported `codeSpace` can be used with URLs.
|
|
269
|
+
* If `domainAlias` is provided, the URL format is `plugin://DOMAIN_ALIAS/COMPONENT_SPACE_EXPORT_ALIAS` .
|
|
270
|
+
* If `privateImport` is enabled, another URL format is `plugin-private://DOMAIN/COMPONENT_IS` .
|
|
271
|
+
*/
|
|
272
|
+
importCodeSpace(id: string, domainAlias?: string, privateImport = false) {
|
|
273
|
+
const cs = this._$env.getCodeSpace(id)
|
|
274
|
+
if (!cs) {
|
|
275
|
+
throw new Error(`There is no space "${id}" in the environment`)
|
|
276
|
+
}
|
|
277
|
+
if (domainAlias) this.space.importSpace(`plugin://${domainAlias}`, cs.space, false)
|
|
278
|
+
if (privateImport) this.space.importSpace(`plugin-private://${id}`, cs.space, true)
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Add a style sheet URL with style scope name
|
|
283
|
+
*
|
|
284
|
+
* The URL should be recognized by the target backend.
|
|
285
|
+
* The `path` should not contain the `.wxss` suffix.
|
|
286
|
+
*/
|
|
287
|
+
addStyleSheet(path: string, styleSheetUrl: string, styleScopeName?: string) {
|
|
288
|
+
this.styleSheetMap[path] = { url: styleSheetUrl, styleScopeName }
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Get a style sheet URL
|
|
293
|
+
*
|
|
294
|
+
* The URL should be recognized by the target backend.
|
|
295
|
+
* The `path` should not contain the `.wxss` suffix.
|
|
296
|
+
*/
|
|
297
|
+
getStyleSheet(path: string): string | undefined {
|
|
298
|
+
return this.styleSheetMap[path]?.url
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
getStyleScopeName(path: string): string | undefined {
|
|
302
|
+
return this.styleSheetMap[path]?.styleScopeName
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Add a compiled template
|
|
307
|
+
*
|
|
308
|
+
* The content is the execution result of the generated string of the template compiler.
|
|
309
|
+
* The `path` should not contain the `.wxml` suffix.
|
|
310
|
+
*/
|
|
311
|
+
addCompiledTemplate(path: string, content: glassEasel.template.ComponentTemplate) {
|
|
312
|
+
this.compiledTemplateMap[path] = content
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Get a compiled template
|
|
317
|
+
*
|
|
318
|
+
* The content is the execution result of the generated string of the template compiler.
|
|
319
|
+
* The `path` should not contain the `.wxml` suffix.
|
|
320
|
+
*/
|
|
321
|
+
getCompiledTemplate(path: string): glassEasel.template.ComponentTemplate | undefined {
|
|
322
|
+
return this.compiledTemplateMap[path]
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Add a static JSON config
|
|
327
|
+
*
|
|
328
|
+
* The `path` should not contain the `.json` suffix.
|
|
329
|
+
*/
|
|
330
|
+
addComponentStaticConfig(path: string, content: ComponentStaticConfig) {
|
|
331
|
+
this.staticConfigMap[path] = content
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Get a static JSON config
|
|
336
|
+
*
|
|
337
|
+
* The `path` should not contain the `.json` suffix.
|
|
338
|
+
*/
|
|
339
|
+
getComponentStaticConfig(path: string): ComponentStaticConfig | undefined {
|
|
340
|
+
return this.staticConfigMap[path]
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/** @internal */
|
|
344
|
+
prepareComponentOptions(
|
|
345
|
+
is: string,
|
|
346
|
+
options?: ComponentDefinitionOptions,
|
|
347
|
+
): [glassEasel.ComponentOptions, StyleIsolation] {
|
|
348
|
+
// accept some fields from static JSON config
|
|
349
|
+
const staticConfig = this.staticConfigMap[is]
|
|
350
|
+
const pureDataPatternString = staticConfig?.pureDataPattern
|
|
351
|
+
const pureDataPattern = pureDataPatternString
|
|
352
|
+
? new RegExp(pureDataPatternString)
|
|
353
|
+
: options?.pureDataPattern
|
|
354
|
+
|
|
355
|
+
// calculate style scope
|
|
356
|
+
const addGlobalClass = staticConfig?.addGlobalClass
|
|
357
|
+
let styleIsolation = staticConfig?.styleIsolation
|
|
358
|
+
if (styleIsolation === undefined) {
|
|
359
|
+
if (staticConfig?.component) {
|
|
360
|
+
styleIsolation = addGlobalClass ? StyleIsolation.ApplyShared : StyleIsolation.Isolated
|
|
361
|
+
} else {
|
|
362
|
+
styleIsolation = StyleIsolation.Shared
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
let styleScope: glassEasel.StyleScopeId | undefined
|
|
366
|
+
let extraStyleScope: glassEasel.StyleScopeId | undefined
|
|
367
|
+
if (
|
|
368
|
+
styleIsolation === StyleIsolation.ApplyShared
|
|
369
|
+
|| styleIsolation === StyleIsolation.PageApplyShared
|
|
370
|
+
) {
|
|
371
|
+
styleScope = this.styleScopeManager.register(this.getStyleScopeName(is) || `__${guid()}`)
|
|
372
|
+
extraStyleScope = this._$sharedStyleScope
|
|
373
|
+
} else if (
|
|
374
|
+
(styleIsolation === StyleIsolation.Shared || styleIsolation === StyleIsolation.PageShared)
|
|
375
|
+
&& this._$isMainSpace
|
|
376
|
+
) {
|
|
377
|
+
styleScope = this._$sharedStyleScope
|
|
378
|
+
} else {
|
|
379
|
+
styleScope = this.styleScopeManager.register(this.getStyleScopeName(is) || `__${guid()}`)
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// construct component options
|
|
383
|
+
const ret: glassEasel.ComponentOptions = {
|
|
384
|
+
idPrefixGenerator: guid,
|
|
385
|
+
multipleSlots: options?.multipleSlots,
|
|
386
|
+
pureDataPattern,
|
|
387
|
+
virtualHost: options?.virtualHost,
|
|
388
|
+
styleScope,
|
|
389
|
+
extraStyleScope,
|
|
390
|
+
dataDeepCopy: options?.dataDeepCopy,
|
|
391
|
+
propertyPassingDeepCopy: options?.propertyPassingDeepCopy,
|
|
392
|
+
propertyEarlyInit: options?.propertyEarlyInit,
|
|
393
|
+
}
|
|
394
|
+
return [ret, styleIsolation]
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Create a component definition environment
|
|
399
|
+
*
|
|
400
|
+
* During the sync execution of `cb` , `Component` and `Behavior` global vars will be available.
|
|
401
|
+
* `globalObject` should be the JavaScript global object, a.k.a. `window` in DOM.
|
|
402
|
+
* Some global variables, a.k.a `Component` `Behavior` `Page` ,
|
|
403
|
+
* will be written into `globalObject` .
|
|
404
|
+
* `path` should be the component path (without ".js" extension).
|
|
405
|
+
*/
|
|
406
|
+
globalComponentEnv<T>(globalObject: any, path: string, cb: () => T): T {
|
|
407
|
+
return this.componentEnv(path, ({ Page, Component, Behavior }) => {
|
|
408
|
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
409
|
+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
410
|
+
const oldPage = globalObject.Page
|
|
411
|
+
const oldComponent = globalObject.Component
|
|
412
|
+
const oldBehavior = globalObject.Behavior
|
|
413
|
+
globalObject.Page = Page
|
|
414
|
+
globalObject.Component = Component
|
|
415
|
+
globalObject.Behavior = Behavior
|
|
416
|
+
const ret = cb()
|
|
417
|
+
globalObject.Page = oldPage
|
|
418
|
+
globalObject.Component = oldComponent
|
|
419
|
+
globalObject.Behavior = oldBehavior
|
|
420
|
+
/* eslint-enable @typescript-eslint/no-unsafe-member-access */
|
|
421
|
+
/* eslint-enable @typescript-eslint/no-unsafe-assignment */
|
|
422
|
+
return ret
|
|
423
|
+
})
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Create a component definition environment
|
|
428
|
+
*
|
|
429
|
+
* Like `globalComponentEnv` , but the global variables are given as callback arguments.
|
|
430
|
+
*/
|
|
431
|
+
componentEnv<T>(path: string, cb: (env: ComponentEnv) => T): T {
|
|
432
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
433
|
+
const self = this
|
|
434
|
+
|
|
435
|
+
// The page constructor
|
|
436
|
+
function pageConstructor<
|
|
437
|
+
TData extends DataList,
|
|
438
|
+
TNewExtraFields extends { [k: PropertyKey]: any },
|
|
439
|
+
>(
|
|
440
|
+
definition: PageDefinition<
|
|
441
|
+
TData,
|
|
442
|
+
TNewExtraFields
|
|
443
|
+
> & ThisType<Component<TData, Empty, TNewExtraFields, undefined>>,
|
|
444
|
+
) {
|
|
445
|
+
return self.component(path).pageDefinition(definition).register()
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// The component constructor
|
|
449
|
+
function componentConstructor(): ComponentBuilder
|
|
450
|
+
function componentConstructor<
|
|
451
|
+
TData extends DataList,
|
|
452
|
+
TProperty extends PropertyList,
|
|
453
|
+
TMethod extends MethodList,
|
|
454
|
+
TComponentExport,
|
|
455
|
+
>(
|
|
456
|
+
definition: ComponentDefinition<
|
|
457
|
+
TData,
|
|
458
|
+
TProperty,
|
|
459
|
+
TMethod,
|
|
460
|
+
TComponentExport
|
|
461
|
+
>,
|
|
462
|
+
): void
|
|
463
|
+
function componentConstructor<
|
|
464
|
+
TData extends DataList,
|
|
465
|
+
TProperty extends PropertyList,
|
|
466
|
+
TMethod extends MethodList,
|
|
467
|
+
TComponentExport,
|
|
468
|
+
>(
|
|
469
|
+
definition?: ComponentDefinition<
|
|
470
|
+
TData,
|
|
471
|
+
TProperty,
|
|
472
|
+
TMethod,
|
|
473
|
+
TComponentExport
|
|
474
|
+
>,
|
|
475
|
+
) {
|
|
476
|
+
if (definition !== undefined) {
|
|
477
|
+
return self.component(path).definition(definition).register()
|
|
478
|
+
}
|
|
479
|
+
return self.component(path)
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// The behavior constructor
|
|
483
|
+
function behaviorConstructor(): BehaviorBuilder
|
|
484
|
+
function behaviorConstructor<
|
|
485
|
+
TData extends DataList,
|
|
486
|
+
TProperty extends PropertyList,
|
|
487
|
+
TMethod extends MethodList,
|
|
488
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
489
|
+
TComponentExport,
|
|
490
|
+
>(
|
|
491
|
+
definition: BehaviorDefinition<
|
|
492
|
+
TData,
|
|
493
|
+
TProperty,
|
|
494
|
+
TMethod
|
|
495
|
+
>,
|
|
496
|
+
): Behavior<TData, TProperty, TMethod, never>
|
|
497
|
+
function behaviorConstructor<
|
|
498
|
+
TData extends DataList,
|
|
499
|
+
TProperty extends PropertyList,
|
|
500
|
+
TMethod extends MethodList,
|
|
501
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
502
|
+
TComponentExport,
|
|
503
|
+
>(
|
|
504
|
+
definition?: BehaviorDefinition<
|
|
505
|
+
TData,
|
|
506
|
+
TProperty,
|
|
507
|
+
TMethod
|
|
508
|
+
>,
|
|
509
|
+
) {
|
|
510
|
+
if (definition !== undefined) {
|
|
511
|
+
return self.behavior().definition(definition).register()
|
|
512
|
+
}
|
|
513
|
+
return self.behavior()
|
|
514
|
+
}
|
|
515
|
+
behaviorConstructor.trait = self.traitBehavior.bind(self)
|
|
516
|
+
|
|
517
|
+
// prepare global vars and execute
|
|
518
|
+
return cb({
|
|
519
|
+
Page: pageConstructor,
|
|
520
|
+
Component: componentConstructor,
|
|
521
|
+
Behavior: behaviorConstructor,
|
|
522
|
+
})
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Build a component outside of a definition environment
|
|
527
|
+
*
|
|
528
|
+
* The method do not need a definition environment, so the global object pollution is avoided.
|
|
529
|
+
* `path` should be the component path (without ".js" extension).
|
|
530
|
+
*/
|
|
531
|
+
component(path: string): ComponentBuilder {
|
|
532
|
+
return ComponentBuilder.create(this, path, this.waitingAliasMap[path])
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Build a behavior outside of a definition environment
|
|
537
|
+
*
|
|
538
|
+
* The method do not need a definition environment, so the global object pollution is avoided.
|
|
539
|
+
* `path` should be the component path (without ".js" extension).
|
|
540
|
+
*/
|
|
541
|
+
behavior(): BehaviorBuilder {
|
|
542
|
+
return BehaviorBuilder.create(this)
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Define a trait behavior
|
|
547
|
+
*/
|
|
548
|
+
traitBehavior<TIn extends { [key: string]: any }>(): TraitBehavior<TIn, TIn>
|
|
549
|
+
traitBehavior<
|
|
550
|
+
TIn extends { [key: string]: any },
|
|
551
|
+
TOut extends { [key: string]: any }
|
|
552
|
+
>(trans: (impl: TIn) => TOut): TraitBehavior<TIn, TOut>
|
|
553
|
+
traitBehavior<
|
|
554
|
+
TIn extends { [key: string]: any },
|
|
555
|
+
TOut extends { [key: string]: any }
|
|
556
|
+
>(trans?: (impl: TIn) => TOut): TraitBehavior<TIn, TOut> {
|
|
557
|
+
if (trans === undefined) {
|
|
558
|
+
return new TraitBehavior(this.space.defineTraitBehavior<TIn>())
|
|
559
|
+
}
|
|
560
|
+
return new TraitBehavior(this.space.defineTraitBehavior<TIn, TOut>(trans))
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
type ResolveBehaviorBuilder<B, TChainingFilter extends ChainingFilterType> =
|
|
565
|
+
typeUtils.IsNever<TChainingFilter> extends false
|
|
566
|
+
? TChainingFilter extends ChainingFilterType
|
|
567
|
+
? Omit<B, TChainingFilter['remove']> & TChainingFilter['add']
|
|
568
|
+
: B
|
|
569
|
+
: B
|
|
570
|
+
|
|
571
|
+
export class BaseBehaviorBuilder<
|
|
572
|
+
TPrevData extends DataList = Empty,
|
|
573
|
+
TData extends DataList = Empty,
|
|
574
|
+
TProperty extends PropertyList = Empty,
|
|
575
|
+
TMethod extends MethodList = Empty,
|
|
576
|
+
TChainingFilter extends ChainingFilterType = never,
|
|
577
|
+
TPendingChainingFilter extends ChainingFilterType = never,
|
|
578
|
+
TComponentExport = undefined,
|
|
579
|
+
> {
|
|
580
|
+
protected _$codeSpace!: CodeSpace
|
|
581
|
+
protected _$!: glassEasel.BehaviorBuilder<
|
|
582
|
+
TPrevData,
|
|
583
|
+
TData,
|
|
584
|
+
TProperty,
|
|
585
|
+
TMethod,
|
|
586
|
+
TChainingFilter,
|
|
587
|
+
TPendingChainingFilter
|
|
588
|
+
>
|
|
589
|
+
protected _$parents: GeneralBehavior[] = []
|
|
590
|
+
|
|
591
|
+
/** Implement a trait behavior */
|
|
592
|
+
implement<TIn extends { [key: string]: any }>(
|
|
593
|
+
traitBehavior: TraitBehavior<TIn, any>,
|
|
594
|
+
impl: TIn,
|
|
595
|
+
): ResolveBehaviorBuilder<this, TChainingFilter> {
|
|
596
|
+
this._$.implement(traitBehavior._$, impl)
|
|
597
|
+
return this as any
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/** Add external classes */
|
|
601
|
+
externalClasses(list: string[]): this {
|
|
602
|
+
this._$.externalClasses(list)
|
|
603
|
+
return this
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
data<T extends DataList>(
|
|
607
|
+
gen: (() => typeUtils.NewFieldList<AllData<TData, TProperty>, T>),
|
|
608
|
+
): ResolveBehaviorBuilder<
|
|
609
|
+
BaseBehaviorBuilder<
|
|
610
|
+
T,
|
|
611
|
+
TData & T,
|
|
612
|
+
TProperty,
|
|
613
|
+
TMethod,
|
|
614
|
+
TChainingFilter,
|
|
615
|
+
TPendingChainingFilter,
|
|
616
|
+
TComponentExport
|
|
617
|
+
>,
|
|
618
|
+
TChainingFilter
|
|
619
|
+
> {
|
|
620
|
+
this._$.data(gen)
|
|
621
|
+
return this as any
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
property<
|
|
625
|
+
N extends string,
|
|
626
|
+
T extends PropertyType,
|
|
627
|
+
V extends PropertyTypeToValueType<T>,
|
|
628
|
+
>(
|
|
629
|
+
name: N,
|
|
630
|
+
def: N extends keyof (TData & TProperty) ? never : typeUtils.PropertyListItem<T, V>,
|
|
631
|
+
): ResolveBehaviorBuilder<
|
|
632
|
+
BaseBehaviorBuilder<
|
|
633
|
+
TPrevData,
|
|
634
|
+
TData,
|
|
635
|
+
TProperty & Record<N, unknown extends V ? T : typeUtils.PropertyOption<T, V>>,
|
|
636
|
+
TMethod,
|
|
637
|
+
TChainingFilter,
|
|
638
|
+
TPendingChainingFilter,
|
|
639
|
+
TComponentExport
|
|
640
|
+
>,
|
|
641
|
+
TChainingFilter
|
|
642
|
+
> {
|
|
643
|
+
this._$.property(name, def)
|
|
644
|
+
return this as any
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* Add some public methods
|
|
649
|
+
*
|
|
650
|
+
* The public method can be used as an event handler, and can be visited in component instance.
|
|
651
|
+
*/
|
|
652
|
+
methods<
|
|
653
|
+
T extends MethodList,
|
|
654
|
+
>(
|
|
655
|
+
funcs: T & ThisType<Component<TData, TProperty, TMethod & T, any>>,
|
|
656
|
+
): ResolveBehaviorBuilder<
|
|
657
|
+
BaseBehaviorBuilder<
|
|
658
|
+
TPrevData,
|
|
659
|
+
TData,
|
|
660
|
+
TProperty,
|
|
661
|
+
TMethod & T,
|
|
662
|
+
TChainingFilter,
|
|
663
|
+
TPendingChainingFilter,
|
|
664
|
+
TComponentExport
|
|
665
|
+
>,
|
|
666
|
+
TChainingFilter
|
|
667
|
+
> {
|
|
668
|
+
this._$.methods(funcs)
|
|
669
|
+
return this as any
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
/**
|
|
673
|
+
* Add a data observer
|
|
674
|
+
*/
|
|
675
|
+
observer<
|
|
676
|
+
P extends typeUtils.ObserverDataPathStrings<
|
|
677
|
+
typeUtils.DataWithPropertyValues<TPrevData, TProperty>
|
|
678
|
+
>,
|
|
679
|
+
V = typeUtils.DeepReadonly<
|
|
680
|
+
typeUtils.GetFromObserverPathString<typeUtils.DataWithPropertyValues<TPrevData, TProperty>, P>
|
|
681
|
+
>
|
|
682
|
+
>(
|
|
683
|
+
paths: P,
|
|
684
|
+
func: (this: Component<TData, TProperty, TMethod, any>, newValue: V) => void,
|
|
685
|
+
once?: boolean,
|
|
686
|
+
): ResolveBehaviorBuilder<this, TChainingFilter>;
|
|
687
|
+
observer<
|
|
688
|
+
P extends typeUtils.ObserverDataPathStrings<
|
|
689
|
+
typeUtils.DataWithPropertyValues<TPrevData, TProperty>
|
|
690
|
+
>[],
|
|
691
|
+
V = {
|
|
692
|
+
[K in keyof P]: typeUtils.DeepReadonly<
|
|
693
|
+
typeUtils.GetFromObserverPathString<
|
|
694
|
+
typeUtils.DataWithPropertyValues<TPrevData, TProperty>,
|
|
695
|
+
P[K]
|
|
696
|
+
>
|
|
697
|
+
>
|
|
698
|
+
}
|
|
699
|
+
>(
|
|
700
|
+
paths: readonly [...P],
|
|
701
|
+
func: (
|
|
702
|
+
this: Component<TData, TProperty, TMethod, any>,
|
|
703
|
+
...newValues: V extends any[] ? V : never
|
|
704
|
+
) => void,
|
|
705
|
+
once?: boolean,
|
|
706
|
+
): ResolveBehaviorBuilder<this, TChainingFilter>;
|
|
707
|
+
observer(
|
|
708
|
+
paths: string | readonly string[],
|
|
709
|
+
func: (this: Component<TData, TProperty, TMethod, any>, ...args: any[]) => any,
|
|
710
|
+
once = false,
|
|
711
|
+
): ResolveBehaviorBuilder<this, TChainingFilter> {
|
|
712
|
+
this._$.observer(paths as any, func as any, once)
|
|
713
|
+
return this as any
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
* Add a lifetime callback
|
|
718
|
+
*/
|
|
719
|
+
lifetime<L extends keyof Lifetimes>(
|
|
720
|
+
name: L,
|
|
721
|
+
func: (
|
|
722
|
+
this: Component<TData, TProperty, TMethod, any>,
|
|
723
|
+
...args: Parameters<Lifetimes[L]>
|
|
724
|
+
) => ReturnType<Lifetimes[L]>,
|
|
725
|
+
once = false,
|
|
726
|
+
): ResolveBehaviorBuilder<this, TChainingFilter> {
|
|
727
|
+
this._$.lifetime(name, func as any, once)
|
|
728
|
+
return this as any
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
/**
|
|
732
|
+
* Add a page-lifetime callback
|
|
733
|
+
*/
|
|
734
|
+
pageLifetime(
|
|
735
|
+
name: string,
|
|
736
|
+
func: (this: Component<TData, TProperty, TMethod, any>, ...args: any[]) => any,
|
|
737
|
+
once = false,
|
|
738
|
+
): ResolveBehaviorBuilder<this, TChainingFilter> {
|
|
739
|
+
this._$.pageLifetime(name, func as any, once)
|
|
740
|
+
return this as any
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
/**
|
|
744
|
+
* Add a relation
|
|
745
|
+
*/
|
|
746
|
+
relation(
|
|
747
|
+
name: string,
|
|
748
|
+
rel: RelationParams & ThisType<Component<TData, TProperty, TMethod, TComponentExport>>,
|
|
749
|
+
): ResolveBehaviorBuilder<this, TChainingFilter> {
|
|
750
|
+
const target = (rel.target instanceof Behavior || rel.target instanceof ComponentType)
|
|
751
|
+
? rel.target._$
|
|
752
|
+
: rel.target
|
|
753
|
+
this._$.relation(name, {
|
|
754
|
+
target,
|
|
755
|
+
type: rel.type,
|
|
756
|
+
linked: rel.linked,
|
|
757
|
+
linkChanged: rel.linkChanged,
|
|
758
|
+
unlinked: rel.unlinked,
|
|
759
|
+
linkFailed: rel.linkFailed,
|
|
760
|
+
} as any)
|
|
761
|
+
return this as any
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
init<TExport extends Record<string, TaggedMethod<(...args: any[]) => any>> | void>(
|
|
765
|
+
func: (
|
|
766
|
+
this: Component<TData, TProperty, TMethod, TComponentExport>,
|
|
767
|
+
builderContext: BuilderContext<
|
|
768
|
+
TPrevData,
|
|
769
|
+
TProperty,
|
|
770
|
+
Component<TData, TProperty, TMethod, TComponentExport>
|
|
771
|
+
>,
|
|
772
|
+
) => TExport,
|
|
773
|
+
// eslint-disable-next-line function-paren-newline
|
|
774
|
+
): ResolveBehaviorBuilder<
|
|
775
|
+
BaseBehaviorBuilder<
|
|
776
|
+
TPrevData,
|
|
777
|
+
TData,
|
|
778
|
+
TProperty,
|
|
779
|
+
TMethod,
|
|
780
|
+
TChainingFilter,
|
|
781
|
+
TPendingChainingFilter,
|
|
782
|
+
TComponentExport
|
|
783
|
+
>,
|
|
784
|
+
TChainingFilter
|
|
785
|
+
> {
|
|
786
|
+
this._$.init(function ({
|
|
787
|
+
data,
|
|
788
|
+
setData,
|
|
789
|
+
implement,
|
|
790
|
+
relation,
|
|
791
|
+
observer,
|
|
792
|
+
lifetime,
|
|
793
|
+
pageLifetime,
|
|
794
|
+
method,
|
|
795
|
+
}) {
|
|
796
|
+
const relationInit = ((rel: RelationParams | TraitRelationParams<any>) => {
|
|
797
|
+
if (rel.target instanceof TraitBehavior) {
|
|
798
|
+
return relation({
|
|
799
|
+
target: rel.target._$,
|
|
800
|
+
type: rel.type,
|
|
801
|
+
linked: rel.linked,
|
|
802
|
+
linkChanged: rel.linkChanged,
|
|
803
|
+
unlinked: rel.unlinked,
|
|
804
|
+
linkFailed: rel.linkFailed,
|
|
805
|
+
} as any)
|
|
806
|
+
}
|
|
807
|
+
const target = (rel.target instanceof Behavior || rel.target instanceof ComponentType)
|
|
808
|
+
? rel.target._$
|
|
809
|
+
: rel.target
|
|
810
|
+
return relation({
|
|
811
|
+
target,
|
|
812
|
+
type: rel.type,
|
|
813
|
+
linked: rel.linked,
|
|
814
|
+
linkChanged: rel.linkChanged,
|
|
815
|
+
unlinked: rel.unlinked,
|
|
816
|
+
linkFailed: rel.linkFailed,
|
|
817
|
+
} as any)
|
|
818
|
+
}) as BuilderContext<TPrevData, TProperty, TMethod>['relation']
|
|
819
|
+
|
|
820
|
+
const implementInit = ((traitBehavior: TraitBehavior<any>, impl: Record<string, any>) => {
|
|
821
|
+
implement(traitBehavior._$, impl)
|
|
822
|
+
}) as BuilderContext<TPrevData, TProperty, TMethod>['implement']
|
|
823
|
+
|
|
824
|
+
const methodCaller = this as unknown as Component<TData, TProperty, TMethod, TComponentExport>
|
|
825
|
+
|
|
826
|
+
func.call(methodCaller, {
|
|
827
|
+
self: methodCaller,
|
|
828
|
+
data,
|
|
829
|
+
setData: (newData, callback) => {
|
|
830
|
+
setData(newData)
|
|
831
|
+
if (callback) {
|
|
832
|
+
glassEasel.triggerRender(methodCaller._$, () => {
|
|
833
|
+
callback()
|
|
834
|
+
})
|
|
835
|
+
}
|
|
836
|
+
},
|
|
837
|
+
implement: implementInit,
|
|
838
|
+
relation: relationInit,
|
|
839
|
+
observer,
|
|
840
|
+
lifetime,
|
|
841
|
+
pageLifetime,
|
|
842
|
+
method,
|
|
843
|
+
})
|
|
844
|
+
})
|
|
845
|
+
return this as any
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
definition<
|
|
849
|
+
TNewData extends DataList = Empty,
|
|
850
|
+
TNewProperty extends PropertyList = Empty,
|
|
851
|
+
TNewMethod extends MethodList = Empty,
|
|
852
|
+
>(
|
|
853
|
+
def: BehaviorDefinition<
|
|
854
|
+
TNewData,
|
|
855
|
+
TNewProperty,
|
|
856
|
+
TNewMethod
|
|
857
|
+
> & ThisType<
|
|
858
|
+
Component<
|
|
859
|
+
TData & TNewData,
|
|
860
|
+
TProperty & TNewProperty,
|
|
861
|
+
TMethod & TNewMethod,
|
|
862
|
+
TComponentExport
|
|
863
|
+
>
|
|
864
|
+
>,
|
|
865
|
+
): ResolveBehaviorBuilder<
|
|
866
|
+
BaseBehaviorBuilder<
|
|
867
|
+
TPrevData,
|
|
868
|
+
TData & TNewData,
|
|
869
|
+
TProperty & TNewProperty,
|
|
870
|
+
TMethod & TNewMethod,
|
|
871
|
+
TChainingFilter,
|
|
872
|
+
TPendingChainingFilter,
|
|
873
|
+
TComponentExport
|
|
874
|
+
>,
|
|
875
|
+
TChainingFilter
|
|
876
|
+
> {
|
|
877
|
+
def.behaviors?.forEach((beh) => beh._$bindedDefinitionFilter?.(def))
|
|
878
|
+
const inner = this._$
|
|
879
|
+
const {
|
|
880
|
+
behaviors,
|
|
881
|
+
properties: rawProperties,
|
|
882
|
+
data: rawData,
|
|
883
|
+
observers: rawObservers,
|
|
884
|
+
methods,
|
|
885
|
+
created,
|
|
886
|
+
attached,
|
|
887
|
+
ready,
|
|
888
|
+
moved,
|
|
889
|
+
detached,
|
|
890
|
+
lifetimes: rawLifetimes,
|
|
891
|
+
pageLifetimes: rawPageLifetimes,
|
|
892
|
+
relations: rawRelations,
|
|
893
|
+
externalClasses,
|
|
894
|
+
} = def
|
|
895
|
+
behaviors?.forEach((beh) => {
|
|
896
|
+
this._$parents.push(beh as GeneralBehavior)
|
|
897
|
+
inner.behavior(beh._$)
|
|
898
|
+
})
|
|
899
|
+
if (rawData !== undefined) {
|
|
900
|
+
if (typeof rawData === 'function') {
|
|
901
|
+
inner.data(rawData as any)
|
|
902
|
+
} else {
|
|
903
|
+
inner.staticData(rawData as any)
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
if (rawProperties !== undefined) {
|
|
907
|
+
const keys = Object.keys(rawProperties)
|
|
908
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
909
|
+
const name = keys[i]!
|
|
910
|
+
inner.property(name, rawProperties[name]!)
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
if (rawObservers !== undefined) {
|
|
914
|
+
if (Array.isArray(rawObservers)) {
|
|
915
|
+
for (let i = 0; i < rawObservers.length; i += 1) {
|
|
916
|
+
const { fields, observer } = rawObservers[i]!
|
|
917
|
+
inner.observer(fields || '**' as any, observer)
|
|
918
|
+
}
|
|
919
|
+
} else {
|
|
920
|
+
const keys = Object.keys(rawObservers)
|
|
921
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
922
|
+
const fields = keys[i]!
|
|
923
|
+
const observer = rawObservers[fields]!
|
|
924
|
+
inner.observer(fields as any, observer)
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
if (methods) inner.methods(methods)
|
|
929
|
+
if (created && rawLifetimes?.created === undefined) inner.lifetime('created', created, true)
|
|
930
|
+
if (attached && rawLifetimes?.attached === undefined) inner.lifetime('attached', attached, true)
|
|
931
|
+
if (ready && rawLifetimes?.ready === undefined) inner.lifetime('ready', ready, true)
|
|
932
|
+
if (moved && rawLifetimes?.moved === undefined) inner.lifetime('moved', moved, true)
|
|
933
|
+
if (detached && rawLifetimes?.detached === undefined) inner.lifetime('detached', detached, true)
|
|
934
|
+
if (rawLifetimes) {
|
|
935
|
+
const keys = Object.keys(rawLifetimes)
|
|
936
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
937
|
+
const name = keys[i]!
|
|
938
|
+
const func = rawLifetimes[name]!
|
|
939
|
+
inner.lifetime(name as any, func, true)
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
if (rawPageLifetimes) {
|
|
943
|
+
const keys = Object.keys(rawPageLifetimes)
|
|
944
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
945
|
+
const name = keys[i]!
|
|
946
|
+
const func = rawPageLifetimes[name]!
|
|
947
|
+
inner.pageLifetime(name, func, true)
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
if (rawRelations) {
|
|
951
|
+
const keys = Object.keys(rawRelations)
|
|
952
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
953
|
+
const name = keys[i]!
|
|
954
|
+
const rel = rawRelations[name]!
|
|
955
|
+
inner.relation(name, rel)
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
if (externalClasses) inner.externalClasses(externalClasses)
|
|
959
|
+
return this as any
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
export class BehaviorBuilder<
|
|
964
|
+
TPrevData extends DataList = Empty,
|
|
965
|
+
TData extends DataList = Empty,
|
|
966
|
+
TProperty extends PropertyList = Empty,
|
|
967
|
+
TMethod extends MethodList = Empty,
|
|
968
|
+
TChainingFilter extends ChainingFilterType = never,
|
|
969
|
+
TPendingChainingFilter extends ChainingFilterType = never,
|
|
970
|
+
TComponentExport = undefined,
|
|
971
|
+
> extends BaseBehaviorBuilder<
|
|
972
|
+
TPrevData,
|
|
973
|
+
TData,
|
|
974
|
+
TProperty,
|
|
975
|
+
TMethod,
|
|
976
|
+
TChainingFilter,
|
|
977
|
+
TPendingChainingFilter,
|
|
978
|
+
TComponentExport
|
|
979
|
+
> {
|
|
980
|
+
private _$definitionFilter: DefinitionFilter | undefined
|
|
981
|
+
|
|
982
|
+
/** @internal */
|
|
983
|
+
static create(codeSpace: CodeSpace): BehaviorBuilder {
|
|
984
|
+
const ret = new BehaviorBuilder()
|
|
985
|
+
ret._$codeSpace = codeSpace
|
|
986
|
+
ret._$ = codeSpace.getComponentSpace()
|
|
987
|
+
.defineWithMethodCaller()
|
|
988
|
+
return ret
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
/** Define a chaining filter */
|
|
992
|
+
chainingFilter<
|
|
993
|
+
TAddedFields extends { [key: string]: any },
|
|
994
|
+
TRemovedFields extends string = never,
|
|
995
|
+
>(
|
|
996
|
+
func: ChainingFilterFunc<TAddedFields, TRemovedFields>,
|
|
997
|
+
): ResolveBehaviorBuilder<
|
|
998
|
+
BehaviorBuilder<TPrevData, TData, TProperty, TMethod, TChainingFilter, {
|
|
999
|
+
add: TAddedFields,
|
|
1000
|
+
remove: TRemovedFields,
|
|
1001
|
+
}, TComponentExport>,
|
|
1002
|
+
TChainingFilter
|
|
1003
|
+
> {
|
|
1004
|
+
this._$.chainingFilter(func as any)
|
|
1005
|
+
return this as any
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
/** Use another behavior */
|
|
1009
|
+
behavior<
|
|
1010
|
+
UData extends DataList,
|
|
1011
|
+
UProperty extends PropertyList,
|
|
1012
|
+
UMethod extends MethodList,
|
|
1013
|
+
UChainingFilter extends ChainingFilterType,
|
|
1014
|
+
>(
|
|
1015
|
+
behavior: Behavior<UData, UProperty, UMethod, UChainingFilter>,
|
|
1016
|
+
): ResolveBehaviorBuilder<
|
|
1017
|
+
BehaviorBuilder<
|
|
1018
|
+
TPrevData,
|
|
1019
|
+
TData & UData,
|
|
1020
|
+
TProperty & UProperty,
|
|
1021
|
+
TMethod & UMethod,
|
|
1022
|
+
UChainingFilter,
|
|
1023
|
+
TPendingChainingFilter,
|
|
1024
|
+
TComponentExport
|
|
1025
|
+
>,
|
|
1026
|
+
UChainingFilter
|
|
1027
|
+
> {
|
|
1028
|
+
this._$parents.push(behavior as GeneralBehavior)
|
|
1029
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
1030
|
+
this._$ = this._$.behavior(behavior._$)
|
|
1031
|
+
return this as any
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
/**
|
|
1035
|
+
* Add some template data fields
|
|
1036
|
+
*
|
|
1037
|
+
* It does not support raw data, but a `gen` function which returns the new data fields.
|
|
1038
|
+
* The `gen` function executes once during component creation.
|
|
1039
|
+
*/
|
|
1040
|
+
override data<T extends DataList>(
|
|
1041
|
+
gen: (() => typeUtils.NewFieldList<AllData<TData, TProperty>, T>),
|
|
1042
|
+
): ResolveBehaviorBuilder<
|
|
1043
|
+
BehaviorBuilder<
|
|
1044
|
+
T,
|
|
1045
|
+
TData & T,
|
|
1046
|
+
TProperty,
|
|
1047
|
+
TMethod,
|
|
1048
|
+
TChainingFilter,
|
|
1049
|
+
TPendingChainingFilter,
|
|
1050
|
+
TComponentExport
|
|
1051
|
+
>,
|
|
1052
|
+
TChainingFilter
|
|
1053
|
+
> {
|
|
1054
|
+
return super.data(gen) as any
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
/**
|
|
1058
|
+
* Add a single property
|
|
1059
|
+
*
|
|
1060
|
+
* The property name should be different from other properties.
|
|
1061
|
+
*/
|
|
1062
|
+
override property<
|
|
1063
|
+
N extends string,
|
|
1064
|
+
T extends PropertyType,
|
|
1065
|
+
V extends PropertyTypeToValueType<T>,
|
|
1066
|
+
>(
|
|
1067
|
+
name: N,
|
|
1068
|
+
def: N extends keyof (TData & TProperty) ? never : typeUtils.PropertyListItem<T, V>,
|
|
1069
|
+
): ResolveBehaviorBuilder<
|
|
1070
|
+
BehaviorBuilder<
|
|
1071
|
+
TPrevData,
|
|
1072
|
+
TData,
|
|
1073
|
+
TProperty & Record<N, unknown extends V ? T : typeUtils.PropertyOption<T, V>>,
|
|
1074
|
+
TMethod,
|
|
1075
|
+
TChainingFilter,
|
|
1076
|
+
TPendingChainingFilter,
|
|
1077
|
+
TComponentExport
|
|
1078
|
+
>,
|
|
1079
|
+
TChainingFilter
|
|
1080
|
+
> {
|
|
1081
|
+
return super.property(name, def) as any
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
/**
|
|
1085
|
+
* Add some public methods
|
|
1086
|
+
*
|
|
1087
|
+
* The public method can be used as an event handler, and can be visited in component instance.
|
|
1088
|
+
*/
|
|
1089
|
+
override methods<
|
|
1090
|
+
T extends MethodList,
|
|
1091
|
+
>(
|
|
1092
|
+
funcs: T & ThisType<Component<TData, TProperty, TMethod & T, any>>,
|
|
1093
|
+
): ResolveBehaviorBuilder<
|
|
1094
|
+
BehaviorBuilder<
|
|
1095
|
+
TPrevData,
|
|
1096
|
+
TData,
|
|
1097
|
+
TProperty,
|
|
1098
|
+
TMethod & T,
|
|
1099
|
+
TChainingFilter,
|
|
1100
|
+
TPendingChainingFilter,
|
|
1101
|
+
TComponentExport
|
|
1102
|
+
>,
|
|
1103
|
+
TChainingFilter
|
|
1104
|
+
> {
|
|
1105
|
+
return super.methods(funcs) as any
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
/**
|
|
1109
|
+
* Execute a function while component instance creation
|
|
1110
|
+
*
|
|
1111
|
+
* A `BuilderContext` is provided to tweak the component creation progress.
|
|
1112
|
+
* The return value is used as the "export" value of the behavior,
|
|
1113
|
+
* which can be imported by other behaviors.
|
|
1114
|
+
*/
|
|
1115
|
+
override init<TExport extends Record<string, TaggedMethod<(...args: any[]) => any>> | void>(
|
|
1116
|
+
func: (
|
|
1117
|
+
this: Component<TData, TProperty, TMethod, TComponentExport>,
|
|
1118
|
+
builderContext: BuilderContext<
|
|
1119
|
+
TPrevData,
|
|
1120
|
+
TProperty,
|
|
1121
|
+
Component<TData, TProperty, TMethod, TComponentExport>
|
|
1122
|
+
>,
|
|
1123
|
+
) => TExport,
|
|
1124
|
+
// eslint-disable-next-line function-paren-newline
|
|
1125
|
+
): ResolveBehaviorBuilder<
|
|
1126
|
+
BehaviorBuilder<
|
|
1127
|
+
TPrevData,
|
|
1128
|
+
TData,
|
|
1129
|
+
TProperty,
|
|
1130
|
+
TMethod,
|
|
1131
|
+
TChainingFilter,
|
|
1132
|
+
TPendingChainingFilter,
|
|
1133
|
+
TComponentExport
|
|
1134
|
+
>,
|
|
1135
|
+
TChainingFilter
|
|
1136
|
+
> {
|
|
1137
|
+
return super.init(func) as any
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
/** Apply a classic definition object */
|
|
1141
|
+
override definition<
|
|
1142
|
+
TNewData extends DataList = Empty,
|
|
1143
|
+
TNewProperty extends PropertyList = Empty,
|
|
1144
|
+
TNewMethod extends MethodList = Empty,
|
|
1145
|
+
>(
|
|
1146
|
+
def: BehaviorDefinition<
|
|
1147
|
+
TNewData,
|
|
1148
|
+
TNewProperty,
|
|
1149
|
+
TNewMethod
|
|
1150
|
+
> & ThisType<
|
|
1151
|
+
Component<
|
|
1152
|
+
TData & TNewData,
|
|
1153
|
+
TProperty & TNewProperty,
|
|
1154
|
+
TMethod & TNewMethod,
|
|
1155
|
+
TComponentExport
|
|
1156
|
+
>
|
|
1157
|
+
>,
|
|
1158
|
+
): ResolveBehaviorBuilder<
|
|
1159
|
+
BehaviorBuilder<
|
|
1160
|
+
TPrevData,
|
|
1161
|
+
TData & TNewData,
|
|
1162
|
+
TProperty & TNewProperty,
|
|
1163
|
+
TMethod & TNewMethod,
|
|
1164
|
+
TChainingFilter,
|
|
1165
|
+
TPendingChainingFilter,
|
|
1166
|
+
TComponentExport
|
|
1167
|
+
>,
|
|
1168
|
+
TChainingFilter
|
|
1169
|
+
> {
|
|
1170
|
+
super.definition(def)
|
|
1171
|
+
if (def.definitionFilter) this._$definitionFilter = def.definitionFilter
|
|
1172
|
+
return this as any
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
/**
|
|
1176
|
+
* Finish the behavior definition process
|
|
1177
|
+
*/
|
|
1178
|
+
register(): Behavior<TData, TProperty, TMethod, TPendingChainingFilter> {
|
|
1179
|
+
return new Behavior(
|
|
1180
|
+
this._$.registerBehavior(),
|
|
1181
|
+
this._$parents,
|
|
1182
|
+
this._$definitionFilter,
|
|
1183
|
+
)
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
/**
|
|
1188
|
+
* A direct way to create a component
|
|
1189
|
+
*/
|
|
1190
|
+
export class ComponentBuilder<
|
|
1191
|
+
TPrevData extends DataList = Empty,
|
|
1192
|
+
TData extends DataList = Empty,
|
|
1193
|
+
TProperty extends PropertyList = Empty,
|
|
1194
|
+
TMethod extends MethodList = Empty,
|
|
1195
|
+
TChainingFilter extends ChainingFilterType = never,
|
|
1196
|
+
TPendingChainingFilter extends ChainingFilterType = never,
|
|
1197
|
+
TComponentExport = undefined,
|
|
1198
|
+
> extends BaseBehaviorBuilder<
|
|
1199
|
+
TPrevData,
|
|
1200
|
+
TData,
|
|
1201
|
+
TProperty,
|
|
1202
|
+
TMethod,
|
|
1203
|
+
TChainingFilter,
|
|
1204
|
+
TPendingChainingFilter,
|
|
1205
|
+
TComponentExport
|
|
1206
|
+
> {
|
|
1207
|
+
private _$is!: string
|
|
1208
|
+
private _$alias?: string[]
|
|
1209
|
+
private _$options?: ComponentDefinitionOptions
|
|
1210
|
+
private _$export?: (source: GeneralComponent | null) => TComponentExport
|
|
1211
|
+
private _$proto?: ComponentProto<TData, TProperty, TMethod, TComponentExport>
|
|
1212
|
+
|
|
1213
|
+
/** @internal */
|
|
1214
|
+
static create(codeSpace: CodeSpace, is: string, alias?: string[]) {
|
|
1215
|
+
const ret = new ComponentBuilder()
|
|
1216
|
+
const overallBehavior = codeSpace._$overallBehavior
|
|
1217
|
+
ret._$codeSpace = codeSpace
|
|
1218
|
+
ret._$ = codeSpace.getComponentSpace()
|
|
1219
|
+
.defineWithMethodCaller(is || '')
|
|
1220
|
+
ret._$is = is || ''
|
|
1221
|
+
ret._$alias = alias
|
|
1222
|
+
ret._$.methodCallerInit(function () {
|
|
1223
|
+
const originalCaller = this as unknown as glassEasel.GeneralComponent
|
|
1224
|
+
let proto = ret._$proto
|
|
1225
|
+
if (proto === undefined) {
|
|
1226
|
+
const methods = originalCaller.getComponentDefinition().behavior.getMethods()
|
|
1227
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
1228
|
+
proto = ret._$proto = new ComponentProto(methods) as any
|
|
1229
|
+
}
|
|
1230
|
+
const caller = proto!.derive()
|
|
1231
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
1232
|
+
caller._$ = originalCaller as any
|
|
1233
|
+
caller._$export = ret._$export
|
|
1234
|
+
return caller
|
|
1235
|
+
})
|
|
1236
|
+
if (overallBehavior) ret._$.behavior(overallBehavior)
|
|
1237
|
+
return ret
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
/**
|
|
1241
|
+
* Set the component options
|
|
1242
|
+
*
|
|
1243
|
+
* If called multiple times, only the latest call is valid.
|
|
1244
|
+
*/
|
|
1245
|
+
options(
|
|
1246
|
+
options: ComponentDefinitionOptions,
|
|
1247
|
+
): ResolveBehaviorBuilder<this, TChainingFilter> {
|
|
1248
|
+
this._$options = options
|
|
1249
|
+
return this as any
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
/** Use another behavior */
|
|
1253
|
+
behavior<
|
|
1254
|
+
UData extends DataList,
|
|
1255
|
+
UProperty extends PropertyList,
|
|
1256
|
+
UMethod extends MethodList,
|
|
1257
|
+
UChainingFilter extends ChainingFilterType,
|
|
1258
|
+
>(
|
|
1259
|
+
behavior: Behavior<UData, UProperty, UMethod, UChainingFilter>,
|
|
1260
|
+
): ResolveBehaviorBuilder<
|
|
1261
|
+
ComponentBuilder<
|
|
1262
|
+
TPrevData,
|
|
1263
|
+
TData & UData,
|
|
1264
|
+
TProperty & UProperty,
|
|
1265
|
+
TMethod & UMethod,
|
|
1266
|
+
UChainingFilter,
|
|
1267
|
+
TPendingChainingFilter,
|
|
1268
|
+
TComponentExport
|
|
1269
|
+
>,
|
|
1270
|
+
UChainingFilter
|
|
1271
|
+
> {
|
|
1272
|
+
this._$parents.push(behavior as GeneralBehavior)
|
|
1273
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
1274
|
+
this._$ = this._$.behavior(behavior._$)
|
|
1275
|
+
return this as any
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
/** Set the export value when the component is being selected */
|
|
1279
|
+
export<TNewComponentExport>(
|
|
1280
|
+
f: (
|
|
1281
|
+
this: Component<TData, TProperty, TMethod, TComponentExport>,
|
|
1282
|
+
source: GeneralComponent | null,
|
|
1283
|
+
) => TNewComponentExport,
|
|
1284
|
+
): ResolveBehaviorBuilder<
|
|
1285
|
+
ComponentBuilder<
|
|
1286
|
+
TPrevData,
|
|
1287
|
+
TData,
|
|
1288
|
+
TProperty,
|
|
1289
|
+
TMethod,
|
|
1290
|
+
TChainingFilter,
|
|
1291
|
+
TPendingChainingFilter,
|
|
1292
|
+
TNewComponentExport
|
|
1293
|
+
>,
|
|
1294
|
+
TChainingFilter
|
|
1295
|
+
> {
|
|
1296
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
1297
|
+
this._$export = f as any
|
|
1298
|
+
return this as any
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
/**
|
|
1302
|
+
* Add some template data fields
|
|
1303
|
+
*
|
|
1304
|
+
* It does not support raw data, but a `gen` function which returns the new data fields.
|
|
1305
|
+
* The `gen` function executes once during component creation.
|
|
1306
|
+
*/
|
|
1307
|
+
override data<T extends DataList>(
|
|
1308
|
+
gen: (() => typeUtils.NewFieldList<AllData<TData, TProperty>, T>),
|
|
1309
|
+
): ResolveBehaviorBuilder<
|
|
1310
|
+
ComponentBuilder<
|
|
1311
|
+
T,
|
|
1312
|
+
TData & T,
|
|
1313
|
+
TProperty,
|
|
1314
|
+
TMethod,
|
|
1315
|
+
TChainingFilter,
|
|
1316
|
+
TPendingChainingFilter,
|
|
1317
|
+
TComponentExport
|
|
1318
|
+
>,
|
|
1319
|
+
TChainingFilter
|
|
1320
|
+
> {
|
|
1321
|
+
return super.data(gen) as any
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
/**
|
|
1325
|
+
* Add a single property
|
|
1326
|
+
*
|
|
1327
|
+
* The property name should be different from other properties.
|
|
1328
|
+
*/
|
|
1329
|
+
override property<
|
|
1330
|
+
N extends string,
|
|
1331
|
+
T extends PropertyType,
|
|
1332
|
+
V extends PropertyTypeToValueType<T>,
|
|
1333
|
+
>(
|
|
1334
|
+
name: N,
|
|
1335
|
+
def: N extends keyof (TData & TProperty) ? never : typeUtils.PropertyListItem<T, V>,
|
|
1336
|
+
): ResolveBehaviorBuilder<
|
|
1337
|
+
ComponentBuilder<
|
|
1338
|
+
TPrevData,
|
|
1339
|
+
TData,
|
|
1340
|
+
TProperty & Record<N, unknown extends V ? T : typeUtils.PropertyOption<T, V>>,
|
|
1341
|
+
TMethod,
|
|
1342
|
+
TChainingFilter,
|
|
1343
|
+
TPendingChainingFilter,
|
|
1344
|
+
TComponentExport
|
|
1345
|
+
>,
|
|
1346
|
+
TChainingFilter
|
|
1347
|
+
> {
|
|
1348
|
+
return super.property(name, def) as any
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
/**
|
|
1352
|
+
* Add some public methods
|
|
1353
|
+
*
|
|
1354
|
+
* The public method can be used as an event handler, and can be visited in component instance.
|
|
1355
|
+
*/
|
|
1356
|
+
override methods<
|
|
1357
|
+
T extends MethodList,
|
|
1358
|
+
>(
|
|
1359
|
+
funcs: T & ThisType<Component<TData, TProperty, TMethod & T, any>>,
|
|
1360
|
+
): ResolveBehaviorBuilder<
|
|
1361
|
+
ComponentBuilder<
|
|
1362
|
+
TPrevData,
|
|
1363
|
+
TData,
|
|
1364
|
+
TProperty,
|
|
1365
|
+
TMethod & T,
|
|
1366
|
+
TChainingFilter,
|
|
1367
|
+
TPendingChainingFilter,
|
|
1368
|
+
TComponentExport
|
|
1369
|
+
>,
|
|
1370
|
+
TChainingFilter
|
|
1371
|
+
> {
|
|
1372
|
+
return super.methods(funcs) as any
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
/**
|
|
1376
|
+
* Execute a function while component instance creation
|
|
1377
|
+
*
|
|
1378
|
+
* A `BuilderContext` is provided to tweak the component creation progress.
|
|
1379
|
+
* The return value is used as the "export" value of the behavior,
|
|
1380
|
+
* which can be imported by other behaviors.
|
|
1381
|
+
*/
|
|
1382
|
+
override init<TExport extends Record<string, TaggedMethod<(...args: any[]) => any>> | void>(
|
|
1383
|
+
func: (
|
|
1384
|
+
this: Component<TData, TProperty, TMethod, TComponentExport>,
|
|
1385
|
+
builderContext: BuilderContext<
|
|
1386
|
+
TPrevData,
|
|
1387
|
+
TProperty,
|
|
1388
|
+
Component<TData, TProperty, TMethod, TComponentExport>
|
|
1389
|
+
>,
|
|
1390
|
+
) => TExport,
|
|
1391
|
+
// eslint-disable-next-line function-paren-newline
|
|
1392
|
+
): ResolveBehaviorBuilder<
|
|
1393
|
+
ComponentBuilder<
|
|
1394
|
+
TPrevData,
|
|
1395
|
+
TData,
|
|
1396
|
+
TProperty,
|
|
1397
|
+
TMethod,
|
|
1398
|
+
TChainingFilter,
|
|
1399
|
+
TPendingChainingFilter,
|
|
1400
|
+
TComponentExport
|
|
1401
|
+
>,
|
|
1402
|
+
TChainingFilter
|
|
1403
|
+
> {
|
|
1404
|
+
return super.init(func) as any
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
/** Apply a classic definition object */
|
|
1408
|
+
override definition<
|
|
1409
|
+
TNewData extends DataList = Empty,
|
|
1410
|
+
TNewProperty extends PropertyList = Empty,
|
|
1411
|
+
TNewMethod extends MethodList = Empty,
|
|
1412
|
+
TNewComponentExport = undefined,
|
|
1413
|
+
>(
|
|
1414
|
+
def: ComponentDefinition<
|
|
1415
|
+
TNewData,
|
|
1416
|
+
TNewProperty,
|
|
1417
|
+
TNewMethod,
|
|
1418
|
+
TNewComponentExport
|
|
1419
|
+
> & ThisType<
|
|
1420
|
+
Component<
|
|
1421
|
+
TData & TNewData,
|
|
1422
|
+
TProperty & TNewProperty,
|
|
1423
|
+
TMethod & TNewMethod,
|
|
1424
|
+
TNewComponentExport
|
|
1425
|
+
>
|
|
1426
|
+
>,
|
|
1427
|
+
): ResolveBehaviorBuilder<
|
|
1428
|
+
ComponentBuilder<
|
|
1429
|
+
TPrevData,
|
|
1430
|
+
TData & TNewData,
|
|
1431
|
+
TProperty & TNewProperty,
|
|
1432
|
+
TMethod & TNewMethod,
|
|
1433
|
+
TChainingFilter,
|
|
1434
|
+
TPendingChainingFilter,
|
|
1435
|
+
TNewComponentExport
|
|
1436
|
+
>,
|
|
1437
|
+
TChainingFilter
|
|
1438
|
+
> {
|
|
1439
|
+
super.definition(def)
|
|
1440
|
+
if (def.options) this.options(def.options)
|
|
1441
|
+
return this as any
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
pageDefinition<
|
|
1445
|
+
TNewData extends DataList,
|
|
1446
|
+
TNewExtraFields extends { [k: PropertyKey]: any },
|
|
1447
|
+
>(
|
|
1448
|
+
def: PageDefinition<
|
|
1449
|
+
TNewData,
|
|
1450
|
+
TNewExtraFields
|
|
1451
|
+
> & ThisType<Component<TData & TNewData, TProperty, TMethod & TNewExtraFields, undefined>>,
|
|
1452
|
+
): ResolveBehaviorBuilder<
|
|
1453
|
+
ComponentBuilder<
|
|
1454
|
+
TPrevData,
|
|
1455
|
+
TData & TNewData,
|
|
1456
|
+
TProperty,
|
|
1457
|
+
TMethod & TNewExtraFields,
|
|
1458
|
+
TChainingFilter,
|
|
1459
|
+
TPendingChainingFilter,
|
|
1460
|
+
TComponentExport
|
|
1461
|
+
>,
|
|
1462
|
+
TChainingFilter
|
|
1463
|
+
> {
|
|
1464
|
+
const freeData = Object.create(null) as { [k: string]: any }
|
|
1465
|
+
const compDef = {
|
|
1466
|
+
methods: {},
|
|
1467
|
+
} as { [k: string]: any }
|
|
1468
|
+
const keys = Object.keys(def)
|
|
1469
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
1470
|
+
const k = keys[i]!
|
|
1471
|
+
if (k === 'data' || k === 'options' || k === 'behaviors') {
|
|
1472
|
+
compDef[k] = def[k]
|
|
1473
|
+
} else if (typeof def[k] === 'function') {
|
|
1474
|
+
(compDef.methods as { [k: string]: unknown })[k] = def[k] as unknown
|
|
1475
|
+
} else {
|
|
1476
|
+
(freeData as { [k: string]: unknown })[k] = def[k]
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
this.definition(compDef)
|
|
1480
|
+
this._$.init(function () {
|
|
1481
|
+
Object.assign(this, glassEasel.dataUtils.simpleDeepCopy(freeData))
|
|
1482
|
+
})
|
|
1483
|
+
return this as any
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
/**
|
|
1487
|
+
* Finish the component definition process
|
|
1488
|
+
*/
|
|
1489
|
+
register(): ComponentType<TData, TProperty, TMethod, TComponentExport> {
|
|
1490
|
+
const is = this._$is
|
|
1491
|
+
const codeSpace = this._$codeSpace
|
|
1492
|
+
|
|
1493
|
+
// processing common fields
|
|
1494
|
+
const [options, styleIsolation] = codeSpace.prepareComponentOptions(is, this._$options)
|
|
1495
|
+
this._$.options(options)
|
|
1496
|
+
const staticConfig = codeSpace.getComponentStaticConfig(is)
|
|
1497
|
+
const using = staticConfig?.usingComponents
|
|
1498
|
+
const generics = staticConfig?.generics
|
|
1499
|
+
const placeholder = staticConfig?.placeholder
|
|
1500
|
+
if (using) this._$.usingComponents(using)
|
|
1501
|
+
if (generics) this._$.generics(generics)
|
|
1502
|
+
if (placeholder) this._$.placeholders(placeholder)
|
|
1503
|
+
const template = codeSpace.getCompiledTemplate(is)
|
|
1504
|
+
if (template) this._$.template(template)
|
|
1505
|
+
|
|
1506
|
+
// do registration
|
|
1507
|
+
codeSpace._$styleIsolationMap[is] = styleIsolation
|
|
1508
|
+
const compDef = this._$.registerComponent()
|
|
1509
|
+
this._$alias?.forEach((alias) => {
|
|
1510
|
+
this._$codeSpace.getComponentSpace().exportComponent(alias, this._$is)
|
|
1511
|
+
})
|
|
1512
|
+
return new ComponentType(compDef)
|
|
1513
|
+
}
|
|
1514
|
+
}
|