@@ -4,21 +4,13 @@ import { MapType, QuickMap } from "./map";
4
4
import { OptionalType } from "./optional" ;
5
5
import { ReferenceType , SafeReferenceType } from "./reference" ;
6
6
import { DateType , IntegerType , LiteralType , SimpleType } from "./simple" ;
7
- import { $identifier } from "./symbols" ;
8
- import type { IAnyClassModelType , IAnyType , IClassModelType , Instance , InstantiateContext , SnapshotIn , ValidOptionalValue } from "./types" ;
9
-
10
- export const $fastInstantiator = Symbol . for ( "mqt:class-model-instantiator" ) ;
11
-
12
- export type CompiledInstantiator < T extends IAnyClassModelType = IAnyClassModelType > = (
13
- instance : Instance < T > ,
14
- snapshot : SnapshotIn < T > ,
15
- context : InstantiateContext
16
- ) => void ;
7
+ import { $env , $identifier , $memoizedKeys , $memos , $parent , $readOnly , $type } from "./symbols" ;
8
+ import type { IAnyType , IClassModelType , ValidOptionalValue } from "./types" ;
17
9
18
10
/**
19
11
* Compiles a fast function for taking snapshots and turning them into instances of a class model.
20
12
**/
21
- export const buildFastInstantiator = < T extends IClassModelType < Record < string , IAnyType > , any , any > > ( model : T ) : CompiledInstantiator < T > => {
13
+ export const buildFastInstantiator = < T extends IClassModelType < Record < string , IAnyType > , any , any > > ( model : T ) : T => {
22
14
return new InstantiatorBuilder ( model ) . build ( ) ;
23
15
} ;
24
16
@@ -38,15 +30,15 @@ class InstantiatorBuilder<T extends IClassModelType<Record<string, IAnyType>, an
38
30
39
31
constructor ( readonly model : T ) { }
40
32
41
- build ( ) : CompiledInstantiator < T > {
33
+ build ( ) : T {
42
34
const segments : string [ ] = [ ] ;
43
35
44
36
for ( const [ key , type ] of Object . entries ( this . model . properties ) ) {
45
37
if ( isDirectlyAssignableType ( type ) ) {
46
38
segments . push ( `
47
39
// simple type for ${ key }
48
- instance ["${ key } "] = ${ this . expressionForDirectlyAssignableType ( key , type ) } ;
49
- ` ) ;
40
+ this ["${ key } "] = ${ this . expressionForDirectlyAssignableType ( key , type ) } ;
41
+ ` ) ;
50
42
} else if ( type instanceof OptionalType ) {
51
43
segments . push ( this . assignmentExpressionForOptionalType ( key , type ) ) ;
52
44
} else if ( type instanceof ReferenceType || type instanceof SafeReferenceType ) {
@@ -58,43 +50,71 @@ class InstantiatorBuilder<T extends IClassModelType<Record<string, IAnyType>, an
58
50
} else {
59
51
segments . push ( `
60
52
// instantiate fallback for ${ key } of type ${ type . name }
61
- instance ["${ key } "] = ${ this . alias ( `model.properties["${ key } "]` ) } .instantiate(
53
+ this ["${ key } "] = ${ this . alias ( `model.properties["${ key } "]` ) } .instantiate(
62
54
snapshot?.["${ key } "],
63
55
context,
64
- instance
56
+ this
65
57
);
66
58
` ) ;
67
59
}
68
60
}
69
61
70
62
for ( const [ key , _metadata ] of Object . entries ( this . model . volatiles ) ) {
71
63
segments . push ( `
72
- instance ["${ key } "] = ${ this . alias ( `model.volatiles["${ key } "]` ) } .initializer(instance );
64
+ this ["${ key } "] = ${ this . alias ( `model.volatiles["${ key } "]` ) } .initializer(this );
73
65
` ) ;
74
66
}
75
67
76
68
const identifierProp = this . model . mstType . identifierAttribute ;
77
69
if ( identifierProp ) {
78
70
segments . push ( `
79
- const id = instance ["${ identifierProp } "];
80
- instance [$identifier] = id;
81
- context.referenceCache.set(id, instance );
71
+ const id = this ["${ identifierProp } "];
72
+ this [$identifier] = id;
73
+ context.referenceCache.set(id, this );
82
74
` ) ;
83
75
}
84
76
85
- const innerFunc = `
86
- return function Instantiate${ this . model . name } (instance, snapshot, context) {
87
- ${ segments . join ( "\n" ) }
77
+ const defineClassStatement = `
78
+ return class ${ this . model . name } extends model {
79
+ [$memos] = null;
80
+ [$memoizedKeys] = null;
81
+
82
+ constructor(
83
+ snapshot,
84
+ context,
85
+ parent,
86
+ /** @hidden */ hackyPreventInitialization = false
87
+ ) {
88
+ super(null, null, null, true);
89
+
90
+ if (hackyPreventInitialization) {
91
+ return;
92
+ }
93
+
94
+ this[$env] = context.env;
95
+ this[$parent] = parent;
96
+
97
+ ${ segments . join ( "\n" ) }
98
+ }
99
+
100
+ get [$readOnly]() {
101
+ return true;
102
+ }
103
+
104
+ get [$type]() {
105
+ return this.constructor;
106
+ }
88
107
}
89
108
` ;
90
109
91
110
const aliasFuncBody = `
92
- const { QuickMap, QuickArray, $identifier } = imports;
111
+ const { QuickMap, QuickArray, $identifier, $env, $parent, $memos, $memoizedKeys, $readOnly, $type } = imports;
112
+
93
113
${ Array . from ( this . aliases . entries ( ) )
94
114
. map ( ( [ expression , alias ] ) => `const ${ alias } = ${ expression } ;` )
95
115
. join ( "\n" ) }
96
116
97
- ${ innerFunc }
117
+ ${ defineClassStatement }
98
118
` ;
99
119
100
120
// console.log(`function for ${this.model.name}`, "\n\n\n", aliasFuncBody, "\n\n\n");
@@ -105,7 +125,7 @@ class InstantiatorBuilder<T extends IClassModelType<Record<string, IAnyType>, an
105
125
const aliasFunc = new Function ( "model" , "imports" , aliasFuncBody ) ;
106
126
107
127
// evaluate aliases and get created inner function
108
- return aliasFunc ( this . model , { $identifier, QuickMap, QuickArray } ) as CompiledInstantiator < T > ;
128
+ return aliasFunc ( this . model , { $identifier, $env , $parent , $memos , $memoizedKeys , $readOnly , $type , QuickMap, QuickArray } ) as T ;
109
129
}
110
130
111
131
private expressionForDirectlyAssignableType ( key : string , type : DirectlyAssignableType ) {
@@ -132,7 +152,7 @@ class InstantiatorBuilder<T extends IClassModelType<Record<string, IAnyType>, an
132
152
if (${ varName } ) {
133
153
const referencedInstance = context.referenceCache.get(${ varName } );
134
154
if (referencedInstance) {
135
- instance ["${ key } "] = referencedInstance;
155
+ this ["${ key } "] = referencedInstance;
136
156
return;
137
157
}
138
158
}
@@ -162,14 +182,14 @@ class InstantiatorBuilder<T extends IClassModelType<Record<string, IAnyType>, an
162
182
let createExpression ;
163
183
if ( isDirectlyAssignableType ( type . type ) ) {
164
184
createExpression = `
165
- instance ["${ key } "] = ${ varName }
185
+ this ["${ key } "] = ${ varName }
166
186
` ;
167
187
} else {
168
188
createExpression = `
169
- instance ["${ key } "] = ${ this . alias ( `model.properties["${ key } "].type` ) } .instantiate(
189
+ this ["${ key } "] = ${ this . alias ( `model.properties["${ key } "].type` ) } .instantiate(
170
190
${ varName } ,
171
191
context,
172
- instance
192
+ this
173
193
);
174
194
` ;
175
195
}
@@ -188,20 +208,20 @@ class InstantiatorBuilder<T extends IClassModelType<Record<string, IAnyType>, an
188
208
if ( ! isDirectlyAssignableType ( type . childrenType ) || type . childrenType instanceof DateType ) {
189
209
return `
190
210
// instantiate fallback for ${ key } of type ${ type . name }
191
- instance ["${ key } "] = ${ this . alias ( `model.properties["${ key } "]` ) } .instantiate(
211
+ this ["${ key } "] = ${ this . alias ( `model.properties["${ key } "]` ) } .instantiate(
192
212
snapshot?.["${ key } "],
193
213
context,
194
- instance
214
+ this
195
215
);
196
216
` ;
197
217
}
198
218
199
219
// Directly assignable types are primitives so we don't need to worry about setting parent/env/etc. Hence, we just
200
220
// pass the snapshot straight through to the constructor.
201
221
return `
202
- instance ["${ key } "] = new QuickArray(
222
+ this ["${ key } "] = new QuickArray(
203
223
${ this . alias ( `model.properties["${ key } "]` ) } ,
204
- instance ,
224
+ this ,
205
225
context.env,
206
226
...(snapshot?.["${ key } "] ?? [])
207
227
);
@@ -212,8 +232,8 @@ class InstantiatorBuilder<T extends IClassModelType<Record<string, IAnyType>, an
212
232
const mapVarName = `map${ key } ` ;
213
233
const snapshotVarName = `snapshotValue${ key } ` ;
214
234
return `
215
- const ${ mapVarName } = new QuickMap(${ this . alias ( `model.properties["${ key } "]` ) } , instance , context.env);
216
- instance ["${ key } "] = ${ mapVarName } ;
235
+ const ${ mapVarName } = new QuickMap(${ this . alias ( `model.properties["${ key } "]` ) } , this , context.env);
236
+ this ["${ key } "] = ${ mapVarName } ;
217
237
const ${ snapshotVarName } = snapshot?.["${ key } "];
218
238
if (${ snapshotVarName } ) {
219
239
for (const key in ${ snapshotVarName } ) {
0 commit comments