@@ -13,7 +13,8 @@ export { VueJSXPluginOptions };
13
13
const hasJSX = ( parentPath : NodePath < t . Program > ) => {
14
14
let fileHasJSX = false ;
15
15
parentPath . traverse ( {
16
- JSXElement ( path ) { // skip ts error
16
+ JSXElement ( path ) {
17
+ // skip ts error
17
18
fileHasJSX = true ;
18
19
path . stop ( ) ;
19
20
} ,
@@ -62,14 +63,9 @@ export default ({ types }: typeof BabelCore) => ({
62
63
if ( importMap [ name ] ) {
63
64
return types . cloneNode ( importMap [ name ] ) ;
64
65
}
65
- const identifier = addNamed (
66
- path ,
67
- name ,
68
- 'vue' ,
69
- {
70
- ensureLiveReference : true ,
71
- } ,
72
- ) ;
66
+ const identifier = addNamed ( path , name , 'vue' , {
67
+ ensureLiveReference : true ,
68
+ } ) ;
73
69
importMap [ name ] = identifier ;
74
70
return identifier ;
75
71
} ) ;
@@ -80,14 +76,18 @@ export default ({ types }: typeof BabelCore) => ({
80
76
if ( importMap . runtimeIsSlot ) {
81
77
return importMap . runtimeIsSlot ;
82
78
}
83
- const { name : isVNodeName } = state . get ( 'isVNode' ) ( ) ;
79
+ const { name : isVNodeName } = state . get (
80
+ 'isVNode' ,
81
+ ) ( ) as t . Identifier ;
84
82
const isSlot = path . scope . generateUidIdentifier ( 'isSlot' ) ;
85
83
const ast = template . ast `
86
84
function ${ isSlot . name } (s) {
87
85
return typeof s === 'function' || (Object.prototype.toString.call(s) === '[object Object]' && !${ isVNodeName } (s));
88
86
}
89
87
` ;
90
- const lastImport = ( path . get ( 'body' ) as NodePath [ ] ) . filter ( ( p ) => p . isImportDeclaration ( ) ) . pop ( ) ;
88
+ const lastImport = ( path . get ( 'body' ) as NodePath [ ] )
89
+ . filter ( ( p ) => p . isImportDeclaration ( ) )
90
+ . pop ( ) ;
91
91
if ( lastImport ) {
92
92
lastImport . insertAfter ( ast ) ;
93
93
}
@@ -97,24 +97,57 @@ export default ({ types }: typeof BabelCore) => ({
97
97
}
98
98
} else {
99
99
// var _vue = require('vue');
100
- let sourceName = '' ;
100
+ let sourceName : t . Identifier ;
101
101
importNames . forEach ( ( name ) => {
102
102
state . set ( name , ( ) => {
103
103
if ( ! sourceName ) {
104
- sourceName = addNamespace (
105
- path ,
106
- 'vue' ,
107
- {
108
- ensureLiveReference : true ,
109
- } ,
110
- ) . name ;
104
+ sourceName = addNamespace ( path , 'vue' , {
105
+ ensureLiveReference : true ,
106
+ } ) ;
111
107
}
112
- return t . memberExpression ( t . identifier ( sourceName ) , t . identifier ( name ) ) ;
108
+ return t . memberExpression ( sourceName , t . identifier ( name ) ) ;
113
109
} ) ;
114
110
} ) ;
111
+
112
+ const helpers : Record < string , t . Identifier > = { } ;
113
+
114
+ const { enableObjectSlots = true } = state . opts ;
115
+ if ( enableObjectSlots ) {
116
+ state . set ( '@vue/babel-plugin-jsx/runtimeIsSlot' , ( ) => {
117
+ if ( helpers . runtimeIsSlot ) {
118
+ return helpers . runtimeIsSlot ;
119
+ }
120
+ const isSlot = path . scope . generateUidIdentifier ( 'isSlot' ) ;
121
+ const { object : objectName } = state . get (
122
+ 'isVNode' ,
123
+ ) ( ) as t . MemberExpression ;
124
+ const ast = template . ast `
125
+ function ${ isSlot . name } (s) {
126
+ return typeof s === 'function' || (Object.prototype.toString.call(s) === '[object Object]' && !${ ( objectName as t . Identifier ) . name } .isVNode(s));
127
+ }
128
+ ` ;
129
+
130
+ const nodePaths = path . get ( 'body' ) as NodePath [ ] ;
131
+ const lastImport = nodePaths
132
+ . filter (
133
+ ( p ) => p . isVariableDeclaration ( )
134
+ && p . node . declarations . some (
135
+ ( d ) => ( d . id as t . Identifier ) ?. name === sourceName . name ,
136
+ ) ,
137
+ )
138
+ . pop ( ) ;
139
+ if ( lastImport ) {
140
+ lastImport . insertAfter ( ast ) ;
141
+ }
142
+ return isSlot ;
143
+ } ) ;
144
+ }
115
145
}
116
146
117
- const { opts : { pragma = '' } , file } = state ;
147
+ const {
148
+ opts : { pragma = '' } ,
149
+ file,
150
+ } = state ;
118
151
119
152
if ( pragma ) {
120
153
state . set ( 'createVNode' , ( ) => t . identifier ( pragma ) ) ;
@@ -134,13 +167,20 @@ export default ({ types }: typeof BabelCore) => ({
134
167
const body = path . get ( 'body' ) as NodePath [ ] ;
135
168
const specifiersMap = new Map < string , t . ImportSpecifier > ( ) ;
136
169
137
- body . filter ( ( nodePath ) => t . isImportDeclaration ( nodePath . node )
138
- && nodePath . node . source . value === 'vue' )
170
+ body
171
+ . filter (
172
+ ( nodePath ) => t . isImportDeclaration ( nodePath . node )
173
+ && nodePath . node . source . value === 'vue' ,
174
+ )
139
175
. forEach ( ( nodePath ) => {
140
176
const { specifiers } = nodePath . node as t . ImportDeclaration ;
141
177
let shouldRemove = false ;
142
178
specifiers . forEach ( ( specifier ) => {
143
- if ( ! specifier . loc && t . isImportSpecifier ( specifier ) && t . isIdentifier ( specifier . imported ) ) {
179
+ if (
180
+ ! specifier . loc
181
+ && t . isImportSpecifier ( specifier )
182
+ && t . isIdentifier ( specifier . imported )
183
+ ) {
144
184
specifiersMap . set ( specifier . imported . name , specifier ) ;
145
185
shouldRemove = true ;
146
186
}
@@ -154,7 +194,10 @@ export default ({ types }: typeof BabelCore) => ({
154
194
( imported ) => specifiersMap . get ( imported ) ! ,
155
195
) ;
156
196
if ( specifiers . length ) {
157
- path . unshiftContainer ( 'body' , t . importDeclaration ( specifiers , t . stringLiteral ( 'vue' ) ) ) ;
197
+ path . unshiftContainer (
198
+ 'body' ,
199
+ t . importDeclaration ( specifiers , t . stringLiteral ( 'vue' ) ) ,
200
+ ) ;
158
201
}
159
202
} ,
160
203
} ,
0 commit comments