glass-easel-miniprogram-adapter 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +49 -0
  2. package/dist/glass_easel_miniprogram_adapter.d.ts +1 -0
  3. package/dist/glass_easel_miniprogram_adapter.js +2 -0
  4. package/dist/glass_easel_miniprogram_adapter.js.map +1 -0
  5. package/dist/types/src/backend.d.ts +51 -0
  6. package/dist/types/src/backend.d.ts.map +1 -0
  7. package/dist/types/src/behavior.d.ts +35 -0
  8. package/dist/types/src/behavior.d.ts.map +1 -0
  9. package/dist/types/src/component.d.ts +160 -0
  10. package/dist/types/src/component.d.ts.map +1 -0
  11. package/dist/types/src/index.d.ts +58 -0
  12. package/dist/types/src/index.d.ts.map +1 -0
  13. package/dist/types/src/selector_query.d.ts +98 -0
  14. package/dist/types/src/selector_query.d.ts.map +1 -0
  15. package/dist/types/src/space.d.ts +369 -0
  16. package/dist/types/src/space.d.ts.map +1 -0
  17. package/dist/types/src/types.d.ts +77 -0
  18. package/dist/types/src/types.d.ts.map +1 -0
  19. package/dist/types/src/utils.d.ts +2 -0
  20. package/dist/types/src/utils.d.ts.map +1 -0
  21. package/dist/types/tests/base/env.d.ts +3 -0
  22. package/dist/types/tests/base/env.d.ts.map +1 -0
  23. package/dist/types/tests/data_update.test.d.ts +2 -0
  24. package/dist/types/tests/data_update.test.d.ts.map +1 -0
  25. package/dist/types/tests/env.test.d.ts +2 -0
  26. package/dist/types/tests/env.test.d.ts.map +1 -0
  27. package/dist/types/tests/selector.test.d.ts +2 -0
  28. package/dist/types/tests/selector.test.d.ts.map +1 -0
  29. package/dist/types/tests/space.test.d.ts +2 -0
  30. package/dist/types/tests/space.test.d.ts.map +1 -0
  31. package/dist/types/tests/trait_behavior.test.d.ts +2 -0
  32. package/dist/types/tests/trait_behavior.test.d.ts.map +1 -0
  33. package/jest.config.js +13 -0
  34. package/package.json +32 -0
  35. package/src/backend.ts +106 -0
  36. package/src/behavior.ts +101 -0
  37. package/src/component.ts +476 -0
  38. package/src/index.ts +82 -0
  39. package/src/selector_query.ts +356 -0
  40. package/src/space.ts +1514 -0
  41. package/src/types.ts +85 -0
  42. package/src/utils.ts +3 -0
  43. package/tests/base/env.ts +20 -0
  44. package/tests/data_update.test.ts +92 -0
  45. package/tests/env.test.ts +141 -0
  46. package/tests/selector.test.ts +407 -0
  47. package/tests/space.test.ts +953 -0
  48. package/tests/trait_behavior.test.ts +141 -0
  49. package/tsconfig.json +11 -0
  50. package/webpack.config.js +78 -0
