mirror of https://github.com/vuejs/core.git
feat(compiler-sfc): expose type resolve APIs
This commit is contained in:
parent
6b13e04b4c
commit
f22e32e365
|
@ -6,6 +6,7 @@ export { compileTemplate } from './compileTemplate'
|
||||||
export { compileStyle, compileStyleAsync } from './compileStyle'
|
export { compileStyle, compileStyleAsync } from './compileStyle'
|
||||||
export { compileScript } from './compileScript'
|
export { compileScript } from './compileScript'
|
||||||
export { rewriteDefault, rewriteDefaultAST } from './rewriteDefault'
|
export { rewriteDefault, rewriteDefaultAST } from './rewriteDefault'
|
||||||
|
export { resolveTypeElements, inferRuntimeType } from './script/resolveType'
|
||||||
export {
|
export {
|
||||||
shouldTransform as shouldTransformRef,
|
shouldTransform as shouldTransformRef,
|
||||||
transform as transformRef,
|
transform as transformRef,
|
||||||
|
@ -52,6 +53,11 @@ export type {
|
||||||
SFCStyleCompileResults
|
SFCStyleCompileResults
|
||||||
} from './compileStyle'
|
} from './compileStyle'
|
||||||
export type { SFCScriptCompileOptions } from './compileScript'
|
export type { SFCScriptCompileOptions } from './compileScript'
|
||||||
|
export type { ScriptCompileContext } from './script/context'
|
||||||
|
export type {
|
||||||
|
TypeResolveContext,
|
||||||
|
SimpleTypeResolveContext
|
||||||
|
} from './script/resolveType'
|
||||||
export type {
|
export type {
|
||||||
AssetURLOptions,
|
AssetURLOptions,
|
||||||
AssetURLTagConfig
|
AssetURLTagConfig
|
||||||
|
|
|
@ -16,12 +16,14 @@ export class ScriptCompileContext {
|
||||||
scriptAst: Program | null
|
scriptAst: Program | null
|
||||||
scriptSetupAst: Program | null
|
scriptSetupAst: Program | null
|
||||||
|
|
||||||
s = new MagicString(this.descriptor.source)
|
source = this.descriptor.source
|
||||||
|
filename = this.descriptor.filename
|
||||||
|
s = new MagicString(this.source)
|
||||||
startOffset = this.descriptor.scriptSetup?.loc.start.offset
|
startOffset = this.descriptor.scriptSetup?.loc.start.offset
|
||||||
endOffset = this.descriptor.scriptSetup?.loc.end.offset
|
endOffset = this.descriptor.scriptSetup?.loc.end.offset
|
||||||
|
|
||||||
// import / type analysis
|
// import / type analysis
|
||||||
scope: TypeScope | undefined
|
scope?: TypeScope
|
||||||
userImports: Record<string, ImportBinding> = Object.create(null)
|
userImports: Record<string, ImportBinding> = Object.create(null)
|
||||||
|
|
||||||
// macros presence check
|
// macros presence check
|
||||||
|
@ -69,7 +71,7 @@ export class ScriptCompileContext {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public descriptor: SFCDescriptor,
|
public descriptor: SFCDescriptor,
|
||||||
public options: SFCScriptCompileOptions
|
public options: Partial<SFCScriptCompileOptions>
|
||||||
) {
|
) {
|
||||||
const { script, scriptSetup } = descriptor
|
const { script, scriptSetup } = descriptor
|
||||||
const scriptLang = script && script.lang
|
const scriptLang = script && script.lang
|
||||||
|
|
|
@ -36,6 +36,32 @@ import { createCache } from '../cache'
|
||||||
import type TS from 'typescript'
|
import type TS from 'typescript'
|
||||||
import { join, extname, dirname } from 'path'
|
import { join, extname, dirname } from 'path'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TypeResolveContext is compatible with ScriptCompileContext
|
||||||
|
* but also allows a simpler version of it with minimal required properties
|
||||||
|
* when resolveType needs to be used in a non-SFC context, e.g. in a babel
|
||||||
|
* plugin. The simplest context can be just:
|
||||||
|
* ```ts
|
||||||
|
* const ctx: SimpleTypeResolveContext = {
|
||||||
|
* filename: '...',
|
||||||
|
* source: '...',
|
||||||
|
* options: {},
|
||||||
|
* error() {},
|
||||||
|
* ast: []
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export type SimpleTypeResolveContext = Pick<
|
||||||
|
ScriptCompileContext,
|
||||||
|
// required
|
||||||
|
'source' | 'filename' | 'error' | 'options'
|
||||||
|
> &
|
||||||
|
Partial<Pick<ScriptCompileContext, 'scope' | 'deps'>> & {
|
||||||
|
ast: Statement[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TypeResolveContext = ScriptCompileContext | SimpleTypeResolveContext
|
||||||
|
|
||||||
type Import = Pick<ImportBinding, 'source' | 'imported'>
|
type Import = Pick<ImportBinding, 'source' | 'imported'>
|
||||||
|
|
||||||
export interface TypeScope {
|
export interface TypeScope {
|
||||||
|
@ -79,7 +105,7 @@ interface ResolvedElements {
|
||||||
* mapped to runtime props or emits.
|
* mapped to runtime props or emits.
|
||||||
*/
|
*/
|
||||||
export function resolveTypeElements(
|
export function resolveTypeElements(
|
||||||
ctx: ScriptCompileContext,
|
ctx: TypeResolveContext,
|
||||||
node: Node & WithScope & { _resolvedElements?: ResolvedElements },
|
node: Node & WithScope & { _resolvedElements?: ResolvedElements },
|
||||||
scope?: TypeScope
|
scope?: TypeScope
|
||||||
): ResolvedElements {
|
): ResolvedElements {
|
||||||
|
@ -94,7 +120,7 @@ export function resolveTypeElements(
|
||||||
}
|
}
|
||||||
|
|
||||||
function innerResolveTypeElements(
|
function innerResolveTypeElements(
|
||||||
ctx: ScriptCompileContext,
|
ctx: TypeResolveContext,
|
||||||
node: Node,
|
node: Node,
|
||||||
scope: TypeScope
|
scope: TypeScope
|
||||||
): ResolvedElements {
|
): ResolvedElements {
|
||||||
|
@ -138,7 +164,7 @@ function innerResolveTypeElements(
|
||||||
) {
|
) {
|
||||||
return resolveBuiltin(ctx, node, typeName as any, scope)
|
return resolveBuiltin(ctx, node, typeName as any, scope)
|
||||||
}
|
}
|
||||||
ctx.error(
|
return ctx.error(
|
||||||
`Unresolvable type reference or unsupported built-in utlility type`,
|
`Unresolvable type reference or unsupported built-in utlility type`,
|
||||||
node,
|
node,
|
||||||
scope
|
scope
|
||||||
|
@ -146,11 +172,11 @@ function innerResolveTypeElements(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.error(`Unresolvable type: ${node.type}`, node, scope)
|
return ctx.error(`Unresolvable type: ${node.type}`, node, scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
function typeElementsToMap(
|
function typeElementsToMap(
|
||||||
ctx: ScriptCompileContext,
|
ctx: TypeResolveContext,
|
||||||
elements: TSTypeElement[],
|
elements: TSTypeElement[],
|
||||||
scope = ctxToScope(ctx)
|
scope = ctxToScope(ctx)
|
||||||
): ResolvedElements {
|
): ResolvedElements {
|
||||||
|
@ -227,7 +253,7 @@ function createProperty(
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveInterfaceMembers(
|
function resolveInterfaceMembers(
|
||||||
ctx: ScriptCompileContext,
|
ctx: TypeResolveContext,
|
||||||
node: TSInterfaceDeclaration & WithScope,
|
node: TSInterfaceDeclaration & WithScope,
|
||||||
scope: TypeScope
|
scope: TypeScope
|
||||||
): ResolvedElements {
|
): ResolvedElements {
|
||||||
|
@ -246,7 +272,7 @@ function resolveInterfaceMembers(
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveMappedType(
|
function resolveMappedType(
|
||||||
ctx: ScriptCompileContext,
|
ctx: TypeResolveContext,
|
||||||
node: TSMappedType,
|
node: TSMappedType,
|
||||||
scope: TypeScope
|
scope: TypeScope
|
||||||
): ResolvedElements {
|
): ResolvedElements {
|
||||||
|
@ -266,7 +292,7 @@ function resolveMappedType(
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveIndexType(
|
function resolveIndexType(
|
||||||
ctx: ScriptCompileContext,
|
ctx: TypeResolveContext,
|
||||||
node: TSIndexedAccessType,
|
node: TSIndexedAccessType,
|
||||||
scope: TypeScope
|
scope: TypeScope
|
||||||
): (TSType & WithScope)[] {
|
): (TSType & WithScope)[] {
|
||||||
|
@ -297,7 +323,7 @@ function resolveIndexType(
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveArrayElementType(
|
function resolveArrayElementType(
|
||||||
ctx: ScriptCompileContext,
|
ctx: TypeResolveContext,
|
||||||
node: Node,
|
node: Node,
|
||||||
scope: TypeScope
|
scope: TypeScope
|
||||||
): TSType[] {
|
): TSType[] {
|
||||||
|
@ -322,11 +348,15 @@ function resolveArrayElementType(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.error('Failed to resolve element type from target type', node)
|
return ctx.error(
|
||||||
|
'Failed to resolve element type from target type',
|
||||||
|
node,
|
||||||
|
scope
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveStringType(
|
function resolveStringType(
|
||||||
ctx: ScriptCompileContext,
|
ctx: TypeResolveContext,
|
||||||
node: Node,
|
node: Node,
|
||||||
scope: TypeScope
|
scope: TypeScope
|
||||||
): string[] {
|
): string[] {
|
||||||
|
@ -373,11 +403,11 @@ function resolveStringType(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.error('Failed to resolve index type into finite keys', node, scope)
|
return ctx.error('Failed to resolve index type into finite keys', node, scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveTemplateKeys(
|
function resolveTemplateKeys(
|
||||||
ctx: ScriptCompileContext,
|
ctx: TypeResolveContext,
|
||||||
node: TemplateLiteral,
|
node: TemplateLiteral,
|
||||||
scope: TypeScope
|
scope: TypeScope
|
||||||
): string[] {
|
): string[] {
|
||||||
|
@ -420,7 +450,7 @@ const SupportedBuiltinsSet = new Set([
|
||||||
type GetSetType<T> = T extends Set<infer V> ? V : never
|
type GetSetType<T> = T extends Set<infer V> ? V : never
|
||||||
|
|
||||||
function resolveBuiltin(
|
function resolveBuiltin(
|
||||||
ctx: ScriptCompileContext,
|
ctx: TypeResolveContext,
|
||||||
node: TSTypeReference | TSExpressionWithTypeArguments,
|
node: TSTypeReference | TSExpressionWithTypeArguments,
|
||||||
name: GetSetType<typeof SupportedBuiltinsSet>,
|
name: GetSetType<typeof SupportedBuiltinsSet>,
|
||||||
scope: TypeScope
|
scope: TypeScope
|
||||||
|
@ -460,7 +490,7 @@ function resolveBuiltin(
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveTypeReference(
|
function resolveTypeReference(
|
||||||
ctx: ScriptCompileContext,
|
ctx: TypeResolveContext,
|
||||||
node: (TSTypeReference | TSExpressionWithTypeArguments) & {
|
node: (TSTypeReference | TSExpressionWithTypeArguments) & {
|
||||||
_resolvedReference?: Node
|
_resolvedReference?: Node
|
||||||
},
|
},
|
||||||
|
@ -481,7 +511,7 @@ function resolveTypeReference(
|
||||||
}
|
}
|
||||||
|
|
||||||
function innerResolveTypeReference(
|
function innerResolveTypeReference(
|
||||||
ctx: ScriptCompileContext,
|
ctx: TypeResolveContext,
|
||||||
scope: TypeScope,
|
scope: TypeScope,
|
||||||
name: string | string[],
|
name: string | string[],
|
||||||
node: TSTypeReference | TSExpressionWithTypeArguments,
|
node: TSTypeReference | TSExpressionWithTypeArguments,
|
||||||
|
@ -536,6 +566,9 @@ function qualifiedNameToPath(node: Identifier | TSQualifiedName): string[] {
|
||||||
|
|
||||||
let ts: typeof TS
|
let ts: typeof TS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
export function registerTS(_ts: any) {
|
export function registerTS(_ts: any) {
|
||||||
ts = _ts
|
ts = _ts
|
||||||
}
|
}
|
||||||
|
@ -543,7 +576,7 @@ export function registerTS(_ts: any) {
|
||||||
type FS = NonNullable<SFCScriptCompileOptions['fs']>
|
type FS = NonNullable<SFCScriptCompileOptions['fs']>
|
||||||
|
|
||||||
function resolveTypeFromImport(
|
function resolveTypeFromImport(
|
||||||
ctx: ScriptCompileContext,
|
ctx: TypeResolveContext,
|
||||||
node: TSTypeReference | TSExpressionWithTypeArguments,
|
node: TSTypeReference | TSExpressionWithTypeArguments,
|
||||||
name: string,
|
name: string,
|
||||||
scope: TypeScope
|
scope: TypeScope
|
||||||
|
@ -685,13 +718,16 @@ function resolveWithTS(
|
||||||
|
|
||||||
const fileToScopeCache = createCache<TypeScope>()
|
const fileToScopeCache = createCache<TypeScope>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
export function invalidateTypeCache(filename: string) {
|
export function invalidateTypeCache(filename: string) {
|
||||||
fileToScopeCache.delete(filename)
|
fileToScopeCache.delete(filename)
|
||||||
tsConfigCache.delete(filename)
|
tsConfigCache.delete(filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
function fileToScope(
|
function fileToScope(
|
||||||
ctx: ScriptCompileContext,
|
ctx: TypeResolveContext,
|
||||||
filename: string,
|
filename: string,
|
||||||
fs: FS
|
fs: FS
|
||||||
): TypeScope {
|
): TypeScope {
|
||||||
|
@ -717,7 +753,7 @@ function fileToScope(
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseFile(
|
function parseFile(
|
||||||
ctx: ScriptCompileContext,
|
ctx: TypeResolveContext,
|
||||||
filename: string,
|
filename: string,
|
||||||
content: string
|
content: string
|
||||||
): Statement[] {
|
): Statement[] {
|
||||||
|
@ -763,24 +799,30 @@ function parseFile(
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
function ctxToScope(ctx: ScriptCompileContext): TypeScope {
|
function ctxToScope(ctx: TypeResolveContext): TypeScope {
|
||||||
if (ctx.scope) {
|
if (ctx.scope) {
|
||||||
return ctx.scope
|
return ctx.scope
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const body =
|
||||||
|
'ast' in ctx
|
||||||
|
? ctx.ast
|
||||||
|
: ctx.scriptAst
|
||||||
|
? [...ctx.scriptAst.body, ...ctx.scriptSetupAst!.body]
|
||||||
|
: ctx.scriptSetupAst!.body
|
||||||
|
|
||||||
const scope: TypeScope = {
|
const scope: TypeScope = {
|
||||||
filename: ctx.descriptor.filename,
|
filename: ctx.filename,
|
||||||
source: ctx.descriptor.source,
|
source: ctx.source,
|
||||||
offset: ctx.startOffset!,
|
offset: 'startOffset' in ctx ? ctx.startOffset! : 0,
|
||||||
imports: Object.create(ctx.userImports),
|
imports:
|
||||||
|
'userImports' in ctx
|
||||||
|
? Object.create(ctx.userImports)
|
||||||
|
: recordImports(body),
|
||||||
types: Object.create(null),
|
types: Object.create(null),
|
||||||
exportedTypes: Object.create(null)
|
exportedTypes: Object.create(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
const body = ctx.scriptAst
|
|
||||||
? [...ctx.scriptAst.body, ...ctx.scriptSetupAst!.body]
|
|
||||||
: ctx.scriptSetupAst!.body
|
|
||||||
|
|
||||||
recordTypes(body, scope)
|
recordTypes(body, scope)
|
||||||
|
|
||||||
return (ctx.scope = scope)
|
return (ctx.scope = scope)
|
||||||
|
@ -894,7 +936,7 @@ function recordImport(node: Node, imports: TypeScope['imports']) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function inferRuntimeType(
|
export function inferRuntimeType(
|
||||||
ctx: ScriptCompileContext,
|
ctx: TypeResolveContext,
|
||||||
node: Node & WithScope,
|
node: Node & WithScope,
|
||||||
scope = node._ownerScope || ctxToScope(ctx)
|
scope = node._ownerScope || ctxToScope(ctx)
|
||||||
): string[] {
|
): string[] {
|
||||||
|
@ -1052,7 +1094,7 @@ export function inferRuntimeType(
|
||||||
}
|
}
|
||||||
|
|
||||||
function flattenTypes(
|
function flattenTypes(
|
||||||
ctx: ScriptCompileContext,
|
ctx: TypeResolveContext,
|
||||||
types: TSType[],
|
types: TSType[],
|
||||||
scope: TypeScope
|
scope: TypeScope
|
||||||
): string[] {
|
): string[] {
|
||||||
|
|
Loading…
Reference in New Issue