@@ -4,21 +4,13 @@ import { MapType, QuickMap } from "./map";
44import { OptionalType } from "./optional" ;
55import { ReferenceType , SafeReferenceType } from "./reference" ;
66import { 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" ;
179
1810/**
1911 * Compiles a fast function for taking snapshots and turning them into instances of a class model.
2012 **/
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 => {
2214 return new InstantiatorBuilder ( model ) . build ( ) ;
2315} ;
2416
@@ -38,15 +30,15 @@ class InstantiatorBuilder<T extends IClassModelType<Record<string, IAnyType>, an
3830
3931 constructor ( readonly model : T ) { }
4032
41- build ( ) : CompiledInstantiator < T > {
33+ build ( ) : T {
4234 const segments : string [ ] = [ ] ;
4335
4436 for ( const [ key , type ] of Object . entries ( this . model . properties ) ) {
4537 if ( isDirectlyAssignableType ( type ) ) {
4638 segments . push ( `
4739 // simple type for ${ key }
48- instance ["${ key } "] = ${ this . expressionForDirectlyAssignableType ( key , type ) } ;
49- ` ) ;
40+ this ["${ key } "] = ${ this . expressionForDirectlyAssignableType ( key , type ) } ;
41+ ` ) ;
5042 } else if ( type instanceof OptionalType ) {
5143 segments . push ( this . assignmentExpressionForOptionalType ( key , type ) ) ;
5244 } else if ( type instanceof ReferenceType || type instanceof SafeReferenceType ) {
@@ -58,43 +50,71 @@ class InstantiatorBuilder<T extends IClassModelType<Record<string, IAnyType>, an
5850 } else {
5951 segments . push ( `
6052 // 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(
6254 snapshot?.["${ key } "],
6355 context,
64- instance
56+ this
6557 );
6658 ` ) ;
6759 }
6860 }
6961
7062 for ( const [ key , _metadata ] of Object . entries ( this . model . volatiles ) ) {
7163 segments . push ( `
72- instance ["${ key } "] = ${ this . alias ( `model.volatiles["${ key } "]` ) } .initializer(instance );
64+ this ["${ key } "] = ${ this . alias ( `model.volatiles["${ key } "]` ) } .initializer(this );
7365 ` ) ;
7466 }
7567
7668 const identifierProp = this . model . mstType . identifierAttribute ;
7769 if ( identifierProp ) {
7870 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 );
8274 ` ) ;
8375 }
8476
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+ }
88107 }
89108 ` ;
90109
91110 const aliasFuncBody = `
92- const { QuickMap, QuickArray, $identifier } = imports;
111+ const { QuickMap, QuickArray, $identifier, $env, $parent, $memos, $memoizedKeys, $readOnly, $type } = imports;
112+
93113 ${ Array . from ( this . aliases . entries ( ) )
94114 . map ( ( [ expression , alias ] ) => `const ${ alias } = ${ expression } ;` )
95115 . join ( "\n" ) }
96116
97- ${ innerFunc }
117+ ${ defineClassStatement }
98118 ` ;
99119
100120 // 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
105125 const aliasFunc = new Function ( "model" , "imports" , aliasFuncBody ) ;
106126
107127 // 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 ;
109129 }
110130
111131 private expressionForDirectlyAssignableType ( key : string , type : DirectlyAssignableType ) {
@@ -132,7 +152,7 @@ class InstantiatorBuilder<T extends IClassModelType<Record<string, IAnyType>, an
132152 if (${ varName } ) {
133153 const referencedInstance = context.referenceCache.get(${ varName } );
134154 if (referencedInstance) {
135- instance ["${ key } "] = referencedInstance;
155+ this ["${ key } "] = referencedInstance;
136156 return;
137157 }
138158 }
@@ -162,14 +182,14 @@ class InstantiatorBuilder<T extends IClassModelType<Record<string, IAnyType>, an
162182 let createExpression ;
163183 if ( isDirectlyAssignableType ( type . type ) ) {
164184 createExpression = `
165- instance ["${ key } "] = ${ varName }
185+ this ["${ key } "] = ${ varName }
166186 ` ;
167187 } else {
168188 createExpression = `
169- instance ["${ key } "] = ${ this . alias ( `model.properties["${ key } "].type` ) } .instantiate(
189+ this ["${ key } "] = ${ this . alias ( `model.properties["${ key } "].type` ) } .instantiate(
170190 ${ varName } ,
171191 context,
172- instance
192+ this
173193 );
174194 ` ;
175195 }
@@ -188,20 +208,20 @@ class InstantiatorBuilder<T extends IClassModelType<Record<string, IAnyType>, an
188208 if ( ! isDirectlyAssignableType ( type . childrenType ) || type . childrenType instanceof DateType ) {
189209 return `
190210 // 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(
192212 snapshot?.["${ key } "],
193213 context,
194- instance
214+ this
195215 );
196216 ` ;
197217 }
198218
199219 // Directly assignable types are primitives so we don't need to worry about setting parent/env/etc. Hence, we just
200220 // pass the snapshot straight through to the constructor.
201221 return `
202- instance ["${ key } "] = new QuickArray(
222+ this ["${ key } "] = new QuickArray(
203223 ${ this . alias ( `model.properties["${ key } "]` ) } ,
204- instance ,
224+ this ,
205225 context.env,
206226 ...(snapshot?.["${ key } "] ?? [])
207227 );
@@ -212,8 +232,8 @@ class InstantiatorBuilder<T extends IClassModelType<Record<string, IAnyType>, an
212232 const mapVarName = `map${ key } ` ;
213233 const snapshotVarName = `snapshotValue${ key } ` ;
214234 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 } ;
217237 const ${ snapshotVarName } = snapshot?.["${ key } "];
218238 if (${ snapshotVarName } ) {
219239 for (const key in ${ snapshotVarName } ) {
0 commit comments