fix(compiler-sfc): fix template usage check false positives on types
fix #5414
This commit is contained in:
parent
ba17792b72
commit
ccf92564d3
@ -535,6 +535,23 @@ return { props, a, emit }
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`SFC compile <script setup> dev mode import usage check TS annotations 1`] = `
|
||||
"import { defineComponent as _defineComponent } from 'vue'
|
||||
import { Foo, Bar, Baz } from './x'
|
||||
|
||||
export default /*#__PURE__*/_defineComponent({
|
||||
setup(__props, { expose }) {
|
||||
expose();
|
||||
|
||||
const a = 1
|
||||
function b() {}
|
||||
|
||||
return { a, b, Baz }
|
||||
}
|
||||
|
||||
})"
|
||||
`;
|
||||
|
||||
exports[`SFC compile <script setup> dev mode import usage check attribute expressions 1`] = `
|
||||
"import { defineComponent as _defineComponent } from 'vue'
|
||||
import { bar, baz } from './x'
|
||||
|
@ -432,6 +432,23 @@ defineExpose({ foo: 123 })
|
||||
expect(content).toMatch(`return { FooBaz, Last }`)
|
||||
assertCode(content)
|
||||
})
|
||||
|
||||
test('TS annotations', () => {
|
||||
const { content } = compile(`
|
||||
<script setup lang="ts">
|
||||
import { Foo, Bar, Baz } from './x'
|
||||
const a = 1
|
||||
function b() {}
|
||||
</script>
|
||||
<template>
|
||||
{{ a as Foo }}
|
||||
{{ b<Bar>() }}
|
||||
{{ Baz }}
|
||||
</template>
|
||||
`)
|
||||
expect(content).toMatch(`return { a, b, Baz }`)
|
||||
assertCode(content)
|
||||
})
|
||||
})
|
||||
|
||||
describe('inlineTemplate mode', () => {
|
||||
|
@ -12,7 +12,12 @@ import {
|
||||
walkIdentifiers
|
||||
} from '@vue/compiler-dom'
|
||||
import { DEFAULT_FILENAME, SFCDescriptor, SFCScriptBlock } from './parse'
|
||||
import { parse as _parse, ParserOptions, ParserPlugin } from '@babel/parser'
|
||||
import {
|
||||
parse as _parse,
|
||||
parseExpression,
|
||||
ParserOptions,
|
||||
ParserPlugin
|
||||
} from '@babel/parser'
|
||||
import { camelize, capitalize, generateCodeFrame, makeMap } from '@vue/shared'
|
||||
import {
|
||||
Node,
|
||||
@ -348,14 +353,23 @@ export function compileScript(
|
||||
local: string,
|
||||
imported: string | false,
|
||||
isType: boolean,
|
||||
isFromSetup: boolean
|
||||
isFromSetup: boolean,
|
||||
needTemplateUsageCheck: boolean
|
||||
) {
|
||||
if (source === 'vue' && imported) {
|
||||
userImportAlias[imported] = local
|
||||
}
|
||||
|
||||
let isUsedInTemplate = true
|
||||
if (isTS && sfc.template && !sfc.template.src && !sfc.template.lang) {
|
||||
// template usage check is only needed in non-inline mode, so we can skip
|
||||
// the work if inlineTemplate is true.
|
||||
let isUsedInTemplate = needTemplateUsageCheck
|
||||
if (
|
||||
needTemplateUsageCheck &&
|
||||
isTS &&
|
||||
sfc.template &&
|
||||
!sfc.template.src &&
|
||||
!sfc.template.lang
|
||||
) {
|
||||
isUsedInTemplate = isImportUsed(local, sfc)
|
||||
}
|
||||
|
||||
@ -813,7 +827,8 @@ export function compileScript(
|
||||
node.importKind === 'type' ||
|
||||
(specifier.type === 'ImportSpecifier' &&
|
||||
specifier.importKind === 'type'),
|
||||
false
|
||||
false,
|
||||
!options.inlineTemplate
|
||||
)
|
||||
}
|
||||
} else if (node.type === 'ExportDefaultDeclaration') {
|
||||
@ -1027,7 +1042,8 @@ export function compileScript(
|
||||
node.importKind === 'type' ||
|
||||
(specifier.type === 'ImportSpecifier' &&
|
||||
specifier.importKind === 'type'),
|
||||
true
|
||||
true,
|
||||
!options.inlineTemplate
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -2051,14 +2067,14 @@ function resolveTemplateUsageCheckString(sfc: SFCDescriptor) {
|
||||
code += `,v${capitalize(camelize(prop.name))}`
|
||||
}
|
||||
if (prop.exp) {
|
||||
code += `,${stripStrings(
|
||||
code += `,${processExp(
|
||||
(prop.exp as SimpleExpressionNode).content
|
||||
)}`
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (node.type === NodeTypes.INTERPOLATION) {
|
||||
code += `,${stripStrings(
|
||||
code += `,${processExp(
|
||||
(node.content as SimpleExpressionNode).content
|
||||
)}`
|
||||
}
|
||||
@ -2071,6 +2087,19 @@ function resolveTemplateUsageCheckString(sfc: SFCDescriptor) {
|
||||
return code
|
||||
}
|
||||
|
||||
function processExp(exp: string) {
|
||||
if (/ as \w|<.*>/.test(exp)) {
|
||||
let ret = ''
|
||||
// has potential type cast or generic arguments that uses types
|
||||
const ast = parseExpression(exp, { plugins: ['typescript'] })
|
||||
walkIdentifiers(ast, node => {
|
||||
ret += `,` + node.name
|
||||
})
|
||||
return ret
|
||||
}
|
||||
return stripStrings(exp)
|
||||
}
|
||||
|
||||
function stripStrings(exp: string) {
|
||||
return exp
|
||||
.replace(/'[^']*'|"[^"]*"/g, '')
|
||||
|
Loading…
Reference in New Issue
Block a user