@@ -541,11 +541,88 @@ const javascript_visitors = {
541
541
542
542
/** @type {import('./types').Visitors } */
543
543
const javascript_visitors_runes = {
544
+ ClassBody ( node , { state, visit, next } ) {
545
+ if ( ! state . analysis . runes ) {
546
+ next ( ) ;
547
+ }
548
+ /** @type {import('estree').PropertyDefinition[] } */
549
+ const deriveds = [ ] ;
550
+ /** @type {import('estree').MethodDefinition | null } */
551
+ let constructor = null ;
552
+ // Get the constructor
553
+ for ( const definition of node . body ) {
554
+ if ( definition . type === 'MethodDefinition' && definition . kind === 'constructor' ) {
555
+ constructor = /** @type {import('estree').MethodDefinition } */ ( visit ( definition ) ) ;
556
+ }
557
+ }
558
+ // Move $derived() runes to the end of the body if there is a constructor
559
+ if ( constructor !== null ) {
560
+ const body = [ ] ;
561
+ for ( const definition of node . body ) {
562
+ if (
563
+ definition . type === 'PropertyDefinition' &&
564
+ ( definition . key . type === 'Identifier' || definition . key . type === 'PrivateIdentifier' )
565
+ ) {
566
+ const is_private = definition . key . type === 'PrivateIdentifier' ;
567
+
568
+ if ( definition . value ?. type === 'CallExpression' ) {
569
+ const rune = get_rune ( definition . value , state . scope ) ;
570
+
571
+ if ( rune === '$derived' ) {
572
+ deriveds . push ( /** @type {import('estree').PropertyDefinition } */ ( visit ( definition ) ) ) ;
573
+ if ( is_private ) {
574
+ // Keep the private #name initializer if private, but remove initial value
575
+ body . push ( {
576
+ ...definition ,
577
+ value : null
578
+ } ) ;
579
+ }
580
+ continue ;
581
+ }
582
+ }
583
+ }
584
+ if ( definition . type !== 'MethodDefinition' || definition . kind !== 'constructor' ) {
585
+ body . push (
586
+ /** @type {import('estree').PropertyDefinition | import('estree').MethodDefinition | import('estree').StaticBlock } */ (
587
+ visit ( definition )
588
+ )
589
+ ) ;
590
+ }
591
+ }
592
+ if ( deriveds . length > 0 ) {
593
+ body . push ( {
594
+ ...constructor ,
595
+ value : {
596
+ ...constructor . value ,
597
+ body : b . block ( [
598
+ ...constructor . value . body . body ,
599
+ ...deriveds . map ( ( d ) => {
600
+ return b . stmt (
601
+ b . assignment (
602
+ '=' ,
603
+ b . member ( b . this , d . key ) ,
604
+ /** @type {import('estree').Expression } */ ( d . value )
605
+ )
606
+ ) ;
607
+ } )
608
+ ] )
609
+ }
610
+ } ) ;
611
+ } else {
612
+ body . push ( constructor ) ;
613
+ }
614
+ return {
615
+ ...node ,
616
+ body
617
+ } ;
618
+ }
619
+ next ( ) ;
620
+ } ,
544
621
PropertyDefinition ( node , { state, next, visit } ) {
545
622
if ( node . value != null && node . value . type === 'CallExpression' ) {
546
623
const rune = get_rune ( node . value , state . scope ) ;
547
624
548
- if ( rune === '$state' || rune === '$state.frozen' ) {
625
+ if ( rune === '$state' || rune === '$state.frozen' || rune === '$derived' ) {
549
626
return {
550
627
...node ,
551
628
value :
@@ -554,26 +631,6 @@ const javascript_visitors_runes = {
554
631
: /** @type {import('estree').Expression } */ ( visit ( node . value . arguments [ 0 ] ) )
555
632
} ;
556
633
}
557
- if ( rune === '$derived' ) {
558
- return {
559
- type : 'MethodDefinition' ,
560
- kind : 'get' ,
561
- key : node . key ,
562
- computed : false ,
563
- static : false ,
564
- value : b . function (
565
- null ,
566
- [ ] ,
567
- b . block ( [
568
- b . return (
569
- node . value . arguments . length === 0
570
- ? null
571
- : /** @type {import('estree').Expression } */ ( visit ( node . value . arguments [ 0 ] ) )
572
- )
573
- ] )
574
- )
575
- } ;
576
- }
577
634
if ( rune === '$derived.by' ) {
578
635
return {
579
636
...node ,
0 commit comments