UNPKG

mobx-keystone-mindreframer

Version:

A MobX powered state management solution based on data trees with first class support for Typescript, snapshots, patches and much more

103 lines (87 loc) 3.04 kB
import { isModelAutoTypeCheckingEnabled } from "../globalConfig/globalConfig" import { toTreeNode } from "../tweaker/tweak" import type { AnyStandardType, TypeToData } from "../typeChecking/schemas" import { typeCheck } from "../typeChecking/typeCheck" import { assertIsString } from "../utils" import { extendFnModelActions, FnModelActions, FnModelActionsDef } from "./actions" declare const dataTypeSymbol: unique symbol /** * Basic functional model methods. */ export interface FnModelBase<Data extends object, Extra> { // just to make typing work properly [dataTypeSymbol]: Data /** * Turns data into a tree node and additionally performs a type check * if model auto type checking is enabled in the global config * and a type was specified. * * @param data Model data. */ create(data: Data): Data /** * Returns the type the model is based on, or `null` if none. */ type: AnyStandardType | null /** * Adds actions to the model. * * @param actions Actions to add. */ actions<A extends FnModelActionsDef>( actions: ThisType<Data> & A ): FnModel<Data, Extra & FnModelActions<Data, A>> } /** * Functional model. */ export type FnModel<Data extends object, Extra> = Extra & FnModelBase<Data, Extra> /** * Gets the data type of a functional model. */ export type FnModelData<FN extends FnModelBase<any, any>> = FN[typeof dataTypeSymbol] /** * Creates a functional model, which can be later extended with views, actions, etc. * * @typeparam DataType Data type. * @param dataType Data type, which must be of an object kind. * @param namespace Namespace for its actions. * @returns */ export function fnModel<DataType extends AnyStandardType>( dataType: DataType, namespace: string ): FnModel<TypeToData<DataType>, {}> /** * Creates a functional model, which can be later extended with views, actions, etc. * * @typeparam Data Data type. * @param namespace Namespace for its actions. * @returns */ export function fnModel<Data extends object>(namespace: string): FnModel<Data, {}> export function fnModel(arg1: any, arg2?: string): FnModel<any, {}> { const actualType: AnyStandardType | null = arguments.length >= 2 ? arg1 : null const namespace = arguments.length >= 2 ? (arg2 as string) : (arg1 as string) assertIsString(namespace, "namespace") const fnModelObj: Partial<FnModelBase<any, {}>> = { create: actualType ? fnModelCreateWithType.bind(undefined, actualType) : fnModelCreateWithoutType, type: actualType, } fnModelObj.actions = extendFnModelActions.bind(undefined, fnModelObj, namespace) return fnModelObj as FnModel<any, {}> } function fnModelCreateWithoutType<Data extends object>(data: Data): Data { return toTreeNode(data) } function fnModelCreateWithType<Data extends object>(actualType: AnyStandardType, data: Data): Data { if (isModelAutoTypeCheckingEnabled()) { const errors = typeCheck(actualType, data) if (errors) { errors.throw(data) } } return toTreeNode(data) }