@@ -608,20 +608,38 @@ const legacy_scope_tweaker = {
608
608
/** @type {import('../types.js').ReactiveStatement } */
609
609
const reactive_statement = {
610
610
assignments : new Set ( ) ,
611
- dependencies : new Set ( )
611
+ dependencies : [ ]
612
612
} ;
613
613
614
614
next ( { ...state , reactive_statement, function_depth : state . scope . function_depth + 1 } ) ;
615
615
616
+ // Every referenced binding becomes a dependency, unless it's on
617
+ // the left-hand side of an `=` assignment
616
618
for ( const [ name , nodes ] of state . scope . references ) {
617
619
const binding = state . scope . get ( name ) ;
618
620
if ( binding === null ) continue ;
619
621
620
- // Include bindings that have references other than assignments and their own declarations
621
- if (
622
- nodes . some ( ( n ) => n . node !== binding . node && ! reactive_statement . assignments . has ( n . node ) )
623
- ) {
624
- reactive_statement . dependencies . add ( binding ) ;
622
+ for ( const { node, path } of nodes ) {
623
+ /** @type {import('estree').Expression } */
624
+ let left = node ;
625
+
626
+ let i = path . length - 1 ;
627
+ let parent = /** @type {import('estree').Expression } */ ( path . at ( i ) ) ;
628
+ while ( parent . type === 'MemberExpression' ) {
629
+ left = parent ;
630
+ parent = /** @type {import('estree').Expression } */ ( path . at ( -- i ) ) ;
631
+ }
632
+
633
+ if (
634
+ parent . type === 'AssignmentExpression' &&
635
+ parent . operator === '=' &&
636
+ parent . left === left
637
+ ) {
638
+ continue ;
639
+ }
640
+
641
+ reactive_statement . dependencies . push ( binding ) ;
642
+ break ;
625
643
}
626
644
}
627
645
@@ -630,8 +648,8 @@ const legacy_scope_tweaker = {
630
648
// Ideally this would be in the validation file, but that isn't possible because this visitor
631
649
// calls "next" before setting the reactive statements.
632
650
if (
633
- reactive_statement . dependencies . size &&
634
- [ ... reactive_statement . dependencies ] . every (
651
+ reactive_statement . dependencies . length &&
652
+ reactive_statement . dependencies . every (
635
653
( d ) => d . scope === state . analysis . module . scope && d . declaration_kind !== 'const'
636
654
)
637
655
) {
@@ -660,15 +678,29 @@ const legacy_scope_tweaker = {
660
678
}
661
679
} ,
662
680
AssignmentExpression ( node , { state, next } ) {
663
- if ( state . reactive_statement && node . operator === '=' ) {
664
- if ( node . left . type === 'MemberExpression' ) {
665
- const id = object ( node . left ) ;
666
- if ( id !== null ) {
667
- state . reactive_statement . assignments . add ( id ) ;
668
- }
669
- } else {
681
+ if ( state . reactive_statement ) {
682
+ const id = node . left . type === 'MemberExpression' ? object ( node . left ) : node . left ;
683
+ if ( id !== null ) {
670
684
for ( const id of extract_identifiers ( node . left ) ) {
671
- state . reactive_statement . assignments . add ( id ) ;
685
+ const binding = state . scope . get ( id . name ) ;
686
+
687
+ if ( binding ) {
688
+ state . reactive_statement . assignments . add ( binding ) ;
689
+ }
690
+ }
691
+ }
692
+ }
693
+
694
+ next ( ) ;
695
+ } ,
696
+ UpdateExpression ( node , { state, next } ) {
697
+ if ( state . reactive_statement ) {
698
+ const id = node . argument . type === 'MemberExpression' ? object ( node . argument ) : node . argument ;
699
+ if ( id ?. type === 'Identifier' ) {
700
+ const binding = state . scope . get ( id . name ) ;
701
+
702
+ if ( binding ) {
703
+ state . reactive_statement . assignments . add ( binding ) ;
672
704
}
673
705
}
674
706
}
@@ -1343,21 +1375,21 @@ function order_reactive_statements(unsorted_reactive_declarations) {
1343
1375
const lookup = new Map ( ) ;
1344
1376
1345
1377
for ( const [ node , declaration ] of unsorted_reactive_declarations ) {
1346
- declaration . assignments . forEach ( ( { name } ) => {
1347
- const statements = lookup . get ( name ) ?? [ ] ;
1378
+ for ( const binding of declaration . assignments ) {
1379
+ const statements = lookup . get ( binding . node . name ) ?? [ ] ;
1348
1380
statements . push ( [ node , declaration ] ) ;
1349
- lookup . set ( name , statements ) ;
1350
- } ) ;
1381
+ lookup . set ( binding . node . name , statements ) ;
1382
+ }
1351
1383
}
1352
1384
1353
1385
/** @type {Array<[string, string]> } */
1354
1386
const edges = [ ] ;
1355
1387
1356
1388
for ( const [ , { assignments, dependencies } ] of unsorted_reactive_declarations ) {
1357
- for ( const { name } of assignments ) {
1358
- for ( const { node } of dependencies ) {
1359
- if ( ! [ ... assignments ] . find ( ( { name } ) => node . name === name ) ) {
1360
- edges . push ( [ name , node . name ] ) ;
1389
+ for ( const assignment of assignments ) {
1390
+ for ( const dependency of dependencies ) {
1391
+ if ( ! assignments . has ( dependency ) ) {
1392
+ edges . push ( [ assignment . node . name , dependency . node . name ] ) ;
1361
1393
}
1362
1394
}
1363
1395
}
@@ -1381,14 +1413,17 @@ function order_reactive_statements(unsorted_reactive_declarations) {
1381
1413
*/
1382
1414
const add_declaration = ( node , declaration ) => {
1383
1415
if ( [ ...reactive_declarations . values ( ) ] . includes ( declaration ) ) return ;
1384
- declaration . dependencies . forEach ( ( { node : { name } } ) => {
1385
- if ( [ ...declaration . assignments ] . some ( ( a ) => a . name === name ) ) return ;
1386
- for ( const [ node , earlier ] of lookup . get ( name ) ?? [ ] ) {
1416
+
1417
+ for ( const binding of declaration . dependencies ) {
1418
+ if ( declaration . assignments . has ( binding ) ) continue ;
1419
+ for ( const [ node , earlier ] of lookup . get ( binding . node . name ) ?? [ ] ) {
1387
1420
add_declaration ( node , earlier ) ;
1388
1421
}
1389
- } ) ;
1422
+ }
1423
+
1390
1424
reactive_declarations . set ( node , declaration ) ;
1391
1425
} ;
1426
+
1392
1427
for ( const [ node , declaration ] of unsorted_reactive_declarations ) {
1393
1428
add_declaration ( node , declaration ) ;
1394
1429
}
0 commit comments