| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973 |
- import { VNode, VNodeChild, isVNode } from './vnode'
- import {
- pauseTracking,
- resetTracking,
- shallowReadonly,
- proxyRefs,
- EffectScope,
- markRaw,
- track,
- TrackOpTypes
- } from '@vue/reactivity'
- import {
- ComponentPublicInstance,
- PublicInstanceProxyHandlers,
- createRenderContext,
- exposePropsOnRenderContext,
- exposeSetupStateOnRenderContext,
- ComponentPublicInstanceConstructor,
- publicPropertiesMap,
- RuntimeCompiledPublicInstanceProxyHandlers
- } from './componentPublicInstance'
- import {
- ComponentPropsOptions,
- NormalizedPropsOptions,
- initProps,
- normalizePropsOptions
- } from './componentProps'
- import { Slots, initSlots, InternalSlots } from './componentSlots'
- import { warn } from './warning'
- import { ErrorCodes, callWithErrorHandling, handleError } from './errorHandling'
- import { AppContext, createAppContext, AppConfig } from './apiCreateApp'
- import { Directive, validateDirectiveName } from './directives'
- import {
- applyOptions,
- ComponentOptions,
- ComputedOptions,
- MethodOptions
- } from './componentOptions'
- import {
- EmitsOptions,
- ObjectEmitsOptions,
- EmitFn,
- emit,
- normalizeEmitsOptions
- } from './componentEmits'
- import {
- EMPTY_OBJ,
- isFunction,
- NOOP,
- isObject,
- NO,
- makeMap,
- isPromise,
- ShapeFlags,
- extend
- } from '@vue/shared'
- import { SuspenseBoundary } from './components/Suspense'
- import { CompilerOptions } from '@vue/compiler-core'
- import { markAttrsAccessed } from './componentRenderUtils'
- import { currentRenderingInstance } from './componentRenderContext'
- import { startMeasure, endMeasure } from './profiling'
- import { convertLegacyRenderFn } from './compat/renderFn'
- import { globalCompatConfig, validateCompatConfig } from './compat/compatConfig'
- import { SchedulerJob } from './scheduler'
- export type Data = Record<string, unknown>
- /**
- * For extending allowed non-declared props on components in TSX
- */
- export interface ComponentCustomProps {}
- /**
- * Default allowed non-declared props on component in TSX
- */
- export interface AllowedComponentProps {
- class?: unknown
- style?: unknown
- }
- // Note: can't mark this whole interface internal because some public interfaces
- // extend it.
- export interface ComponentInternalOptions {
- /**
- * @internal
- */
- __scopeId?: string
- /**
- * @internal
- */
- __cssModules?: Data
- /**
- * @internal
- */
- __hmrId?: string
- /**
- * Compat build only, for bailing out of certain compatibility behavior
- */
- __isBuiltIn?: boolean
- /**
- * This one should be exposed so that devtools can make use of it
- */
- __file?: string
- }
- export interface FunctionalComponent<P = {}, E extends EmitsOptions = {}>
- extends ComponentInternalOptions {
- // use of any here is intentional so it can be a valid JSX Element constructor
- (props: P, ctx: Omit<SetupContext<E>, 'expose'>): any
- props?: ComponentPropsOptions<P>
- emits?: E | (keyof E)[]
- inheritAttrs?: boolean
- displayName?: string
- }
- export interface ClassComponent {
- new (...args: any[]): ComponentPublicInstance<any, any, any, any, any>
- __vccOpts: ComponentOptions
- }
- /**
- * Concrete component type matches its actual value: it's either an options
- * object, or a function. Use this where the code expects to work with actual
- * values, e.g. checking if its a function or not. This is mostly for internal
- * implementation code.
- */
- export type ConcreteComponent<
- Props = {},
- RawBindings = any,
- D = any,
- C extends ComputedOptions = ComputedOptions,
- M extends MethodOptions = MethodOptions
- > =
- | ComponentOptions<Props, RawBindings, D, C, M>
- | FunctionalComponent<Props, any>
- /**
- * A type used in public APIs where a component type is expected.
- * The constructor type is an artificial type returned by defineComponent().
- */
- export type Component<
- Props = any,
- RawBindings = any,
- D = any,
- C extends ComputedOptions = ComputedOptions,
- M extends MethodOptions = MethodOptions
- > =
- | ConcreteComponent<Props, RawBindings, D, C, M>
- | ComponentPublicInstanceConstructor<Props>
- export { ComponentOptions }
- type LifecycleHook<TFn = Function> = TFn[] | null
- export const enum LifecycleHooks {
- BEFORE_CREATE = 'bc',
- CREATED = 'c',
- BEFORE_MOUNT = 'bm',
- MOUNTED = 'm',
- BEFORE_UPDATE = 'bu',
- UPDATED = 'u',
- BEFORE_UNMOUNT = 'bum',
- UNMOUNTED = 'um',
- DEACTIVATED = 'da',
- ACTIVATED = 'a',
- RENDER_TRIGGERED = 'rtg',
- RENDER_TRACKED = 'rtc',
- ERROR_CAPTURED = 'ec',
- SERVER_PREFETCH = 'sp'
- }
- export interface SetupContext<E = EmitsOptions> {
- attrs: Data
- slots: Slots
- emit: EmitFn<E>
- expose: (exposed?: Record<string, any>) => void
- }
- /**
- * @internal
- */
- export type InternalRenderFunction = {
- (
- ctx: ComponentPublicInstance,
- cache: ComponentInternalInstance['renderCache'],
- // for compiler-optimized bindings
- $props: ComponentInternalInstance['props'],
- $setup: ComponentInternalInstance['setupState'],
- $data: ComponentInternalInstance['data'],
- $options: ComponentInternalInstance['ctx']
- ): VNodeChild
- _rc?: boolean // isRuntimeCompiled
- // __COMPAT__ only
- _compatChecked?: boolean // v3 and already checked for v2 compat
- _compatWrapped?: boolean // is wrapped for v2 compat
- }
- /**
- * We expose a subset of properties on the internal instance as they are
- * useful for advanced external libraries and tools.
- */
- export interface ComponentInternalInstance {
- uid: number
- type: ConcreteComponent
- parent: ComponentInternalInstance | null
- root: ComponentInternalInstance
- appContext: AppContext
- /**
- * Vnode representing this component in its parent's vdom tree
- */
- vnode: VNode
- /**
- * The pending new vnode from parent updates
- * @internal
- */
- next: VNode | null
- /**
- * Root vnode of this component's own vdom tree
- */
- subTree: VNode
- /**
- * Bound effect runner to be passed to schedulers
- */
- update: SchedulerJob
- /**
- * The render function that returns vdom tree.
- * @internal
- */
- render: InternalRenderFunction | null
- /**
- * SSR render function
- * @internal
- */
- ssrRender?: Function | null
- /**
- * Object containing values this component provides for its descendents
- * @internal
- */
- provides: Data
- /**
- * Tracking reactive effects (e.g. watchers) associated with this component
- * so that they can be automatically stopped on component unmount
- * @internal
- */
- scope: EffectScope
- /**
- * cache for proxy access type to avoid hasOwnProperty calls
- * @internal
- */
- accessCache: Data | null
- /**
- * cache for render function values that rely on _ctx but won't need updates
- * after initialized (e.g. inline handlers)
- * @internal
- */
- renderCache: (Function | VNode)[]
- /**
- * Resolved component registry, only for components with mixins or extends
- * @internal
- */
- components: Record<string, ConcreteComponent> | null
- /**
- * Resolved directive registry, only for components with mixins or extends
- * @internal
- */
- directives: Record<string, Directive> | null
- /**
- * Resolved filters registry, v2 compat only
- * @internal
- */
- filters?: Record<string, Function>
- /**
- * resolved props options
- * @internal
- */
- propsOptions: NormalizedPropsOptions
- /**
- * resolved emits options
- * @internal
- */
- emitsOptions: ObjectEmitsOptions | null
- /**
- * resolved inheritAttrs options
- * @internal
- */
- inheritAttrs?: boolean
- /**
- * is custom element?
- */
- isCE?: boolean
- /**
- * custom element specific HMR method
- */
- ceReload?: () => void
- // the rest are only for stateful components ---------------------------------
- // main proxy that serves as the public instance (`this`)
- proxy: ComponentPublicInstance | null
- // exposed properties via expose()
- exposed: Record<string, any> | null
- exposeProxy: Record<string, any> | null
- /**
- * alternative proxy used only for runtime-compiled render functions using
- * `with` block
- * @internal
- */
- withProxy: ComponentPublicInstance | null
- /**
- * This is the target for the public instance proxy. It also holds properties
- * injected by user options (computed, methods etc.) and user-attached
- * custom properties (via `this.x = ...`)
- * @internal
- */
- ctx: Data
- // state
- data: Data
- props: Data
- attrs: Data
- slots: InternalSlots
- refs: Data
- emit: EmitFn
- /**
- * used for keeping track of .once event handlers on components
- * @internal
- */
- emitted: Record<string, boolean> | null
- /**
- * used for caching the value returned from props default factory functions to
- * avoid unnecessary watcher trigger
- * @internal
- */
- propsDefaults: Data
- /**
- * setup related
- * @internal
- */
- setupState: Data
- /**
- * devtools access to additional info
- * @internal
- */
- devtoolsRawSetupState?: any
- /**
- * @internal
- */
- setupContext: SetupContext | null
- /**
- * suspense related
- * @internal
- */
- suspense: SuspenseBoundary | null
- /**
- * suspense pending batch id
- * @internal
- */
- suspenseId: number
- /**
- * @internal
- */
- asyncDep: Promise<any> | null
- /**
- * @internal
- */
- asyncResolved: boolean
- // lifecycle
- isMounted: boolean
- isUnmounted: boolean
- isDeactivated: boolean
- /**
- * @internal
- */
- [LifecycleHooks.BEFORE_CREATE]: LifecycleHook
- /**
- * @internal
- */
- [LifecycleHooks.CREATED]: LifecycleHook
- /**
- * @internal
- */
- [LifecycleHooks.BEFORE_MOUNT]: LifecycleHook
- /**
- * @internal
- */
- [LifecycleHooks.MOUNTED]: LifecycleHook
- /**
- * @internal
- */
- [LifecycleHooks.BEFORE_UPDATE]: LifecycleHook
- /**
- * @internal
- */
- [LifecycleHooks.UPDATED]: LifecycleHook
- /**
- * @internal
- */
- [LifecycleHooks.BEFORE_UNMOUNT]: LifecycleHook
- /**
- * @internal
- */
- [LifecycleHooks.UNMOUNTED]: LifecycleHook
- /**
- * @internal
- */
- [LifecycleHooks.RENDER_TRACKED]: LifecycleHook
- /**
- * @internal
- */
- [LifecycleHooks.RENDER_TRIGGERED]: LifecycleHook
- /**
- * @internal
- */
- [LifecycleHooks.ACTIVATED]: LifecycleHook
- /**
- * @internal
- */
- [LifecycleHooks.DEACTIVATED]: LifecycleHook
- /**
- * @internal
- */
- [LifecycleHooks.ERROR_CAPTURED]: LifecycleHook
- /**
- * @internal
- */
- [LifecycleHooks.SERVER_PREFETCH]: LifecycleHook<() => Promise<unknown>>
- }
- const emptyAppContext = createAppContext()
- let uid = 0
- export function createComponentInstance(
- vnode: VNode,
- parent: ComponentInternalInstance | null,
- suspense: SuspenseBoundary | null
- ) {
- const type = vnode.type as ConcreteComponent
- // inherit parent app context - or - if root, adopt from root vnode
- const appContext =
- (parent ? parent.appContext : vnode.appContext) || emptyAppContext
- const instance: ComponentInternalInstance = {
- uid: uid++,
- vnode,
- type,
- parent,
- appContext,
- root: null!, // to be immediately set
- next: null,
- subTree: null!, // will be set synchronously right after creation
- update: null!, // will be set synchronously right after creation
- scope: new EffectScope(),
- render: null,
- proxy: null,
- exposed: null,
- exposeProxy: null,
- withProxy: null,
- provides: parent ? parent.provides : Object.create(appContext.provides),
- accessCache: null!,
- renderCache: [],
- // local resovled assets
- components: null,
- directives: null,
- // resolved props and emits options
- propsOptions: normalizePropsOptions(type, appContext),
- emitsOptions: normalizeEmitsOptions(type, appContext),
- // emit
- emit: null as any, // to be set immediately
- emitted: null,
- // props default value
- propsDefaults: EMPTY_OBJ,
- // inheritAttrs
- inheritAttrs: type.inheritAttrs,
- // state
- ctx: EMPTY_OBJ,
- data: EMPTY_OBJ,
- props: EMPTY_OBJ,
- attrs: EMPTY_OBJ,
- slots: EMPTY_OBJ,
- refs: EMPTY_OBJ,
- setupState: EMPTY_OBJ,
- setupContext: null,
- // suspense related
- suspense,
- suspenseId: suspense ? suspense.pendingId : 0,
- asyncDep: null,
- asyncResolved: false,
- // lifecycle hooks
- // not using enums here because it results in computed properties
- isMounted: false,
- isUnmounted: false,
- isDeactivated: false,
- bc: null,
- c: null,
- bm: null,
- m: null,
- bu: null,
- u: null,
- um: null,
- bum: null,
- da: null,
- a: null,
- rtg: null,
- rtc: null,
- ec: null,
- sp: null
- }
- if (__DEV__) {
- instance.ctx = createRenderContext(instance)
- } else {
- instance.ctx = { _: instance }
- }
- instance.root = parent ? parent.root : instance
- instance.emit = emit.bind(null, instance)
- // apply custom element special handling
- if (vnode.ce) {
- vnode.ce(instance)
- }
- return instance
- }
- export let currentInstance: ComponentInternalInstance | null = null
- export const getCurrentInstance: () => ComponentInternalInstance | null = () =>
- currentInstance || currentRenderingInstance
- export const setCurrentInstance = (instance: ComponentInternalInstance) => {
- currentInstance = instance
- instance.scope.on()
- }
- export const unsetCurrentInstance = () => {
- currentInstance && currentInstance.scope.off()
- currentInstance = null
- }
- const isBuiltInTag = /*#__PURE__*/ makeMap('slot,component')
- export function validateComponentName(name: string, config: AppConfig) {
- const appIsNativeTag = config.isNativeTag || NO
- if (isBuiltInTag(name) || appIsNativeTag(name)) {
- warn(
- 'Do not use built-in or reserved HTML elements as component id: ' + name
- )
- }
- }
- export function isStatefulComponent(instance: ComponentInternalInstance) {
- return instance.vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT
- }
- export let isInSSRComponentSetup = false
- export function setupComponent(
- instance: ComponentInternalInstance,
- isSSR = false
- ) {
- isInSSRComponentSetup = isSSR
- const { props, children } = instance.vnode
- const isStateful = isStatefulComponent(instance)
- initProps(instance, props, isStateful, isSSR)
- initSlots(instance, children)
- const setupResult = isStateful
- ? setupStatefulComponent(instance, isSSR)
- : undefined
- isInSSRComponentSetup = false
- return setupResult
- }
- function setupStatefulComponent(
- instance: ComponentInternalInstance,
- isSSR: boolean
- ) {
- const Component = instance.type as ComponentOptions
- if (__DEV__) {
- if (Component.name) {
- validateComponentName(Component.name, instance.appContext.config)
- }
- if (Component.components) {
- const names = Object.keys(Component.components)
- for (let i = 0; i < names.length; i++) {
- validateComponentName(names[i], instance.appContext.config)
- }
- }
- if (Component.directives) {
- const names = Object.keys(Component.directives)
- for (let i = 0; i < names.length; i++) {
- validateDirectiveName(names[i])
- }
- }
- if (Component.compilerOptions && isRuntimeOnly()) {
- warn(
- `"compilerOptions" is only supported when using a build of Vue that ` +
- `includes the runtime compiler. Since you are using a runtime-only ` +
- `build, the options should be passed via your build tool config instead.`
- )
- }
- }
- // 0. create render proxy property access cache
- instance.accessCache = Object.create(null)
- // 1. create public instance / render proxy
- // also mark it raw so it's never observed
- instance.proxy = markRaw(new Proxy(instance.ctx, PublicInstanceProxyHandlers))
- if (__DEV__) {
- exposePropsOnRenderContext(instance)
- }
- // 2. call setup()
- const { setup } = Component
- if (setup) {
- const setupContext = (instance.setupContext =
- setup.length > 1 ? createSetupContext(instance) : null)
- setCurrentInstance(instance)
- pauseTracking()
- const setupResult = callWithErrorHandling(
- setup,
- instance,
- ErrorCodes.SETUP_FUNCTION,
- [__DEV__ ? shallowReadonly(instance.props) : instance.props, setupContext]
- )
- resetTracking()
- unsetCurrentInstance()
- if (isPromise(setupResult)) {
- setupResult.then(unsetCurrentInstance, unsetCurrentInstance)
- if (isSSR) {
- // return the promise so server-renderer can wait on it
- return setupResult
- .then((resolvedResult: unknown) => {
- handleSetupResult(instance, resolvedResult, isSSR)
- })
- .catch(e => {
- handleError(e, instance, ErrorCodes.SETUP_FUNCTION)
- })
- } else if (__FEATURE_SUSPENSE__) {
- // async setup returned Promise.
- // bail here and wait for re-entry.
- instance.asyncDep = setupResult
- } else if (__DEV__) {
- warn(
- `setup() returned a Promise, but the version of Vue you are using ` +
- `does not support it yet.`
- )
- }
- } else {
- handleSetupResult(instance, setupResult, isSSR)
- }
- } else {
- finishComponentSetup(instance, isSSR)
- }
- }
- export function handleSetupResult(
- instance: ComponentInternalInstance,
- setupResult: unknown,
- isSSR: boolean
- ) {
- if (isFunction(setupResult)) {
- // setup returned an inline render function
- if (__NODE_JS__ && (instance.type as ComponentOptions).__ssrInlineRender) {
- // when the function's name is `ssrRender` (compiled by SFC inline mode),
- // set it as ssrRender instead.
- instance.ssrRender = setupResult
- } else {
- instance.render = setupResult as InternalRenderFunction
- }
- } else if (isObject(setupResult)) {
- if (__DEV__ && isVNode(setupResult)) {
- warn(
- `setup() should not return VNodes directly - ` +
- `return a render function instead.`
- )
- }
- // setup returned bindings.
- // assuming a render function compiled from template is present.
- if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
- instance.devtoolsRawSetupState = setupResult
- }
- instance.setupState = proxyRefs(setupResult)
- if (__DEV__) {
- exposeSetupStateOnRenderContext(instance)
- }
- } else if (__DEV__ && setupResult !== undefined) {
- warn(
- `setup() should return an object. Received: ${
- setupResult === null ? 'null' : typeof setupResult
- }`
- )
- }
- finishComponentSetup(instance, isSSR)
- }
- type CompileFunction = (
- template: string | object,
- options?: CompilerOptions
- ) => InternalRenderFunction
- let compile: CompileFunction | undefined
- let installWithProxy: (i: ComponentInternalInstance) => void
- /**
- * For runtime-dom to register the compiler.
- * Note the exported method uses any to avoid d.ts relying on the compiler types.
- */
- export function registerRuntimeCompiler(_compile: any) {
- compile = _compile
- installWithProxy = i => {
- if (i.render!._rc) {
- i.withProxy = new Proxy(i.ctx, RuntimeCompiledPublicInstanceProxyHandlers)
- }
- }
- }
- // dev only
- export const isRuntimeOnly = () => !compile
- export function finishComponentSetup(
- instance: ComponentInternalInstance,
- isSSR: boolean,
- skipOptions?: boolean
- ) {
- const Component = instance.type as ComponentOptions
- if (__COMPAT__) {
- convertLegacyRenderFn(instance)
- if (__DEV__ && Component.compatConfig) {
- validateCompatConfig(Component.compatConfig)
- }
- }
- // template / render function normalization
- if (__NODE_JS__ && isSSR) {
- // 1. the render function may already exist, returned by `setup`
- // 2. otherwise try to use the `Component.render`
- // 3. if the component doesn't have a render function,
- // set `instance.render` to NOOP so that it can inherit the render
- // function from mixins/extend
- instance.render = (instance.render ||
- Component.render ||
- NOOP) as InternalRenderFunction
- } else if (!instance.render) {
- // could be set from setup()
- if (compile && !Component.render) {
- const template =
- (__COMPAT__ &&
- instance.vnode.props &&
- instance.vnode.props['inline-template']) ||
- Component.template
- if (template) {
- if (__DEV__) {
- startMeasure(instance, `compile`)
- }
- const { isCustomElement, compilerOptions } = instance.appContext.config
- const { delimiters, compilerOptions: componentCompilerOptions } =
- Component
- const finalCompilerOptions: CompilerOptions = extend(
- extend(
- {
- isCustomElement,
- delimiters
- },
- compilerOptions
- ),
- componentCompilerOptions
- )
- if (__COMPAT__) {
- // pass runtime compat config into the compiler
- finalCompilerOptions.compatConfig = Object.create(globalCompatConfig)
- if (Component.compatConfig) {
- extend(finalCompilerOptions.compatConfig, Component.compatConfig)
- }
- }
- Component.render = compile(template, finalCompilerOptions)
- if (__DEV__) {
- endMeasure(instance, `compile`)
- }
- }
- }
- instance.render = (Component.render || NOOP) as InternalRenderFunction
- // for runtime-compiled render functions using `with` blocks, the render
- // proxy used needs a different `has` handler which is more performant and
- // also only allows a whitelist of globals to fallthrough.
- if (installWithProxy) {
- installWithProxy(instance)
- }
- }
- // support for 2.x options
- if (__FEATURE_OPTIONS_API__ && !(__COMPAT__ && skipOptions)) {
- setCurrentInstance(instance)
- pauseTracking()
- applyOptions(instance)
- resetTracking()
- unsetCurrentInstance()
- }
- // warn missing template/render
- // the runtime compilation of template in SSR is done by server-render
- if (__DEV__ && !Component.render && instance.render === NOOP && !isSSR) {
- /* istanbul ignore if */
- if (!compile && Component.template) {
- warn(
- `Component provided template option but ` +
- `runtime compilation is not supported in this build of Vue.` +
- (__ESM_BUNDLER__
- ? ` Configure your bundler to alias "vue" to "vue/dist/vue.esm-bundler.js".`
- : __ESM_BROWSER__
- ? ` Use "vue.esm-browser.js" instead.`
- : __GLOBAL__
- ? ` Use "vue.global.js" instead.`
- : ``) /* should not happen */
- )
- } else {
- warn(`Component is missing template or render function.`)
- }
- }
- }
- function createAttrsProxy(instance: ComponentInternalInstance): Data {
- return new Proxy(
- instance.attrs,
- __DEV__
- ? {
- get(target, key: string) {
- markAttrsAccessed()
- track(instance, TrackOpTypes.GET, '$attrs')
- return target[key]
- },
- set() {
- warn(`setupContext.attrs is readonly.`)
- return false
- },
- deleteProperty() {
- warn(`setupContext.attrs is readonly.`)
- return false
- }
- }
- : {
- get(target, key: string) {
- track(instance, TrackOpTypes.GET, '$attrs')
- return target[key]
- }
- }
- )
- }
- export function createSetupContext(
- instance: ComponentInternalInstance
- ): SetupContext {
- const expose: SetupContext['expose'] = exposed => {
- if (__DEV__ && instance.exposed) {
- warn(`expose() should be called only once per setup().`)
- }
- instance.exposed = exposed || {}
- }
- let attrs: Data
- if (__DEV__) {
- // We use getters in dev in case libs like test-utils overwrite instance
- // properties (overwrites should not be done in prod)
- return Object.freeze({
- get attrs() {
- return attrs || (attrs = createAttrsProxy(instance))
- },
- get slots() {
- return shallowReadonly(instance.slots)
- },
- get emit() {
- return (event: string, ...args: any[]) => instance.emit(event, ...args)
- },
- expose
- })
- } else {
- return {
- get attrs() {
- return attrs || (attrs = createAttrsProxy(instance))
- },
- slots: instance.slots,
- emit: instance.emit,
- expose
- }
- }
- }
- export function getExposeProxy(instance: ComponentInternalInstance) {
- if (instance.exposed) {
- return (
- instance.exposeProxy ||
- (instance.exposeProxy = new Proxy(proxyRefs(markRaw(instance.exposed)), {
- get(target, key: string) {
- if (key in target) {
- return target[key]
- } else if (key in publicPropertiesMap) {
- return publicPropertiesMap[key](instance)
- }
- }
- }))
- )
- }
- }
- const classifyRE = /(?:^|[-_])(\w)/g
- const classify = (str: string): string =>
- str.replace(classifyRE, c => c.toUpperCase()).replace(/[-_]/g, '')
- export function getComponentName(
- Component: ConcreteComponent
- ): string | undefined {
- return isFunction(Component)
- ? Component.displayName || Component.name
- : Component.name
- }
- /* istanbul ignore next */
- export function formatComponentName(
- instance: ComponentInternalInstance | null,
- Component: ConcreteComponent,
- isRoot = false
- ): string {
- let name = getComponentName(Component)
- if (!name && Component.__file) {
- const match = Component.__file.match(/([^/\\]+)\.\w+$/)
- if (match) {
- name = match[1]
- }
- }
- if (!name && instance && instance.parent) {
- // try to infer the name based on reverse resolution
- const inferFromRegistry = (registry: Record<string, any> | undefined) => {
- for (const key in registry) {
- if (registry[key] === Component) {
- return key
- }
- }
- }
- name =
- inferFromRegistry(
- instance.components ||
- (instance.parent.type as ComponentOptions).components
- ) || inferFromRegistry(instance.appContext.components)
- }
- return name ? classify(name) : isRoot ? `App` : `Anonymous`
- }
- export function isClassComponent(value: unknown): value is ClassComponent {
- return isFunction(value) && '__vccOpts' in value
- }
|