Skip to content
This repository was archived by the owner on Dec 25, 2024. It is now read-only.

Commit 1c42237

Browse files
committed
fix(parser): handle more cases
1 parent 98cf455 commit 1c42237

File tree

5 files changed

+91
-14
lines changed

5 files changed

+91
-14
lines changed

src/parse.ts

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Parser as HTMLParser } from 'htmlparser2'
22
import { parse } from '@babel/parser'
3-
import { PrivateName, Expression, Statement } from '@babel/types'
3+
import { PrivateName, Expression, Statement, SpreadElement } from '@babel/types'
44
import { camelize, capitalize, isHTMLTag, isSVGTag, isVoidTag } from '@vue/shared'
55
import { ParseResult, TagMeta } from './types'
66

@@ -34,6 +34,9 @@ export function parseVueSFC(code: string, id?: string): ParseResult {
3434

3535
const parser = new HTMLParser({
3636
onopentag(name, attributes) {
37+
if (!name)
38+
return
39+
3740
if (name === 'template')
3841
templateLevel += 1
3942

@@ -131,8 +134,25 @@ export function getIdentifiersDeclaration(nodes: Statement[], identifiers = new
131134
}
132135
else if (node.type === 'VariableDeclaration') {
133136
for (const declarator of node.declarations) {
134-
// @ts-expect-error
135-
identifiers.add(declarator.id.name)
137+
if (declarator.id.type === 'Identifier') {
138+
identifiers.add(declarator.id.name)
139+
}
140+
else if (declarator.id.type === 'ObjectPattern') {
141+
for (const property of declarator.id.properties) {
142+
if (property.type === 'ObjectProperty' && property.key.type === 'Identifier')
143+
identifiers.add(property.key.name)
144+
else if (property.type === 'RestElement' && property.argument.type === 'Identifier')
145+
identifiers.add(property.argument.name)
146+
}
147+
}
148+
else if (declarator.id.type === 'ArrayPattern') {
149+
for (const element of declarator.id.elements) {
150+
if (element?.type === 'Identifier')
151+
identifiers.add(element.name)
152+
else if (element?.type === 'RestElement' && element.argument.type === 'Identifier')
153+
identifiers.add(element.argument.name)
154+
}
155+
}
136156
}
137157
}
138158
else if (node.type === 'FunctionDeclaration') {
@@ -146,7 +166,7 @@ export function getIdentifiersDeclaration(nodes: Statement[], identifiers = new
146166
return identifiers
147167
}
148168

149-
export function getIdentifiersUsage(node?: Expression | PrivateName | Statement, identifiers = new Set<string>()) {
169+
export function getIdentifiersUsage(node?: Expression | SpreadElement | PrivateName | Statement | null, identifiers = new Set<string>()) {
150170
if (!node)
151171
return identifiers
152172

@@ -171,6 +191,9 @@ export function getIdentifiersUsage(node?: Expression | PrivateName | Statement,
171191
getIdentifiersUsage(node.left, identifiers)
172192
getIdentifiersUsage(node.right, identifiers)
173193
}
194+
else if (node.type === 'UnaryExpression') {
195+
getIdentifiersUsage(node.argument, identifiers)
196+
}
174197
else if (node.type === 'ForOfStatement' || node.type === 'ForInStatement') {
175198
getIdentifiersUsage(node.right, identifiers)
176199
}
@@ -181,10 +204,20 @@ export function getIdentifiersUsage(node?: Expression | PrivateName | Statement,
181204
}
182205
else if (node.type === 'ObjectExpression') {
183206
node.properties.forEach((prop) => {
184-
// @ts-expect-error
185-
getIdentifiersUsage(prop.value, identifiers)
207+
if (prop.type === 'ObjectProperty')
208+
getIdentifiersUsage(prop.key, identifiers)
209+
else if (prop.type === 'SpreadElement')
210+
getIdentifiersUsage(prop, identifiers)
186211
})
187212
}
213+
else if (node.type === 'ArrayExpression') {
214+
node.elements.forEach((element) => {
215+
getIdentifiersUsage(element, identifiers)
216+
})
217+
}
218+
else if (node.type === 'SpreadElement') {
219+
getIdentifiersUsage(node.argument, identifiers)
220+
}
188221
// else {
189222
// console.log(node)
190223
// }

src/transformScriptSetup.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,17 @@ export function transformScriptSetup(result: ParseResult) {
4040
// get all identifiers in `<script setup>`
4141
getIdentifiersDeclaration([...imports, ...nodes], identifiers)
4242

43-
const returns = Array.from(identifiers).filter(i => result.template.identifiers.has(i))
44-
const components = Array.from(identifiers).filter(i => result.template.components.has(i)
45-
|| result.template.components.has(camelize(i))
46-
|| result.template.components.has(capitalize(camelize(i))),
47-
)
43+
// filter out identifiers that are used in `<template>`
44+
const returns = Array.from(identifiers)
45+
.filter(Boolean)
46+
.filter(i => result.template.identifiers.has(i))
47+
const components = Array.from(identifiers)
48+
.filter(Boolean)
49+
.filter(i => result.template.components.has(i)
50+
|| result.template.components.has(camelize(i))
51+
|| result.template.components.has(capitalize(camelize(i))),
52+
)
4853

49-
// TODO: apply macros
5054
// append `<script setup>` imports to `<script>`
5155
scriptAst.program.body.unshift(...imports)
5256

test/__snapshots__/transform.test.ts.snap

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,30 @@ export default __sfc_main;
4646
"
4747
`;
4848
49+
exports[`transform fixture ObjectDestructure.vue 1`] = `
50+
"<template>
51+
<div></div>
52+
</template>
53+
54+
<script >
55+
import { toRefs, reactive } from 'vue';
56+
const __sfc_main = {};
57+
58+
__sfc_main.setup = (__props, __ctx) => {
59+
const state = reactive({
60+
data: 'hello'
61+
});
62+
const {
63+
data
64+
} = toRefs(state);
65+
return {};
66+
};
67+
68+
export default __sfc_main;
69+
</script>
70+
"
71+
`;
72+
4973
exports[`transform fixture TemplateOnly.vue 1`] = `
5074
"<template>
5175
<div>

test/fixtures/ObjectDestructure.vue

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<template>
2+
<div></div>
3+
</template>
4+
5+
<script setup>
6+
import { toRefs, reactive } from 'vue'
7+
const state = reactive({ data: 'hello' })
8+
const { data } = toRefs(state)
9+
</script>

test/parse.test.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,13 @@ describe('parse', () => {
77
['var a = 1', ['a']],
88
['import { foo, t as bar } from "z"', ['foo', 'bar']],
99
['import foo from "z"', ['foo']],
10+
['import * as foo from "z"', ['foo']],
1011
['function foo(bar) {const a = z}', ['foo']],
1112
['console.log(foo)', []],
13+
['const { data } = toRefs(state)', ['data']],
14+
['const { data, ...args } = bar', ['data', 'args']],
15+
['const { foo: bar } = bar', ['foo']],
16+
['let [a, b,, ...c] = bar', ['a', 'b', 'c']],
1217
]
1318

1419
for (const [input, output] of cases) {
@@ -30,9 +35,11 @@ describe('parse', () => {
3035
['for (let x in foo) {}', ['foo']],
3136
['for (let [x, idx] of foo) {}', ['foo']],
3237
['a + b', ['a', 'b']],
33-
['a ? "" : b', ['a', 'b']],
38+
['a ? "" : b < c', ['a', 'b', 'c']],
3439
['a == b && a === c', ['a', 'b', 'c']],
35-
['({ a, b })', ['a', 'b']],
40+
['({ a, b, ...args, [c]: 1 })', ['a', 'b', 'args', 'c']],
41+
['!a', ['a']],
42+
['[a,b,...args]', ['a', 'b', 'args']],
3643
]
3744

3845
for (const [input, output] of cases) {

0 commit comments

Comments
 (0)