@ -3,7 +3,7 @@
/** @import { ComponentContext, ComponentServerTransformState } from '../../types.js' */
import { is _event _attribute , is _text _attribute } from '../../../../../utils/ast.js' ;
import { binding _properties } from '../../../../bindings.js' ;
import { create_attribute , ExpressionMetadata, is _custom _element _node } from '../../../../nodes.js' ;
import { ExpressionMetadata, is _custom _element _node } from '../../../../nodes.js' ;
import { regex _starts _with _newline } from '../../../../patterns.js' ;
import * as b from '#compiler/builders' ;
import {
@ -21,6 +21,11 @@ import { escape_html } from '../../../../../../escaping.js';
const WHITESPACE _INSENSITIVE _ATTRIBUTES = [ 'class' , 'style' ] ;
/ * *
* @ typedef { { type : 'transformed' , name : string , expression : Expression } } TransformedAttribute
* An attribute whose expression has already been transformed and must not be visited again .
* /
/ * *
* Writes the output to the template output . Some elements may have attributes on them that require the
* their output to be the child content instead . In this case , an object is returned .
@ -29,7 +34,7 @@ const WHITESPACE_INSENSITIVE_ATTRIBUTES = ['class', 'style'];
* @ param { ( expression : Expression , metadata : ExpressionMetadata ) => Expression } transform
* /
export function build _element _attributes ( node , context , transform ) {
/** @type {Array<AST.Attribute | AST.SpreadAttribute >} */
/** @type {Array<AST.Attribute | AST.SpreadAttribute | TransformedAttribute >} */
const attributes = [ ] ;
/** @type {AST.ClassDirective[]} */
@ -145,42 +150,26 @@ export function build_element_attributes(node, context, transform) {
attr . value [ 0 ] . data === 'checkbox'
) ;
attributes . push (
create _attribute ( 'checked' , null , - 1 , - 1 , [
{
type : 'ExpressionTag' ,
start : - 1 ,
end : - 1 ,
expression : is _checkbox
? b . call (
b . member ( attribute . expression , 'includes' ) ,
build _attribute _value ( value _attribute . value , context , transform )
)
: b . binary (
'===' ,
attribute . expression ,
build _attribute _value ( value _attribute . value , context , transform )
) ,
metadata : {
expression : new ExpressionMetadata ( )
}
}
] )
) ;
attributes . push ( {
type : 'transformed' ,
name : 'checked' ,
expression : is _checkbox
? b . call (
b . member ( expression , 'includes' ) ,
build _attribute _value ( value _attribute . value , context , transform )
)
: b . binary (
'===' ,
expression ,
build _attribute _value ( value _attribute . value , context , transform )
)
} ) ;
} else {
attributes . push (
create _attribute ( attribute . name , null , - 1 , - 1 , [
{
type : 'ExpressionTag' ,
start : - 1 ,
end : - 1 ,
expression ,
metadata : {
expression : new ExpressionMetadata ( )
}
}
] )
) ;
attributes . push ( {
type : 'transformed' ,
name : get _attribute _name ( node , attribute ) ,
expression
} ) ;
}
} else if ( attribute . type === 'SpreadAttribute' ) {
attributes . push ( attribute ) ;
@ -217,7 +206,21 @@ export function build_element_attributes(node, context, transform) {
} else {
const css _hash = node . metadata . scoped ? context . state . analysis . css . hash : null ;
for ( const attribute of /** @type {AST.Attribute[]} */ ( attributes ) ) {
for ( const attribute of /** @type {Array<AST.Attribute | TransformedAttribute>} */ (
attributes
) ) {
if ( attribute . type === 'transformed' ) {
context . state . template . push (
b . call (
'$.attr' ,
b . literal ( attribute . name ) ,
attribute . expression ,
is _boolean _attribute ( attribute . name ) && b . true
)
) ;
continue ;
}
const name = get _attribute _name ( node , attribute ) ;
const can _use _literal =
( name !== 'class' || class _directives . length === 0 ) &&
@ -298,14 +301,16 @@ function get_attribute_name(element, attribute) {
/ * *
* @ param { AST . RegularElement | AST . SvelteElement } element
* @ param { Array < AST . Attribute | AST . SpreadAttribute | AST . BindDirective > } attributes
* @ param { Array < AST . Attribute | AST . SpreadAttribute | AST . BindDirective | TransformedAttribute > } attributes
* @ param { ComponentContext } context
* @ param { ( expression : Expression , metadata : ExpressionMetadata ) => Expression } transform
* /
export function build _spread _object ( element , attributes , context , transform ) {
const object = b . object (
attributes . map ( ( attribute ) => {
if ( attribute . type === 'Attribute' ) {
if ( attribute . type === 'transformed' ) {
return b . prop ( 'init' , b . key ( attribute . name ) , attribute . expression ) ;
} else if ( attribute . type === 'Attribute' ) {
const name = get _attribute _name ( element , attribute ) ;
const value = build _attribute _value (
attribute . value ,
@ -340,7 +345,7 @@ export function build_spread_object(element, attributes, context, transform) {
/ * *
*
* @ param { AST . RegularElement | AST . SvelteElement } element
* @ param { Array < AST . Attribute | AST . SpreadAttribute > } attributes
* @ param { Array < AST . Attribute | AST . SpreadAttribute | TransformedAttribute > } attributes
* @ param { AST . StyleDirective [ ] } style _directives
* @ param { AST . ClassDirective [ ] } class _directives
* @ param { ComponentContext } context
@ -356,7 +361,7 @@ function build_element_spread_attributes(
) {
const args = prepare _element _spread (
element ,
/** @type {Array<AST.Attribute | AST.SpreadAttribute | AST.BindDirective>} */ ( attributes ) ,
attributes ,
style _directives ,
class _directives ,
context ,
@ -410,7 +415,7 @@ export function prepare_element_spread_object(element, context, transform) {
/ * *
* Prepare args for $ . attributes ( ... ) : compute object , css _hash , classes , styles and flags .
* @ param { AST . RegularElement | AST . SvelteElement } element
* @ param { Array < AST . Attribute | AST . SpreadAttribute | AST . BindDirective > } attributes
* @ param { Array < AST . Attribute | AST . SpreadAttribute | AST . BindDirective | TransformedAttribute > } attributes
* @ param { AST . StyleDirective [ ] } style _directives
* @ param { AST . ClassDirective [ ] } class _directives
* @ param { ComponentContext } context