Program,
VariableDeclarator,
Expression,
- VariableDeclaration
+ VariableDeclaration,
+ ImportDeclaration,
+ ImportSpecifier,
+ ImportDefaultSpecifier,
+ ImportNamespaceSpecifier
} from '@babel/types'
import MagicString, { SourceMap } from 'magic-string'
import { walk } from 'estree-walker'
const CONVERT_SYMBOL = '$'
const ESCAPE_SYMBOL = '$$'
+const IMPORT_SOURCE = 'vue/macros'
const shorthands = ['ref', 'computed', 'shallowRef', 'toRef', 'customRef']
const transformCheckRE = /[^\w]\$(?:\$|ref|computed|shallowRef)?\s*(\(|\<)/
importedHelpers: string[]
}
+export interface ImportBinding {
+ local: string
+ imported: string
+ source: string
+ specifier: ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier
+}
+
export function transform(
src: string,
{
// TODO remove when out of experimental
warnExperimental()
- let convertSymbol = CONVERT_SYMBOL
- let escapeSymbol = ESCAPE_SYMBOL
+ const userImports: Record<string, ImportBinding> = Object.create(null)
+ for (const node of ast.body) {
+ if (node.type !== 'ImportDeclaration') continue
+ walkImportDeclaration(node)
+ }
// macro import handling
- for (const node of ast.body) {
- if (
- node.type === 'ImportDeclaration' &&
- node.source.value === 'vue/macros'
- ) {
- // remove macro imports
- s.remove(node.start! + offset, node.end! + offset)
- // check aliasing
- for (const specifier of node.specifiers) {
- if (specifier.type === 'ImportSpecifier') {
- const imported = (specifier.imported as Identifier).name
- const local = specifier.local.name
- if (local !== imported) {
- if (imported === ESCAPE_SYMBOL) {
- escapeSymbol = local
- } else if (imported === CONVERT_SYMBOL) {
- convertSymbol = local
- } else {
- error(
- `macro imports for ref-creating methods do not support aliasing.`,
- specifier
- )
- }
- }
- }
+ let convertSymbol: string | undefined
+ let escapeSymbol: string | undefined
+ for (const { local, imported, source, specifier } of Object.values(
+ userImports
+ )) {
+ if (source === IMPORT_SOURCE) {
+ if (imported === ESCAPE_SYMBOL) {
+ escapeSymbol = local
+ } else if (imported === CONVERT_SYMBOL) {
+ convertSymbol = local
+ } else if (imported !== local) {
+ error(
+ `macro imports for ref-creating methods do not support aliasing.`,
+ specifier
+ )
}
}
}
+ // default symbol
+ if (!convertSymbol && !userImports[CONVERT_SYMBOL]) {
+ convertSymbol = CONVERT_SYMBOL
+ }
+ if (!escapeSymbol && !userImports[ESCAPE_SYMBOL]) {
+ escapeSymbol = ESCAPE_SYMBOL
+ }
+
const importedHelpers = new Set<string>()
const rootScope: Scope = {}
const scopeStack: Scope[] = [rootScope]
}
}
+ function walkImportDeclaration(node: ImportDeclaration) {
+ const source = node.source.value
+ if (source === IMPORT_SOURCE) {
+ s.remove(node.start! + offset, node.end! + offset)
+ }
+
+ for (const specifier of node.specifiers) {
+ const local = specifier.local.name
+ const imported =
+ (specifier.type === 'ImportSpecifier' &&
+ specifier.imported.type === 'Identifier' &&
+ specifier.imported.name) ||
+ 'default'
+ userImports[local] = {
+ source,
+ local,
+ imported,
+ specifier
+ }
+ }
+ }
+
function isRefCreationCall(callee: string): string | false {
+ if (!convertSymbol || currentScope[convertSymbol] !== undefined) {
+ return false
+ }
if (callee === convertSymbol) {
return convertSymbol
}
)
}
- if (callee === escapeSymbol) {
+ if (
+ escapeSymbol &&
+ currentScope[escapeSymbol] === undefined &&
+ callee === escapeSymbol
+ ) {
s.remove(node.callee.start! + offset, node.callee.end! + offset)
escapeScope = node
}