@@ -27,41 +27,6 @@ export interface StatefulModule {
27
27
} ;
28
28
}
29
29
30
- export function createStateGetter < TargetModule extends StatefulModule > (
31
- target : TargetModule ,
32
- propertyKey : string ,
33
- valueReference : Reference < State < unknown > | undefined > ,
34
- prefix : string ,
35
- debugInfo : { parentName : string ; baseModuleNames : string }
36
- ) {
37
- return ( ) => {
38
- const { value } = valueReference ;
39
- // Short-circuit this to return the state in case its already initialized
40
- if ( value !== undefined && value . path !== undefined ) {
41
- return value ;
42
- }
43
-
44
- if ( target . name === undefined ) {
45
- throw errors . missingName ( target . constructor . name ) ;
46
- }
47
-
48
- if ( ! target . parent ) {
49
- throw errors . missingParent (
50
- target . constructor . name ,
51
- debugInfo . parentName ,
52
- debugInfo . baseModuleNames
53
- ) ;
54
- }
55
-
56
- const path = Path . fromProperty ( target . name , propertyKey , prefix ) ;
57
- if ( value ) {
58
- value . path = path ;
59
- value . stateServiceProvider = target . parent . stateServiceProvider ;
60
- }
61
- return value ;
62
- } ;
63
- }
64
-
65
30
/**
66
31
* Decorates a runtime module property as state, passing down some
67
32
* underlying values to improve developer experience.
@@ -71,31 +36,62 @@ export function state() {
71
36
target : TargetTransitioningModule ,
72
37
propertyKey : string
73
38
) => {
74
- const stateReference = createReference < State < unknown > | undefined > (
75
- undefined
76
- ) ;
77
-
78
- const isProtocol = target instanceof TransitioningProtocolModule ;
79
- const statePrefix = isProtocol
80
- ? PROTOKIT_PREFIXES . STATE_PROTOCOL
81
- : PROTOKIT_PREFIXES . STATE_RUNTIME ;
82
- const debugInfo = isProtocol
83
- ? { parentName : "protocol" , baseModuleNames : "...Hook" }
84
- : { parentName : "runtime" , baseModuleNames : "RuntimeModule" } ;
85
-
86
39
Object . defineProperty ( target , propertyKey , {
87
40
enumerable : true ,
88
41
89
- get : createStateGetter (
90
- target ,
91
- propertyKey ,
92
- stateReference ,
93
- statePrefix ,
94
- debugInfo
95
- ) ,
42
+ get : function get ( this : TargetTransitioningModule ) {
43
+ // The reason for why we store the state value in this weird way is that
44
+ // in the decorator on the prototype of the class. This means that if there
45
+ // are multiple instances of this class, any closure that this getter shares
46
+ // will be the same for all instances.
47
+ // Therefore, we need to somehow save the set instance on the instance itself
48
+
49
+ // eslint-disable-next-line max-len
50
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions,@typescript-eslint/no-unsafe-assignment
51
+ const reference : Reference < State < unknown > > | undefined = ( this as any ) [
52
+ `protokit_state_cache_${ propertyKey } `
53
+ ] ;
54
+
55
+ // Short-circuit this to return the state in case its already initialized
56
+ if ( reference !== undefined && reference . value . path !== undefined ) {
57
+ return reference . value ;
58
+ }
59
+
60
+ if ( this . name === undefined ) {
61
+ throw errors . missingName ( this . constructor . name ) ;
62
+ }
63
+
64
+ const isProtocol = target instanceof TransitioningProtocolModule ;
65
+
66
+ if ( ! this . parent ) {
67
+ const debugInfo = isProtocol
68
+ ? { parentName : "protocol" , baseModuleNames : "...Hook" }
69
+ : { parentName : "runtime" , baseModuleNames : "RuntimeModule" } ;
70
+
71
+ throw errors . missingParent (
72
+ this . constructor . name ,
73
+ debugInfo . parentName ,
74
+ debugInfo . baseModuleNames
75
+ ) ;
76
+ }
77
+
78
+ const statePrefix = isProtocol
79
+ ? PROTOKIT_PREFIXES . STATE_PROTOCOL
80
+ : PROTOKIT_PREFIXES . STATE_RUNTIME ;
81
+ const path = Path . fromProperty ( this . name , propertyKey , statePrefix ) ;
82
+ if ( reference ) {
83
+ const { value } = reference ;
84
+ value . path = path ;
85
+ value . stateServiceProvider = this . parent . stateServiceProvider ;
86
+ }
87
+ return reference ?. value ;
88
+ } ,
96
89
97
- set : ( newValue : State < unknown > ) => {
98
- stateReference . value = newValue ;
90
+ set : function set (
91
+ this : TargetTransitioningModule & any ,
92
+ newValue : State < unknown >
93
+ ) {
94
+ this [ `protokit_state_cache_${ propertyKey } ` ] = createReference ( newValue ) ;
99
95
} ,
100
96
} ) ;
101
97
} ;
0 commit comments