@@ -15,6 +15,7 @@ import type {
1515 TransformContext ,
1616} from '../transform'
1717import {
18+ DynamicFlag ,
1819 IRNodeTypes ,
1920 type IRProp ,
2021 type IRProps ,
@@ -29,8 +30,7 @@ export const isReservedProp = /*#__PURE__*/ makeMap(
2930
3031export const transformElement : NodeTransform = ( node , context ) => {
3132 return function postTransformElement ( ) {
32- node = context . node
33-
33+ ; ( { node } = context )
3434 if (
3535 ! (
3636 node . type === NodeTypes . ELEMENT &&
@@ -41,37 +41,94 @@ export const transformElement: NodeTransform = (node, context) => {
4141 return
4242 }
4343
44- const { tag, props } = node
45- const isComponent = node . tagType === ElementTypes . COMPONENT
44+ const { tag, tagType } = node
45+ const isComponent = tagType === ElementTypes . COMPONENT
46+ const propsResult = buildProps (
47+ node ,
48+ context as TransformContext < ElementNode > ,
49+ )
50+
51+ ; ( isComponent ? transformComponentElement : transformNativeElement ) (
52+ tag ,
53+ propsResult ,
54+ context ,
55+ )
56+ }
57+ }
4658
47- context . template += `<${ tag } `
48- if ( props . length ) {
49- buildProps (
50- node ,
51- context as TransformContext < ElementNode > ,
52- undefined ,
53- isComponent ,
54- )
55- }
56- const { scopeId } = context . options
57- if ( scopeId ) {
58- context . template += ` ${ scopeId } `
59- }
60- context . template += `>` + context . childrenTemplate . join ( '' )
59+ function transformComponentElement (
60+ tag : string ,
61+ propsResult : PropsResult ,
62+ context : TransformContext ,
63+ ) {
64+ const { bindingMetadata } = context . options
65+ const resolve = ! bindingMetadata [ tag ]
66+ context . dynamic . flags |= DynamicFlag . NON_TEMPLATE | DynamicFlag . INSERT
67+
68+ context . registerOperation ( {
69+ type : IRNodeTypes . CREATE_COMPONENT_NODE ,
70+ id : context . reference ( ) ,
71+ tag,
72+ props : propsResult [ 0 ] ? propsResult [ 1 ] : [ propsResult [ 1 ] ] ,
73+ resolve,
74+ } )
75+ }
6176
62- // TODO remove unnecessary close tag, e.g. if it's the last element of the template
63- if ( ! isVoidTag ( tag ) ) {
64- context . template += `</${ tag } >`
77+ function transformNativeElement (
78+ tag : string ,
79+ propsResult : ReturnType < typeof buildProps > ,
80+ context : TransformContext ,
81+ ) {
82+ const { scopeId } = context . options
83+
84+ context . template += `<${ tag } `
85+ if ( scopeId ) context . template += ` ${ scopeId } `
86+
87+ if ( propsResult [ 0 ] /* dynamic props */ ) {
88+ const [ , dynamicArgs , expressions ] = propsResult
89+ context . registerEffect ( expressions , [
90+ {
91+ type : IRNodeTypes . SET_DYNAMIC_PROPS ,
92+ element : context . reference ( ) ,
93+ props : dynamicArgs ,
94+ } ,
95+ ] )
96+ } else {
97+ for ( const prop of propsResult [ 1 ] ) {
98+ const { key, values } = prop
99+ if ( key . isStatic && values . length === 1 && values [ 0 ] . isStatic ) {
100+ context . template += ` ${ key . content } `
101+ if ( values [ 0 ] . content ) context . template += `="${ values [ 0 ] . content } "`
102+ } else {
103+ context . registerEffect ( values , [
104+ {
105+ type : IRNodeTypes . SET_PROP ,
106+ element : context . reference ( ) ,
107+ prop,
108+ } ,
109+ ] )
110+ }
65111 }
66112 }
113+
114+ context . template += `>` + context . childrenTemplate . join ( '' )
115+ // TODO remove unnecessary close tag, e.g. if it's the last element of the template
116+ if ( ! isVoidTag ( tag ) ) {
117+ context . template += `</${ tag } >`
118+ }
67119}
68120
121+ export type PropsResult =
122+ | [ dynamic : true , props : IRProps [ ] , expressions : SimpleExpressionNode [ ] ]
123+ | [ dynamic : false , props : IRProp [ ] ]
124+
69125function buildProps (
70126 node : ElementNode ,
71127 context : TransformContext < ElementNode > ,
72- props : ( VaporDirectiveNode | AttributeNode ) [ ] = node . props as any ,
73- isComponent : boolean ,
74- ) {
128+ ) : PropsResult {
129+ const props = node . props as ( VaporDirectiveNode | AttributeNode ) [ ]
130+ if ( props . length === 0 ) return [ false , [ ] ]
131+
75132 const dynamicArgs : IRProps [ ] = [ ]
76133 const dynamicExpr : SimpleExpressionNode [ ] = [ ]
77134 let results : DirectiveTransformResult [ ] = [ ]
@@ -112,31 +169,11 @@ function buildProps(
112169 if ( dynamicArgs . length || results . some ( ( { key } ) => ! key . isStatic ) ) {
113170 // take rest of props as dynamic props
114171 pushMergeArg ( )
115- context . registerEffect ( dynamicExpr , [
116- {
117- type : IRNodeTypes . SET_DYNAMIC_PROPS ,
118- element : context . reference ( ) ,
119- props : dynamicArgs ,
120- } ,
121- ] )
122- } else {
123- const irProps = dedupeProperties ( results )
124- for ( const prop of irProps ) {
125- const { key, values } = prop
126- if ( key . isStatic && values . length === 1 && values [ 0 ] . isStatic ) {
127- context . template += ` ${ key . content } `
128- if ( values [ 0 ] . content ) context . template += `="${ values [ 0 ] . content } "`
129- } else {
130- context . registerEffect ( values , [
131- {
132- type : IRNodeTypes . SET_PROP ,
133- element : context . reference ( ) ,
134- prop,
135- } ,
136- ] )
137- }
138- }
172+ return [ true , dynamicArgs , dynamicExpr ]
139173 }
174+
175+ const irProps = dedupeProperties ( results )
176+ return [ false , irProps ]
140177}
141178
142179function transformProp (
0 commit comments