@@ -13,7 +13,8 @@ export { VueJSXPluginOptions };
1313const hasJSX = ( parentPath : NodePath < t . Program > ) => {
1414 let fileHasJSX = false ;
1515 parentPath . traverse ( {
16- JSXElement ( path ) { // skip ts error
16+ JSXElement ( path ) {
17+ // skip ts error
1718 fileHasJSX = true ;
1819 path . stop ( ) ;
1920 } ,
@@ -62,14 +63,9 @@ export default ({ types }: typeof BabelCore) => ({
6263 if ( importMap [ name ] ) {
6364 return types . cloneNode ( importMap [ name ] ) ;
6465 }
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+ } ) ;
7369 importMap [ name ] = identifier ;
7470 return identifier ;
7571 } ) ;
@@ -80,14 +76,18 @@ export default ({ types }: typeof BabelCore) => ({
8076 if ( importMap . runtimeIsSlot ) {
8177 return importMap . runtimeIsSlot ;
8278 }
83- const { name : isVNodeName } = state . get ( 'isVNode' ) ( ) ;
79+ const { name : isVNodeName } = state . get (
80+ 'isVNode' ,
81+ ) ( ) as t . Identifier ;
8482 const isSlot = path . scope . generateUidIdentifier ( 'isSlot' ) ;
8583 const ast = template . ast `
8684 function ${ isSlot . name } (s) {
8785 return typeof s === 'function' || (Object.prototype.toString.call(s) === '[object Object]' && !${ isVNodeName } (s));
8886 }
8987 ` ;
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 ( ) ;
9191 if ( lastImport ) {
9292 lastImport . insertAfter ( ast ) ;
9393 }
@@ -97,24 +97,57 @@ export default ({ types }: typeof BabelCore) => ({
9797 }
9898 } else {
9999 // var _vue = require('vue');
100- let sourceName = '' ;
100+ let sourceName : t . Identifier ;
101101 importNames . forEach ( ( name ) => {
102102 state . set ( name , ( ) => {
103103 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+ } ) ;
111107 }
112- return t . memberExpression ( t . identifier ( sourceName ) , t . identifier ( name ) ) ;
108+ return t . memberExpression ( sourceName , t . identifier ( name ) ) ;
113109 } ) ;
114110 } ) ;
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+ }
115145 }
116146
117- const { opts : { pragma = '' } , file } = state ;
147+ const {
148+ opts : { pragma = '' } ,
149+ file,
150+ } = state ;
118151
119152 if ( pragma ) {
120153 state . set ( 'createVNode' , ( ) => t . identifier ( pragma ) ) ;
@@ -134,13 +167,20 @@ export default ({ types }: typeof BabelCore) => ({
134167 const body = path . get ( 'body' ) as NodePath [ ] ;
135168 const specifiersMap = new Map < string , t . ImportSpecifier > ( ) ;
136169
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+ )
139175 . forEach ( ( nodePath ) => {
140176 const { specifiers } = nodePath . node as t . ImportDeclaration ;
141177 let shouldRemove = false ;
142178 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+ ) {
144184 specifiersMap . set ( specifier . imported . name , specifier ) ;
145185 shouldRemove = true ;
146186 }
@@ -154,7 +194,10 @@ export default ({ types }: typeof BabelCore) => ({
154194 ( imported ) => specifiersMap . get ( imported ) ! ,
155195 ) ;
156196 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+ ) ;
158201 }
159202 } ,
160203 } ,
0 commit comments