mirror of https://github.com/vuejs/core.git
fix(compile-sfc): fix identifier prefixing edge case caused by reused AST (#9867)
close #9853 close #9863
This commit is contained in:
parent
1d79b64ebc
commit
eb51b23d85
|
@ -55,14 +55,24 @@ export function walkIdentifiers(
|
||||||
// mark property in destructure pattern
|
// mark property in destructure pattern
|
||||||
;(node as any).inPattern = true
|
;(node as any).inPattern = true
|
||||||
} else if (isFunctionType(node)) {
|
} else if (isFunctionType(node)) {
|
||||||
// walk function expressions and add its arguments to known identifiers
|
if (node.scopeIds) {
|
||||||
// so that we don't prefix them
|
node.scopeIds.forEach(id => markKnownIds(id, knownIds))
|
||||||
walkFunctionParams(node, id => markScopeIdentifier(node, id, knownIds))
|
} else {
|
||||||
|
// walk function expressions and add its arguments to known identifiers
|
||||||
|
// so that we don't prefix them
|
||||||
|
walkFunctionParams(node, id =>
|
||||||
|
markScopeIdentifier(node, id, knownIds)
|
||||||
|
)
|
||||||
|
}
|
||||||
} else if (node.type === 'BlockStatement') {
|
} else if (node.type === 'BlockStatement') {
|
||||||
// #3445 record block-level local variables
|
if (node.scopeIds) {
|
||||||
walkBlockDeclarations(node, id =>
|
node.scopeIds.forEach(id => markKnownIds(id, knownIds))
|
||||||
markScopeIdentifier(node, id, knownIds)
|
} else {
|
||||||
)
|
// #3445 record block-level local variables
|
||||||
|
walkBlockDeclarations(node, id =>
|
||||||
|
markScopeIdentifier(node, id, knownIds)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
leave(node: Node & { scopeIds?: Set<string> }, parent: Node | undefined) {
|
leave(node: Node & { scopeIds?: Set<string> }, parent: Node | undefined) {
|
||||||
|
@ -227,6 +237,14 @@ export function extractIdentifiers(
|
||||||
return nodes
|
return nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function markKnownIds(name: string, knownIds: Record<string, number>) {
|
||||||
|
if (name in knownIds) {
|
||||||
|
knownIds[name]++
|
||||||
|
} else {
|
||||||
|
knownIds[name] = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function markScopeIdentifier(
|
function markScopeIdentifier(
|
||||||
node: Node & { scopeIds?: Set<string> },
|
node: Node & { scopeIds?: Set<string> },
|
||||||
child: Identifier,
|
child: Identifier,
|
||||||
|
@ -236,11 +254,7 @@ function markScopeIdentifier(
|
||||||
if (node.scopeIds && node.scopeIds.has(name)) {
|
if (node.scopeIds && node.scopeIds.has(name)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (name in knownIds) {
|
markKnownIds(name, knownIds)
|
||||||
knownIds[name]++
|
|
||||||
} else {
|
|
||||||
knownIds[name] = 1
|
|
||||||
}
|
|
||||||
;(node.scopeIds || (node.scopeIds = new Set())).add(name)
|
;(node.scopeIds || (node.scopeIds = new Set())).add(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import {
|
||||||
SFCTemplateCompileOptions
|
SFCTemplateCompileOptions
|
||||||
} from '../src/compileTemplate'
|
} from '../src/compileTemplate'
|
||||||
import { parse, SFCTemplateBlock } from '../src/parse'
|
import { parse, SFCTemplateBlock } from '../src/parse'
|
||||||
|
import { compileScript } from '../src'
|
||||||
|
|
||||||
function compile(opts: Omit<SFCTemplateCompileOptions, 'id'>) {
|
function compile(opts: Omit<SFCTemplateCompileOptions, 'id'>) {
|
||||||
return compileTemplate({
|
return compileTemplate({
|
||||||
|
@ -397,6 +398,35 @@ test('dynamic v-on + static v-on should merged', () => {
|
||||||
expect(result.code).toMatchSnapshot()
|
expect(result.code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #9853 regression found in Nuxt tests
|
||||||
|
// walkIdentifiers can get called multiple times on the same node
|
||||||
|
// due to #9729 calling it during SFC template usage check.
|
||||||
|
// conditions needed:
|
||||||
|
// 1. `<script setup lang="ts">`
|
||||||
|
// 2. Has import
|
||||||
|
// 3. inlineTemplate: false
|
||||||
|
// 4. AST being reused
|
||||||
|
test('prefixing edge case for reused AST', () => {
|
||||||
|
const src = `
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Foo } from './foo'
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
{{ list.map((t, index) => ({ t: t })) }}
|
||||||
|
</template>
|
||||||
|
`
|
||||||
|
const { descriptor } = parse(src)
|
||||||
|
// compileScript triggers importUsageCheck
|
||||||
|
compileScript(descriptor, { id: 'xxx' })
|
||||||
|
const { code } = compileTemplate({
|
||||||
|
id: 'xxx',
|
||||||
|
filename: 'test.vue',
|
||||||
|
ast: descriptor.template!.ast,
|
||||||
|
source: descriptor.template!.content
|
||||||
|
})
|
||||||
|
expect(code).not.toMatch(`_ctx.t`)
|
||||||
|
})
|
||||||
|
|
||||||
interface Pos {
|
interface Pos {
|
||||||
line: number
|
line: number
|
||||||
column: number
|
column: number
|
||||||
|
|
Loading…
Reference in New Issue