resolveAssets.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import {
  2. type ComponentOptions,
  3. type ConcreteComponent,
  4. currentInstance,
  5. getComponentName,
  6. } from '../component'
  7. import { currentRenderingInstance } from '../componentRenderContext'
  8. import type { Directive } from '../directives'
  9. import { camelize, capitalize, isString } from '@vue/shared'
  10. import { warn } from '../warning'
  11. import type { VNodeTypes } from '../vnode'
  12. export const COMPONENTS = 'components'
  13. export const DIRECTIVES = 'directives'
  14. export const FILTERS = 'filters'
  15. export type AssetTypes = typeof COMPONENTS | typeof DIRECTIVES | typeof FILTERS
  16. /**
  17. * @private
  18. */
  19. export function resolveComponent(
  20. name: string,
  21. maybeSelfReference?: boolean,
  22. ): ConcreteComponent | string {
  23. return resolveAsset(COMPONENTS, name, true, maybeSelfReference) || name
  24. }
  25. export const NULL_DYNAMIC_COMPONENT = Symbol.for('v-ndc')
  26. /**
  27. * @private
  28. */
  29. export function resolveDynamicComponent(component: unknown): VNodeTypes {
  30. if (isString(component)) {
  31. return resolveAsset(COMPONENTS, component, false) || component
  32. } else {
  33. // invalid types will fallthrough to createVNode and raise warning
  34. return (component || NULL_DYNAMIC_COMPONENT) as any
  35. }
  36. }
  37. /**
  38. * @private
  39. */
  40. export function resolveDirective(name: string): Directive | undefined {
  41. return resolveAsset(DIRECTIVES, name)
  42. }
  43. /**
  44. * v2 compat only
  45. * @internal
  46. */
  47. export function resolveFilter(name: string): Function | undefined {
  48. return resolveAsset(FILTERS, name)
  49. }
  50. /**
  51. * @private
  52. * overload 1: components
  53. */
  54. function resolveAsset(
  55. type: typeof COMPONENTS,
  56. name: string,
  57. warnMissing?: boolean,
  58. maybeSelfReference?: boolean,
  59. ): ConcreteComponent | undefined
  60. // overload 2: directives
  61. function resolveAsset(
  62. type: typeof DIRECTIVES,
  63. name: string,
  64. ): Directive | undefined
  65. // implementation
  66. // overload 3: filters (compat only)
  67. function resolveAsset(type: typeof FILTERS, name: string): Function | undefined
  68. // implementation
  69. function resolveAsset(
  70. type: AssetTypes,
  71. name: string,
  72. warnMissing = true,
  73. maybeSelfReference = false,
  74. ) {
  75. const instance = currentRenderingInstance || currentInstance
  76. if (instance) {
  77. const Component = instance.type
  78. // explicit self name has highest priority
  79. if (type === COMPONENTS) {
  80. const selfName = getComponentName(
  81. Component,
  82. false /* do not include inferred name to avoid breaking existing code */,
  83. )
  84. if (
  85. selfName &&
  86. (selfName === name ||
  87. selfName === camelize(name) ||
  88. selfName === capitalize(camelize(name)))
  89. ) {
  90. return Component
  91. }
  92. }
  93. const res =
  94. // local registration
  95. // check instance[type] first which is resolved for options API
  96. resolve(instance[type] || (Component as ComponentOptions)[type], name) ||
  97. // global registration
  98. resolve(instance.appContext[type], name)
  99. if (!res && maybeSelfReference) {
  100. // fallback to implicit self-reference
  101. return Component
  102. }
  103. if (__DEV__ && warnMissing && !res) {
  104. const extra =
  105. type === COMPONENTS
  106. ? `\nIf this is a native custom element, make sure to exclude it from ` +
  107. `component resolution via compilerOptions.isCustomElement.`
  108. : ``
  109. warn(`Failed to resolve ${type.slice(0, -1)}: ${name}${extra}`)
  110. }
  111. return res
  112. } else if (__DEV__) {
  113. warn(
  114. `resolve${capitalize(type.slice(0, -1))} ` +
  115. `can only be used in render() or setup().`,
  116. )
  117. }
  118. }
  119. function resolve(registry: Record<string, any> | undefined, name: string) {
  120. return (
  121. registry &&
  122. (registry[name] ||
  123. registry[camelize(name)] ||
  124. registry[capitalize(camelize(name))])
  125. )
  126. }