@@ -1099,50 +1099,58 @@ function create_block(parent, name, nodes, context) {
1099
1099
body . push ( ...state . init ) ;
1100
1100
} else if ( trimmed . length > 0 ) {
1101
1101
const id = b . id ( context . state . scope . generate ( 'fragment' ) ) ;
1102
- const node_id = b . id ( context . state . scope . generate ( 'node' ) ) ;
1103
1102
1104
- process_children ( trimmed , node_id , {
1105
- ...context ,
1106
- state
1107
- } ) ;
1103
+ const use_space_template =
1104
+ trimmed . some ( ( node ) => node . type === 'ExpressionTag' ) &&
1105
+ trimmed . every ( ( node ) => node . type === 'Text' || node . type === 'ExpressionTag' ) ;
1106
+
1107
+ if ( use_space_template ) {
1108
+ // special case — we can use `$.space` instead of creating a unique template
1109
+ const id = b . id ( context . state . scope . generate ( 'text' ) ) ;
1110
+
1111
+ process_children ( trimmed , ( ) => id , false , {
1112
+ ...context ,
1113
+ state
1114
+ } ) ;
1115
+
1116
+ body . push ( b . var ( id , b . call ( '$.space' , b . id ( '$$anchor' ) ) ) , ...state . init ) ;
1117
+ close = b . stmt ( b . call ( '$.close' , b . id ( '$$anchor' ) , id ) ) ;
1118
+ } else {
1119
+ /** @type {(is_text: boolean) => import('estree').Expression } */
1120
+ const expression = ( is_text ) =>
1121
+ is_text ? b . call ( '$.child_frag' , id , b . true ) : b . call ( '$.child_frag' , id ) ;
1122
+
1123
+ process_children ( trimmed , expression , false , { ...context , state } ) ;
1108
1124
1109
- const template = state . template [ 0 ] ;
1125
+ const use_comment_template = state . template . length === 1 && state . template [ 0 ] === '<!>' ;
1110
1126
1111
- if ( state . template . length === 1 && ( template === ' ' || template === '<!>' ) ) {
1112
- if ( template === ' ' ) {
1113
- body . push ( b . var ( node_id , b . call ( '$.space' , b . id ( '$$anchor' ) ) ) , ...state . init ) ;
1114
- close = b . stmt ( b . call ( '$.close' , b . id ( '$$anchor' ) , node_id ) ) ;
1127
+ if ( use_comment_template ) {
1128
+ // special case — we can use `$.comment` instead of creating a unique template
1129
+ body . push ( b . var ( id , b . call ( '$.comment' , b . id ( '$$anchor' ) ) ) ) ;
1115
1130
} else {
1131
+ const callee = namespace === 'svg' ? '$.svg_template' : '$.template' ;
1132
+
1133
+ state . hoisted . push (
1134
+ b . var (
1135
+ template_name ,
1136
+ b . call ( callee , b . template ( [ b . quasi ( state . template . join ( '' ) , true ) ] , [ ] ) , b . true )
1137
+ )
1138
+ ) ;
1139
+
1116
1140
body . push (
1117
- b . var ( id , b . call ( '$.comment' , b . id ( '$$anchor' ) ) ) ,
1118
- b . var ( node_id , b . call ( '$.child_frag' , id ) ) ,
1119
- ...state . init
1141
+ b . var (
1142
+ id ,
1143
+ b . call (
1144
+ '$.open_frag' ,
1145
+ b . id ( '$$anchor' ) ,
1146
+ b . literal ( ! state . metadata . template_needs_import_node ) ,
1147
+ template_name
1148
+ )
1149
+ )
1120
1150
) ;
1121
- close = b . stmt ( b . call ( '$.close_frag' , b . id ( '$$anchor' ) , id ) ) ;
1122
1151
}
1123
- } else {
1124
- const callee = namespace === 'svg' ? '$.svg_template' : '$.template' ;
1125
1152
1126
- state . hoisted . push (
1127
- b . var (
1128
- template_name ,
1129
- b . call ( callee , b . template ( [ b . quasi ( state . template . join ( '' ) , true ) ] , [ ] ) , b . true )
1130
- )
1131
- ) ;
1132
-
1133
- body . push (
1134
- b . var (
1135
- id ,
1136
- b . call (
1137
- '$.open_frag' ,
1138
- b . id ( '$$anchor' ) ,
1139
- b . literal ( ! state . metadata . template_needs_import_node ) ,
1140
- template_name
1141
- )
1142
- ) ,
1143
- b . var ( node_id , b . call ( '$.child_frag' , id ) ) ,
1144
- ...state . init
1145
- ) ;
1153
+ body . push ( ...state . init ) ;
1146
1154
1147
1155
close = b . stmt ( b . call ( '$.close_frag' , b . id ( '$$anchor' ) , id ) ) ;
1148
1156
}
@@ -1418,39 +1426,36 @@ function serialize_event_attribute(node, context) {
1418
1426
* (e.g. `{a} b {c}`) into a single update function. Along the way it creates
1419
1427
* corresponding template node references these updates are applied to.
1420
1428
* @param {import('#compiler').SvelteNode[] } nodes
1421
- * @param {import('estree').Expression } parent
1429
+ * @param {(is_text: boolean) => import('estree').Expression } expression
1430
+ * @param {boolean } is_element
1422
1431
* @param {import('../types.js').ComponentContext } context
1423
1432
*/
1424
- function process_children ( nodes , parent , { visit, state } ) {
1433
+ function process_children ( nodes , expression , is_element , { visit, state } ) {
1425
1434
const within_bound_contenteditable = state . metadata . bound_contenteditable ;
1426
1435
1427
1436
/** @typedef {Array<import('#compiler').Text | import('#compiler').ExpressionTag> } Sequence */
1428
1437
1429
1438
/** @type {Sequence } */
1430
1439
let sequence = [ ] ;
1431
1440
1432
- let expression = parent ;
1433
-
1434
1441
/**
1435
1442
* @param {Sequence } sequence
1436
- * @param {boolean } in_fragment
1437
1443
*/
1438
- function flush_sequence ( sequence , in_fragment ) {
1444
+ function flush_sequence ( sequence ) {
1439
1445
if ( sequence . length === 1 ) {
1440
1446
const node = sequence [ 0 ] ;
1441
1447
1442
- if ( ( in_fragment && node . type === 'ExpressionTag' ) || node . type === 'Text' ) {
1443
- expression = b . call ( '$.sibling' , expression ) ;
1444
- }
1445
-
1446
1448
if ( node . type === 'Text' ) {
1449
+ let prev = expression ;
1450
+ expression = ( ) => b . call ( '$.sibling' , prev ( true ) ) ;
1447
1451
state . template . push ( node . raw ) ;
1448
1452
return ;
1449
1453
}
1450
1454
1451
1455
state . template . push ( ' ' ) ;
1452
1456
1453
- const text_id = get_node_id ( expression , state , 'text' ) ;
1457
+ const text_id = get_node_id ( expression ( true ) , state , 'text' ) ;
1458
+
1454
1459
const singular = b . stmt (
1455
1460
b . call (
1456
1461
'$.text_effect' ,
@@ -1487,50 +1492,47 @@ function process_children(nodes, parent, { visit, state }) {
1487
1492
) ;
1488
1493
}
1489
1494
1490
- return ;
1491
- }
1495
+ expression = ( is_text ) =>
1496
+ is_text ? b . call ( '$.sibling' , text_id , b . true ) : b . call ( '$.sibling' , text_id ) ;
1497
+ } else {
1498
+ const text_id = get_node_id ( expression ( true ) , state , 'text' ) ;
1492
1499
1493
- state . template . push ( ' ' ) ;
1500
+ state . template . push ( ' ' ) ;
1494
1501
1495
- const text_id = get_node_id ( expression , state , 'text' ) ;
1496
- const contains_call_expression = sequence . some (
1497
- ( n ) => n . type === 'ExpressionTag' && n . metadata . contains_call_expression
1498
- ) ;
1499
- const assignment = serialize_template_literal ( sequence , visit , state ) [ 1 ] ;
1500
- const init = b . stmt ( b . assignment ( '=' , b . member ( text_id , b . id ( 'nodeValue' ) ) , assignment ) ) ;
1501
- const singular = b . stmt ( b . call ( '$.text_effect' , text_id , b . thunk ( assignment ) ) ) ;
1502
+ const contains_call_expression = sequence . some (
1503
+ ( n ) => n . type === 'ExpressionTag' && n . metadata . contains_call_expression
1504
+ ) ;
1505
+ const assignment = serialize_template_literal ( sequence , visit , state ) [ 1 ] ;
1506
+ const init = b . stmt ( b . assignment ( '=' , b . member ( text_id , b . id ( 'nodeValue' ) ) , assignment ) ) ;
1507
+ const singular = b . stmt ( b . call ( '$.text_effect' , text_id , b . thunk ( assignment ) ) ) ;
1502
1508
1503
- if ( contains_call_expression && ! within_bound_contenteditable ) {
1504
- state . update_effects . push ( singular ) ;
1505
- } else if (
1506
- sequence . some ( ( node ) => node . type === 'ExpressionTag' && node . metadata . dynamic ) &&
1507
- ! within_bound_contenteditable
1508
- ) {
1509
- state . update . push ( {
1510
- singular,
1511
- grouped : b . stmt ( b . call ( '$.text' , text_id , assignment ) )
1512
- } ) ;
1513
- } else {
1514
- state . init . push ( init ) ;
1515
- }
1509
+ if ( contains_call_expression && ! within_bound_contenteditable ) {
1510
+ state . update_effects . push ( singular ) ;
1511
+ } else if (
1512
+ sequence . some ( ( node ) => node . type === 'ExpressionTag' && node . metadata . dynamic ) &&
1513
+ ! within_bound_contenteditable
1514
+ ) {
1515
+ state . update . push ( {
1516
+ singular,
1517
+ grouped : b . stmt ( b . call ( '$.text' , text_id , assignment ) )
1518
+ } ) ;
1519
+ } else {
1520
+ state . init . push ( init ) ;
1521
+ }
1516
1522
1517
- expression = b . call ( '$.sibling' , text_id ) ;
1523
+ expression = ( is_text ) =>
1524
+ is_text ? b . call ( '$.sibling' , text_id , b . true ) : b . call ( '$.sibling' , text_id ) ;
1525
+ }
1518
1526
}
1519
1527
1520
- let is_fragment = false ;
1521
1528
for ( let i = 0 ; i < nodes . length ; i += 1 ) {
1522
1529
const node = nodes [ i ] ;
1523
1530
1524
1531
if ( node . type === 'Text' || node . type === 'ExpressionTag' ) {
1525
1532
sequence . push ( node ) ;
1526
1533
} else {
1527
1534
if ( sequence . length > 0 ) {
1528
- flush_sequence ( sequence , is_fragment ) ;
1529
- // Ensure we move to the next sibling for the case where we move reference within a fragment
1530
- if ( ! is_fragment && sequence . length === 1 && sequence [ 0 ] . type === 'ExpressionTag' ) {
1531
- expression = b . call ( '$.sibling' , expression ) ;
1532
- is_fragment = true ;
1533
- }
1535
+ flush_sequence ( sequence ) ;
1534
1536
sequence = [ ] ;
1535
1537
}
1536
1538
@@ -1544,23 +1546,18 @@ function process_children(nodes, parent, { visit, state }) {
1544
1546
// get hoisted inside clean_nodes?
1545
1547
visit ( node , state ) ;
1546
1548
} else {
1547
- if (
1548
- node . type === 'EachBlock' &&
1549
- nodes . length === 1 &&
1550
- parent . type === 'CallExpression' &&
1551
- parent . callee . type === 'Identifier' &&
1552
- parent . callee . name === '$.child'
1553
- ) {
1549
+ if ( node . type === 'EachBlock' && nodes . length === 1 && is_element ) {
1554
1550
node . metadata . is_controlled = true ;
1555
1551
visit ( node , state ) ;
1556
1552
} else {
1557
1553
const id = get_node_id (
1558
- expression ,
1554
+ expression ( false ) ,
1559
1555
state ,
1560
1556
node . type === 'RegularElement' ? node . name : 'node'
1561
1557
) ;
1562
1558
1563
- expression = b . call ( '$.sibling' , id ) ;
1559
+ expression = ( is_text ) =>
1560
+ is_text ? b . call ( '$.sibling' , id , b . true ) : b . call ( '$.sibling' , id ) ;
1564
1561
1565
1562
visit ( node , {
1566
1563
...state ,
@@ -1572,7 +1569,7 @@ function process_children(nodes, parent, { visit, state }) {
1572
1569
}
1573
1570
1574
1571
if ( sequence . length > 0 ) {
1575
- flush_sequence ( sequence , false ) ;
1572
+ flush_sequence ( sequence ) ;
1576
1573
}
1577
1574
}
1578
1575
@@ -2041,12 +2038,14 @@ export const template_visitors = {
2041
2038
2042
2039
process_children (
2043
2040
trimmed ,
2044
- b . call (
2045
- '$.child' ,
2046
- node . name === 'template'
2047
- ? b . member ( context . state . node , b . id ( 'content' ) )
2048
- : context . state . node
2049
- ) ,
2041
+ ( ) =>
2042
+ b . call (
2043
+ '$.child' ,
2044
+ node . name === 'template'
2045
+ ? b . member ( context . state . node , b . id ( 'content' ) )
2046
+ : context . state . node
2047
+ ) ,
2048
+ true ,
2050
2049
{ ...context , state }
2051
2050
) ;
2052
2051
0 commit comments