Skip to content

Commit fbd0fe9

Browse files
committed
feat(reactivity-transform): support optionally importing macros
1 parent db729ce commit fbd0fe9

File tree

3 files changed

+81
-26
lines changed

3 files changed

+81
-26
lines changed

packages/ref-transform/__tests__/__snapshots__/refTransform.spec.ts.snap

+12
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,18 @@ exports[`handle TS casting syntax 1`] = `
8080
"
8181
`;
8282
83+
exports[`macro import alias and removal 1`] = `
84+
"import { ref as _ref, toRef as _toRef } from 'vue'
85+
86+
87+
88+
let a = _ref(1)
89+
const __$temp_1 = (useMouse()),
90+
x = _toRef(__$temp_1, 'x'),
91+
y = _toRef(__$temp_1, 'y')
92+
"
93+
`;
94+
8395
exports[`mixing $ref & $computed declarations 1`] = `
8496
"import { ref as _ref, computed as _computed } from 'vue'
8597

packages/ref-transform/__tests__/refTransform.spec.ts

+16
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,22 @@ test('handle TS casting syntax', () => {
362362
assertCode(code)
363363
})
364364

365+
test('macro import alias and removal', () => {
366+
const { code } = transform(
367+
`
368+
import { $ as fromRefs, $ref } from 'vue/macros'
369+
370+
let a = $ref(1)
371+
const { x, y } = fromRefs(useMouse())
372+
`
373+
)
374+
// should remove imports
375+
expect(code).not.toMatch(`from 'vue/macros'`)
376+
expect(code).toMatch(`let a = _ref(1)`)
377+
expect(code).toMatch(`const __$temp_1 = (useMouse())`)
378+
assertCode(code)
379+
})
380+
365381
describe('errors', () => {
366382
test('$ref w/ destructure', () => {
367383
expect(() => transform(`let { a } = $ref(1)`)).toThrow(

packages/ref-transform/src/refTransform.ts

+53-26
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import {
2222
import { parse, ParserPlugin } from '@babel/parser'
2323
import { hasOwn, isArray, isString } from '@vue/shared'
2424

25-
const TO_VAR_SYMBOL = '$'
25+
const CONVERT_SYMBOL = '$'
2626
const ESCAPE_SYMBOL = '$$'
2727
const shorthands = ['ref', 'computed', 'shallowRef', 'toRef', 'customRef']
2828
const transformCheckRE = /[^\w]\$(?:\$|ref|computed|shallowRef)?\s*(\(|\<)/
@@ -114,10 +114,44 @@ export function transformAST(
114114
// TODO remove when out of experimental
115115
warnExperimental()
116116

117+
let convertSymbol = CONVERT_SYMBOL
118+
let escapeSymbol = ESCAPE_SYMBOL
119+
120+
// macro import handling
121+
for (const node of ast.body) {
122+
if (
123+
node.type === 'ImportDeclaration' &&
124+
node.source.value === 'vue/macros'
125+
) {
126+
// remove macro imports
127+
s.remove(node.start! + offset, node.end! + offset)
128+
// check aliasing
129+
for (const specifier of node.specifiers) {
130+
if (specifier.type === 'ImportSpecifier') {
131+
const imported = (specifier.imported as Identifier).name
132+
const local = specifier.local.name
133+
if (local !== imported) {
134+
if (imported === ESCAPE_SYMBOL) {
135+
escapeSymbol = local
136+
} else if (imported === CONVERT_SYMBOL) {
137+
convertSymbol = local
138+
} else {
139+
error(
140+
`macro imports for ref-creating methods do not support aliasing.`,
141+
specifier
142+
)
143+
}
144+
}
145+
}
146+
}
147+
}
148+
}
149+
117150
const importedHelpers = new Set<string>()
118151
const rootScope: Scope = {}
119152
const scopeStack: Scope[] = [rootScope]
120153
let currentScope: Scope = rootScope
154+
let escapeScope: CallExpression | undefined // inside $$()
121155
const excludedIds = new WeakSet<Identifier>()
122156
const parentStack: Node[] = []
123157
const propsLocalToPublicMap = Object.create(null)
@@ -135,6 +169,16 @@ export function transformAST(
135169
}
136170
}
137171

172+
function isRefCreationCall(callee: string): string | false {
173+
if (callee === convertSymbol) {
174+
return convertSymbol
175+
}
176+
if (callee[0] === '$' && shorthands.includes(callee.slice(1))) {
177+
return callee
178+
}
179+
return false
180+
}
181+
138182
function error(msg: string, node: Node) {
139183
const e = new Error(msg)
140184
;(e as any).node = node
@@ -174,20 +218,16 @@ export function transformAST(
174218
if (stmt.type === 'VariableDeclaration') {
175219
if (stmt.declare) continue
176220
for (const decl of stmt.declarations) {
177-
let toVarCall
221+
let refCall
178222
const isCall =
179223
decl.init &&
180224
decl.init.type === 'CallExpression' &&
181225
decl.init.callee.type === 'Identifier'
182226
if (
183227
isCall &&
184-
(toVarCall = isToVarCall((decl as any).init.callee.name))
228+
(refCall = isRefCreationCall((decl as any).init.callee.name))
185229
) {
186-
processRefDeclaration(
187-
toVarCall,
188-
decl.id,
189-
decl.init as CallExpression
190-
)
230+
processRefDeclaration(refCall, decl.id, decl.init as CallExpression)
191231
} else {
192232
const isProps =
193233
isRoot &&
@@ -220,7 +260,7 @@ export function transformAST(
220260
call: CallExpression
221261
) {
222262
excludedIds.add(call.callee as Identifier)
223-
if (method === TO_VAR_SYMBOL) {
263+
if (method === convertSymbol) {
224264
// $
225265
// remove macro
226266
s.remove(call.callee.start! + offset, call.callee.end! + offset)
@@ -491,9 +531,6 @@ export function transformAST(
491531

492532
// check root scope first
493533
walkScope(ast, true)
494-
495-
// inside $$()
496-
let escapeScope: CallExpression | undefined
497534
;(walk as any)(ast, {
498535
enter(node: Node, parent?: Node) {
499536
parent && parentStack.push(parent)
@@ -544,16 +581,16 @@ export function transformAST(
544581
if (node.type === 'CallExpression' && node.callee.type === 'Identifier') {
545582
const callee = node.callee.name
546583

547-
const toVarCall = isToVarCall(callee)
548-
if (toVarCall && (!parent || parent.type !== 'VariableDeclarator')) {
584+
const refCall = isRefCreationCall(callee)
585+
if (refCall && (!parent || parent.type !== 'VariableDeclarator')) {
549586
return error(
550-
`${toVarCall} can only be used as the initializer of ` +
587+
`${refCall} can only be used as the initializer of ` +
551588
`a variable declaration.`,
552589
node
553590
)
554591
}
555592

556-
if (callee === ESCAPE_SYMBOL) {
593+
if (callee === escapeSymbol) {
557594
s.remove(node.callee.start! + offset, node.callee.end! + offset)
558595
escapeScope = node
559596
}
@@ -596,16 +633,6 @@ export function transformAST(
596633
}
597634
}
598635

599-
function isToVarCall(callee: string): string | false {
600-
if (callee === TO_VAR_SYMBOL) {
601-
return TO_VAR_SYMBOL
602-
}
603-
if (callee[0] === TO_VAR_SYMBOL && shorthands.includes(callee.slice(1))) {
604-
return callee
605-
}
606-
return false
607-
}
608-
609636
const RFC_LINK = `https://github.com/vuejs/rfcs/discussions/369`
610637
const hasWarned: Record<string, boolean> = {}
611638

0 commit comments

Comments
 (0)