@@ -1099,50 +1099,58 @@ function create_block(parent, name, nodes, context) {
10991099 body . push ( ...state . init ) ;
11001100 } else if ( trimmed . length > 0 ) {
11011101 const id = b . id ( context . state . scope . generate ( 'fragment' ) ) ;
1102- const node_id = b . id ( context . state . scope . generate ( 'node' ) ) ;
11031102
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 } ) ;
11081124
1109- const template = state . template [ 0 ] ;
1125+ const use_comment_template = state . template . length === 1 && state . template [ 0 ] === '<!>' ;
11101126
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' ) ) ) ) ;
11151130 } 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+
11161140 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+ )
11201150 ) ;
1121- close = b . stmt ( b . call ( '$.close_frag' , b . id ( '$$anchor' ) , id ) ) ;
11221151 }
1123- } else {
1124- const callee = namespace === 'svg' ? '$.svg_template' : '$.template' ;
11251152
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 ) ;
11461154
11471155 close = b . stmt ( b . call ( '$.close_frag' , b . id ( '$$anchor' ) , id ) ) ;
11481156 }
@@ -1418,39 +1426,36 @@ function serialize_event_attribute(node, context) {
14181426 * (e.g. `{a} b {c}`) into a single update function. Along the way it creates
14191427 * corresponding template node references these updates are applied to.
14201428 * @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
14221431 * @param {import('../types.js').ComponentContext } context
14231432 */
1424- function process_children ( nodes , parent , { visit, state } ) {
1433+ function process_children ( nodes , expression , is_element , { visit, state } ) {
14251434 const within_bound_contenteditable = state . metadata . bound_contenteditable ;
14261435
14271436 /** @typedef {Array<import('#compiler').Text | import('#compiler').ExpressionTag> } Sequence */
14281437
14291438 /** @type {Sequence } */
14301439 let sequence = [ ] ;
14311440
1432- let expression = parent ;
1433-
14341441 /**
14351442 * @param {Sequence } sequence
1436- * @param {boolean } in_fragment
14371443 */
1438- function flush_sequence ( sequence , in_fragment ) {
1444+ function flush_sequence ( sequence ) {
14391445 if ( sequence . length === 1 ) {
14401446 const node = sequence [ 0 ] ;
14411447
1442- if ( ( in_fragment && node . type === 'ExpressionTag' ) || node . type === 'Text' ) {
1443- expression = b . call ( '$.sibling' , expression ) ;
1444- }
1445-
14461448 if ( node . type === 'Text' ) {
1449+ let prev = expression ;
1450+ expression = ( ) => b . call ( '$.sibling' , prev ( true ) ) ;
14471451 state . template . push ( node . raw ) ;
14481452 return ;
14491453 }
14501454
14511455 state . template . push ( ' ' ) ;
14521456
1453- const text_id = get_node_id ( expression , state , 'text' ) ;
1457+ const text_id = get_node_id ( expression ( true ) , state , 'text' ) ;
1458+
14541459 const singular = b . stmt (
14551460 b . call (
14561461 '$.text_effect' ,
@@ -1487,50 +1492,47 @@ function process_children(nodes, parent, { visit, state }) {
14871492 ) ;
14881493 }
14891494
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' ) ;
14921499
1493- state . template . push ( ' ' ) ;
1500+ state . template . push ( ' ' ) ;
14941501
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 ) ) ) ;
15021508
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+ }
15161522
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+ }
15181526 }
15191527
1520- let is_fragment = false ;
15211528 for ( let i = 0 ; i < nodes . length ; i += 1 ) {
15221529 const node = nodes [ i ] ;
15231530
15241531 if ( node . type === 'Text' || node . type === 'ExpressionTag' ) {
15251532 sequence . push ( node ) ;
15261533 } else {
15271534 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 ) ;
15341536 sequence = [ ] ;
15351537 }
15361538
@@ -1544,23 +1546,18 @@ function process_children(nodes, parent, { visit, state }) {
15441546 // get hoisted inside clean_nodes?
15451547 visit ( node , state ) ;
15461548 } 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 ) {
15541550 node . metadata . is_controlled = true ;
15551551 visit ( node , state ) ;
15561552 } else {
15571553 const id = get_node_id (
1558- expression ,
1554+ expression ( false ) ,
15591555 state ,
15601556 node . type === 'RegularElement' ? node . name : 'node'
15611557 ) ;
15621558
1563- expression = b . call ( '$.sibling' , id ) ;
1559+ expression = ( is_text ) =>
1560+ is_text ? b . call ( '$.sibling' , id , b . true ) : b . call ( '$.sibling' , id ) ;
15641561
15651562 visit ( node , {
15661563 ...state ,
@@ -1572,7 +1569,7 @@ function process_children(nodes, parent, { visit, state }) {
15721569 }
15731570
15741571 if ( sequence . length > 0 ) {
1575- flush_sequence ( sequence , false ) ;
1572+ flush_sequence ( sequence ) ;
15761573 }
15771574}
15781575
@@ -2041,12 +2038,14 @@ export const template_visitors = {
20412038
20422039 process_children (
20432040 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 ,
20502049 { ...context , state }
20512050 ) ;
20522051
0 commit comments