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

Commit 0a74ffe

Browse files
committed
refactor: cleanup
1 parent 1ea2171 commit 0a74ffe

File tree

6 files changed

+155
-153
lines changed

6 files changed

+155
-153
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Bring `<script setup>` to Vue 2
1212
- [x] Merge with normal scripts
1313
- [x] Vite plugin
1414
- [x] Webpack plugin
15+
- [ ] Top-level await
1516

1617
## Sponsors
1718

src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
export * from './parse'
21
export * from './transform'

src/parse.ts

Lines changed: 2 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,8 @@
11
import { Parser as HTMLParser } from 'htmlparser2'
2-
import { types as t } from '@babel/core'
3-
import { parse, ParserOptions, ParserPlugin } from '@babel/parser'
2+
import { parse, ParserOptions } from '@babel/parser'
43
import { camelize, capitalize, isHTMLTag, isSVGTag, isVoidTag } from '@vue/shared'
54
import traverse from '@babel/traverse'
6-
import generate from '@babel/generator'
7-
8-
interface TagMeta {
9-
start: number
10-
end: number
11-
contentStart: number
12-
contentEnd: number
13-
content: string
14-
attrs: Record<string, string>
15-
found: boolean
16-
}
17-
18-
export interface ParseResult {
19-
id?: string
20-
template: {
21-
components: Set<string>
22-
identifiers: Set<string>
23-
}
24-
scriptSetup: TagMeta
25-
script: TagMeta
26-
}
5+
import { ParseResult, TagMeta } from './types'
276

287
export function parseVueSFC(code: string, id?: string): ParseResult {
298
const components = new Set<string>()
@@ -145,131 +124,3 @@ export function getIdentifiersFromCode(code: string, identifiers = new Set<strin
145124
})
146125
return identifiers
147126
}
148-
149-
export function transformScriptSetup(result: ParseResult) {
150-
if (result.script.found && result.scriptSetup.found && result.scriptSetup.attrs.lang !== result.script.attrs.lang)
151-
throw new SyntaxError('<script setup> language must be the same as <script>')
152-
153-
const lang = result.scriptSetup.attrs.lang || result.script.attrs.lang
154-
const plugins: ParserPlugin[] = []
155-
if (lang === 'ts')
156-
plugins.push('typescript')
157-
else if (lang === 'jsx')
158-
plugins.push('jsx')
159-
else if (lang === 'tsx')
160-
plugins.push('typescript', 'jsx')
161-
else if (lang !== 'js')
162-
throw new SyntaxError(`Unsupported script language: ${lang}`)
163-
164-
const identifiers = new Set<string>()
165-
const scriptSetupAst = parse(result.scriptSetup.content, {
166-
sourceType: 'module',
167-
plugins,
168-
})
169-
const scriptAst = parse(result.script.content || 'export default {}', {
170-
sourceType: 'module',
171-
plugins,
172-
})
173-
174-
// get all identifiers in `<script setup>`
175-
traverse(scriptSetupAst as any, {
176-
Identifier(path) {
177-
identifiers.add(path.node.name)
178-
},
179-
})
180-
181-
const returns = Array.from(identifiers).filter(i => result.template.identifiers.has(i))
182-
const components = Array.from(identifiers).filter(i =>
183-
result.template.components.has(i)
184-
|| result.template.components.has(camelize(i))
185-
|| result.template.components.has(capitalize(camelize(i))),
186-
)
187-
188-
const imports = scriptSetupAst.program.body.filter(n => n.type === 'ImportDeclaration')
189-
const scriptSetupBody = scriptSetupAst.program.body.filter(n => n.type !== 'ImportDeclaration')
190-
// TODO: apply macros
191-
192-
// append `<script setup>` imports to `<script>`
193-
scriptAst.program.body.unshift(...imports)
194-
195-
// replace `export default` with a temproray variable
196-
// `const __sfc_main = { ... }`
197-
traverse(scriptAst as any, {
198-
ExportDefaultDeclaration(path) {
199-
const decl = path.node.declaration
200-
path.replaceWith(
201-
t.variableDeclaration('const', [
202-
t.variableDeclarator(
203-
t.identifier('__sfc_main'),
204-
decl as any,
205-
),
206-
]),
207-
)
208-
},
209-
})
210-
211-
// inject setup function
212-
// `__sfc_main.setup = () => {}`
213-
if (scriptSetupBody.length) {
214-
const returnStatement = t.returnStatement(
215-
t.objectExpression(
216-
returns.map((i) => {
217-
const id = t.identifier(i)
218-
return t.objectProperty(id, id, false, true)
219-
}),
220-
),
221-
)
222-
223-
scriptAst.program.body.push(
224-
t.expressionStatement(
225-
t.assignmentExpression('=',
226-
t.memberExpression(t.identifier('__sfc_main'), t.identifier('setup')),
227-
t.arrowFunctionExpression([], t.blockStatement([
228-
...scriptSetupBody,
229-
returnStatement as any,
230-
])),
231-
),
232-
) as any,
233-
)
234-
}
235-
236-
// inject components
237-
// `__sfc_main.components = Object.assign({ ... }, __sfc_main.components)`
238-
if (components.length) {
239-
const componentsObject = t.objectExpression(
240-
components.map((i) => {
241-
const id = t.identifier(i)
242-
return t.objectProperty(id, id, false, true)
243-
}),
244-
)
245-
246-
scriptAst.program.body.push(
247-
t.expressionStatement(
248-
t.assignmentExpression('=',
249-
t.memberExpression(t.identifier('__sfc_main'), t.identifier('components')),
250-
t.callExpression(
251-
t.memberExpression(t.identifier('Object'), t.identifier('assign')),
252-
[
253-
componentsObject,
254-
t.memberExpression(
255-
t.identifier('__sfc_main'),
256-
t.identifier('components'),
257-
),
258-
],
259-
),
260-
),
261-
) as any,
262-
)
263-
}
264-
265-
// re-export
266-
// `export default __sfc_main`
267-
scriptAst.program.body.push(
268-
t.exportDefaultDeclaration(t.identifier('__sfc_main')) as any,
269-
)
270-
271-
return {
272-
ast: scriptAst,
273-
code: generate(scriptAst as any).code,
274-
}
275-
}

