Skip to content

Commit 7663a79

Browse files
authoredNov 9, 2022
fix(reactivity-transform): respect user defined symbols that conflict with macros (#6840)
closes #6838
1 parent bad3f3c commit 7663a79

File tree

3 files changed

+121
-29
lines changed

3 files changed

+121
-29
lines changed
 

‎packages/reactivity-transform/__tests__/__snapshots__/reactivityTransform.spec.ts.snap

+21
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,27 @@ exports[`object destructure w/ mid-path default values 1`] = `
199199
"
200200
`;
201201
202+
exports[`should not overwrite current scope 1`] = `
203+
"
204+
const fn = () => {
205+
const $ = () => 'foo'
206+
const $ref = () => 'bar'
207+
const $$ = () => 'baz'
208+
console.log($())
209+
console.log($ref())
210+
console.log($$())
211+
}
212+
"
213+
`;
214+
215+
exports[`should not overwrite importing 1`] = `
216+
"
217+
import { $, $$ } from './foo'
218+
$('foo')
219+
$$('bar')
220+
"
221+
`;
222+
202223
exports[`should not rewrite scope variable 1`] = `
203224
"import { ref as _ref } from 'vue'
204225

‎packages/reactivity-transform/__tests__/reactivityTransform.spec.ts

+29
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,35 @@ test('macro import alias and removal', () => {
416416
assertCode(code)
417417
})
418418

419+
// #6838
420+
test('should not overwrite importing', () => {
421+
const { code } = transform(
422+
`
423+
import { $, $$ } from './foo'
424+
$('foo')
425+
$$('bar')
426+
`
427+
)
428+
assertCode(code)
429+
})
430+
431+
// #6838
432+
test('should not overwrite current scope', () => {
433+
const { code } = transform(
434+
`
435+
const fn = () => {
436+
const $ = () => 'foo'
437+
const $ref = () => 'bar'
438+
const $$ = () => 'baz'
439+
console.log($())
440+
console.log($ref())
441+
console.log($$())
442+
}
443+
`
444+
)
445+
assertCode(code)
446+
})
447+
419448
describe('errors', () => {
420449
test('$ref w/ destructure', () => {
421450
expect(() => transform(`let { a } = $ref(1)`)).toThrow(

‎packages/reactivity-transform/src/reactivityTransform.ts

+71-29
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ import {
88
Program,
99
VariableDeclarator,
1010
Expression,
11-
VariableDeclaration
11+
VariableDeclaration,
12+
ImportDeclaration,
13+
ImportSpecifier,
14+
ImportDefaultSpecifier,
15+
ImportNamespaceSpecifier
1216
} from '@babel/types'
1317
import MagicString, { SourceMap } from 'magic-string'
1418
import { walk } from 'estree-walker'
@@ -25,6 +29,7 @@ import { hasOwn, isArray, isString, genPropsAccessExp } from '@vue/shared'
2529

2630
const CONVERT_SYMBOL = '$'
2731
const ESCAPE_SYMBOL = '$$'
32+
const IMPORT_SOURCE = 'vue/macros'
2833
const shorthands = ['ref', 'computed', 'shallowRef', 'toRef', 'customRef']
2934
const transformCheckRE = /[^\w]\$(?:\$|ref|computed|shallowRef)?\s*(\(|\<)/
3035

@@ -48,6 +53,13 @@ export interface RefTransformResults {
4853
importedHelpers: string[]
4954
}
5055

56+
export interface ImportBinding {
57+
local: string
58+
imported: string
59+
source: string
60+
specifier: ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier
61+
}
62+
5163
export function transform(
5264
src: string,
5365
{
@@ -115,39 +127,40 @@ export function transformAST(
115127
// TODO remove when out of experimental
116128
warnExperimental()
117129

118-
let convertSymbol = CONVERT_SYMBOL
119-
let escapeSymbol = ESCAPE_SYMBOL
130+
const userImports: Record<string, ImportBinding> = Object.create(null)
131+
for (const node of ast.body) {
132+
if (node.type !== 'ImportDeclaration') continue
133+
walkImportDeclaration(node)
134+
}
120135

121136
// macro import handling
122-
for (const node of ast.body) {
123-
if (
124-
node.type === 'ImportDeclaration' &&
125-
node.source.value === 'vue/macros'
126-
) {
127-
// remove macro imports
128-
s.remove(node.start! + offset, node.end! + offset)
129-
// check aliasing
130-
for (const specifier of node.specifiers) {
131-
if (specifier.type === 'ImportSpecifier') {
132-
const imported = (specifier.imported as Identifier).name
133-
const local = specifier.local.name
134-
if (local !== imported) {
135-
if (imported === ESCAPE_SYMBOL) {
136-
escapeSymbol = local
137-
} else if (imported === CONVERT_SYMBOL) {
138-
convertSymbol = local
139-
} else {
140-
error(
141-
`macro imports for ref-creating methods do not support aliasing.`,
142-
specifier
143-
)
144-
}
145-
}
146-
}
137+
let convertSymbol: string | undefined
138+
let escapeSymbol: string | undefined
139+
for (const { local, imported, source, specifier } of Object.values(
140+
userImports
141+
)) {
142+
if (source === IMPORT_SOURCE) {
143+
if (imported === ESCAPE_SYMBOL) {
144+
escapeSymbol = local
145+
} else if (imported === CONVERT_SYMBOL) {
146+
convertSymbol = local
147+
} else if (imported !== local) {
148+
error(
149+
`macro imports for ref-creating methods do not support aliasing.`,
150+
specifier
151+
)
147152
}
148153
}
149154
}
150155

156+
// default symbol
157+
if (!convertSymbol && !userImports[CONVERT_SYMBOL]) {
158+
convertSymbol = CONVERT_SYMBOL
159+
}
160+
if (!escapeSymbol && !userImports[ESCAPE_SYMBOL]) {
161+
escapeSymbol = ESCAPE_SYMBOL
162+
}
163+
151164
const importedHelpers = new Set<string>()
152165
const rootScope: Scope = {}
153166
const scopeStack: Scope[] = [rootScope]
@@ -170,7 +183,32 @@ export function transformAST(
170183
}
171184
}
172185

186+
function walkImportDeclaration(node: ImportDeclaration) {
187+
const source = node.source.value
188+
if (source === IMPORT_SOURCE) {
189+
s.remove(node.start! + offset, node.end! + offset)
190+
}
191+
192+
for (const specifier of node.specifiers) {
193+
const local = specifier.local.name
194+
const imported =
195+
(specifier.type === 'ImportSpecifier' &&
196+
specifier.imported.type === 'Identifier' &&
197+
specifier.imported.name) ||
198+
'default'
199+
userImports[local] = {
200+
source,
201+
local,
202+
imported,
203+
specifier
204+
}
205+
}
206+
}
207+
173208
function isRefCreationCall(callee: string): string | false {
209+
if (!convertSymbol || currentScope[convertSymbol] !== undefined) {
210+
return false
211+
}
174212
if (callee === convertSymbol) {
175213
return convertSymbol
176214
}
@@ -628,7 +666,11 @@ export function transformAST(
628666
)
629667
}
630668

631-
if (callee === escapeSymbol) {
669+
if (
670+
escapeSymbol &&
671+
currentScope[escapeSymbol] === undefined &&
672+
callee === escapeSymbol
673+
) {
632674
s.remove(node.callee.start! + offset, node.callee.end! + offset)
633675
escapeScope = node
634676
}

0 commit comments

Comments
 (0)
Please sign in to comment.