11import {
22 HELPER_PREFIX ,
33 importHelperFn ,
4- type MagicString ,
4+ type MagicStringAST ,
55} from '@vue-macros/common'
66import { walkIdentifiers } from '@vue/compiler-sfc'
77import { withDefaultsHelperId } from './helper'
@@ -10,6 +10,7 @@ import type { Node } from '@babel/types'
1010
1111type Options = {
1212 withDefaultsFrom ?: string
13+ skipDefaultProps ?: boolean
1314 generateRestProps ?: (
1415 restPropsName : string ,
1516 index : number ,
@@ -23,45 +24,52 @@ type Prop = {
2324 value : string
2425 defaultValue ?: string
2526 isRest ?: boolean
26- isRequired ?: boolean
2727}
2828
2929export function restructure (
30- s : MagicString ,
30+ s : MagicStringAST ,
3131 node : FunctionalNode ,
3232 options : Options = { } ,
3333) : Prop [ ] {
3434 let index = 0
3535 const propList : Prop [ ] = [ ]
3636 for ( const param of node . params ) {
3737 const path = `${ HELPER_PREFIX } props${ index ++ || '' } `
38- const props = getProps ( param , path , s , [ ] , options )
38+ const props = getProps ( s , options , param , path )
3939 if ( props ) {
40- const hasDefaultValue = props . some ( ( i ) => i . defaultValue )
4140 s . overwrite ( param . start ! , param . end ! , path )
42- propList . push (
43- ...( hasDefaultValue
44- ? props . map ( ( i ) => ( {
45- ...i ,
46- path : i . path . replace ( HELPER_PREFIX , `${ HELPER_PREFIX } default_` ) ,
47- } ) )
48- : props ) ,
49- )
41+ propList . push ( ...props )
5042 }
5143 }
5244
5345 if ( propList . length ) {
5446 const defaultValues : Record < string , Prop [ ] > = { }
5547 const rests = [ ]
5648 for ( const prop of propList ) {
57- if ( prop . defaultValue ) {
58- const basePath = prop . path . split ( / \. | \[ / ) [ 0 ]
59- ; ( defaultValues [ basePath ] ??= [ ] ) . push ( prop )
60- }
6149 if ( prop . isRest ) {
6250 rests . push ( prop )
6351 }
52+ if ( prop . defaultValue ) {
53+ const paths = prop . path . split ( / \. | \[ / )
54+ if ( ! options . skipDefaultProps || paths . length !== 1 ) {
55+ ; ( defaultValues [ paths [ 0 ] ] ??= [ ] ) . push ( prop )
56+ }
57+ }
58+ }
59+
60+ for ( const [ index , rest ] of rests . entries ( ) ) {
61+ prependFunctionalNode (
62+ node ,
63+ s ,
64+ options . generateRestProps ?.( rest . name , index , rests ) ??
65+ `\nconst ${ rest . name } = ${ importHelperFn (
66+ s ,
67+ 0 ,
68+ 'createPropsRestProxy' ,
69+ ) } (${ rest . path } , [${ rest . value } ])`,
70+ )
6471 }
72+
6573 for ( const [ path , values ] of Object . entries ( defaultValues ) ) {
6674 const createPropsDefaultProxy = importHelperFn (
6775 s ,
@@ -70,10 +78,6 @@ export function restructure(
7078 undefined ,
7179 options . withDefaultsFrom ?? withDefaultsHelperId ,
7280 )
73- const resolvedPath = path . replace (
74- `${ HELPER_PREFIX } default_` ,
75- HELPER_PREFIX ,
76- )
7781 const resolvedValues = values
7882 . map (
7983 ( i ) => `'${ i . path . replace ( path , '' ) } ${ i . value } ': ${ i . defaultValue } ` ,
@@ -82,20 +86,7 @@ export function restructure(
8286 prependFunctionalNode (
8387 node ,
8488 s ,
85- `\nconst ${ path } = ${ createPropsDefaultProxy } (${ resolvedPath } , {${ resolvedValues } })` ,
86- )
87- }
88-
89- for ( const [ index , rest ] of rests . entries ( ) ) {
90- prependFunctionalNode (
91- node ,
92- s ,
93- options . generateRestProps ?.( rest . name , index , rests ) ??
94- `\nconst ${ rest . name } = ${ importHelperFn (
95- s ,
96- 0 ,
97- 'createPropsRestProxy' ,
98- ) } (${ rest . path } , [${ rest . value } ])`,
89+ `\n${ path } = ${ createPropsDefaultProxy } (${ path } , {${ resolvedValues } })` ,
9990 )
10091 }
10192
@@ -123,11 +114,11 @@ export function restructure(
123114}
124115
125116function getProps (
117+ s : MagicStringAST ,
118+ options : Options ,
126119 node : Node ,
127- path : string = '' ,
128- s : MagicString ,
120+ path = '' ,
129121 props : Prop [ ] = [ ] ,
130- options : Options ,
131122) {
132123 const properties =
133124 node . type === 'ObjectPattern'
@@ -141,7 +132,11 @@ function getProps(
141132 properties . forEach ( ( prop , index ) => {
142133 if ( prop ?. type === 'Identifier' ) {
143134 // { foo }
144- props . push ( { name : prop . name , path, value : `[${ index } ]` } )
135+ props . push ( {
136+ name : prop . name ,
137+ path,
138+ value : `[${ index } ]` ,
139+ } )
145140 propNames . push ( `'${ prop . name } '` )
146141 } else if (
147142 prop ?. type === 'AssignmentPattern' &&
@@ -152,33 +147,41 @@ function getProps(
152147 path,
153148 name : prop . left . name ,
154149 value : `[${ index } ]` ,
155- defaultValue : s . slice ( prop . right . start ! , prop . right . end ! ) ,
150+ defaultValue : s . sliceNode ( getDefaultValue ( prop . right ) ) ,
156151 } )
157152 propNames . push ( `'${ prop . left . name } '` )
158153 } else if (
159154 prop ?. type === 'ObjectProperty' &&
160155 prop . key . type === 'Identifier'
161156 ) {
162- if (
163- prop . value . type === 'AssignmentPattern' &&
164- prop . value . left . type === 'Identifier'
165- ) {
166- // { foo: bar = 'foo' }
167- props . push ( {
168- path,
169- name : prop . value . left . name ,
170- value : `.${ prop . key . name } ` ,
171- defaultValue : s . slice ( prop . value . right . start ! , prop . value . right . end ! ) ,
172- isRequired : prop . value . right . type === 'TSNonNullExpression' ,
173- } )
157+ if ( prop . value . type === 'AssignmentPattern' ) {
158+ if ( prop . value . left . type === 'Identifier' ) {
159+ // { foo: bar = 'foo' }
160+ props . push ( {
161+ path,
162+ name : prop . value . left . name ,
163+ value : `.${ prop . key . name } ` ,
164+ defaultValue : s . sliceNode ( getDefaultValue ( prop . value . right ) ) ,
165+ } )
166+ } else {
167+ // { foo: { bar } = {} }
168+ getProps (
169+ s ,
170+ options ,
171+ prop . value . left ,
172+ `${ path } .${ prop . key . name } ` ,
173+ props ,
174+ )
175+ }
174176 } else if (
175- ! getProps ( prop . value , `${ path } .${ prop . key . name } ` , s , props , options )
177+ ! getProps ( s , options , prop . value , `${ path } .${ prop . key . name } ` , props )
176178 ) {
177179 // { foo: bar }
180+ const name =
181+ prop . value . type === 'Identifier' ? prop . value . name : prop . key . name
178182 props . push ( {
179183 path,
180- name :
181- prop . value . type === 'Identifier' ? prop . value . name : prop . key . name ,
184+ name,
182185 value : `.${ prop . key . name } ` ,
183186 } )
184187 }
@@ -196,15 +199,25 @@ function getProps(
196199 isRest : true ,
197200 } )
198201 } else if ( prop ) {
199- getProps ( prop , `${ path } [${ index } ]` , s , props , options )
202+ getProps ( s , options , prop , `${ path } [${ index } ]` , props )
200203 }
201204 } )
202205 return props . length ? props : undefined
203206}
204207
208+ export function getDefaultValue ( node : Node ) : Node {
209+ if ( node . type === 'TSNonNullExpression' ) {
210+ return getDefaultValue ( node . expression )
211+ }
212+ if ( node . type === 'TSAsExpression' ) {
213+ return getDefaultValue ( node . expression )
214+ }
215+ return node
216+ }
217+
205218function prependFunctionalNode (
206219 node : FunctionalNode ,
207- s : MagicString ,
220+ s : MagicStringAST ,
208221 result : string ,
209222) : void {
210223 const isBlockStatement = node . body . type === 'BlockStatement'
0 commit comments