import { currentInstance, ConcreteComponent, ComponentOptions, getComponentName } from '../component' import { currentRenderingInstance } from '../componentRenderContext' import { Directive } from '../directives' import { camelize, capitalize, isString } from '@vue/shared' import { warn } from '../warning' import { VNodeTypes } from '../vnode' export const COMPONENTS = 'components' export const DIRECTIVES = 'directives' export const FILTERS = 'filters' export type AssetTypes = typeof COMPONENTS | typeof DIRECTIVES | typeof FILTERS /** * @private */ export function resolveComponent( name: string, maybeSelfReference?: boolean ): ConcreteComponent | string { return resolveAsset(COMPONENTS, name, true, maybeSelfReference) || name } export const NULL_DYNAMIC_COMPONENT = Symbol() /** * @private */ export function resolveDynamicComponent(component: unknown): VNodeTypes { if (isString(component)) { return resolveAsset(COMPONENTS, component, false) || component } else { // invalid types will fallthrough to createVNode and raise warning return (component || NULL_DYNAMIC_COMPONENT) as any } } /** * @private */ export function resolveDirective(name: string): Directive | undefined { return resolveAsset(DIRECTIVES, name) } /** * v2 compat only * @internal */ export function resolveFilter(name: string): Function | undefined { return resolveAsset(FILTERS, name) } /** * @private * overload 1: components */ function resolveAsset( type: typeof COMPONENTS, name: string, warnMissing?: boolean, maybeSelfReference?: boolean ): ConcreteComponent | undefined // overload 2: directives function resolveAsset( type: typeof DIRECTIVES, name: string ): Directive | undefined // implementation // overload 3: filters (compat only) function resolveAsset(type: typeof FILTERS, name: string): Function | undefined // implementation function resolveAsset( type: AssetTypes, name: string, warnMissing = true, maybeSelfReference = false ) { const instance = currentRenderingInstance || currentInstance if (instance) { const Component = instance.type // explicit self name has highest priority if (type === COMPONENTS) { const selfName = getComponentName(Component) if ( selfName && (selfName === name || selfName === camelize(name) || selfName === capitalize(camelize(name))) ) { return Component } } const res = // local registration // check instance[type] first for components with mixin or extends. resolve(instance[type] || (Component as ComponentOptions)[type], name) || // global registration resolve(instance.appContext[type], name) if (!res && maybeSelfReference) { // fallback to implicit self-reference return Component } if (__DEV__ && warnMissing && !res) { warn(`Failed to resolve ${type.slice(0, -1)}: ${name}`) } return res } else if (__DEV__) { warn( `resolve${capitalize(type.slice(0, -1))} ` + `can only be used in render() or setup().` ) } } function resolve(registry: Record | undefined, name: string) { return ( registry && (registry[name] || registry[camelize(name)] || registry[capitalize(camelize(name))]) ) }