mirror of https://github.com/vuejs/core.git
fix(compiler-sfc): check import source during binding analysation (#6826)
fix #6825
This commit is contained in:
parent
fdc5902cce
commit
4a00fddfed
|
@ -356,6 +356,42 @@ defineExpose({ foo: 123 })
|
||||||
content.lastIndexOf(`import { x }`)
|
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()
|
// in dev mode, declared bindings are returned as an object from setup()
|
||||||
|
|
|
@ -129,6 +129,7 @@ export interface SFCScriptCompileOptions {
|
||||||
export interface ImportBinding {
|
export interface ImportBinding {
|
||||||
isType: boolean
|
isType: boolean
|
||||||
imported: string
|
imported: string
|
||||||
|
local: string
|
||||||
source: string
|
source: string
|
||||||
isFromSetup: boolean
|
isFromSetup: boolean
|
||||||
isUsedInTemplate: boolean
|
isUsedInTemplate: boolean
|
||||||
|
@ -272,7 +273,6 @@ export function compileScript(
|
||||||
const bindingMetadata: BindingMetadata = {}
|
const bindingMetadata: BindingMetadata = {}
|
||||||
const helperImports: Set<string> = new Set()
|
const helperImports: Set<string> = new Set()
|
||||||
const userImports: Record<string, ImportBinding> = Object.create(null)
|
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 scriptBindings: Record<string, BindingTypes> = Object.create(null)
|
||||||
const setupBindings: Record<string, BindingTypes> = Object.create(null)
|
const setupBindings: Record<string, BindingTypes> = Object.create(null)
|
||||||
|
|
||||||
|
@ -362,10 +362,6 @@ export function compileScript(
|
||||||
isFromSetup: boolean,
|
isFromSetup: boolean,
|
||||||
needTemplateUsageCheck: boolean
|
needTemplateUsageCheck: boolean
|
||||||
) {
|
) {
|
||||||
if (source === 'vue' && imported) {
|
|
||||||
userImportAlias[imported] = local
|
|
||||||
}
|
|
||||||
|
|
||||||
// template usage check is only needed in non-inline mode, so we can skip
|
// template usage check is only needed in non-inline mode, so we can skip
|
||||||
// the work if inlineTemplate is true.
|
// the work if inlineTemplate is true.
|
||||||
let isUsedInTemplate = needTemplateUsageCheck
|
let isUsedInTemplate = needTemplateUsageCheck
|
||||||
|
@ -382,6 +378,7 @@ export function compileScript(
|
||||||
userImports[local] = {
|
userImports[local] = {
|
||||||
isType,
|
isType,
|
||||||
imported: imported || 'default',
|
imported: imported || 'default',
|
||||||
|
local,
|
||||||
source,
|
source,
|
||||||
isFromSetup,
|
isFromSetup,
|
||||||
isUsedInTemplate
|
isUsedInTemplate
|
||||||
|
@ -990,7 +987,7 @@ export function compileScript(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (node.declaration) {
|
if (node.declaration) {
|
||||||
walkDeclaration(node.declaration, scriptBindings, userImportAlias)
|
walkDeclaration(node.declaration, scriptBindings, userImports)
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
(node.type === 'VariableDeclaration' ||
|
(node.type === 'VariableDeclaration' ||
|
||||||
|
@ -999,7 +996,7 @@ export function compileScript(
|
||||||
node.type === 'TSEnumDeclaration') &&
|
node.type === 'TSEnumDeclaration') &&
|
||||||
!node.declare
|
!node.declare
|
||||||
) {
|
) {
|
||||||
walkDeclaration(node, scriptBindings, userImportAlias)
|
walkDeclaration(node, scriptBindings, userImports)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1199,7 +1196,7 @@ export function compileScript(
|
||||||
node.type === 'ClassDeclaration') &&
|
node.type === 'ClassDeclaration') &&
|
||||||
!node.declare
|
!node.declare
|
||||||
) {
|
) {
|
||||||
walkDeclaration(node, setupBindings, userImportAlias)
|
walkDeclaration(node, setupBindings, userImports)
|
||||||
}
|
}
|
||||||
|
|
||||||
// walk statements & named exports / variable declarations for top level
|
// walk statements & named exports / variable declarations for top level
|
||||||
|
@ -1654,8 +1651,17 @@ function registerBinding(
|
||||||
function walkDeclaration(
|
function walkDeclaration(
|
||||||
node: Declaration,
|
node: Declaration,
|
||||||
bindings: Record<string, BindingTypes>,
|
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') {
|
if (node.type === 'VariableDeclaration') {
|
||||||
const isConst = node.kind === 'const'
|
const isConst = node.kind === 'const'
|
||||||
// export const foo = ...
|
// export const foo = ...
|
||||||
|
@ -1669,7 +1675,7 @@ function walkDeclaration(
|
||||||
)
|
)
|
||||||
if (id.type === 'Identifier') {
|
if (id.type === 'Identifier') {
|
||||||
let bindingType
|
let bindingType
|
||||||
const userReactiveBinding = userImportAlias['reactive'] || 'reactive'
|
const userReactiveBinding = getUserBinding('reactive')
|
||||||
if (isCallOf(init, userReactiveBinding)) {
|
if (isCallOf(init, userReactiveBinding)) {
|
||||||
// treat reactive() calls as let since it's meant to be mutable
|
// treat reactive() calls as let since it's meant to be mutable
|
||||||
bindingType = isConst
|
bindingType = isConst
|
||||||
|
@ -1685,7 +1691,7 @@ function walkDeclaration(
|
||||||
? BindingTypes.SETUP_REACTIVE_CONST
|
? BindingTypes.SETUP_REACTIVE_CONST
|
||||||
: BindingTypes.SETUP_CONST
|
: BindingTypes.SETUP_CONST
|
||||||
} else if (isConst) {
|
} else if (isConst) {
|
||||||
if (isCallOf(init, userImportAlias['ref'] || 'ref')) {
|
if (isCallOf(init, getUserBinding('ref'))) {
|
||||||
bindingType = BindingTypes.SETUP_REF
|
bindingType = BindingTypes.SETUP_REF
|
||||||
} else {
|
} else {
|
||||||
bindingType = BindingTypes.SETUP_MAYBE_REF
|
bindingType = BindingTypes.SETUP_MAYBE_REF
|
||||||
|
@ -1982,10 +1988,11 @@ function genRuntimeEmits(emits: Set<string>) {
|
||||||
|
|
||||||
function isCallOf(
|
function isCallOf(
|
||||||
node: Node | null | undefined,
|
node: Node | null | undefined,
|
||||||
test: string | ((id: string) => boolean)
|
test: string | ((id: string) => boolean) | null | undefined
|
||||||
): node is CallExpression {
|
): node is CallExpression {
|
||||||
return !!(
|
return !!(
|
||||||
node &&
|
node &&
|
||||||
|
test &&
|
||||||
node.type === 'CallExpression' &&
|
node.type === 'CallExpression' &&
|
||||||
node.callee.type === 'Identifier' &&
|
node.callee.type === 'Identifier' &&
|
||||||
(typeof test === 'string'
|
(typeof test === 'string'
|
||||||
|
@ -1994,7 +2001,7 @@ function isCallOf(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function canNeverBeRef(node: Node, userReactiveImport: string): boolean {
|
function canNeverBeRef(node: Node, userReactiveImport?: string): boolean {
|
||||||
if (isCallOf(node, userReactiveImport)) {
|
if (isCallOf(node, userReactiveImport)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue