1
1
import {
2
2
HELPER_PREFIX ,
3
3
importHelperFn ,
4
- type MagicString ,
4
+ type MagicStringAST ,
5
5
} from '@vue-macros/common'
6
6
import { walkIdentifiers } from '@vue/compiler-sfc'
7
7
import { withDefaultsHelperId } from './helper'
@@ -10,6 +10,7 @@ import type { Node } from '@babel/types'
10
10
11
11
type Options = {
12
12
withDefaultsFrom ?: string
13
+ skipDefaultProps ?: boolean
13
14
generateRestProps ?: (
14
15
restPropsName : string ,
15
16
index : number ,
@@ -23,45 +24,52 @@ type Prop = {
23
24
value : string
24
25
defaultValue ?: string
25
26
isRest ?: boolean
26
- isRequired ?: boolean
27
27
}
28
28
29
29
export function restructure (
30
- s : MagicString ,
30
+ s : MagicStringAST ,
31
31
node : FunctionalNode ,
32
32
options : Options = { } ,
33
33
) : Prop [ ] {
34
34
let index = 0
35
35
const propList : Prop [ ] = [ ]
36
36
for ( const param of node . params ) {
37
37
const path = `${ HELPER_PREFIX } props${ index ++ || '' } `
38
- const props = getProps ( param , path , s , [ ] , options )
38
+ const props = getProps ( s , options , param , path )
39
39
if ( props ) {
40
- const hasDefaultValue = props . some ( ( i ) => i . defaultValue )
41
40
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 )
50
42
}
51
43
}
52
44
53
45
if ( propList . length ) {
54
46
const defaultValues : Record < string , Prop [ ] > = { }
55
47
const rests = [ ]
56
48
for ( const prop of propList ) {
57
- if ( prop . defaultValue ) {
58
- const basePath = prop . path . split ( / \. | \[ / ) [ 0 ]
59
- ; ( defaultValues [ basePath ] ??= [ ] ) . push ( prop )
60
- }
61
49
if ( prop . isRest ) {
62
50
rests . push ( prop )
63
51
}
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
+ )
64
71
}
72
+
65
73
for ( const [ path , values ] of Object . entries ( defaultValues ) ) {
66
74
const createPropsDefaultProxy = importHelperFn (
67
75
s ,
@@ -70,10 +78,6 @@ export function restructure(
70
78
undefined ,
71
79
options . withDefaultsFrom ?? withDefaultsHelperId ,
72
80
)
73
- const resolvedPath = path . replace (
74
- `${ HELPER_PREFIX } default_` ,
75
- HELPER_PREFIX ,
76
- )
77
81
const resolvedValues = values
78
82
. map (
79
83
( i ) => `'${ i . path . replace ( path , '' ) } ${ i . value } ': ${ i . defaultValue } ` ,
@@ -82,20 +86,7 @@ export function restructure(
82
86
prependFunctionalNode (
83
87
node ,
84
88
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 } })` ,
99
90
)
100
91
}
101
92
@@ -123,11 +114,11 @@ export function restructure(
123
114
}
124
115
125
116
function getProps (
117
+ s : MagicStringAST ,
118
+ options : Options ,
126
119
node : Node ,
127
- path : string = '' ,
128
- s : MagicString ,
120
+ path = '' ,
129
121
props : Prop [ ] = [ ] ,
130
- options : Options ,
131
122
) {
132
123
const properties =
133
124
node . type === 'ObjectPattern'
@@ -141,7 +132,11 @@ function getProps(
141
132
properties . forEach ( ( prop , index ) => {
142
133
if ( prop ?. type === 'Identifier' ) {
143
134
// { foo }
144
- props . push ( { name : prop . name , path, value : `[${ index } ]` } )
135
+ props . push ( {
136
+ name : prop . name ,
137
+ path,
138
+ value : `[${ index } ]` ,
139
+ } )
145
140
propNames . push ( `'${ prop . name } '` )
146
141
} else if (
147
142
prop ?. type === 'AssignmentPattern' &&
@@ -152,33 +147,41 @@ function getProps(
152
147
path,
153
148
name : prop . left . name ,
154
149
value : `[${ index } ]` ,
155
- defaultValue : s . slice ( prop . right . start ! , prop . right . end ! ) ,
150
+ defaultValue : s . sliceNode ( getDefaultValue ( prop . right ) ) ,
156
151
} )
157
152
propNames . push ( `'${ prop . left . name } '` )
158
153
} else if (
159
154
prop ?. type === 'ObjectProperty' &&
160
155
prop . key . type === 'Identifier'
161
156
) {
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
+ }
174
176
} else if (
175
- ! getProps ( prop . value , `${ path } .${ prop . key . name } ` , s , props , options )
177
+ ! getProps ( s , options , prop . value , `${ path } .${ prop . key . name } ` , props )
176
178
) {
177
179
// { foo: bar }
180
+ const name =
181
+ prop . value . type === 'Identifier' ? prop . value . name : prop . key . name
178
182
props . push ( {
179
183
path,
180
- name :
181
- prop . value . type === 'Identifier' ? prop . value . name : prop . key . name ,
184
+ name,
182
185
value : `.${ prop . key . name } ` ,
183
186
} )
184
187
}
@@ -196,15 +199,25 @@ function getProps(
196
199
isRest : true ,
197
200
} )
198
201
} else if ( prop ) {
199
- getProps ( prop , `${ path } [${ index } ]` , s , props , options )
202
+ getProps ( s , options , prop , `${ path } [${ index } ]` , props )
200
203
}
201
204
} )
202
205
return props . length ? props : undefined
203
206
}
204
207
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
+
205
218
function prependFunctionalNode (
206
219
node : FunctionalNode ,
207
- s : MagicString ,
220
+ s : MagicStringAST ,
208
221
result : string ,
209
222
) : void {
210
223
const isBlockStatement = node . body . type === 'BlockStatement'
0 commit comments