@@ -18,60 +18,49 @@ export const javascript_visitors_runes = {
1818 /** @type {string[] } */
1919 const private_ids = [ ] ;
2020
21- /**
22- *
23- * @param {import("estree").PropertyDefinition } definition
24- * @param {boolean } is_private
25- * @param {string } name
26- */
27- function create_state_field ( definition , is_private , name ) {
28- if ( definition . value ?. type === 'CallExpression' ) {
29- const rune = get_rune ( definition . value , state . scope ) ;
30- if (
31- rune === '$state' ||
32- rune === '$state.frozen' ||
33- rune === '$derived' ||
34- rune === '$derived.by'
35- ) {
36- /** @type {import('../types.js').StateField } */
37- const field = {
38- kind :
39- rune === '$state'
40- ? 'state'
41- : rune === '$state.frozen'
42- ? 'frozen_state'
43- : rune === '$derived.by'
44- ? 'derived_call'
45- : 'derived' ,
46- // @ts -expect-error this is set in the next pass
47- id : is_private ? definition . key : null
48- } ;
49-
50- if ( is_private ) {
51- private_state . set ( name , field ) ;
52- } else {
53- public_state . set ( name , field ) ;
54- }
55- }
56- }
57- }
58-
5921 for ( const definition of node . body ) {
6022 if (
6123 definition . type === 'PropertyDefinition' &&
62- ( definition . key . type === 'Identifier' || definition . key . type === 'PrivateIdentifier' )
24+ ( definition . key . type === 'Identifier' ||
25+ definition . key . type === 'PrivateIdentifier' ||
26+ definition . key . type === 'Literal' )
6327 ) {
64- const { type, name } = definition . key ;
28+ const type = definition . key . type ;
29+ const name = get_name ( definition . key ) ;
30+ if ( ! name ) continue ;
6531
6632 const is_private = type === 'PrivateIdentifier' ;
6733 if ( is_private ) private_ids . push ( name ) ;
6834
69- create_state_field ( definition , is_private , name ) ;
70- } else if ( definition . type === 'PropertyDefinition' && definition . key . type === 'Literal' ) {
71- const name = definition . key . value
72- ?. toString ( )
73- . replaceAll ( regex_invalid_identifier_chars , '_' ) ;
74- if ( name ) create_state_field ( definition , false , name ) ;
35+ if ( definition . value ?. type === 'CallExpression' ) {
36+ const rune = get_rune ( definition . value , state . scope ) ;
37+ if (
38+ rune === '$state' ||
39+ rune === '$state.frozen' ||
40+ rune === '$derived' ||
41+ rune === '$derived.by'
42+ ) {
43+ /** @type {import('../types.js').StateField } */
44+ const field = {
45+ kind :
46+ rune === '$state'
47+ ? 'state'
48+ : rune === '$state.frozen'
49+ ? 'frozen_state'
50+ : rune === '$derived.by'
51+ ? 'derived_call'
52+ : 'derived' ,
53+ // @ts -expect-error this is set in the next pass
54+ id : is_private ? definition . key : null
55+ } ;
56+
57+ if ( is_private ) {
58+ private_state . set ( name , field ) ;
59+ } else {
60+ public_state . set ( name , field ) ;
61+ }
62+ }
63+ }
7564 }
7665 }
7766
@@ -91,114 +80,94 @@ export const javascript_visitors_runes = {
9180
9281 const child_state = { ...state , public_state, private_state } ;
9382
94- /**
95- *
96- * @param {import("estree").PropertyDefinition } definition
97- * @param {boolean } is_private
98- * @param {string } name
99- */
100- function replace_class_body ( definition , is_private , name ) {
101- const field = ( is_private ? private_state : public_state ) . get ( name ) ;
102-
103- if ( definition . value ?. type === 'CallExpression' && field !== undefined ) {
104- let value = null ;
105-
106- if ( definition . value . arguments . length > 0 ) {
107- const init = /** @type {import('estree').Expression } **/ (
108- visit ( definition . value . arguments [ 0 ] , child_state )
109- ) ;
110-
111- value =
112- field . kind === 'state'
113- ? b . call (
114- '$.source' ,
115- should_proxy_or_freeze ( init , state . scope ) ? b . call ( '$.proxy' , init ) : init
116- )
117- : field . kind === 'frozen_state'
118- ? b . call (
119- '$.source' ,
120- should_proxy_or_freeze ( init , state . scope ) ? b . call ( '$.freeze' , init ) : init
121- )
122- : field . kind === 'derived_call'
123- ? b . call ( '$.derived' , init )
124- : b . call ( '$.derived' , b . thunk ( init ) ) ;
125- } else {
126- // if no arguments, we know it's state as `$derived()` is a compile error
127- value = b . call ( '$.source' ) ;
128- }
129-
130- if ( is_private ) {
131- body . push ( b . prop_def ( field . id , value ) ) ;
132- } else {
133- // #foo;
134- const member = b . member ( b . this , field . id ) ;
135- body . push ( b . prop_def ( field . id , value ) ) ;
136-
137- // get foo() { return this.#foo; }
138- body . push ( b . method ( 'get' , definition . key , [ ] , [ b . return ( b . call ( '$.get' , member ) ) ] ) ) ;
139-
140- if ( field . kind === 'state' ) {
141- // set foo(value) { this.#foo = value; }
142- const value = b . id ( 'value' ) ;
143- body . push (
144- b . method (
145- 'set' ,
146- definition . key ,
147- [ value ] ,
148- [ b . stmt ( b . call ( '$.set' , member , b . call ( '$.proxy' , value ) ) ) ]
149- )
150- ) ;
151- }
152-
153- if ( field . kind === 'frozen_state' ) {
154- // set foo(value) { this.#foo = value; }
155- const value = b . id ( 'value' ) ;
156- body . push (
157- b . method (
158- 'set' ,
159- definition . key ,
160- [ value ] ,
161- [ b . stmt ( b . call ( '$.set' , member , b . call ( '$.freeze' , value ) ) ) ]
162- )
163- ) ;
164- }
165-
166- if ( ( field . kind === 'derived' || field . kind === 'derived_call' ) && state . options . dev ) {
167- body . push (
168- b . method (
169- 'set' ,
170- definition . key ,
171- [ b . id ( '_' ) ] ,
172- [ b . throw_error ( `Cannot update a derived property ('${ name } ')` ) ]
173- )
174- ) ;
175- }
176- }
177-
178- return true ;
179- }
180- return false ;
181- }
182-
18383 // Replace parts of the class body
18484 for ( const definition of node . body ) {
18585 if (
18686 definition . type === 'PropertyDefinition' &&
187- ( definition . key . type === 'Identifier' || definition . key . type === 'PrivateIdentifier' )
87+ ( definition . key . type === 'Identifier' ||
88+ definition . key . type === 'PrivateIdentifier' ||
89+ definition . key . type === 'Literal' )
18890 ) {
189- const name = definition . key . name ;
91+ const name = get_name ( definition . key ) ;
92+ if ( ! name ) continue ;
19093
19194 const is_private = definition . key . type === 'PrivateIdentifier' ;
95+ const field = ( is_private ? private_state : public_state ) . get ( name ) ;
19296
193- if ( replace_class_body ( definition , is_private , name ) ) {
194- continue ;
195- }
196- } else if ( definition . type === 'PropertyDefinition' && definition . key . type === 'Literal' ) {
197- const name = definition . key . value
198- ?. toString ( )
199- . replaceAll ( regex_invalid_identifier_chars , '_' ) ;
97+ if ( definition . value ?. type === 'CallExpression' && field !== undefined ) {
98+ let value = null ;
99+
100+ if ( definition . value . arguments . length > 0 ) {
101+ const init = /** @type {import('estree').Expression } **/ (
102+ visit ( definition . value . arguments [ 0 ] , child_state )
103+ ) ;
104+
105+ value =
106+ field . kind === 'state'
107+ ? b . call (
108+ '$.source' ,
109+ should_proxy_or_freeze ( init , state . scope ) ? b . call ( '$.proxy' , init ) : init
110+ )
111+ : field . kind === 'frozen_state'
112+ ? b . call (
113+ '$.source' ,
114+ should_proxy_or_freeze ( init , state . scope ) ? b . call ( '$.freeze' , init ) : init
115+ )
116+ : field . kind === 'derived_call'
117+ ? b . call ( '$.derived' , init )
118+ : b . call ( '$.derived' , b . thunk ( init ) ) ;
119+ } else {
120+ // if no arguments, we know it's state as `$derived()` is a compile error
121+ value = b . call ( '$.source' ) ;
122+ }
200123
201- if ( name && replace_class_body ( definition , false , name ) ) {
124+ if ( is_private ) {
125+ body . push ( b . prop_def ( field . id , value ) ) ;
126+ } else {
127+ // #foo;
128+ const member = b . member ( b . this , field . id ) ;
129+ body . push ( b . prop_def ( field . id , value ) ) ;
130+
131+ // get foo() { return this.#foo; }
132+ body . push ( b . method ( 'get' , definition . key , [ ] , [ b . return ( b . call ( '$.get' , member ) ) ] ) ) ;
133+
134+ if ( field . kind === 'state' ) {
135+ // set foo(value) { this.#foo = value; }
136+ const value = b . id ( 'value' ) ;
137+ body . push (
138+ b . method (
139+ 'set' ,
140+ definition . key ,
141+ [ value ] ,
142+ [ b . stmt ( b . call ( '$.set' , member , b . call ( '$.proxy' , value ) ) ) ]
143+ )
144+ ) ;
145+ }
146+
147+ if ( field . kind === 'frozen_state' ) {
148+ // set foo(value) { this.#foo = value; }
149+ const value = b . id ( 'value' ) ;
150+ body . push (
151+ b . method (
152+ 'set' ,
153+ definition . key ,
154+ [ value ] ,
155+ [ b . stmt ( b . call ( '$.set' , member , b . call ( '$.freeze' , value ) ) ) ]
156+ )
157+ ) ;
158+ }
159+
160+ if ( ( field . kind === 'derived' || field . kind === 'derived_call' ) && state . options . dev ) {
161+ body . push (
162+ b . method (
163+ 'set' ,
164+ definition . key ,
165+ [ b . id ( '_' ) ] ,
166+ [ b . throw_error ( `Cannot update a derived property ('${ name } ')` ) ]
167+ )
168+ ) ;
169+ }
170+ }
202171 continue ;
203172 }
204173 }
@@ -475,3 +444,14 @@ export const javascript_visitors_runes = {
475444 context . next ( ) ;
476445 }
477446} ;
447+
448+ /**
449+ * @param {import('estree').Identifier | import('estree').PrivateIdentifier | import('estree').Literal } node
450+ */
451+ function get_name ( node ) {
452+ if ( node . type === 'Literal' ) {
453+ return node . value ?. toString ( ) . replace ( regex_invalid_identifier_chars , '_' ) ;
454+ } else {
455+ return node . name ;
456+ }
457+ }
0 commit comments