import { isFunction } from '@vue/shared' import { currentInstance } from './component' import { currentApp } from './apiCreateVaporApp' import { warn } from './warning' export interface InjectionKey extends Symbol {} export function provide | string | number>( key: K, value: K extends InjectionKey ? V : T, ) { if (!currentInstance) { if (__DEV__) { warn(`provide() can only be used inside setup().`) } } else { let provides = currentInstance.provides // by default an instance inherits its parent's provides object // but when it needs to provide values of its own, it creates its // own provides object using parent provides object as prototype. // this way in `inject` we can simply look up injections from direct // parent and let the prototype chain do the work. const parentProvides = currentInstance.parent && currentInstance.parent.provides if (parentProvides === provides) { provides = currentInstance.provides = Object.create(parentProvides) } // TS doesn't allow symbol as index type provides[key as string] = value } } export function inject(key: InjectionKey | string): T | undefined export function inject( key: InjectionKey | string, defaultValue: T, treatDefaultAsFactory?: false, ): T export function inject( key: InjectionKey | string, defaultValue: T | (() => T), treatDefaultAsFactory: true, ): T export function inject( key: InjectionKey | string, defaultValue?: unknown, treatDefaultAsFactory = false, ) { const instance = currentInstance // also support looking up from app-level provides w/ `app.runWithContext()` if (instance || currentApp) { // #2400 // to support `app.use` plugins, // fallback to appContext's `provides` if the instance is at root const provides = instance ? instance.parent == null ? instance.appContext && instance.appContext.provides : instance.parent.provides : currentApp!._context.provides if (provides && (key as string | symbol) in provides) { // TS doesn't allow symbol as index type return provides[key as string] } else if (arguments.length > 1) { return treatDefaultAsFactory && isFunction(defaultValue) ? defaultValue.call(instance && instance) : defaultValue } else if (__DEV__) { warn(`injection "${String(key)}" not found.`) } } else if (__DEV__) { warn(`inject() can only be used inside setup() or functional components.`) } } /** * Returns true if `inject()` can be used without warning about being called in the wrong place (e.g. outside of * setup()). This is used by libraries that want to use `inject()` internally without triggering a warning to the end * user. One example is `useRoute()` in `vue-router`. */ export function hasInjectionContext(): boolean { return !!(currentInstance || currentApp) }