Skip to content

Commit 87ac6b6

Browse files
committed
feat(restructure): support RestElement
1 parent 9f1a148 commit 87ac6b6

File tree

2 files changed

+78
-13
lines changed

2 files changed

+78
-13
lines changed

src/core/transformRestructure.ts

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
babelParse,
44
generateTransform,
55
getLang,
6+
importHelperFn,
67
walkAST,
78
} from '@vue-macros/common'
89
import { walkIdentifiers } from '@vue-vapor/compiler-core'
@@ -18,12 +19,25 @@ export function transformRestructure(code: string, id: string) {
1819
enter(node) {
1920
if (isFunctionExpression(node)) {
2021
const result = new Map()
22+
const restResult = new Map()
2123
for (const param of node.params) {
2224
const paths = `_ctx${index++}`
23-
if (resolveParams(param, paths, result)) {
25+
if (resolveParam(param, paths, result, restResult)) {
2426
s.overwrite(param.start!, param.end!, paths)
2527
}
2628
}
29+
30+
if (restResult.size) {
31+
for (const [key, value] of restResult) {
32+
const result = `${key} = ${importHelperFn(s, 0, 'createPropsRestProxy', 'vue')}(${value})`
33+
if (node.body.type === 'BlockStatement') {
34+
s.appendRight(node.body.start! + 1, `const ${result};`)
35+
} else {
36+
s.appendRight(node.body.start!, `(${result},`)
37+
s.appendRight(node.body.end!, ')')
38+
}
39+
}
40+
}
2741
if (!result.size) return
2842

2943
walkIdentifiers(
@@ -48,30 +62,47 @@ export function transformRestructure(code: string, id: string) {
4862
return generateTransform(s, id)
4963
}
5064

51-
function resolveParams(
65+
function resolveParam(
5266
param: Node,
5367
paths: string = '',
5468
result: Map<string, string>,
69+
restResult: Map<string, string>,
5570
) {
56-
const elements =
71+
const properties =
5772
param.type === 'ObjectPattern'
5873
? param.properties
5974
: param.type === 'ArrayPattern'
6075
? param.elements
6176
: []
62-
if (!elements.length) return
77+
if (!properties.length) return
6378

64-
elements.forEach((element, index) => {
65-
if (element?.type === 'Identifier') {
66-
result.set(element.name, `${paths}[${index}]`)
79+
const propNames: string[] = []
80+
properties.forEach((prop, index) => {
81+
if (prop?.type === 'Identifier') {
82+
result.set(prop.name, `${paths}[${index}]`)
83+
propNames.push(`'${prop.name}'`)
84+
} else if (
85+
prop?.type === 'ObjectProperty' &&
86+
prop.key.type === 'Identifier'
87+
) {
88+
if (
89+
!resolveParam(
90+
prop.value,
91+
`${paths}.${prop.key.name}`,
92+
result,
93+
restResult,
94+
)
95+
) {
96+
result.set(prop.key.name, `${paths}.${prop.key.name}`)
97+
propNames.push(`'${prop.key.name}'`)
98+
}
6799
} else if (
68-
element?.type === 'ObjectProperty' &&
69-
element.key.type === 'Identifier'
100+
prop?.type === 'RestElement' &&
101+
prop?.argument.type === 'Identifier'
70102
) {
71-
if (!resolveParams(element.value, `${paths}.${element.key.name}`, result))
72-
result.set(element.key.name, `${paths}.${element.key.name}`)
73-
} else if (element) {
74-
resolveParams(element, `${paths}[${index}]`, result)
103+
restResult.set(prop.argument.name, `${paths}, [${propNames.join(', ')}]`)
104+
} else if (prop) {
105+
resolveParam(prop, `${paths}[${index}]`, result, restResult)
75106
}
76107
})
77108
return true

test/transformReconstruct.spec.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,38 @@ describe('transform', () => {
2323
`,
2424
)
2525
})
26+
27+
test('reconstruct arrowFunctionExpression', () => {
28+
const { code } = transformRestructure(
29+
`const App = ([{root: {foo, ...rest}}]) => (
30+
<>{[foo, rest]}</>
31+
)`,
32+
'tsx',
33+
)!
34+
expect(code).toMatchInlineSnapshot(
35+
`
36+
"
37+
import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue";const App = (_ctx0) => (
38+
(rest = __MACROS_createPropsRestProxy(_ctx0[0].root, ['foo']),<>{[_ctx0[0].root.foo, rest]}</>)
39+
)"
40+
`,
41+
)
42+
})
43+
44+
test('reconstruct functionDeclaration', () => {
45+
const { code } = transformRestructure(
46+
`function App({foo, ...rest}){
47+
return <>{[foo, rest]}</>
48+
}`,
49+
'tsx',
50+
)!
51+
expect(code).toMatchInlineSnapshot(
52+
`
53+
"
54+
import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue";function App(_ctx0){const rest = __MACROS_createPropsRestProxy(_ctx0, ['foo']);
55+
return <>{[_ctx0.foo, rest]}</>
56+
}"
57+
`,
58+
)
59+
})
2660
})

0 commit comments

Comments
 (0)