1
1
import {
2
2
type AttributeNode ,
3
+ createCompilerError ,
3
4
type ElementNode ,
4
5
ElementTypes ,
6
+ ErrorCodes ,
7
+ ExpressionNode ,
8
+ isStaticExp ,
5
9
NodeTypes ,
10
+ type ObjectExpression ,
6
11
} from '@vue/compiler-dom'
7
12
import { isBuiltInDirective , isReservedProp , isVoidTag } from '@vue/shared'
8
- import type { NodeTransform , TransformContext } from '../transform'
13
+ import {
14
+ DirectiveTransformResult ,
15
+ NodeTransform ,
16
+ TransformContext ,
17
+ } from '../transform'
9
18
import { IRNodeTypes , type VaporDirectiveNode } from '../ir'
10
19
11
20
export const transformElement : NodeTransform = ( node , ctx ) => {
@@ -49,16 +58,120 @@ function buildProps(
49
58
props : ElementNode [ 'props' ] = node . props ,
50
59
isComponent : boolean ,
51
60
) {
61
+ const expressions = [ ]
62
+ const properties : ObjectExpression [ 'properties' ] = [ ]
63
+ const mergeArgs : ExpressionNode [ ] = [ ]
64
+
65
+ const pushMergeArg = ( arg ?: ExpressionNode ) => {
66
+ if ( properties . length ) {
67
+ // TODO dedupe properties
68
+ mergeArgs . push ( [ ...properties ] )
69
+ properties . length = 0
70
+ }
71
+ }
72
+
52
73
for ( const prop of props ) {
53
- transformProp ( prop as VaporDirectiveNode | AttributeNode , node , context )
74
+ if ( prop . type === NodeTypes . DIRECTIVE ) {
75
+ const isVBind = prop . name === 'bind'
76
+ if ( ! prop . arg && isVBind ) {
77
+ if ( prop . exp ) {
78
+ if ( isVBind ) {
79
+ pushMergeArg ( )
80
+ expressions . push ( prop . exp )
81
+ mergeArgs . push ( [ prop . exp ] )
82
+ }
83
+ } else {
84
+ context . options . onError (
85
+ createCompilerError ( ErrorCodes . X_V_BIND_NO_EXPRESSION , prop . loc ) ,
86
+ )
87
+ }
88
+ continue
89
+ }
90
+ }
91
+
92
+ const result = transformProp (
93
+ prop as VaporDirectiveNode | AttributeNode ,
94
+ node ,
95
+ context ,
96
+ )
97
+ if ( result ) {
98
+ const { props : propsObj } = result
99
+ for ( const prop of propsObj ) {
100
+ ! isStaticExp ( prop . key ) && expressions . push ( prop . key )
101
+ ! isStaticExp ( prop . value ) && expressions . push ( prop . value )
102
+ }
103
+ properties . push ( ...propsObj )
104
+ }
105
+ }
106
+
107
+ if ( mergeArgs . length ) {
108
+ pushMergeArg ( )
109
+ if ( mergeArgs . length > 1 ) {
110
+ context . registerEffect ( expressions , [
111
+ {
112
+ type : IRNodeTypes . SET_ARR_PROPS ,
113
+ loc : node . loc ,
114
+ element : context . reference ( ) ,
115
+ value : mergeArgs ,
116
+ needMerge : true ,
117
+ } ,
118
+ ] )
119
+ } else {
120
+ context . registerEffect ( expressions , [
121
+ {
122
+ type : IRNodeTypes . SET_ARR_PROPS ,
123
+ loc : node . loc ,
124
+ element : context . reference ( ) ,
125
+ value : mergeArgs ,
126
+ needMerge : false ,
127
+ } ,
128
+ ] )
129
+ }
130
+ } else if ( properties . length ) {
131
+ let hasDynamicKey = false
132
+ for ( let i = 0 ; i < properties . length ; i ++ ) {
133
+ const key = properties [ i ] . key
134
+ if ( isStaticExp ( key ) ) {
135
+ // todo
136
+ } else if ( ! key . isHandlerKey ) {
137
+ hasDynamicKey = true
138
+ }
139
+ }
140
+ if ( ! hasDynamicKey ) {
141
+ // TODO handle class/style prop
142
+ for ( const prop of properties ) {
143
+ context . registerEffect (
144
+ [ prop . value ] ,
145
+ [
146
+ {
147
+ ...prop ,
148
+ type : IRNodeTypes . SET_PROP ,
149
+ loc : prop . loc ,
150
+ element : context . reference ( ) ,
151
+ key : prop . key ,
152
+ value : prop . value ,
153
+ } ,
154
+ ] ,
155
+ )
156
+ }
157
+ } else {
158
+ context . registerEffect ( expressions , [
159
+ {
160
+ type : IRNodeTypes . SET_OBJ_PROPS ,
161
+ loc : node . loc ,
162
+ element : context . reference ( ) ,
163
+ value : properties ,
164
+ } ,
165
+ ] )
166
+ }
54
167
}
55
168
}
56
169
57
170
function transformProp (
58
171
prop : VaporDirectiveNode | AttributeNode ,
59
172
node : ElementNode ,
60
173
context : TransformContext < ElementNode > ,
61
- ) : void {
174
+ ) : void | DirectiveTransformResult {
62
175
const { name, loc } = prop
63
176
if ( isReservedProp ( name ) ) return
64
177
@@ -70,7 +183,7 @@ function transformProp(
70
183
71
184
const directiveTransform = context . options . directiveTransforms [ name ]
72
185
if ( directiveTransform ) {
73
- directiveTransform ( prop , node , context )
186
+ return directiveTransform ( prop , node , context )
74
187
} else if ( ! isBuiltInDirective ( name ) ) {
75
188
context . registerOperation ( {
76
189
type : IRNodeTypes . WITH_DIRECTIVE ,
0 commit comments