src/transform.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import MagicString from 'magic-string'
2-
import { transformScriptSetup, parseVueSFC } from './parse'
2+
import { parseVueSFC } from './parse'
3+
import { transformScriptSetup } from './transformScriptSetup'
34

45
export function transform(sfc: string, id?: string) {
56
const s = new MagicString(sfc)

src/transformScriptSetup.ts

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import { types as t } from '@babel/core'
2+
import { parse, ParserPlugin } from '@babel/parser'
3+
import { camelize, capitalize } from '@vue/shared'
4+
import traverse from '@babel/traverse'
5+
import generate from '@babel/generator'
6+
import { ParseResult } from './types'
7+
8+
export function transformScriptSetup(result: ParseResult) {
9+
if (result.script.found && result.scriptSetup.found && result.scriptSetup.attrs.lang !== result.script.attrs.lang)
10+
throw new SyntaxError('<script setup> language must be the same as <script>')
11+
12+
const lang = result.scriptSetup.attrs.lang || result.script.attrs.lang
13+
const plugins: ParserPlugin[] = []
14+
if (lang === 'ts')
15+
plugins.push('typescript')
16+
else if (lang === 'jsx')
17+
plugins.push('jsx')
18+
else if (lang === 'tsx')
19+
plugins.push('typescript', 'jsx')
20+
else if (lang !== 'js')
21+
throw new SyntaxError(`Unsupported script language: ${lang}`)
22+
23+
const identifiers = new Set<string>()
24+
const scriptSetupAst = parse(result.scriptSetup.content, {
25+
sourceType: 'module',
26+
plugins,
27+
})
28+
const scriptAst = parse(result.script.content || 'export default {}', {
29+
sourceType: 'module',
30+
plugins,
31+
})
32+
33+
// get all identifiers in `<script setup>`
34+
traverse(scriptSetupAst as any, {
35+
Identifier(path) {
36+
identifiers.add(path.node.name)
37+
},
38+
})
39+
40+
const returns = Array.from(identifiers).filter(i => result.template.identifiers.has(i))
41+
const components = Array.from(identifiers).filter(i => result.template.components.has(i)
42+
|| result.template.components.has(camelize(i))
43+
|| result.template.components.has(capitalize(camelize(i))),
44+
)
45+
46+
const imports = scriptSetupAst.program.body.filter(n => n.type === 'ImportDeclaration')
47+
const scriptSetupBody = scriptSetupAst.program.body.filter(n => n.type !== 'ImportDeclaration')
48+
// TODO: apply macros
49+
// append `<script setup>` imports to `<script>`
50+
scriptAst.program.body.unshift(...imports)
51+
52+
const __sfc = t.identifier('__sfc_main')
53+
54+
// replace `export default` with a temproray variable
55+
// `const __sfc_main = { ... }`
56+
traverse(scriptAst as any, {
57+
ExportDefaultDeclaration(path) {
58+
const decl = path.node.declaration
59+
path.replaceWith(
60+
t.variableDeclaration('const', [
61+
t.variableDeclarator(
62+
__sfc,
63+
decl as any,
64+
),
65+
]),
66+
)
67+
},
68+
})
69+
70+
// inject setup function
71+
// `__sfc_main.setup = () => {}`
72+
if (scriptSetupBody.length) {
73+
const returnStatement = t.returnStatement(
74+
t.objectExpression(
75+
returns.map((i) => {
76+
const id = t.identifier(i)
77+
return t.objectProperty(id, id, false, true)
78+
}),
79+
),
80+
)
81+
82+
scriptAst.program.body.push(
83+
t.expressionStatement(
84+
t.assignmentExpression('=',
85+
t.memberExpression(__sfc, t.identifier('setup')),
86+
t.arrowFunctionExpression([], t.blockStatement([
87+
...scriptSetupBody,
88+
returnStatement as any,
89+
])),
90+
),
91+
) as any,
92+
)
93+
}
94+
95+
// inject components
96+
// `__sfc_main.components = Object.assign({ ... }, __sfc_main.components)`
97+
if (components.length) {
98+
const componentsObject = t.objectExpression(
99+
components.map((i) => {
100+
const id = t.identifier(i)
101+
return t.objectProperty(id, id, false, true)
102+
}),
103+
)
104+
105+
scriptAst.program.body.push(
106+
t.expressionStatement(
107+
t.assignmentExpression('=',
108+
t.memberExpression(__sfc, t.identifier('components')),
109+
t.callExpression(
110+
t.memberExpression(t.identifier('Object'), t.identifier('assign')),
111+
[
112+
componentsObject,
113+
t.memberExpression(__sfc, t.identifier('components')),
114+
],
115+
),
116+
),
117+
) as any,
118+
)
119+
}
120+
121+
// re-export
122+
// `export default __sfc_main`
123+
scriptAst.program.body.push(
124+
t.exportDefaultDeclaration(__sfc) as any,
125+
)
126+
127+
return {
128+
ast: scriptAst,
129+
code: generate(scriptAst as any).code,
130+
}
131+
}

src/types.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
export interface TagMeta {
2+
start: number
3+
end: number
4+
contentStart: number
5+
contentEnd: number
6+
content: string
7+
attrs: Record<string, string>
8+
found: boolean
9+
}
10+
11+
export interface ParseResult {
12+
id?: string
13+
template: {
14+
components: Set<string>
15+
identifiers: Set<string>
16+
}
17+
scriptSetup: TagMeta
18+
script: TagMeta
19+
}

0 commit comments

Comments
 (0)