import { computed, ComputedRef, ref, Ref, UnwrapRef } from 'vue'; import { useGuids } from './use-guids'; const noFactoryErrorMsg = 'no valid factory was provided'; const noKeyErrorMsg = 'no valid key was provided'; const refs: { [key: string]: any } = {}; function useSingleton(key: string): T; function useSingleton(key: string, factory: () => T): T; function useSingleton(key: string, factory?: () => T): T { if (!key) { throw new Error(noKeyErrorMsg); } if (!!refs[key]) { return refs[key] as T; } if (!!factory && typeof factory === 'function') { const ref = factory(); refs[key] = ref; return ref; } throw new Error(noFactoryErrorMsg); } function useSingletonRef(key: string): Ref>; function useSingletonRef(key: string, factory: () => T): Ref>; function useSingletonRef(key: string, factory?: () => T): Ref> { if (!key) { throw new Error(noKeyErrorMsg); } if (!!refs[key]) { return refs[key] as Ref>; } if (!!factory && typeof factory === 'function') { const refFactory = () => ref(factory()); const item: any = useSingleton(key, refFactory); return item; } throw new Error(noFactoryErrorMsg); } function useSingletonComputed(key: string): ComputedRef; function useSingletonComputed(key: string, factory: () => T): ComputedRef; function useSingletonComputed(key: string, factory?: () => T): ComputedRef { if (!key) { throw new Error(noKeyErrorMsg); } if (!!refs[key]) { return refs[key] as ComputedRef; } if (!!factory && typeof factory === 'function') { const refFactory = () => computed(factory); return useSingleton(key, refFactory); } throw new Error(noFactoryErrorMsg); } type Lazy = { value: T }; function useLazy(factory: () => T): Lazy; function useLazy(key: string, factory: () => T): Lazy; function useLazy(keyOrFactory: string | (() => T), factory?: () => T): Lazy { if (typeof keyOrFactory === 'function') { const { generateGuid } = useGuids(); const key = generateGuid(); return { get value() { return useSingleton(key, keyOrFactory); }, }; } else if (!!factory) { return { get value() { return useSingleton(keyOrFactory, factory); }, }; } else { throw new Error(noFactoryErrorMsg); } } function useLazyRef(factory: () => T): Lazy>>; function useLazyRef(key: string, factory: () => T): Lazy>>; function useLazyRef(keyOrFactory: string | (() => T), factory?: () => T): Lazy>> { const factoryToUse: () => T = (factory || keyOrFactory) as any; if (typeof factoryToUse !== 'function') { throw new Error(noFactoryErrorMsg); } const { generateGuid } = useGuids(); const key = typeof keyOrFactory === 'string' ? keyOrFactory : generateGuid(); const refFactory = () => ref(factoryToUse()); const item: any = useLazy(key, refFactory); return item; } function useLazyComputed(factory: () => T): Lazy>; function useLazyComputed(key: string, factory: () => T): Lazy>; function useLazyComputed(keyOrFactory: string | (() => T), factory?: () => T): Lazy> { const factoryToUse: () => T = (factory || keyOrFactory) as any; if (typeof factoryToUse !== 'function') { throw new Error(noFactoryErrorMsg); } const { generateGuid } = useGuids(); const key = typeof keyOrFactory === 'string' ? keyOrFactory : generateGuid(); const refFactory = () => computed(factoryToUse); const item: any = useLazy(key, refFactory); return item; } export { useSingleton, useSingletonComputed, useSingletonRef, useLazy, useLazyComputed, useLazyRef };