import { ComponentInternalInstance , Data , SetupContext , ComponentInternalOptions , Component , ConcreteComponent , InternalRenderFunction , LifecycleHooks } from './component' ; import { isFunction , extend , isString , isObject , isArray , NOOP , isPromise } from '@vue/shared' ; import { computed , isRef , Ref } from '@vue/reactivity' ; import { watch , WatchOptions , WatchCallback , createPathGetter } from './apiWatch' ; import { provide , inject } from './apiInject' ; import { onBeforeMount , onMounted , onBeforeUpdate , onUpdated , onErrorCaptured , onRenderTracked , onBeforeUnmount , onUnmounted , onActivated , onDeactivated , onRenderTriggered , DebuggerHook , ErrorCapturedHook , onServerPrefetch } from './apiLifecycle' ; import { reactive , ComputedGetter , WritableComputedOptions } from '@vue/reactivity' ; import { ComponentObjectPropsOptions , ExtractPropTypes , ExtractDefaultPropTypes } from './componentProps' ; import { EmitsOptions , EmitsToProps } from './componentEmits' ; import { Directive } from './directives' ; import { CreateComponentPublicInstance , ComponentPublicInstance } from './componentPublicInstance' ; import { warn } from './warning' ; import { VNodeChild } from './vnode' ; import { callWithAsyncErrorHandling } from './errorHandling' ; import { LooseRequired , UnionToIntersection } from './helpers/typeUtils' ; import { deepMergeData } from './compat/data' ; import { DeprecationTypes } from './compat/compatConfig' ; import { CompatConfig , isCompatEnabled , softAssertCompatEnabled } from './compat/compatConfig' ; import { OptionMergeFunction } from './apiCreateApp' ; example export interface ComponentCustomOptions { } export type RenderFunction = ( ) => VNodeChild ; type ExtractOptionProp < T > = T extends ComponentOptionsBase < infer P , any , any , any , any , any , any , any > ? unknown extends P ? { } : P : { } ; export interface ComponentOptionsBase < Props , RawBindings , D , C extends ComputedOptions , M extends MethodOptions , Mixin extends ComponentOptionsMixin , Extends extends ComponentOptionsMixin , E extends EmitsOptions , EE extends string = string , Defaults = { } > extends LegacyOptions < Props , D , C , M , Mixin , Extends > , ComponentInternalOptions , ComponentCustomOptions { setup ? : ( this : void , props : Readonly < LooseRequired < Props & UnionToIntersection < ExtractOptionProp < Mixin > > & UnionToIntersection < ExtractOptionProp < Extends > > > > , ctx : SetupContext < E > ) => Promise < RawBindings > | RawBindings | RenderFunction | void ; name ? : string ; template ? : string | object ; render ? : Function ; components ? : Record < string , Component > ; directives ? : Record < string , Directive > ; inheritAttrs ? : boolean ; emits ? : ( E | EE [ ] ) & ThisType < void > ; expose ? : string [ ] ; serverPrefetch ? ( ) : Promise < any > ; compilerOptions ? : RuntimeCompilerOptions ; internal ssrRender ? : ( ctx : any , push : ( item : any ) => void , parentInstance : ComponentInternalInstance , attrs : Data | undefined , $props : ComponentInternalInstance [ 'props' ] , $setup : ComponentInternalInstance [ 'setupState' ] , $data : ComponentInternalInstance [ 'data' ] , $options : ComponentInternalInstance [ 'ctx' ] ) => void ; internal __ssrInlineRender ? : boolean ; internal __asyncLoader ? : ( ) => Promise < ConcreteComponent > ; internal __asyncResolved ? : ConcreteComponent ; call ? : ( this : unknown , ... args : unknown [ ] ) => never ; __isFragment ? : never ; __isTeleport ? : never ; __isSuspense ? : never ; __defaults ? : Defaults ; } /**
 * Subset of compiler options that makes sense for the runtime.
 */ export interface RuntimeCompilerOptions { isCustomElement ? : ( tag : string ) => boolean ; whitespace ? : 'preserve' | 'condense' ; comments ? : boolean ; delimiters ? : [ string , string ] ; } export type ComponentOptionsWithoutProps < Props = { } , RawBindings = { } , D = { } , C extends ComputedOptions = { } , M extends MethodOptions = { } , Mixin extends ComponentOptionsMixin = ComponentOptionsMixin , Extends extends ComponentOptionsMixin = ComponentOptionsMixin , E extends EmitsOptions = EmitsOptions , EE extends string = string , PE = Props & EmitsToProps < E > > = ComponentOptionsBase < PE , RawBindings , D , C , M , Mixin , Extends , E , EE , { } > & { props ? : undefined ; } & ThisType < CreateComponentPublicInstance < PE , RawBindings , D , C , M , Mixin , Extends , E > > ; export type ComponentOptionsWithArrayProps < PropNames extends string = string , RawBindings = { } , D = { } , C extends ComputedOptions = { } , M extends MethodOptions = { } , Mixin extends ComponentOptionsMixin = ComponentOptionsMixin , Extends extends ComponentOptionsMixin = ComponentOptionsMixin , E extends EmitsOptions = EmitsOptions , EE extends string = string , Props = Readonly < { [ key in PropNames ] ? : any ; } > & EmitsToProps < E > > = ComponentOptionsBase < Props , RawBindings , D , C , M , Mixin , Extends , E , EE , { } > & { props : PropNames [ ] ; } & ThisType < CreateComponentPublicInstance < Props , RawBindings , D , C , M , Mixin , Extends , E > > ; export type ComponentOptionsWithObjectProps < PropsOptions = ComponentObjectPropsOptions , RawBindings = { } , D = { } , C extends ComputedOptions = { } , M extends MethodOptions = { } , Mixin extends ComponentOptionsMixin = ComponentOptionsMixin , Extends extends ComponentOptionsMixin = ComponentOptionsMixin , E extends EmitsOptions = EmitsOptions , EE extends string = string , Props = Readonly < ExtractPropTypes < PropsOptions > > & EmitsToProps < E > , Defaults = ExtractDefaultPropTypes < PropsOptions > > = ComponentOptionsBase < Props , RawBindings , D , C , M , Mixin , Extends , E , EE , Defaults > & { props : PropsOptions & ThisType < void > ; } & ThisType < CreateComponentPublicInstance < Props , RawBindings , D , C , M , Mixin , Extends , E , Props , Defaults , false > > ; export type ComponentOptions < Props = { } , RawBindings = any , D = any , C extends ComputedOptions = any , M extends MethodOptions = any , Mixin extends ComponentOptionsMixin = any , Extends extends ComponentOptionsMixin = any , E extends EmitsOptions = any > = ComponentOptionsBase < Props , RawBindings , D , C , M , Mixin , Extends , E > & ThisType < CreateComponentPublicInstance < { } , RawBindings , D , C , M , Mixin , Extends , E , Readonly < Props > > > ; export type ComponentOptionsMixin = ComponentOptionsBase < any , any , any , any , any , any , any , any , any , any > ; export type ComputedOptions = Record < string , ComputedGetter < any > | WritableComputedOptions < any > > ; export interface MethodOptions { [ key ] : Function ; } export type ExtractComputedReturns < T extends any > = { [ key in keyof T ] : T [ key ] extends { get : ( ... args : any [ ] ) => infer TReturn ; } ? TReturn : T [ key ] extends ( ... args : any [ ] ) => infer TReturn ? TReturn : never ; } ; export type ObjectWatchOptionItem = { handler : WatchCallback | string ; } & WatchOptions ; type WatchOptionItem = string | WatchCallback | ObjectWatchOptionItem ; type ComponentWatchOptionItem = WatchOptionItem | WatchOptionItem [ ] ; type ComponentWatchOptions = Record < string , ComponentWatchOptionItem > ; type ComponentInjectOptions = string [ ] | ObjectInjectOptions ; type ObjectInjectOptions = Record < string | symbol , string | symbol | { from ? : string | symbol ; default ? : unknown ; } > ; interface LegacyOptions < Props , D , C extends ComputedOptions , M extends MethodOptions , Mixin extends ComponentOptionsMixin , Extends extends ComponentOptionsMixin > { compatConfig ? : CompatConfig ; [ key ] : any ; data ? : ( this : CreateComponentPublicInstance < Props , { } , { } , { } , MethodOptions , Mixin , Extends > , vm : CreateComponentPublicInstance < Props , { } , { } , { } , MethodOptions , Mixin , Extends > ) => D ; computed ? : C ; methods ? : M ; watch ? : ComponentWatchOptions ; provide ? : Data | Function ; inject ? : ComponentInjectOptions ; filters ? : Record < string , Function > ; mixins ? : Mixin [ ] ; extends ? : Extends ; beforeCreate ? ( ) : void ; created ? ( ) : void ; beforeMount ? ( ) : void ; mounted ? ( ) : void ; beforeUpdate ? ( ) : void ; updated ? ( ) : void ; activated ? ( ) : void ; deactivated ? ( ) : void ; deprecated beforeDestroy ? ( ) : void ; beforeUnmount ? ( ) : void ; deprecated destroyed ? ( ) : void ; unmounted ? ( ) : void ; renderTracked ? : DebuggerHook ; renderTriggered ? : DebuggerHook ; errorCaptured ? : ErrorCapturedHook ; deprecated delimiters ? : [ string , string ] ; /**
     * #3468
     *
     * type-only, used to assist Mixin's type inference,
     * typescript will try to simplify the inferred `Mixin` type,
     * with the `__differenciator`, typescript won't be able to combine different mixins,
     * because the `__differenciator` will be different
     */ __differentiator ? : keyof D | keyof C | keyof M ; } type MergedHook < T = ( ) => void > = T | T [ ] ; export type MergedComponentOptions = ComponentOptions & MergedComponentOptionsOverride ; export type MergedComponentOptionsOverride = { beforeCreate ? : MergedHook ; created ? : MergedHook ; beforeMount ? : MergedHook ; mounted ? : MergedHook ; beforeUpdate ? : MergedHook ; updated ? : MergedHook ; activated ? : MergedHook ; deactivated ? : MergedHook ; deprecated beforeDestroy ? : MergedHook ; beforeUnmount ? : MergedHook ; deprecated destroyed ? : MergedHook ; unmounted ? : MergedHook ; renderTracked ? : MergedHook < DebuggerHook > ; renderTriggered ? : MergedHook < DebuggerHook > ; errorCaptured ? : MergedHook < ErrorCapturedHook > ; } ; export type OptionTypesKeys = 'P' | 'B' | 'D' | 'C' | 'M' | 'Defaults' ; export type OptionTypesType < P = { } , B = { } , D = { } , C extends ComputedOptions = { } , M extends MethodOptions = { } , Defaults = { } > = { P : P ; B : B ; D : D ; C : C ; M : M ; Defaults : Defaults ; } ; const enum OptionTypes { PROPS = 'Props' , DATA = 'Data' , COMPUTED = 'Computed' , METHODS = 'Methods' , INJECT = 'Inject' } function createDuplicateChecker ( ) { const cache = Object . create ( null ) ; return ( type , key ) => { if ( cache [ key ] ) { warn ( `${ type } property "${ key }" is already defined in ${ cache [ key ] }.` ) ; } else { cache [ key ] = type ; } } ; } export let shouldCacheAccess = true ; export function applyOptions ( instance ) { const options = resolveMergedOptions ( instance ) ; const publicThis = instance . proxy ! as any ; const ctx = instance . ctx ; shouldCacheAccess = false ; if ( options . beforeCreate ) { callHook ( options . beforeCreate , instance , LifecycleHooks . BEFORE_CREATE ) ; } const { data : dataOptions , computed : computedOptions , methods , watch : watchOptions , provide : provideOptions , inject : injectOptions , created , beforeMount , mounted , beforeUpdate , updated , activated , deactivated , beforeDestroy , beforeUnmount , destroyed , unmounted , render , renderTracked , renderTriggered , errorCaptured , serverPrefetch , expose , inheritAttrs , components , directives , filters } = options ; const checkDuplicateProperties = __DEV__ ? createDuplicateChecker ( ) : null ; if ( __DEV__ ) { const [ propsOptions ] = instance . propsOptions ; if ( propsOptions ) { for ( const key in propsOptions ) { checkDuplicateProperties ! ( OptionTypes . PROPS , key ) ; } } } if ( injectOptions ) { resolveInjections ( injectOptions , ctx , checkDuplicateProperties , instance . appContext . config . unwrapInjectedRef ) ; } if ( methods ) { for ( const key in methods ) { const methodHandler = ( methods as MethodOptions ) [ key ] ; if ( isFunction ( methodHandler ) ) { if ( __DEV__ ) { Object . defineProperty ( ctx , key , { value : methodHandler . bind ( publicThis ) , configurable : true , enumerable : true , writable : true } ) ; } else { ctx [ key ] = methodHandler . bind ( publicThis ) ; } if ( __DEV__ ) { checkDuplicateProperties ! ( OptionTypes . METHODS , key ) ; } } else if ( __DEV__ ) { warn ( `Method "${ key }" has type "${ typeof methodHandler }" in the component definition. ` + `Did you reference the function correctly?` ) ; } } } if ( dataOptions ) { if ( __DEV__ && ! isFunction ( dataOptions ) ) { warn ( `The data option must be a function. ` + `Plain object usage is no longer supported.` ) ; } const data = dataOptions . call ( publicThis , publicThis ) ; if ( __DEV__ && isPromise ( data ) ) { warn ( `data() returned a Promise - note data() cannot be async; If you ` + `intend to perform data fetching before component renders, use ` + `async setup() + <Suspense>.` ) ; } if ( ! isObject ( data ) ) { __DEV__ && warn ( `data() should return an object.` ) ; } else { instance . data = reactive ( data ) ; if ( __DEV__ ) { for ( const key in data ) { checkDuplicateProperties ! ( OptionTypes . DATA , key ) ; if ( key [ 0 ] !== '$' && key [ 0 ] !== '_' ) { Object . defineProperty ( ctx , key , { configurable : true , enumerable : true , get : ( ) => data [ key ] , set : NOOP } ) ; } } } } } shouldCacheAccess = true ; if ( computedOptions ) { for ( const key in computedOptions ) { const opt = ( computedOptions as ComputedOptions ) [ key ] ; const get = isFunction ( opt ) ? opt . bind ( publicThis , publicThis ) : isFunction ( opt . get ) ? opt . get . bind ( publicThis , publicThis ) : NOOP ; if ( __DEV__ && get === NOOP ) { warn ( `Computed property "${ key }" has no getter.` ) ; } const set = ! isFunction ( opt ) && isFunction ( opt . set ) ? opt . set . bind ( publicThis ) : __DEV__ ? ( ) => { warn ( `Write operation failed: computed property "${ key }" is readonly.` ) ; } : NOOP ; const c = computed ( { get , set } ) ; Object . defineProperty ( ctx , key , { enumerable : true , configurable : true , get : ( ) => c . value , set : v => ( c . value = v ) } ) ; if ( __DEV__ ) { checkDuplicateProperties ! ( OptionTypes . COMPUTED , key ) ; } } } if ( watchOptions ) { for ( const key in watchOptions ) { createWatcher ( watchOptions [ key ] , ctx , publicThis , key ) ; } } if ( provideOptions ) { const provides = isFunction ( provideOptions ) ? provideOptions . call ( publicThis ) : provideOptions ; Reflect . ownKeys ( provides ) . forEach ( key => { provide ( key , provides [ key ] ) ; } ) ; } if ( created ) { callHook ( created , instance , LifecycleHooks . CREATED ) ; } function registerLifecycleHook ( register , hook ? ) { if ( isArray ( hook ) ) { hook . forEach ( _hook => register ( _hook . bind ( publicThis ) ) ) ; } else if ( hook ) { register ( ( hook as Function ) . bind ( publicThis ) ) ; } } registerLifecycleHook ( onBeforeMount , beforeMount ) ; registerLifecycleHook ( onMounted , mounted ) ; registerLifecycleHook ( onBeforeUpdate , beforeUpdate ) ; registerLifecycleHook ( onUpdated , updated ) ; registerLifecycleHook ( onActivated , activated ) ; registerLifecycleHook ( onDeactivated , deactivated ) ; registerLifecycleHook ( onErrorCaptured , errorCaptured ) ; registerLifecycleHook ( onRenderTracked , renderTracked ) ; registerLifecycleHook ( onRenderTriggered , renderTriggered ) ; registerLifecycleHook ( onBeforeUnmount , beforeUnmount ) ; registerLifecycleHook ( onUnmounted , unmounted ) ; registerLifecycleHook ( onServerPrefetch , serverPrefetch ) ; if ( __COMPAT__ ) { if ( beforeDestroy && softAssertCompatEnabled ( DeprecationTypes . OPTIONS_BEFORE_DESTROY , instance ) ) { registerLifecycleHook ( onBeforeUnmount , beforeDestroy ) ; } if ( destroyed && softAssertCompatEnabled ( DeprecationTypes . OPTIONS_DESTROYED , instance ) ) { registerLifecycleHook ( onUnmounted , destroyed ) ; } } if ( isArray ( expose ) ) { if ( expose . length ) { const exposed = instance . exposed || ( instance . exposed = { } ) ; expose . forEach ( key => { Object . defineProperty ( exposed , key , { get : ( ) => publicThis [ key ] , set : val => ( publicThis [ key ] = val ) } ) ; } ) ; } else if ( ! instance . exposed ) { instance . exposed = { } ; } } if ( render && instance . render === NOOP ) { instance . render = render as InternalRenderFunction ; } if ( inheritAttrs != null ) { instance . inheritAttrs = inheritAttrs ; } if ( components ) instance . components = components as any ; if ( directives ) instance . directives = directives ; if ( __COMPAT__ && filters && isCompatEnabled ( DeprecationTypes . FILTERS , instance ) ) { instance . filters = filters ; } } export function resolveInjections ( injectOptions , ctx , checkDuplicateProperties = NOOP as any , unwrapRef = false ) { if ( isArray ( injectOptions ) ) { injectOptions = normalizeInject ( injectOptions ) ! ; } for ( const key in injectOptions ) { const opt = ( injectOptions as ObjectInjectOptions ) [ key ] ; let injected ; if ( isObject ( opt ) ) { if ( 'default' in opt ) { injected = inject ( opt . from || key , opt . default , true ) ; } else { injected = inject ( opt . from || key ) ; } } else { injected = inject ( opt ) ; } if ( isRef ( injected ) ) { if ( unwrapRef ) { Object . defineProperty ( ctx , key , { enumerable : true , configurable : true , get : ( ) => ( injected as Ref ) . value , set : v => ( ( injected as Ref ) . value = v ) } ) ; } else { if ( __DEV__ ) { warn ( `injected property "${ key }" is a ref and will be auto-unwrapped ` + `and no longer needs \`.value\` in the next minor release. ` + `To opt-in to the new behavior now, ` + `set \`app.config.unwrapInjectedRef = true\` (this config is ` + `temporary and will not be needed in the future.)` ) ; } ctx [ key ] = injected ; } } else { ctx [ key ] = injected ; } if ( __DEV__ ) { checkDuplicateProperties ! ( OptionTypes . INJECT , key ) ; } } } function callHook ( hook , instance , type ) { callWithAsyncErrorHandling ( isArray ( hook ) ? hook . map ( h => h . bind ( instance . proxy ! ) ) : hook . bind ( instance . proxy ! ) , instance , type ) ; } export function createWatcher ( raw , ctx , publicThis , key ) { const getter = key . includes ( '.' ) ? createPathGetter ( publicThis , key ) : ( ) => ( publicThis as any ) [ key ] ; if ( isString ( raw ) ) { const handler = ctx [ raw ] ; if ( isFunction ( handler ) ) { watch ( getter , handler as WatchCallback ) ; } else if ( __DEV__ ) { warn ( `Invalid watch handler specified by key "${ raw }"` , handler ) ; } } else if ( isFunction ( raw ) ) { watch ( getter , raw . bind ( publicThis ) ) ; } else if ( isObject ( raw ) ) { if ( isArray ( raw ) ) { raw . forEach ( r => createWatcher ( r , ctx , publicThis , key ) ) ; } else { const handler = isFunction ( raw . handler ) ? raw . handler . bind ( publicThis ) : ( ctx [ raw . handler ] as WatchCallback ) ; if ( isFunction ( handler ) ) { watch ( getter , handler , raw ) ; } else if ( __DEV__ ) { warn ( `Invalid watch handler specified by key "${ raw . handler }"` , handler ) ; } } } else if ( __DEV__ ) { warn ( `Invalid watch option: "${ key }"` , raw ) ; } } /**
 * Resolve merged options and cache it on the component.
 * This is done only once per-component since the merging does not involve
 * instances.
 */ export function resolveMergedOptions ( instance ) { const base = instance . type as ComponentOptions ; const { mixins , extends : extendsOptions } = base ; const { mixins : globalMixins , optionsCache : cache , config : { optionMergeStrategies } } = instance . appContext ; const cached = cache . get ( base ) ; let resolved ; if ( cached ) { resolved = cached ; } else if ( ! globalMixins . length && ! mixins && ! extendsOptions ) { if ( __COMPAT__ && isCompatEnabled ( DeprecationTypes . PRIVATE_APIS , instance ) ) { resolved = extend ( { } , base ) as MergedComponentOptions ; resolved . parent = instance . parent && instance . parent . proxy ; resolved . propsData = instance . vnode . props ; } else { resolved = base as MergedComponentOptions ; } } else { resolved = { } ; if ( globalMixins . length ) { globalMixins . forEach ( m => mergeOptions ( resolved , m , optionMergeStrategies , true ) ) ; } mergeOptions ( resolved , base , optionMergeStrategies ) ; } cache . set ( base , resolved ) ; return resolved ; } export function mergeOptions ( to , from , strats , asMixin = false ) { if ( __COMPAT__ && isFunction ( from ) ) { from = from . options ; } const { mixins , extends : extendsOptions } = from ; if ( extendsOptions ) { mergeOptions ( to , extendsOptions , strats , true ) ; } if ( mixins ) { mixins . forEach ( ( m ) => mergeOptions ( to , m , strats , true ) ) ; } for ( const key in from ) { if ( asMixin && key === 'expose' ) { __DEV__ && warn ( `"expose" option is ignored when declared in mixins or extends. ` + `It should only be declared in the base component itself.` ) ; } else { const strat = internalOptionMergeStrats [ key ] || ( strats && strats [ key ] ) ; to [ key ] = strat ? strat ( to [ key ] , from [ key ] ) : from [ key ] ; } } return to ; } export const internalOptionMergeStrats = { data : mergeDataFn , props : mergeObjectOptions , emits : mergeObjectOptions , methods : mergeObjectOptions , computed : mergeObjectOptions , beforeCreate : mergeAsArray , created : mergeAsArray , beforeMount : mergeAsArray , mounted : mergeAsArray , beforeUpdate : mergeAsArray , updated : mergeAsArray , beforeDestroy : mergeAsArray , destroyed : mergeAsArray , activated : mergeAsArray , deactivated : mergeAsArray , errorCaptured : mergeAsArray , serverPrefetch : mergeAsArray , components : mergeObjectOptions , directives : mergeObjectOptions , watch : mergeWatchOptions , provide : mergeDataFn , inject : mergeInject } ; if ( __COMPAT__ ) { internalOptionMergeStrats . filters = mergeObjectOptions ; } function mergeDataFn ( to , from ) { if ( ! from ) { return to ; } if ( ! to ) { return from ; } return function mergedDataFn ( this ) { return ( __COMPAT__ && isCompatEnabled ( DeprecationTypes . OPTIONS_DATA_MERGE , null ) ? deepMergeData : extend ) ( isFunction ( to ) ? to . call ( this , this ) : to , isFunction ( from ) ? from . call ( this , this ) : from ) ; } ; } function mergeInject ( to , from ) { return mergeObjectOptions ( normalizeInject ( to ) , normalizeInject ( from ) ) ; } function normalizeInject ( raw ) { if ( isArray ( raw ) ) { const res = { } ; for ( let i = 0 ; i < raw . length ; i ++ ) { res [ raw [ i ] ] = raw [ i ] ; } return res ; } return raw ; } function mergeAsArray < T = Function > ( to , from ) { return to ? [ ... new Set ( [ ] . concat ( to as any , from as any ) ) ] : from ; } function mergeObjectOptions ( to , from ) { return to ? extend ( extend ( Object . create ( null ) , to ) , from ) : from ; } function mergeWatchOptions ( to , from ) { if ( ! to ) return from ; if ( ! from ) return to ; const merged = extend ( Object . create ( null ) , to ) ; for ( const key in from ) { merged [ key ] = mergeAsArray ( to [ key ] , from [ key ] ) ; } return merged ; }