UNPKG

mobx-bonsai

Version:

A fast lightweight alternative to MobX-State-Tree + Y.js two-way binding

230 lines (229 loc) 10.3 kB
import { IComputedValueOptions } from 'mobx'; import { Merge, SetOptional } from 'type-fest'; import { Dispose } from '../../utils/disposable'; import { PrependArgument } from '../../utils/PrependArgument'; import { NodeTypeKey, NodeTypeValue, nodeTypeKey } from './nodeType'; /** * Base interface for node types with type-specific capabilities. * * @template TNode - The object type representing a node * @template TCapabilities - Node type capabilities, can be "typed" and/or "keyed" * @template TOptional - Optional properties of the node type * @template TKey - Property key used for node identification (if keyed) * @template TOther - Additional type information */ interface BaseNodeTypeWithType<TNode extends object, TCapabilities extends "typed" | "keyed", TOptional extends keyof TNode, TKey extends keyof TNode | never, TOther> { /** * Unique identifier for this node type */ typeId: TNode extends { [nodeTypeKey]: NodeTypeValue; } ? TNode[NodeTypeKey] : undefined; /** * Checks if the node is of a specific type * * @param node - Node to check * @returns true if the node type matches, false otherwise */ nodeIsOfType(node: object): node is TNode; /** * Unregisters this node type */ unregister(): void; /** * Unregisters this node type (disposable pattern) */ [Symbol.dispose](): void; /** * Registers a callback to run when nodes of this type are initialized * * @param callback - Function to execute when a node is initialized * * @returns The same node type with the added initialization callback */ onInit(callback: (node: TNode) => void): BaseNodeType<TNode, TCapabilities, TOptional, TKey, TOther>; _initNode(node: TNode): void; _addOnInit(callback: (node: TNode) => void): Dispose; /** * Configures this type to use a specific property as the node key * * @template TKey - Property key in the node type * @param key - Property name to use as the node key * @returns A keyed node type using the specified property as key */ withKey<TKey extends keyof TNode>(key: TKey): BaseNodeType<TNode, TCapabilities | "keyed", TOptional, TKey, TOther>; /** * Makes this node type immutable. * * Immutable nodes cannot be modified after creation and sub-objects are not turned into nodes. * This is useful for creating read-only nodes or for performance optimizations. */ frozen(): BaseNodeType<TNode, TCapabilities, TOptional, TKey, TOther>; /** * true if the node type is frozen, false otherwise */ isFrozen: boolean; } /** * Interface that represents a node type with a key property. * Provides functionality for accessing and finding nodes by their unique keys. * * @template TNode - The node type * @template TKey - The key of the node's unique identifier property */ interface BaseNodeTypeWithKey<TNode, TKey extends keyof TNode> { /** * Property name containing the node's unique key */ key: TKey; /** * Gets the unique key value for a node * * @param node - Node to get the key from * @returns The node's key value or undefined */ getKey(node: TNode): TNode[TKey] | undefined; /** * Retrieves a node by its key (if it exists) * * @param key - Key to search for * @returns The node with the specified key or undefined */ findByKey(key: TNode[TKey]): TNode | undefined; } /** * Base node type definition with core functionality * * @template TNode - Node structure that adheres to this type * @template TOptional - Optional keys in the node structure * @template TCapabilities - Type of capabilities (untyped, typed or keyed) * @template TKey - Key field in the node structure (if any) * @template TOther - Additional properties and methods */ export type BaseNodeType<TNode extends object, TCapabilities extends "untyped" | "typed" | "keyed", TOptional extends keyof TNode, TKey extends keyof TNode | never, TOther> = { /** * Node constructor. * Requires all keys from TNode except those in TOptional (which may be omitted). */ (data: SetOptional<TNode, TOptional | TKey>): TNode; /** * Returns a snapshot based on the provided data. */ snapshot(data: SetOptional<TNode, TOptional | TKey>): TNode; /** * Adds volatile state properties to nodes of this type * * Volatile state is not persisted in snapshots and is local to each node instance. * * @template TVolatiles - Record of volatile property getter functions * @param volatile - Object where each key defines a getter function for volatile state * @returns The same NodeType with added accessor methods for the volatile state */ volatile<TVolatiles extends Record<string, () => any>>(volatile: TVolatiles): BaseNodeType<TNode, TCapabilities, TOptional, TKey, Merge<TOther, VolatileAccessors<TVolatiles, TNode>>>; /** * Registers action methods for nodes of this type * * Actions are methods that can modify the node state and are automatically * wrapped in MobX actions for proper state tracking. * * @template TActions - Record of action methods * * @param actions - An object of action methods * * @returns The same NodeType with added action methods that accept a node as their first parameter */ actions<TActions extends Record<string, (this: TNode, ...args: any[]) => any>>(actions: TActions): BaseNodeType<TNode, TCapabilities, TOptional, TKey, Merge<TOther, { [k in keyof TActions]: PrependArgument<TActions[k], TNode>; }>>; /** * Registers getter methods for nodes of this type * * Getters are methods that derive values from the node state without modifying it. * * @template TGetters - Record of getter methods * * @param getters - An object of getter methods * * @returns The same NodeType with added getter methods that accept a node as their first parameter */ getters<TGetters extends Record<string, (this: TNode, ...args: any[]) => any>>(getters: TGetters): BaseNodeType<TNode, TCapabilities, TOptional, TKey, Merge<TOther, { [k in keyof TGetters]: PrependArgument<TGetters[k], TNode>; }>>; /** * Registers computed methods for nodes of this type * * Computed methods derive values from the node state and are automatically * memoized by MobX for performance optimization. * * @template TComputeds - Record of computed properties * @param computeds - Function that receives a node and returns an object of computed accessor methods * @returns The same NodeType with added computed methods that accept a node as their first parameter */ computeds<TComputeds extends Record<string, ComputedEntry<TNode, any>>>(computeds: TComputeds): BaseNodeType<TNode, TCapabilities, TOptional, TKey, Merge<TOther, { [k in keyof TComputeds]: TComputeds[k] extends () => any ? PrependArgument<TComputeds[k], TNode> : TComputeds[k] extends ComputedFnWithOptions<TNode, any> ? PrependArgument<TComputeds[k]["get"], TNode> : never; }>>; /** * Generates setter methods for specified properties * * @param properties - Names of properties to create setters for * @returns The same NodeType with added setter methods */ settersFor<K extends keyof TNode & string>(...properties: readonly K[]): BaseNodeType<TNode, TCapabilities, TOptional, TKey, Merge<TOther, { [P in K as `set${Capitalize<P>}`]: (node: TNode, value: Readonly<TNode[P]>) => void; }>>; /** * Define default values for keys in TOptional. * When omitted, those properties are filled with the results of these generators. * * @template TGen - Record of default value generators */ defaults<TGen extends { [K in keyof TNode]?: () => TNode[K]; }>(defaultGenerators: TGen): BaseNodeType<TNode, TCapabilities, TOptional | (keyof TGen & keyof TNode), TKey, TOther>; /** * Default generators defined so far. */ defaultGenerators?: { [K in keyof TNode]?: () => TNode[K]; }; /** * Extend this type from another untyped node type. * The base node type can be a subset of the current node type. * * @template TBaseNode - Base node type (must be a subset of TNode) * @template TExtendedOther - Additional properties and methods from the base type * @param nodeType - Node type to extend from */ extends<TExtendedNode extends object, TExtendedOptional extends keyof TExtendedNode, TExtendedOther>(nodeType: BaseNodeType<TExtendedNode, "untyped", TExtendedOptional, never, TExtendedOther>): TNode extends TExtendedNode ? BaseNodeType<TNode, TCapabilities, TOptional | TExtendedOptional, TKey, Merge<TOther, TExtendedOther>> : never; _extendsKeys: Set<string>; } & (TCapabilities extends "typed" | "keyed" ? BaseNodeTypeWithType<TNode, TCapabilities, TOptional, TKey, TOther> & (TCapabilities extends "keyed" ? BaseNodeTypeWithKey<TNode, TKey> : unknown) : unknown) & TOther; /** * Configuration for a computed property with options * * @template TThis - This type for the computed function * @template T - Return type of the computed value */ export type ComputedFnWithOptions<TThis, T> = { get: (this: TThis) => T; } & Omit<IComputedValueOptions<T>, "get" | "set">; /** * Computed property definition that can be a function or configuration object * * @template TThis - This type for the computed function * @template T - Return type of the computed value */ export type ComputedEntry<TThis, T> = ((this: TThis) => T) | ComputedFnWithOptions<TThis, T>; /** * Generates accessor methods for volatile properties * * @template T - Record of volatile property getter functions * @template TNode - The node type these accessors operate on */ export type VolatileAccessors<T extends Record<string, () => any>, TNode> = { [K in keyof T as `set${Capitalize<string & K>}`]: (n: TNode, value: ReturnType<T[K]>) => void; } & { [K in keyof T as `get${Capitalize<string & K>}`]: (n: TNode) => ReturnType<T[K]>; } & { [K in keyof T as `reset${Capitalize<string & K>}`]: (n: TNode) => void; }; export {};