@ -33,16 +33,21 @@ import {
import { escape _html } from '../../../../escaping.js' ;
import { escape _html } from '../../../../escaping.js' ;
import { sanitize _template _string } from '../../../utils/sanitize_template_string.js' ;
import { sanitize _template _string } from '../../../utils/sanitize_template_string.js' ;
import {
import {
BLOCK_ANCHOR ,
EMPTY_COMMENT ,
BLOCK _CLOSE ,
BLOCK _CLOSE ,
BLOCK _ CLOSE_ELSE ,
BLOCK _ OPEN ,
BLOCK _OPEN
BLOCK _OPEN _ELSE
} from '../../../../internal/server/hydration.js' ;
} from '../../../../internal/server/hydration.js' ;
import { filename , locator } from '../../../state.js' ;
import { filename , locator } from '../../../state.js' ;
export const block _open = b . literal ( BLOCK _OPEN ) ;
/** Opens an if/each block, so that we can remove nodes in the case of a mismatch */
export const block _close = b . literal ( BLOCK _CLOSE ) ;
const block _open = b . literal ( BLOCK _OPEN ) ;
export const block _anchor = b . literal ( BLOCK _ANCHOR ) ;
/** Closes an if/each block, so that we can remove nodes in the case of a mismatch. Also serves as an anchor for these blocks */
const block _close = b . literal ( BLOCK _CLOSE ) ;
/** Empty comment to keep text nodes separate, or provide an anchor node for blocks */
const empty _comment = b . literal ( EMPTY _COMMENT ) ;
/ * *
/ * *
* @ param { import ( 'estree' ) . Node } node
* @ param { import ( 'estree' ) . Node } node
@ -996,22 +1001,32 @@ function serialize_inline_component(node, expression, context) {
statement = b . block ( [ ... snippet _declarations , statement ] ) ;
statement = b . block ( [ ... snippet _declarations , statement ] ) ;
}
}
const dynamic =
node . type === 'SvelteComponent' || ( node . type === 'Component' && node . metadata . dynamic ) ;
if ( custom _css _props . length > 0 ) {
if ( custom _css _props . length > 0 ) {
statement = b . stmt (
context . state . template . push (
b . call (
b . stmt (
'$.css_props' ,
b . call (
b . id ( '$$payload' ) ,
'$.css_props' ,
b . literal ( context . state . namespace === 'svg' ? false : true ) ,
b . id ( '$$payload' ) ,
b . object ( custom _css _props ) ,
b . literal ( context . state . namespace === 'svg' ? false : true ) ,
b . thunk ( b . block ( [ statement ] ) )
b . object ( custom _css _props ) ,
b . thunk ( b . block ( [ statement ] ) ) ,
dynamic && b . true
)
)
)
) ;
) ;
} else {
if ( dynamic ) {
context . state . template . push ( empty _comment ) ;
}
context . state . template . push ( statement ) ;
context . state . template . push ( statement ) ;
} else if ( context . state . skip _hydration _boundaries ) {
context . state . template . push ( statement ) ;
if ( ! context . state . skip_hydration _boundaries ) {
} else {
context . state . template . push ( empty _comment ) ;
context . state . template . push ( block _open , statement , block _close ) ;
}
}
}
}
}
@ -1119,7 +1134,7 @@ const template_visitors = {
const parent = context . path . at ( - 1 ) ? ? node ;
const parent = context . path . at ( - 1 ) ? ? node ;
const namespace = infer _namespace ( context . state . namespace , parent , node . nodes ) ;
const namespace = infer _namespace ( context . state . namespace , parent , node . nodes ) ;
const { hoisted , trimmed , is _standalone } = clean _nodes (
const { hoisted , trimmed , is _standalone , is _text _first } = clean _nodes (
parent ,
parent ,
node . nodes ,
node . nodes ,
context . path ,
context . path ,
@ -1142,13 +1157,18 @@ const template_visitors = {
context . visit ( node , state ) ;
context . visit ( node , state ) ;
}
}
if ( is _text _first ) {
// insert `<!---->` to prevent this from being glued to the previous fragment
state . template . push ( empty _comment ) ;
}
process _children ( trimmed , { ... context , state } ) ;
process _children ( trimmed , { ... context , state } ) ;
return b . block ( [ ... state . init , ... serialize _template ( state . template ) ] ) ;
return b . block ( [ ... state . init , ... serialize _template ( state . template ) ] ) ;
} ,
} ,
HtmlTag ( node , context ) {
HtmlTag ( node , context ) {
const expression = /** @type {import('estree').Expression} */ ( context . visit ( node . expression ) ) ;
const expression = /** @type {import('estree').Expression} */ ( context . visit ( node . expression ) ) ;
context . state . template . push ( block_open , expression , block _close ) ;
context . state . template . push ( empty_comment , expression , empty _comment ) ;
} ,
} ,
ConstTag ( node , { state , visit } ) {
ConstTag ( node , { state , visit } ) {
const declaration = node . declaration . declarations [ 0 ] ;
const declaration = node . declaration . declarations [ 0 ] ;
@ -1188,10 +1208,6 @@ const template_visitors = {
return /** @type {import('estree').Expression} */ ( context . visit ( arg ) ) ;
return /** @type {import('estree').Expression} */ ( context . visit ( arg ) ) ;
} ) ;
} ) ;
if ( ! context . state . skip _hydration _boundaries ) {
context . state . template . push ( block _open ) ;
}
context . state . template . push (
context . state . template . push (
b . stmt (
b . stmt (
( node . expression . type === 'CallExpression' ? b . call : b . maybe _call ) (
( node . expression . type === 'CallExpression' ? b . call : b . maybe _call ) (
@ -1203,7 +1219,7 @@ const template_visitors = {
) ;
) ;
if ( ! context . state . skip _hydration _boundaries ) {
if ( ! context . state . skip _hydration _boundaries ) {
context . state . template . push ( block_close ) ;
context . state . template . push ( empty_comment ) ;
}
}
} ,
} ,
ClassDirective ( ) {
ClassDirective ( ) {
@ -1353,7 +1369,6 @@ const template_visitors = {
} ,
} ,
EachBlock ( node , context ) {
EachBlock ( node , context ) {
const state = context . state ;
const state = context . state ;
state . template . push ( block _open ) ;
const each _node _meta = node . metadata ;
const each _node _meta = node . metadata ;
const collection = /** @type {import('estree').Expression} */ ( context . visit ( node . expression ) ) ;
const collection = /** @type {import('estree').Expression} */ ( context . visit ( node . expression ) ) ;
@ -1376,12 +1391,8 @@ const template_visitors = {
each . push ( b . let ( node . index , index ) ) ;
each . push ( b . let ( node . index , index ) ) ;
}
}
each . push ( b . stmt ( b . assignment ( '+=' , b . id ( '$$payload.out' ) , b . literal ( BLOCK _OPEN ) ) ) ) ;
each . push ( ... /** @type {import('estree').BlockStatement} */ ( context . visit ( node . body ) ) . body ) ;
each . push ( ... /** @type {import('estree').BlockStatement} */ ( context . visit ( node . body ) ) . body ) ;
each . push ( b . stmt ( b . assignment ( '+=' , b . id ( '$$payload.out' ) , b . literal ( BLOCK _CLOSE ) ) ) ) ;
const for _loop = b . for (
const for _loop = b . for (
b . let ( index , b . literal ( 0 ) ) ,
b . let ( index , b . literal ( 0 ) ) ,
b . binary ( '<' , index , b . member ( array _id , b . id ( 'length' ) ) ) ,
b . binary ( '<' , index , b . member ( array _id , b . id ( 'length' ) ) ) ,
@ -1389,26 +1400,27 @@ const template_visitors = {
b . block ( each )
b . block ( each )
) ;
) ;
const close = b . stmt ( b . assignment ( '+=' , b . id ( '$$payload.out' ) , b . literal ( BLOCK _CLOSE ) ) ) ;
if ( node . fallback ) {
if ( node . fallback ) {
const open = b . stmt ( b . assignment ( '+=' , b . id ( '$$payload.out' ) , block _open ) ) ;
const fallback = /** @type {import('estree').BlockStatement} */ (
const fallback = /** @type {import('estree').BlockStatement} */ (
context . visit ( node . fallback )
context . visit ( node . fallback )
) ;
) ;
fallback . body . p ush(
fallback . body . un shift (
b . stmt ( b . assignment ( '+=' , b . id ( '$$payload.out' ) , b . literal ( BLOCK _ CLOSE _ELSE ) ) )
b . stmt ( b . assignment ( '+=' , b . id ( '$$payload.out' ) , b . literal ( BLOCK _ OPEN _ELSE ) ) )
) ;
) ;
state . template . push (
state . template . push (
b . if (
b . if (
b . binary ( '!==' , b . member ( array _id , b . id ( 'length' ) ) , b . literal ( 0 ) ) ,
b . binary ( '!==' , b . member ( array _id , b . id ( 'length' ) ) , b . literal ( 0 ) ) ,
b . block ( [ for_loop , close ] ) ,
b . block ( [ open, for_loop ] ) ,
fallback
fallback
)
) ,
block _close
) ;
) ;
} else {
} else {
state . template . push ( for_loop , close) ;
state . template . push ( block_open , for_loop , block_ close) ;
}
}
} ,
} ,
IfBlock ( node , context ) {
IfBlock ( node , context ) {
@ -1422,16 +1434,17 @@ const template_visitors = {
? /** @type {import('estree').BlockStatement} */ ( context . visit ( node . alternate ) )
? /** @type {import('estree').BlockStatement} */ ( context . visit ( node . alternate ) )
: b . block ( [ ] ) ;
: b . block ( [ ] ) ;
consequent . body . push ( b . stmt ( b . assignment ( '+=' , b . id ( '$$payload.out' ) , b . literal ( BLOCK _CLOSE ) ) ) ) ;
consequent . body . unshift ( b . stmt ( b . assignment ( '+=' , b . id ( '$$payload.out' ) , block _open ) ) ) ;
alternate . body . push (
b . stmt ( b . assignment ( '+=' , b . id ( '$$payload.out' ) , b . literal ( BLOCK _CLOSE _ELSE ) ) )
alternate . body . unshift (
b . stmt ( b . assignment ( '+=' , b . id ( '$$payload.out' ) , b . literal ( BLOCK _OPEN _ELSE ) ) )
) ;
) ;
context . state . template . push ( b lock_open , b . if ( test , consequent , alternate ) ) ;
context . state . template . push ( b . if ( test , consequent , alternate ) , block _close ) ;
} ,
} ,
AwaitBlock ( node , context ) {
AwaitBlock ( node , context ) {
context . state . template . push (
context . state . template . push (
block_open ,
empty_comment ,
b . stmt (
b . stmt (
b . call (
b . call (
'$.await' ,
'$.await' ,
@ -1455,12 +1468,12 @@ const template_visitors = {
)
)
)
)
) ,
) ,
block_close
empty_comment
) ;
) ;
} ,
} ,
KeyBlock ( node , context ) {
KeyBlock ( node , context ) {
const block = /** @type {import('estree').BlockStatement} */ ( context . visit ( node . fragment ) ) ;
const block = /** @type {import('estree').BlockStatement} */ ( context . visit ( node . fragment ) ) ;
context . state . template . push ( block_open , block , block _close ) ;
context . state . template . push ( empty_comment , block , empty _comment ) ;
} ,
} ,
SnippetBlock ( node , context ) {
SnippetBlock ( node , context ) {
const fn = b . function _declaration (
const fn = b . function _declaration (
@ -1594,7 +1607,7 @@ const template_visitors = {
const slot = b . call ( '$.slot' , b . id ( '$$payload' ) , expression , props _expression , fallback ) ;
const slot = b . call ( '$.slot' , b . id ( '$$payload' ) , expression , props _expression , fallback ) ;
context . state . template . push ( block_open , b . stmt ( slot ) , block _close ) ;
context . state . template . push ( empty_comment , b . stmt ( slot ) , empty _comment ) ;
} ,
} ,
SvelteHead ( node , context ) {
SvelteHead ( node , context ) {
const block = /** @type {import('estree').BlockStatement} */ ( context . visit ( node . fragment ) ) ;
const block = /** @type {import('estree').BlockStatement} */ ( context . visit ( node . fragment ) ) ;