content.lastIndexOf(`import { x }`)
)
})
+
+ describe('import ref/reactive function from other place', () => {
+ test('import directly', () => {
+ const { bindings } = compile(`
+ <script setup>
+ import { ref, reactive } from './foo'
+
+ const foo = ref(1)
+ const bar = reactive(1)
+ </script>
+ `)
+ expect(bindings).toStrictEqual({
+ ref: BindingTypes.SETUP_MAYBE_REF,
+ reactive: BindingTypes.SETUP_MAYBE_REF,
+ foo: BindingTypes.SETUP_MAYBE_REF,
+ bar: BindingTypes.SETUP_MAYBE_REF
+ })
+ })
+
+ test('import w/ alias', () => {
+ const { bindings } = compile(`
+ <script setup>
+ import { ref as _ref, reactive as _reactive } from './foo'
+
+ const foo = ref(1)
+ const bar = reactive(1)
+ </script>
+ `)
+ expect(bindings).toStrictEqual({
+ _reactive: BindingTypes.SETUP_MAYBE_REF,
+ _ref: BindingTypes.SETUP_MAYBE_REF,
+ foo: BindingTypes.SETUP_REF,
+ bar: BindingTypes.SETUP_REACTIVE_CONST
+ })
+ })
+ })
})
// in dev mode, declared bindings are returned as an object from setup()
export interface ImportBinding {
isType: boolean
imported: string
+ local: string
source: string
isFromSetup: boolean
isUsedInTemplate: boolean
const bindingMetadata: BindingMetadata = {}
const helperImports: Set<string> = new Set()
const userImports: Record<string, ImportBinding> = Object.create(null)
- const userImportAlias: Record<string, string> = Object.create(null)
const scriptBindings: Record<string, BindingTypes> = Object.create(null)
const setupBindings: Record<string, BindingTypes> = Object.create(null)
isFromSetup: boolean,
needTemplateUsageCheck: boolean
) {
- if (source === 'vue' && imported) {
- userImportAlias[imported] = local
- }
-
// template usage check is only needed in non-inline mode, so we can skip
// the work if inlineTemplate is true.
let isUsedInTemplate = needTemplateUsageCheck
userImports[local] = {
isType,
imported: imported || 'default',
+ local,
source,
isFromSetup,
isUsedInTemplate
}
}
if (node.declaration) {
- walkDeclaration(node.declaration, scriptBindings, userImportAlias)
+ walkDeclaration(node.declaration, scriptBindings, userImports)
}
} else if (
(node.type === 'VariableDeclaration' ||
node.type === 'TSEnumDeclaration') &&
!node.declare
) {
- walkDeclaration(node, scriptBindings, userImportAlias)
+ walkDeclaration(node, scriptBindings, userImports)
}
}
node.type === 'ClassDeclaration') &&
!node.declare
) {
- walkDeclaration(node, setupBindings, userImportAlias)
+ walkDeclaration(node, setupBindings, userImports)
}
// walk statements & named exports / variable declarations for top level
function walkDeclaration(
node: Declaration,
bindings: Record<string, BindingTypes>,
- userImportAlias: Record<string, string>
+ userImports: Record<string, ImportBinding>
) {
+ function getUserBinding(name: string) {
+ const binding = Object.values(userImports).find(
+ binding => binding.source === 'vue' && binding.imported === name
+ )
+ if (binding) return binding.local
+ else if (!userImports[name]) return name
+ return undefined
+ }
+
if (node.type === 'VariableDeclaration') {
const isConst = node.kind === 'const'
// export const foo = ...
)
if (id.type === 'Identifier') {
let bindingType
- const userReactiveBinding = userImportAlias['reactive'] || 'reactive'
+ const userReactiveBinding = getUserBinding('reactive')
if (isCallOf(init, userReactiveBinding)) {
// treat reactive() calls as let since it's meant to be mutable
bindingType = isConst
? BindingTypes.SETUP_REACTIVE_CONST
: BindingTypes.SETUP_CONST
} else if (isConst) {
- if (isCallOf(init, userImportAlias['ref'] || 'ref')) {
+ if (isCallOf(init, getUserBinding('ref'))) {
bindingType = BindingTypes.SETUP_REF
} else {
bindingType = BindingTypes.SETUP_MAYBE_REF
function isCallOf(
node: Node | null | undefined,
- test: string | ((id: string) => boolean)
+ test: string | ((id: string) => boolean) | null | undefined
): node is CallExpression {
return !!(
node &&
+ test &&
node.type === 'CallExpression' &&
node.callee.type === 'Identifier' &&
(typeof test === 'string'
)
}
-function canNeverBeRef(node: Node, userReactiveImport: string): boolean {
+function canNeverBeRef(node: Node, userReactiveImport?: string): boolean {
if (isCallOf(node, userReactiveImport)) {
return true
}