@@ -1344,64 +1344,48 @@ const template_visitors = {
1344
1344
1345
1345
state . template . push ( block_close ) ;
1346
1346
} ,
1347
- ClassDirective ( node ) {
1347
+ ClassDirective ( ) {
1348
1348
throw new Error ( 'Node should have been handled elsewhere' ) ;
1349
1349
} ,
1350
- StyleDirective ( node ) {
1350
+ StyleDirective ( ) {
1351
1351
throw new Error ( 'Node should have been handled elsewhere' ) ;
1352
1352
} ,
1353
1353
RegularElement ( node , context ) {
1354
- const metadata = {
1355
- ...context . state . metadata ,
1356
- namespace : determine_namespace_for_children ( node , context . state . metadata . namespace )
1357
- } ;
1358
-
1359
1354
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 ) ;
1361
1356
context . state . template . push ( t_string ( '>' ) ) ;
1362
1357
1358
+ const namespace = determine_namespace_for_children ( node , context . state . metadata . namespace ) ;
1359
+
1363
1360
/** @type {import('./types').ComponentServerTransformState } */
1364
1361
const state = {
1365
1362
...context . state ,
1366
- metadata,
1363
+ metadata : { ... context . state . metadata , namespace } ,
1367
1364
preserve_whitespace :
1368
1365
context . state . preserve_whitespace ||
1369
- ( ( node . name === 'pre' || node . name === 'textarea' ) && metadata . namespace !== 'foreign' )
1366
+ ( ( node . name === 'pre' || node . name === 'textarea' ) && namespace !== 'foreign' )
1370
1367
} ;
1371
1368
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
-
1385
1369
const { hoisted, trimmed } = clean_nodes (
1386
1370
node ,
1387
1371
node . fragment . nodes ,
1388
- inner_context . path ,
1389
- metadata . namespace ,
1372
+ context . path ,
1373
+ namespace ,
1390
1374
{
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 ) )
1393
1377
} ,
1394
1378
state . preserve_whitespace ,
1395
1379
state . options . preserveComments
1396
1380
) ;
1397
1381
1398
1382
for ( const node of hoisted ) {
1399
- inner_context . visit ( node , state ) ;
1383
+ context . visit ( node , state ) ;
1400
1384
}
1401
1385
1402
- if ( context . state . options . dev ) {
1386
+ if ( state . options . dev ) {
1403
1387
const location = /** @type {import('locate-character').Location } */ ( locator ( node . start ) ) ;
1404
- context . state . template . push (
1388
+ state . template . push (
1405
1389
t_statement (
1406
1390
b . stmt (
1407
1391
b . call (
@@ -1416,40 +1400,39 @@ const template_visitors = {
1416
1400
) ;
1417
1401
}
1418
1402
1419
- process_children ( trimmed , node , inner_context ) ;
1403
+ if ( body === null ) {
1404
+ process_children ( trimmed , node , { ...context , state } ) ;
1405
+ } else {
1406
+ let id = body ;
1420
1407
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 ) ) ) ;
1431
1411
}
1432
1412
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
+
1433
1418
// 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 (
1435
1420
t_statement (
1436
1421
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 ) ] )
1443
1425
)
1444
1426
)
1445
1427
) ;
1446
1428
}
1447
1429
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 } >` ) ) ;
1450
1432
}
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' ) ) ) ) ;
1453
1436
}
1454
1437
} ,
1455
1438
SvelteElement ( node , context ) {
@@ -1834,7 +1817,7 @@ function serialize_element_attributes(node, context) {
1834
1817
/** @type {import('estree').ExpressionStatement[] } */
1835
1818
const lets = [ ] ;
1836
1819
1837
- /** @type {{ escape: boolean; expression: import('estree').Expression } | null } */
1820
+ /** @type {import('estree').Expression | null } */
1838
1821
let content = null ;
1839
1822
1840
1823
let has_spread = false ;
@@ -1857,10 +1840,7 @@ function serialize_element_attributes(node, context) {
1857
1840
// also see related code in analysis phase
1858
1841
attribute . value [ 0 ] . data = '\n' + attribute . value [ 0 ] . data ;
1859
1842
}
1860
- content = {
1861
- escape : true ,
1862
- expression : serialize_attribute_value ( attribute . value , context )
1863
- } ;
1843
+ content = b . call ( '$.escape' , serialize_attribute_value ( attribute . value , context ) ) ;
1864
1844
} else if ( node . name !== 'select' ) {
1865
1845
// omit value attribute for select elements, it's irrelevant for the initially selected value and has no
1866
1846
// effect on the selected value after the user interacts with the select element (the value _property_ does, but not the attribute)
@@ -1903,19 +1883,12 @@ function serialize_element_attributes(node, context) {
1903
1883
if ( binding ?. omit_in_ssr ) continue ;
1904
1884
1905
1885
if ( ContentEditableBindings . includes ( attribute . name ) ) {
1906
- content = {
1907
- escape : false ,
1908
- expression : /** @type {import('estree').Expression } */ (
1909
- context . visit ( attribute . expression )
1910
- )
1911
- } ;
1886
+ content = /** @type {import('estree').Expression } */ ( context . visit ( attribute . expression ) ) ;
1912
1887
} 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
- } ;
1888
+ content = b . call (
1889
+ '$.escape' ,
1890
+ /** @type {import('estree').Expression } */ ( context . visit ( attribute . expression ) )
1891
+ ) ;
1919
1892
} else if ( attribute . name === 'group' ) {
1920
1893
const value_attribute = /** @type {import('#compiler').Attribute | undefined } */ (
1921
1894
node . attributes . find ( ( attr ) => attr . type === 'Attribute' && attr . name === 'value' )
0 commit comments