@@ -1344,64 +1344,48 @@ const template_visitors = {
13441344
13451345 state . template . push ( block_close ) ;
13461346 } ,
1347- ClassDirective ( node ) {
1347+ ClassDirective ( ) {
13481348 throw new Error ( 'Node should have been handled elsewhere' ) ;
13491349 } ,
1350- StyleDirective ( node ) {
1350+ StyleDirective ( ) {
13511351 throw new Error ( 'Node should have been handled elsewhere' ) ;
13521352 } ,
13531353 RegularElement ( node , context ) {
1354- const metadata = {
1355- ...context . state . metadata ,
1356- namespace : determine_namespace_for_children ( node , context . state . metadata . namespace )
1357- } ;
1358-
13591354 context . state . template . push ( t_string ( `<${ node . name } ` ) ) ;
1360- const body_expression = serialize_element_attributes ( node , context ) ;
1355+ const body = serialize_element_attributes ( node , context ) ;
13611356 context . state . template . push ( t_string ( '>' ) ) ;
13621357
1358+ const namespace = determine_namespace_for_children ( node , context . state . metadata . namespace ) ;
1359+
13631360 /** @type {import('./types').ComponentServerTransformState } */
13641361 const state = {
13651362 ...context . state ,
1366- metadata,
1363+ metadata : { ... context . state . metadata , namespace } ,
13671364 preserve_whitespace :
13681365 context . state . preserve_whitespace ||
1369- ( ( node . name === 'pre' || node . name === 'textarea' ) && metadata . namespace !== 'foreign' )
1366+ ( ( node . name === 'pre' || node . name === 'textarea' ) && namespace !== 'foreign' )
13701367 } ;
13711368
1372- /** @type {import('./types').ComponentContext } */
1373- const inner_context =
1374- body_expression !== null
1375- ? {
1376- ...context ,
1377- state : {
1378- ...state ,
1379- template : [ ] ,
1380- init : [ ]
1381- }
1382- }
1383- : { ...context , state } ;
1384-
13851369 const { hoisted, trimmed } = clean_nodes (
13861370 node ,
13871371 node . fragment . nodes ,
1388- inner_context . path ,
1389- metadata . namespace ,
1372+ context . path ,
1373+ namespace ,
13901374 {
1391- ...context . state ,
1392- scope : /** @type {import('../../scope').Scope } */ ( context . state . scopes . get ( node . fragment ) )
1375+ ...state ,
1376+ scope : /** @type {import('../../scope').Scope } */ ( state . scopes . get ( node . fragment ) )
13931377 } ,
13941378 state . preserve_whitespace ,
13951379 state . options . preserveComments
13961380 ) ;
13971381
13981382 for ( const node of hoisted ) {
1399- inner_context . visit ( node , state ) ;
1383+ context . visit ( node , state ) ;
14001384 }
14011385
1402- if ( context . state . options . dev ) {
1386+ if ( state . options . dev ) {
14031387 const location = /** @type {import('locate-character').Location } */ ( locator ( node . start ) ) ;
1404- context . state . template . push (
1388+ state . template . push (
14051389 t_statement (
14061390 b . stmt (
14071391 b . call (
@@ -1416,40 +1400,39 @@ const template_visitors = {
14161400 ) ;
14171401 }
14181402
1419- process_children ( trimmed , node , inner_context ) ;
1403+ if ( body === null ) {
1404+ process_children ( trimmed , node , { ...context , state } ) ;
1405+ } else {
1406+ let id = body ;
14201407
1421- if ( body_expression !== null ) {
1422- let body_id ;
1423- const expression = body_expression . escape
1424- ? b . call ( '$.escape' , body_expression . expression )
1425- : body_expression . expression ;
1426- if ( expression . type === 'Identifier' ) {
1427- body_id = expression ;
1428- } else {
1429- body_id = b . id ( context . state . scope . generate ( '$$body' ) ) ;
1430- context . state . template . push ( t_statement ( b . const ( body_id , expression ) ) ) ;
1408+ if ( body . type !== 'Identifier' ) {
1409+ id = b . id ( state . scope . generate ( '$$body' ) ) ;
1410+ state . template . push ( t_statement ( b . const ( id , body ) ) ) ;
14311411 }
14321412
1413+ // if this is a `<textarea>` value or a contenteditable binding, we only add
1414+ // the body if the attribute/binding is falsy
1415+ const inner_state = { ...state , template : [ ] , init : [ ] } ;
1416+ process_children ( trimmed , node , { ...context , state : inner_state } ) ;
1417+
14331418 // Use the body expression as the body if it's truthy, otherwise use the inner template
1434- context . state . template . push (
1419+ state . template . push (
14351420 t_statement (
14361421 b . if (
1437- body_id ,
1438- b . block ( serialize_template ( [ t_expression ( body_id ) ] ) ) ,
1439- b . block ( [
1440- ...inner_context . state . init ,
1441- ...serialize_template ( inner_context . state . template )
1442- ] )
1422+ id ,
1423+ b . block ( serialize_template ( [ t_expression ( id ) ] ) ) ,
1424+ b . block ( [ ...inner_state . init , ...serialize_template ( inner_state . template ) ] )
14431425 )
14441426 )
14451427 ) ;
14461428 }
14471429
1448- if ( ! VoidElements . includes ( node . name ) && metadata . namespace !== 'foreign' ) {
1449- context . state . template . push ( t_string ( `</${ node . name } >` ) ) ;
1430+ if ( ! VoidElements . includes ( node . name ) && namespace !== 'foreign' ) {
1431+ state . template . push ( t_string ( `</${ node . name } >` ) ) ;
14501432 }
1451- if ( context . state . options . dev ) {
1452- context . state . template . push ( t_statement ( b . stmt ( b . call ( '$.pop_element' ) ) ) ) ;
1433+
1434+ if ( state . options . dev ) {
1435+ state . template . push ( t_statement ( b . stmt ( b . call ( '$.pop_element' ) ) ) ) ;
14531436 }
14541437 } ,
14551438 SvelteElement ( node , context ) {
@@ -1467,59 +1450,35 @@ const template_visitors = {
14671450 context . state . init . push ( b . stmt ( b . call ( '$.validate_dynamic_element_tag' , b . thunk ( tag ) ) ) ) ;
14681451 }
14691452
1470- const metadata = {
1471- ...context . state . metadata ,
1472- namespace : determine_namespace_for_children ( node , context . state . metadata . namespace )
1473- } ;
1474- /** @type {import('./types').ComponentContext } */
1475- const inner_context = {
1476- ...context ,
1477- state : {
1478- ...context . state ,
1479- metadata,
1480- template : [ ] ,
1481- init : [ ]
1482- }
1453+ const state = {
1454+ ...context . state ,
1455+ metadata : {
1456+ ...context . state . metadata ,
1457+ namespace : determine_namespace_for_children ( node , context . state . metadata . namespace )
1458+ } ,
1459+ template : [ ] ,
1460+ init : [ ]
14831461 } ;
14841462
1485- const main = /** @type {import('estree').BlockStatement } */ (
1486- context . visit ( node . fragment , {
1487- ...context . state ,
1488- metadata
1489- } )
1490- ) ;
1491-
1492- serialize_element_attributes ( node , inner_context ) ;
1463+ serialize_element_attributes ( node , { ...context , state } ) ;
14931464
14941465 if ( context . state . options . dev ) {
14951466 context . state . template . push (
14961467 t_statement ( b . stmt ( b . call ( '$.push_element' , tag , b . id ( '$$payload' ) ) ) )
14971468 ) ;
14981469 }
14991470
1500- context . state . template . push (
1501- t_statement (
1502- b . if (
1503- tag ,
1471+ const attributes = b . block ( [ ... state . init , ... serialize_template ( state . template ) ] ) ;
1472+ const children = /** @type { import('estree').BlockStatement } */ (
1473+ context . visit ( node . fragment , state )
1474+ ) ;
15041475
1505- b . stmt (
1506- b . call (
1507- '$.element' ,
1508- b . id ( '$$payload' ) ,
1509- tag ,
1510- b . thunk (
1511- b . block ( [
1512- ...inner_context . state . init ,
1513- ...serialize_template ( inner_context . state . template )
1514- ] )
1515- ) ,
1516- b . thunk ( main )
1517- )
1518- )
1519- )
1520- ) ,
1521- block_anchor
1476+ const body = b . stmt (
1477+ b . call ( '$.element' , b . id ( '$$payload' ) , tag , b . thunk ( attributes ) , b . thunk ( children ) )
15221478 ) ;
1479+
1480+ context . state . template . push ( t_statement ( b . if ( tag , body ) ) , block_anchor ) ;
1481+
15231482 if ( context . state . options . dev ) {
15241483 context . state . template . push ( t_statement ( b . stmt ( b . call ( '$.pop_element' ) ) ) ) ;
15251484 }
@@ -1834,7 +1793,7 @@ function serialize_element_attributes(node, context) {
18341793 /** @type {import('estree').ExpressionStatement[] } */
18351794 const lets = [ ] ;
18361795
1837- /** @type {{ escape: boolean; expression: import('estree').Expression } | null } */
1796+ /** @type {import('estree').Expression | null } */
18381797 let content = null ;
18391798
18401799 let has_spread = false ;
@@ -1857,10 +1816,7 @@ function serialize_element_attributes(node, context) {
18571816 // also see related code in analysis phase
18581817 attribute . value [ 0 ] . data = '\n' + attribute . value [ 0 ] . data ;
18591818 }
1860- content = {
1861- escape : true ,
1862- expression : serialize_attribute_value ( attribute . value , context )
1863- } ;
1819+ content = b . call ( '$.escape' , serialize_attribute_value ( attribute . value , context ) ) ;
18641820 } else if ( node . name !== 'select' ) {
18651821 // omit value attribute for select elements, it's irrelevant for the initially selected value and has no
18661822 // effect on the selected value after the user interacts with the select element (the value _property_ does, but not the attribute)
@@ -1903,19 +1859,12 @@ function serialize_element_attributes(node, context) {
19031859 if ( binding ?. omit_in_ssr ) continue ;
19041860
19051861 if ( ContentEditableBindings . includes ( attribute . name ) ) {
1906- content = {
1907- escape : false ,
1908- expression : /** @type {import('estree').Expression } */ (
1909- context . visit ( attribute . expression )
1910- )
1911- } ;
1862+ content = /** @type {import('estree').Expression } */ ( context . visit ( attribute . expression ) ) ;
19121863 } else if ( attribute . name === 'value' && node . name === 'textarea' ) {
1913- content = {
1914- escape : true ,
1915- expression : /** @type {import('estree').Expression } */ (
1916- context . visit ( attribute . expression )
1917- )
1918- } ;
1864+ content = b . call (
1865+ '$.escape' ,
1866+ /** @type {import('estree').Expression } */ ( context . visit ( attribute . expression ) )
1867+ ) ;
19191868 } else if ( attribute . name === 'group' ) {
19201869 const value_attribute = /** @type {import('#compiler').Attribute | undefined } */ (
19211870 node . attributes . find ( ( attr ) => attr . type === 'Attribute' && attr . name === 'value' )
0 commit comments