@@ -0,0 +1,476 @@
1
+ import * as glassEasel from 'glass-easel'
2
+ import {
3
+ utils as typeUtils,
4
+ } from './types'
5
+ import { ComponentType, GeneralBehavior, TraitBehavior } from './behavior'
6
+ import { SelectorQuery } from './selector_query'
7
+
8
+ type DataList = typeUtils.DataList
9
+ type PropertyList = typeUtils.PropertyList
10
+ type MethodList = typeUtils.MethodList
11
+ export type AllData<
12
+ TData extends DataList,
13
+ TProperty extends PropertyList,
14
+ > = typeUtils.DataWithPropertyValues<TData, TProperty>
15
+
16
+ type ExportType<
17
+ UData extends DataList,
18
+ UProperty extends PropertyList,
19
+ UMethod extends MethodList,
20
+ UComponentExport,
21
+ > = (
22
+ UComponentExport extends undefined
23
+ ? Component<UData, UProperty, UMethod, UComponentExport>
24
+ : UComponentExport
25
+ )
26
+
27
+ const filterComponentExportWithType = <
28
+ UData extends DataList,
29
+ UProperty extends PropertyList,
30
+ UMethod extends MethodList,
31
+ UComponentExport,
32
+ >(
33
+ source: ComponentCaller<any, any, any, any>,
34
+ elem: glassEasel.Element,
35
+ componentType: ComponentType<UData, UProperty, UMethod, UComponentExport>,
36
+ ): ExportType<UData, UProperty, UMethod, UComponentExport> | undefined => {
37
+ const comp = elem.asInstanceOf(componentType._$)
38
+ if (comp === null) return undefined
39
+ const selectedSpace = comp.getRootBehavior().ownerSpace
40
+ const uncheckedCaller = comp.getMethodCaller()
41
+ const caller = uncheckedCaller instanceof ComponentCaller ? uncheckedCaller : null
42
+ const sourceSpace = source._$.getRootBehavior().ownerSpace
43
+ const defaultResult = selectedSpace !== sourceSpace ? null : caller
44
+ const ret = caller?._$export?.(selectedSpace !== sourceSpace ? null : source) as unknown
45
+ if (ret === undefined) {
46
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
47
+ return defaultResult as any
48
+ }
49
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
50
+ return ret as any
51
+ }
52
+
53
+ const filterComponentExport = (
54
+ source: ComponentCaller<any, any, any, any>,
55
+ elem: glassEasel.Element,
56
+ ): any => {
57
+ if (elem instanceof glassEasel.Component) {
58
+ const selectedSpace = elem.getRootBehavior().ownerSpace
59
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
60
+ const uncheckedCaller = elem.getMethodCaller()
61
+ const caller = uncheckedCaller instanceof ComponentCaller ? uncheckedCaller : null
62
+ const sourceSpace = source._$.getRootBehavior().ownerSpace
63
+ const defaultResult = selectedSpace !== sourceSpace ? null : caller
64
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
65
+ const ret = caller?._$export?.(selectedSpace !== sourceSpace ? null : source)
66
+ if (ret === undefined) {
67
+ return defaultResult as any
68
+ }
69
+ return ret
70
+ }
71
+ return undefined
72
+ }
73
+
74
+ export type GeneralComponent = Component<any, any, any, any>
75
+
76
+ export type Component<
77
+ TData extends DataList,
78
+ TProperty extends PropertyList,
79
+ TMethod extends MethodList,
80
+ TComponentExport,
81
+ > = ComponentCaller<TData, TProperty, TMethod, TComponentExport>
82
+ & { [k in keyof TMethod]: TMethod[k] }
83
+
84
+ export class ComponentCaller<
85
+ TData extends DataList,
86
+ TProperty extends PropertyList,
87
+ TMethod extends MethodList,
88
+ TComponentExport,
89
+ > {
90
+ /** @internal */
91
+ _$!: glassEasel.Component<
92
+ TData,
93
+ TProperty,
94
+ TMethod
95
+ >
96
+ /** @internal */
97
+ _$export?: (source: GeneralComponent | null) => TComponentExport
98
+
99
+ /** The component path in the code space */
100
+ get is(): string {
101
+ return this._$.is
102
+ }
103
+ set is(value: string) {
104
+ Object.defineProperty(this, 'is', {
105
+ value,
106
+ writable: true,
107
+ enumerable: true,
108
+ configurable: true,
109
+ })
110
+ }
111
+
112
+ /** The `id` field in the template */
113
+ get id(): string {
114
+ return this._$.id
115
+ }
116
+ set id(value: string) {
117
+ Object.defineProperty(this, 'id', {
118
+ value,
119
+ writable: true,
120
+ enumerable: true,
121
+ configurable: true,
122
+ })
123
+ }
124
+
125
+ /** The `data-*` field in the template */
126
+ get dataset(): { [key: string]: any } | null {
127
+ return this._$.dataset
128
+ }
129
+ set dataset(value: { [key: string]: any } | null) {
130
+ Object.defineProperty(this, 'dataset', {
131
+ value,
132
+ writable: true,
133
+ enumerable: true,
134
+ configurable: true,
135
+ })
136
+ }
137
+
138
+ /** The component data and property values */
139
+ get data(): AllData<TData, TProperty> {
140
+ return this._$.data
141
+ }
142
+ set data(value: AllData<TData, TProperty>) {
143
+ Object.defineProperty(this, 'data', {
144
+ value,
145
+ writable: true,
146
+ enumerable: true,
147
+ configurable: true,
148
+ })
149
+ }
150
+
151
+ /** The component data and property values (same as `data` ) */
152
+ get properties(): AllData<TData, TProperty> {
153
+ return this._$.data
154
+ }
155
+ set properties(value: AllData<TData, TProperty>) {
156
+ Object.defineProperty(this, 'properties', {
157
+ value,
158
+ writable: true,
159
+ enumerable: true,
160
+ configurable: true,
161
+ })
162
+ }
163
+
164
+ /**
165
+ * Group several data update calls
166
+ *
167
+ * This method is designed for hinting the backend that some updates should be handled together.
168
+ * However, this is done automatically now,
169
+ * so this method is just for backward compatibilities.
170
+ */
171
+ // eslint-disable-next-line class-methods-use-this
172
+ groupSetData(callback: () => void) {
173
+ callback()
174
+ }
175
+
176
+ /**
177
+ * Do a classic data update
178
+ *
179
+ * The `callback` is called after the update applies in the backend.
180
+ * In most cases, you SHOULD NOT wait the backend update (that might be very slow),
181
+ * and most calls, including read calls such as `selectComponent` , simply works immediately.
182
+ * However, when called inside observers,
183
+ * the data update will not be applied to templates immediately
184
+ * (it is recommanded to use `updateData` instead in observers).
185
+ */
186
+ setData(
187
+ newData: Partial<typeUtils.SetDataSetter<typeUtils.DataWithPropertyValues<TData, TProperty>>>,
188
+ callback?: () => void,
189
+ ): void
190
+ setData(data: Record<string, any>, callback?: () => void) {
191
+ this._$.setData(data as any)
192
+ if (callback) {
193
+ glassEasel.triggerRender(this._$, () => {
194
+ callback()
195
+ })
196
+ }
197
+ }
198
+
199
+ /**
200
+ * Schedule a classic data updates
201
+ *
202
+ * The data update will not be applied until next `setData` or `applyDataUpdates` call.
203
+ * When called inside observers, the data update will be applied when observer ends.
204
+ * All data observers will not be triggered immediately before applied.
205
+ * Reads of the data will get the unchanged value before applied.
206
+ */
207
+ updateData(
208
+ newData: Partial<typeUtils.SetDataSetter<typeUtils.DataWithPropertyValues<TData, TProperty>>>,
209
+ ): void
210
+ updateData(newData: Record<string, any>): void {
211
+ this._$.updateData(newData as any)
212
+ }
213
+
214
+ /**
215
+ * Schedule a data update on a single specified path
216
+ *
217
+ * The data update will not be applied until next `setData` or `applyDataUpdates` call.
218
+ * All data observers will not be triggered immediately before applied.
219
+ * Reads of the data will get the unchanged value before applied.
220
+ */
221
+ replaceDataOnPath<
222
+ T extends (string | number)[],
223
+ >(
224
+ path: readonly [...T],
225
+ data: typeUtils.GetFromDataPath<typeUtils.DataWithPropertyValues<TData, TProperty>, T>,
226
+ ): void;
227
+ replaceDataOnPath(path: any, data: any) {
228
+ this._$.replaceDataOnPath(path, data)
229
+ }
230
+
231
+ /**
232
+ * Schedule an array update
233
+ *
234
+ * The behavior is like `Array.prototype.slice` .
235
+ * Break the array before the `index`-th item, delete `del` items, and insert some items here.
236
+ * If `index` is undefined, negative, or larger than the length of the array,
237
+ * no items will be deleted and new items will be appended to the end of the array.
238
+ * The data update will not be applied until next `setData` or `applyDataUpdates` call.
239
+ * All data observers will not be triggered immediately before applied.
240
+ * Reads of the data will get the unchanged value before applied.
241
+ */
242
+ spliceArrayDataOnPath<
243
+ T extends (string | number)[],
244
+ >(
245
+ path: readonly [...T],
246
+ index: typeUtils.GetFromDataPath<
247
+ typeUtils.DataWithPropertyValues<TData, TProperty>,
248
+ T
249
+ > extends any[] ? number | undefined : never,
250
+ del: typeUtils.GetFromDataPath<
251
+ typeUtils.DataWithPropertyValues<TData, TProperty>,
252
+ T
253
+ > extends any[] ? number | undefined : never,
254
+ inserts: typeUtils.GetFromDataPath<
255
+ typeUtils.DataWithPropertyValues<TData, TProperty>,
256
+ T
257
+ > extends (infer I)[] ? I[] : never
258
+ ): void;
259
+ spliceArrayDataOnPath(
260
+ path: (string | number)[],
261
+ index: number | undefined,
262
+ del: number | undefined,
263
+ inserts: unknown[],
264
+ ) {
265
+ this._$.spliceArrayDataOnPath(path, index as any, del as any, inserts as any)
266
+ }
267
+
268
+ /**
269
+ * Apply all scheduled updates immediately
270
+ *
271
+ * Inside observers, it is generally not .
272
+ */
273
+ applyDataUpdates() {
274
+ this._$.applyDataUpdates()
275
+ }
276
+
277
+ /**
278
+ * Pending all data updates in the callback, and apply updates after callback returns
279
+ *
280
+ * This function helps grouping several `replaceDataOnPath` or `spliceArrayDataOnPath` calls,
281
+ * and then apply them at the end of the callback.
282
+ * `setData` and `applyDataUpdates` calls inside the callback still apply updates immediately.
283
+ */
284
+ groupUpdates<T>(callback: () => T): T {
285
+ return this._$.groupUpdates(callback)
286
+ }
287
+
288
+ /**
289
+ * Check whether the `other` behavior is a dependent behavior or a implemented trait behavior
290
+ */
291
+ hasBehavior(behavior: GeneralBehavior | TraitBehavior<any, any>) {
292
+ return this._$.hasBehavior(behavior._$)
293
+ }
294
+
295
+ /**
296
+ * Get the trait behavior implementation of the component
297
+ *
298
+ * Returns `undefined` if the specified trait behavior is not implemented.
299
+ */
300
+ traitBehavior<TOut extends { [key: string]: any }>(
301
+ traitBehavior: TraitBehavior<any, TOut>,
302
+ ): TOut | undefined {
303
+ return this._$.traitBehavior(traitBehavior._$)
304
+ }
305
+
306
+ /** Trigger an event */
307
+ triggerEvent(
308
+ name: string,
309
+ detail: any,
310
+ options: {
311
+ bubbles?: boolean,
312
+ composed?: boolean,
313
+ capturePhase?: boolean,
314
+ },
315
+ ) {
316
+ return this._$.triggerEvent(name, detail, options)
317
+ }
318
+
319
+ /** Create a selector query for searching element inside the component */
320
+ createSelectorQuery(): SelectorQuery {
321
+ return new SelectorQuery(this)
322
+ }
323
+
324
+ // TODO support animate / applyAnimation / clearAnimation
325
+ // TODO support createIntersectionObserver
326
+ // TODO support createMediaQueryObserver
327
+ // TODO support setUpdatePerformanceListener
328
+
329
+ /**
330
+ * Query an element inside the component
331
+ *
332
+ * If `componentType` is provided, this method will check the selected component type.
333
+ * If the component type does not match, `null` is returned.
334
+ */
335
+ selectComponent(selector: string): any
336
+ selectComponent<
337
+ UData extends DataList,
338
+ UProperty extends PropertyList,
339
+ UMethod extends MethodList,
340
+ UComponentExport,
341
+ >(
342
+ selector: string,
343
+ componentType: ComponentType<UData, UProperty, UMethod, UComponentExport>,
344
+ ): ExportType<UData, UProperty, UMethod, UComponentExport> | null
345
+ selectComponent<
346
+ UData extends DataList,
347
+ UProperty extends PropertyList,
348
+ UMethod extends MethodList,
349
+ UComponentExport,
350
+ >(
351
+ selector: string,
352
+ componentType?: ComponentType<UData, UProperty, UMethod, UComponentExport>,
353
+ ): ExportType<UData, UProperty, UMethod, UComponentExport> | null {
354
+ const target = this._$.getShadowRoot()!.querySelector(selector)
355
+ if (target === null) return null
356
+ return componentType
357
+ ? filterComponentExportWithType(this, target, componentType) ?? null
358
+ : filterComponentExport(this, target) ?? null
359
+ }
360
+
361
+ /**
362
+ * Query all elements inside the component
363
+ *
364
+ * If `componentType` is provided, this method will check the selected component type.
365
+ * If a component type does not match, it is not returned.
366
+ */
367
+ selectAllComponents(selector: string): GeneralComponent[]
368
+ selectAllComponents<
369
+ UData extends DataList,
370
+ UProperty extends PropertyList,
371
+ UMethod extends MethodList,
372
+ UComponentExport,
373
+ >(
374
+ selector: string,
375
+ componentType: ComponentType<UData, UProperty, UMethod, UComponentExport>,
376
+ ): ExportType<UData, UProperty, UMethod, UComponentExport>[]
377
+ selectAllComponents<
378
+ UData extends DataList,
379
+ UProperty extends PropertyList,
380
+ UMethod extends MethodList,
381
+ UComponentExport,
382
+ >(
383
+ selector: string,
384
+ componentType?: ComponentType<UData, UProperty, UMethod, UComponentExport>,
385
+ ): ExportType<UData, UProperty, UMethod, UComponentExport>[] {
386
+ const targets = this._$.getShadowRoot()!.querySelectorAll(selector)
387
+ const ret = [] as ExportType<UData, UProperty, UMethod, UComponentExport>[]
388
+ targets.forEach((target) => {
389
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
390
+ const r = componentType
391
+ ? filterComponentExportWithType(this, target, componentType)
392
+ : filterComponentExport(this, target)
393
+ if (r !== undefined) ret.push(r)
394
+ })
395
+ return ret
396
+ }
397
+
398
+ /**
399
+ * Get the owner component
400
+ *
401
+ * If `componentType` is provided, this method will check the selected component type.
402
+ * If a component type does not match, `null` is returned.
403
+ */
404
+ selectOwnerComponent(): any
405
+ selectOwnerComponent<
406
+ UData extends DataList,
407
+ UProperty extends PropertyList,
408
+ UMethod extends MethodList,
409
+ UComponentExport,
410
+ >(
411
+ componentType: ComponentType<UData, UProperty, UMethod, UComponentExport>,
412
+ ): ExportType<UData, UProperty, UMethod, UComponentExport> | null
413
+ selectOwnerComponent<
414
+ UData extends DataList,
415
+ UProperty extends PropertyList,
416
+ UMethod extends MethodList,
417
+ UComponentExport,
418
+ >(
419
+ componentType?: ComponentType<UData, UProperty, UMethod, UComponentExport>,
420
+ ): ExportType<UData, UProperty, UMethod, UComponentExport> | null {
421
+ const target = this._$.ownerShadowRoot?.getHostNode()
422
+ if (target === undefined) return null
423
+ return componentType
424
+ ? filterComponentExportWithType(this, target, componentType) ?? null
425
+ : filterComponentExport(this, target) ?? null
426
+ }
427
+
428
+ getRelationNodes(relationKey: string): GeneralComponent[] {
429
+ return this._$.getRelationNodes(relationKey).map(
430
+ (target) => target.getMethodCaller() as any as GeneralComponent,
431
+ )
432
+ }
433
+
434
+ /** Cast the component into a general-typed one */
435
+ general(): GeneralComponent {
436
+ return this
437
+ }
438
+
439
+ /**
440
+ * Cast the component into the specified type
441
+ *
442
+ * Returns `null` if the component node is not the instance of the specified component.
443
+ */
444
+ asInstanceOf<
445
+ UData extends DataList,
446
+ UProperty extends PropertyList,
447
+ UMethod extends MethodList,
448
+ UComponentExport,
449
+ >(
450
+ componentType: ComponentType<UData, UProperty, UMethod, UComponentExport>,
451
+ ): Component<UData, UProperty, UMethod, UComponentExport> | null {
452
+ const inner = this._$.asInstanceOf(componentType._$)
453
+ if (!inner) return null
454
+ return this as unknown as Component<UData, UProperty, UMethod, UComponentExport>
455
+ }
456
+ }
457
+
458
+ export class ComponentProto<
459
+ TData extends DataList,
460
+ TProperty extends PropertyList,
461
+ TMethod extends MethodList,
462
+ TComponentExport,
463
+ > {
464
+ private proto: Component<TData, TProperty, TMethod, TComponentExport>
465
+
466
+ constructor(methods: TMethod, componentExport?: () => TComponentExport) {
467
+ this.proto = Object.create(ComponentCaller.prototype) as
468
+ Component<TData, TProperty, TMethod, TComponentExport>
469
+ Object.assign(this.proto, methods)
470
+ this.proto._$export = componentExport
471
+ }
472
+
473
+ derive(): Component<TData, TProperty, TMethod, TComponentExport> {
474
+ return Object.create(this.proto) as Component<TData, TProperty, TMethod, TComponentExport>
475
+ }
476
+ }
package/src/index.ts ADDED
@@ -0,0 +1,82 @@
1
+ import * as glassEasel from 'glass-easel'
2
+ import { AssociatedBackend } from './backend'
3
+ import {
4
+ CodeSpace,
5
+ } from './space'
6
+
7
+ export * as glassEasel from 'glass-easel'
8
+ export * as types from './types'
9
+ export { StyleIsolation } from './types'
10
+ export * from './space'
11
+ export { AssociatedBackend, Root } from './backend'
12
+ export * as component from './component'
13
+
14
+ /**
15
+ * A mini-program API environment
16
+ *
17
+ * Each environment manages multiple backend contexts.
18
+ * However, a backend context should be exclusively managed by a single environment
19
+ * (to avoid `StyleScopeId` confliction).
20
+ * It is able to create multiple `CodeSpace` within the environment.
21
+ */
22
+ export class MiniProgramEnv {
23
+ private codeSpaceMap: { [id: string]: CodeSpace }
24
+ private globalCodeSpace: CodeSpace
25
+
26
+ /**
27
+ * Create an empty mini-program API environment
28
+ */
29
+ constructor() {
30
+ this.codeSpaceMap = Object.create(null) as { [id: string]: CodeSpace }
31
+ this.globalCodeSpace = new CodeSpace(this, false, {})
32
+ }
33
+
34
+ /**
35
+ * Get a global code space in which global components can be defined
36
+ *
37
+ * External glass-easel based components can be defined in this code space.
38
+ * All global components should be defined before any other `CodeSpace` created!
39
+ */
40
+ getGlobalCodeSpace(): CodeSpace {
41
+ return this.globalCodeSpace
42
+ }
43
+
44
+ /**
45
+ * Associate a backend context
46
+ *
47
+ * If `backendContext` is not given, the DOM-based backend is used
48
+ * (causes failure if running outside browsers).
49
+ * The backend context SHOULD NOT be associated by other environments!
50
+ */
51
+ associateBackend(backendContent?: glassEasel.GeneralBackendContext): AssociatedBackend {
52
+ const ctx = backendContent ?? new glassEasel.domlikeBackend.CurrentWindowBackendContext()
53
+ return new AssociatedBackend(this, ctx)
54
+ }
55
+
56
+ /**
57
+ * Create a component space that can manage WXML, WXSS, JS and static JSON config files
58
+ *
59
+ * The space can be specified as a *main* space.
60
+ * This makes some features available:
61
+ * * the `app.wxss` will be used as a style sheet for all root components in the space;
62
+ * * the `StyleIsolation.Shared` is accepted for components in the space.
63
+ * Non-main spaces usually act as plugins.
64
+ * `publicComponents` is a map for specifying a map of aliases and component paths.
65
+ */
66
+ createCodeSpace(
67
+ id: string,
68
+ isMainSpace: boolean,
69
+ publicComponents = Object.create(null) as { [alias: string]: string },
70
+ ): CodeSpace {
71
+ const cs = new CodeSpace(this, isMainSpace, publicComponents, this.globalCodeSpace)
72
+ this.codeSpaceMap[id] = cs
73
+ return cs
74
+ }
75
+
76
+ /**
77
+ * Get a component space by the `id` specified when created
78
+ */
79
+ getCodeSpace(id: string): CodeSpace | undefined {
80
+ return this.codeSpaceMap[id]
81
+ }
82
+ }