UNPKG

mobx

Version:

Simple, scalable state management.

232 lines (207 loc) 7.64 kB
import { IEnhancer, IEqualsComparer, IObservableArray, IObservableMapInitialValues, IMapEntries, IReadonlyMapEntries, IKeyValueMap, IObservableSetInitialValues, IObservableValue, ObservableMap, ObservableSet, ObservableValue, asDynamicObservableObject, createObservableArray, deepEnhancer, extendObservable, isES6Map, isES6Set, isObservable, isPlainObject, referenceEnhancer, Annotation, shallowEnhancer, refStructEnhancer, AnnotationsMap, assign, createObservableAnnotation, createAutoAnnotation, initObservable, decorateObservable20223_ } from "../internal" import { createDecoratorAnnotation, type DecoratorAnnotation } from "./decoratorannotation" import type { ClassAccessorAndFieldDecorator } from "../types/decorator_fills" export const OBSERVABLE = "observable" export const OBSERVABLE_REF = "observable.ref" export const OBSERVABLE_SHALLOW = "observable.shallow" export const OBSERVABLE_STRUCT = "observable.struct" export type CreateObservableOptions = { name?: string equals?: IEqualsComparer<any> deep?: boolean defaultDecorator?: Annotation autoBind?: boolean } // Predefined bags of create observable options, to avoid allocating temporarily option objects // in the majority of cases export const defaultCreateObservableOptions: CreateObservableOptions = { deep: true, name: undefined, defaultDecorator: undefined } Object.freeze(defaultCreateObservableOptions) export function asCreateObservableOptions(thing: any): CreateObservableOptions { return thing || defaultCreateObservableOptions } const observableAnnotation = createObservableAnnotation(OBSERVABLE) const observableRefAnnotation = createObservableAnnotation(OBSERVABLE_REF, { enhancer_: referenceEnhancer }) const observableShallowAnnotation = createObservableAnnotation(OBSERVABLE_SHALLOW, { enhancer_: shallowEnhancer }) const observableStructAnnotation = createObservableAnnotation(OBSERVABLE_STRUCT, { enhancer_: refStructEnhancer }) function createObservableDecoratorAnnotation( annotation: Annotation ): DecoratorAnnotation<ClassAccessorAndFieldDecorator> { return createDecoratorAnnotation(annotation, decorateObservable20223_) } export function getEnhancerFromOptions(options: CreateObservableOptions): IEnhancer<any> { return options.deep === true ? deepEnhancer : options.deep === false ? referenceEnhancer : getEnhancerFromAnnotation(options.defaultDecorator) } export function getAnnotationFromOptions( options?: CreateObservableOptions ): Annotation | undefined { return options ? options.defaultDecorator ?? createAutoAnnotation(options) : undefined } export function getEnhancerFromAnnotation(annotation?: Annotation): IEnhancer<any> { return !annotation ? deepEnhancer : annotation.options_?.enhancer_ ?? deepEnhancer } /** * Turns an object, array or function into a reactive structure. * @param v the value which should become observable. */ function createObservable(v: any, arg2?: any, arg3?: any) { if (arg2 && typeof arg2.kind === "string") { return decorateObservable20223_(observableAnnotation, v, arg2) } // already observable - ignore if (isObservable(v)) { return v } // plain object if (isPlainObject(v)) { return observable.object(v, arg2, arg3) } // Array if (Array.isArray(v)) { return observable.array(v, arg2) } // Map if (isES6Map(v)) { return observable.map(v, arg2) } // Set if (isES6Set(v)) { return observable.set(v, arg2) } // other object - ignore if (typeof v === "object" && v !== null) { return v } // anything else return observable.box(v, arg2) } export interface IObservableValueFactory { <T>(value: T, options?: CreateObservableOptions): IObservableValue<T> <T>(value?: T, options?: CreateObservableOptions): IObservableValue<T | undefined> } export interface IObservableMapFactory { <K = any, V = any>(): ObservableMap<K, V> <K, V>(initialValues?: IMapEntries<K, V>, options?: CreateObservableOptions): ObservableMap< K, V > <K, V>( initialValues?: IReadonlyMapEntries<K, V>, options?: CreateObservableOptions ): ObservableMap<K, V> <K, V>(initialValues?: IKeyValueMap<V>, options?: CreateObservableOptions): ObservableMap<K, V> <K, V>(initialValues?: Map<K, V>, options?: CreateObservableOptions): ObservableMap<K, V> <K = any, V = any>(initialValues: undefined, options?: CreateObservableOptions): ObservableMap< K, V > } export interface IObservableFactory extends Annotation, ClassAccessorAndFieldDecorator { <T = any>(value: T[], options?: CreateObservableOptions): IObservableArray<T> <T = any>(value: Set<T>, options?: CreateObservableOptions): ObservableSet<T> <K = any, V = any>(value: Map<K, V>, options?: CreateObservableOptions): ObservableMap<K, V> <T extends object>( value: T, annotations?: AnnotationsMap<T, never>, options?: CreateObservableOptions ): T box: IObservableValueFactory array: <T = any>(initialValues?: T[], options?: CreateObservableOptions) => IObservableArray<T> set: <T = any>( initialValues?: IObservableSetInitialValues<T>, options?: CreateObservableOptions ) => ObservableSet<T> map: IObservableMapFactory object: <T = any>( props: T, annotations?: AnnotationsMap<T, never>, options?: CreateObservableOptions ) => T } const observableFactories: IObservableFactory = { box<T = any>(value: T, options?: CreateObservableOptions): IObservableValue<T> { const o = asCreateObservableOptions(options) return new ObservableValue(value, getEnhancerFromOptions(o), o.name, true, o.equals) }, array<T = any>(initialValues?: T[], options?: CreateObservableOptions): IObservableArray<T> { const o = asCreateObservableOptions(options) return createObservableArray(initialValues, getEnhancerFromOptions(o), o.name) }, map<K = any, V = any>( initialValues?: IObservableMapInitialValues<K, V>, options?: CreateObservableOptions ): ObservableMap<K, V> { const o = asCreateObservableOptions(options) return new ObservableMap<K, V>(initialValues, getEnhancerFromOptions(o), o.name) }, set<T = any>( initialValues?: IObservableSetInitialValues<T>, options?: CreateObservableOptions ): ObservableSet<T> { const o = asCreateObservableOptions(options) return new ObservableSet<T>(initialValues, getEnhancerFromOptions(o), o.name) }, object<T extends object = any>( props: T, annotations?: AnnotationsMap<T, never>, options?: CreateObservableOptions ): T { return initObservable(() => extendObservable(asDynamicObservableObject({}, options), props, annotations) ) } } as any export const observableRef = createObservableDecoratorAnnotation(observableRefAnnotation) export const observableShallow = createObservableDecoratorAnnotation(observableShallowAnnotation) export const observableDeep = createObservableDecoratorAnnotation(observableAnnotation) export const observableStruct = createObservableDecoratorAnnotation(observableStructAnnotation) // eslint-disable-next-line export var observable: IObservableFactory = assign( createObservable, observableAnnotation, observableFactories )