diff --git a/packages/compiler-sfc/src/compileScript.ts b/packages/compiler-sfc/src/compileScript.ts index 538366ac1..3fb435223 100644 --- a/packages/compiler-sfc/src/compileScript.ts +++ b/packages/compiler-sfc/src/compileScript.ts @@ -1,30 +1,21 @@ import MagicString from 'magic-string' import { - BindingMetadata, BindingTypes, - createRoot, - NodeTypes, - transform, - parserOptions, UNREF, - SimpleExpressionNode, isFunctionType, walkIdentifiers, getImportedName } from '@vue/compiler-dom' import { DEFAULT_FILENAME, SFCDescriptor, SFCScriptBlock } from './parse' -import { parse as _parse, parseExpression, ParserPlugin } from '@babel/parser' -import { camelize, capitalize, generateCodeFrame, makeMap } from '@vue/shared' +import { parse as _parse, ParserPlugin } from '@babel/parser' +import { generateCodeFrame } from '@vue/shared' import { Node, Declaration, ObjectPattern, - ObjectExpression, ArrayPattern, Identifier, ExportSpecifier, - TSType, - ArrayExpression, Statement, CallExpression, AwaitExpression, @@ -41,7 +32,6 @@ import { import { compileTemplate, SFCTemplateCompileOptions } from './compileTemplate' import { warnOnce } from './warn' import { rewriteDefaultAST } from './rewriteDefault' -import { createCache } from './cache' import { shouldTransform, transformAST } from '@vue/reactivity-transform' import { transformDestructuredProps } from './script/definePropsDestructure' import { ScriptCompileContext } from './script/context' @@ -57,23 +47,16 @@ import { DEFINE_EMITS } from './script/defineEmits' import { DEFINE_MODEL, processDefineModel } from './script/defineModel' -import { - resolveObjectKey, - UNKNOWN_TYPE, - isLiteralNode, - unwrapTSNode, - isCallOf -} from './script/utils' +import { isLiteralNode, unwrapTSNode, isCallOf } from './script/utils' +import { inferRuntimeType } from './script/resolveType' +import { analyzeScriptBindings } from './script/analyzeScriptBindings' +import { isImportUsed } from './script/importUsageCheck' // Special compiler macros const DEFINE_EXPOSE = 'defineExpose' const DEFINE_OPTIONS = 'defineOptions' const DEFINE_SLOTS = 'defineSlots' -const isBuiltInDir = makeMap( - `once,memo,if,for,else,else-if,slot,text,html,on,bind,model,show,cloak,is` -) - export interface SFCScriptCompileOptions { /** * Scope ID for prefixing injected CSS variables. @@ -968,32 +951,10 @@ export function compileScript( } // 7. analyze binding metadata + // `defineProps` & `defineModel` also register props bindings if (scriptAst) { Object.assign(ctx.bindingMetadata, analyzeScriptBindings(scriptAst.body)) } - if (ctx.propsRuntimeDecl) { - for (const key of getObjectOrArrayExpressionKeys(ctx.propsRuntimeDecl)) { - ctx.bindingMetadata[key] = BindingTypes.PROPS - } - } - for (const key in ctx.modelDecls) { - ctx.bindingMetadata[key] = BindingTypes.PROPS - } - // props aliases - if (ctx.propsDestructureDecl) { - if (ctx.propsDestructureRestId) { - ctx.bindingMetadata[ctx.propsDestructureRestId] = - BindingTypes.SETUP_REACTIVE_CONST - } - for (const key in ctx.propsDestructuredBindings) { - const { local } = ctx.propsDestructuredBindings[key] - if (local !== key) { - ctx.bindingMetadata[local] = BindingTypes.PROPS_ALIASED - ;(ctx.bindingMetadata.__propsAliases || - (ctx.bindingMetadata.__propsAliases = {}))[local] = key - } - } - } for (const [key, { isType, imported, source }] of Object.entries( userImports )) { @@ -1478,156 +1439,6 @@ function recordType(node: Node, declaredTypes: Record) { } } -function inferRuntimeType( - node: TSType, - declaredTypes: Record -): string[] { - switch (node.type) { - case 'TSStringKeyword': - return ['String'] - case 'TSNumberKeyword': - return ['Number'] - case 'TSBooleanKeyword': - return ['Boolean'] - case 'TSObjectKeyword': - return ['Object'] - case 'TSNullKeyword': - return ['null'] - case 'TSTypeLiteral': { - // TODO (nice to have) generate runtime property validation - const types = new Set() - for (const m of node.members) { - if ( - m.type === 'TSCallSignatureDeclaration' || - m.type === 'TSConstructSignatureDeclaration' - ) { - types.add('Function') - } else { - types.add('Object') - } - } - return types.size ? Array.from(types) : ['Object'] - } - case 'TSFunctionType': - return ['Function'] - case 'TSArrayType': - case 'TSTupleType': - // TODO (nice to have) generate runtime element type/length checks - return ['Array'] - - case 'TSLiteralType': - switch (node.literal.type) { - case 'StringLiteral': - return ['String'] - case 'BooleanLiteral': - return ['Boolean'] - case 'NumericLiteral': - case 'BigIntLiteral': - return ['Number'] - default: - return [UNKNOWN_TYPE] - } - - case 'TSTypeReference': - if (node.typeName.type === 'Identifier') { - if (declaredTypes[node.typeName.name]) { - return declaredTypes[node.typeName.name] - } - switch (node.typeName.name) { - case 'Array': - case 'Function': - case 'Object': - case 'Set': - case 'Map': - case 'WeakSet': - case 'WeakMap': - case 'Date': - case 'Promise': - return [node.typeName.name] - - // TS built-in utility types - // https://www.typescriptlang.org/docs/handbook/utility-types.html - case 'Partial': - case 'Required': - case 'Readonly': - case 'Record': - case 'Pick': - case 'Omit': - case 'InstanceType': - return ['Object'] - - case 'Uppercase': - case 'Lowercase': - case 'Capitalize': - case 'Uncapitalize': - return ['String'] - - case 'Parameters': - case 'ConstructorParameters': - return ['Array'] - - case 'NonNullable': - if (node.typeParameters && node.typeParameters.params[0]) { - return inferRuntimeType( - node.typeParameters.params[0], - declaredTypes - ).filter(t => t !== 'null') - } - break - case 'Extract': - if (node.typeParameters && node.typeParameters.params[1]) { - return inferRuntimeType( - node.typeParameters.params[1], - declaredTypes - ) - } - break - case 'Exclude': - case 'OmitThisParameter': - if (node.typeParameters && node.typeParameters.params[0]) { - return inferRuntimeType( - node.typeParameters.params[0], - declaredTypes - ) - } - break - } - } - // cannot infer, fallback to UNKNOWN: ThisParameterType - return [UNKNOWN_TYPE] - - case 'TSParenthesizedType': - return inferRuntimeType(node.typeAnnotation, declaredTypes) - - case 'TSUnionType': - return flattenTypes(node.types, declaredTypes) - case 'TSIntersectionType': { - return flattenTypes(node.types, declaredTypes).filter( - t => t !== UNKNOWN_TYPE - ) - } - - case 'TSSymbolKeyword': - return ['Symbol'] - - default: - return [UNKNOWN_TYPE] // no runtime check - } -} - -function flattenTypes( - types: TSType[], - declaredTypes: Record -): string[] { - return [ - ...new Set( - ([] as string[]).concat( - ...types.map(t => inferRuntimeType(t, declaredTypes)) - ) - ) - ] -} - function inferEnumType(node: TSEnumDeclaration): string[] { const types = new Set() for (const m of node.members) { @@ -1708,251 +1519,3 @@ function isStaticNode(node: Node): boolean { return false } } - -/** - * Analyze bindings in normal `