import type { Directive } from '../runtime/compiler' ; import type { InjectionKey } from './inject' ; import type { ComponentInstance } from '../types' ; import { hyphenate , isFunction } from '@vue/shared' ; import { warn } from '../warn' ; type PluginInstallFunction = ( app : App , ... args : any [ ] ) => any ; export type Plugin = PluginInstallFunction & { install ? : PluginInstallFunction ; } | { install : PluginInstallFunction ; } ; export interface App { container : ComponentInstance | null ; context : AppContext ; version : string ; config : AppConfig ; use ( plugin , ... options ) : this ; directive ( name ) : Directive ; directive ( name , directive ) : this ; provide < T > ( key , value ) : this ; } export interface AppConfig { performance : boolean ; errorHandler ? ( err , instance , info ) : void ; warnHandler ? ( msg , instance , trace ) : void ; } export interface AppContext { app : App ; config : AppConfig ; directives : Record < string , Directive > ; provides : Record < string | symbol , unknown > ; internal reload ? ( ) : void ; } export const applications = new Map < string , App > ( ) ; export function createApp ( root ) { const installedPlugins = new Set ( ) ; const context = { app : null , config : { performance : false , errorHandler : null , warnHandler : null , } , directives : { } , provides : Object . create ( null ) } ; const app = ( context . app = { container : null , version : __VERSION__ , context , get config ( ) { return context . config ; } , use ( plugin , ... args ) { if ( ! installedPlugins . has ( plugin ) ) { if ( plugin && isFunction ( plugin . install ) ) { installedPlugins . add ( plugin ) ; if ( isFunction ( plugin ) ) { plugin ( app , ... args ) ; } else if ( isFunction ( plugin . install ) ) { plugin . install ( app , ... args ) ; } else if ( __DEV__ ) { warn ( `A plugin must either be a function or an object with an 'install' function.` ) ; } installedPlugins . add ( plugin ) ; } } else if ( __DEV__ ) { warn ( `Plugin has already been applied to target app.` ) ; } return app ; } , directive ( name , directive ? ) { if ( __DEV__ ) { } name = hyphenate ( name ) ; if ( ! directive ) { return context . directives [ name ] as any ; } if ( __DEV__ && context . directives [ name ] ) { warn ( `Directive '${ name }' has already been registered in target app.` ) ; } context . directives [ name ] = directive ; return app ; } , provide ( key , value ) { if ( __DEV__ && ( key as string | symbol ) in context . provides ) { warn ( `App already provides property with key '${ String ( key ) }'. It will be overwritten with the new value.` ) ; } context . provides [ key as string ] = value ; return app ; } , } ) ; applications . set ( root , app ) ; return app ; }