From ccf92564d339cdee3947aecfba2e861c88864883 Mon Sep 17 00:00:00 2001 From: Evan You Date: Thu, 12 May 2022 18:23:10 +0800 Subject: [PATCH] fix(compiler-sfc): fix template usage check false positives on types fix #5414 --- .../__snapshots__/compileScript.spec.ts.snap | 17 +++++++ .../__tests__/compileScript.spec.ts | 17 +++++++ packages/compiler-sfc/src/compileScript.ts | 45 +++++++++++++++---- 3 files changed, 71 insertions(+), 8 deletions(-) diff --git a/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap b/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap index cbe274ef..757b1534 100644 --- a/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap +++ b/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap @@ -535,6 +535,23 @@ return { props, a, emit } }" `; +exports[`SFC compile + + `) + expect(content).toMatch(`return { a, b, Baz }`) + assertCode(content) + }) }) describe('inlineTemplate mode', () => { diff --git a/packages/compiler-sfc/src/compileScript.ts b/packages/compiler-sfc/src/compileScript.ts index 9c9c7ffb..509934d6 100644 --- a/packages/compiler-sfc/src/compileScript.ts +++ b/packages/compiler-sfc/src/compileScript.ts @@ -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, '')