2021-04-19 12:29:55 -04:00

133 lines
3.3 KiB
TypeScript

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<string, any> | undefined, name: string) {
return (
registry &&
(registry[name] ||
registry[camelize(name)] ||
registry[capitalize(camelize(name))])
)
}