UNPKG

mute8-solid

Version:
1 lines 14.1 kB
{"version":3,"sources":["../../mute8/mute8.ts","../mute8-solid.ts"],"names":["O","J","toJson","deepClone","obj","freeze","assign","entries","defineProperty","MUT_FN_NAME","BIND_SYMBOLD","defaultPlugin","v","Subject","_Subject","state","plugin","fn","id","observer","update","actionName","args","newFinal","key","value","StoreCore","_StoreCore","d","core","asyncProxy","buildActionProxy","_","actionsProxy","name","f","p","ext","extension","bigProxy","subject","store","actions","proxy","aProxy","buildProxy","createSignal","onCleanup","options","prev","cur","newStore","setValue","sub","s","property","obs"],"mappings":"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","sourcesContent":["// Utils\nconst O = Object;\nconst J = JSON;\nexport const toJson = J.stringify\nconst deepClone = (obj: object) => J.parse(toJson(obj))\nconst freeze = O.freeze\nconst assign = O.assign;\nconst entries = O.entries;\nconst defineProperty = O.defineProperty;\nconst MUT_FN_NAME = \"mut\"\nconst BIND_SYMBOLD = Symbol()\n\nexport type CallArgs = any[] | Function;\nexport interface Plugin<T> {\n /** BeforeInit() */\n BI(initState: T): T\n /** BeforeUpdate() */\n BU(newState: T): T\n /** AfterChange() */\n AC(oldState: Readonly<T>, newState: T, actionName?: string, args?: CallArgs): void\n}\nconst defaultPlugin: <T>() => Plugin<T> = () => ({\n BI: (v) => v,\n BU: (v) => v,\n AC: () => { }\n})\n\nclass Subject<T> {\n private id: number = 0; // subscription id\n private c: Record<number, SubFn<T>> = {} // subscription container\n private s: Readonly<T> // current state\n private p: Plugin<T> // plugin\n private ps: Sub | null // parent sub (Observer only)\n\n constructor(\n state: T,\n plugin?: Plugin<T> // plugins not allowed for Observer\n ) {\n this.p = plugin ?? defaultPlugin()\n this.s = freeze(this.p.BI(state))\n }\n\n destroy() {\n this.ps?.destroy()\n this.ps = null\n }\n\n sanp(): Readonly<T> {\n return this.s\n }\n\n sub(fn: SubFn<T>): Sub {\n const id = this.id++\n this.c[id] = fn\n return {\n destroy: () => delete this.c[id]\n }\n }\n\n select<O>(fn: SelectFn<T, O>): Observer<O> {\n const observer = new Subject(fn(this.sanp()))\n observer.ps = this.sub(v => observer.mut(fn(v)))\n return observer;\n }\n\n mut(update: Partial<T>, actionName?: string, args?: CallArgs): void {\n // for Observer always full update\n let newFinal: T = update as T;\n if (!this.ps) {\n newFinal = this.p.BU(assign(deepClone(this.s), update))\n }\n\n if (toJson(this.s) !== toJson(newFinal)) {\n this.p.AC(this.s, newFinal, actionName, args)\n this.s = freeze(newFinal)\n // notify subscribers\n O.keys(this.c).forEach(id => this.c[id]?.(this.s))\n }\n }\n\n set<K extends keyof T>(key: K & string | typeof MUT_FN_NAME, value: T[K] | Partial<T>): void {\n const actionName = \"set.\" + key;\n const v = (key === MUT_FN_NAME ? value : { [key]: value }) as Partial<T>;\n this.mut(v, actionName, [value])\n }\n}\n\ninterface Observer<T> {\n sub(fn: SubFn<T>): Sub\n select<O>(fn: SelectFn<T, O>): Observer<O>\n sanp(): Readonly<T>\n destroy(): void\n}\n\nclass StoreCore<T extends object, A, AA> {\n private readonly p: Readonly<StoreProxy<T, A, AA>>;\n readonly s: Subject<T>\n\n constructor(d: StoreDefiniton<T, A, AA>) {\n const core = this;\n this.s = new Subject(d.value)\n \n const asyncProxy = buildActionProxy(d.async ?? {} as AA, (_, fn) => {\n return async (...args: any[]) => await fn.bind(core.p)(...args)\n })\n const actionsProxy = buildActionProxy(d.actions ?? {} as A, (name, fn) => {\n return (...args: any[]) => core.mut(v => fn.bind(v)(...args), name, args)\n })\n // experimental (recursive actions)\n core[BIND_SYMBOLD] = buildActionProxy(d.actions ?? {} as A, (_, fn) => {\n return (...args: any[]) => fn.bind(core[BIND_SYMBOLD][BIND_SYMBOLD])(...args)\n })\n\n // init proxy\n this.p = {\n snap: () => core.s.sanp(),\n sub: (v: any) => core.s.sub(v),\n select: (f: any) => core.s.select(f),\n actions: freeze(actionsProxy),\n async: freeze(asyncProxy),\n /** @ts-ignore */\n set mut(v: Partial<T>) { core.s.set(MUT_FN_NAME, v) },\n /** @ts-ignore */\n get mut() { return core.mut.bind(core) }\n }\n\n // init plugin\n const p = d.plugin?.(core.p) ?? defaultPlugin()\n this.s = new Subject(d.value, p)\n }\n\n // synchronius / non async\n private mut(fn: (v: T) => void, actionName?: string, args?: any[]): void {\n const core = this;\n const state = deepClone(core.s.sanp())\n core[BIND_SYMBOLD][BIND_SYMBOLD] = state;\n assign(state, {actions: core[BIND_SYMBOLD]})\n fn(state)\n delete state.actions\n core.s.mut(state, actionName, args ?? fn)\n }\n\n static build<T extends object, A, AA>(\n state: StoreDefiniton<T, A, AA>,\n ext?: ProxyExtension<T, A, AA>\n ): Store<T, A, AA> {\n const core = new StoreCore(state)\n const extension = !ext ? {} : { [ext.name]: ext.init(core as StoreCore<any, any, any>) } as {}\n const bigProxy = assign(extension, core.p)\n\n // build store representation (proxy)\n const subject = core.s;\n const store = {}\n for (const [key, _] of entries(state.value)) {\n defineProperty(store, key, {\n get() { return subject.sanp()[key] },\n set(v) { subject.set(key as any, v) }\n })\n }\n defineProperty(store, MUT_FN_NAME, {\n get() { return core.mut.bind(core) },\n set(v) { subject.set(MUT_FN_NAME, v) }\n })\n return freeze(assign(store, bigProxy)) as Store<T, A, AA>\n }\n\n}\n\nconst buildActionProxy = <T>(actions: T, proxy: (fnName: string, builder: Function) => Function): T => {\n const aProxy: Record<string, Function> = {}\n entries(actions as object).forEach(([name, fn]) => aProxy[name] = proxy(name, fn))\n return aProxy as T\n}\n\n// Proxy\ninterface SmalProxy<T, A> {\n snap(): T\n set mut(v: Partial<T>)\n get mut(): (fn: (v: T) => void, actionName?: string) => void\n actions: Readonly<A>\n}\nexport interface StoreProxy<T, A, AA> extends SmalProxy<T, A> {\n sub(fn: SubFn<T>): Sub\n select<O>(fn: (value: Readonly<T>) => O): Observer<O>\n async: Readonly<AA>\n}\nexport interface ProxyExtension<T extends object, A, AA> {\n name: string,\n init(core: StoreCore<T, A, AA>): object\n}\n\n// Use Only for internal ProxyExtension\nexport const buildProxy = StoreCore.build;\ntype ExcludeKeys = { async?: never, actions?: never, snap?: never, sub?: never, mut?: never }\n// Public\nexport type PluginBuilder = (<T extends object>(proxy: StoreProxy<T, any, any>) => Plugin<T>) | null\nexport type Store<T, A, AA> = StoreProxy<T, A, AA> & T\nexport type SubFn<T> = (value: Readonly<T>) => void\nexport type SelectFn<T, O> = (value: Readonly<T>) => O\nexport type Sub = { destroy(): void }\n\nexport type VoidFn = ((...args: any) => undefined)\nexport type AsyncFn = ((...args: any) => Promise<void>);\nexport interface StoreDefiniton<T extends object, A, AA> {\n value: T & object & ExcludeKeys\n actions?: A & ThisType<T & {actions: Readonly<A>}> & Record<string, VoidFn>\n async?: AA & ThisType<SmalProxy<T, A>> & Record<string, AsyncFn>\n plugin?: PluginBuilder\n}\nexport const newStore = <T extends object, A, AA>(state: StoreDefiniton<T, A, AA>) => {\n return buildProxy(state) as Store<T, A, AA>\n}\n","import { Store as StoreMute8, StoreDefiniton, ProxyExtension, buildProxy, SelectFn, toJson } from \"../mute8/mute8\"\nimport { createSignal, onCleanup, type Accessor, type SignalOptions, } from 'solid-js';\n\ninterface SolidExtension<T> {\n use(): [Accessor<T>, (newValeu: Partial<T>) => void]\n useOne<K extends keyof T>(property: K): [Accessor<T[K]>, (newValue: T[K]) => void]\n select<O>(fn: SelectFn<T, O>): Accessor<O>\n}\n\nexport type Store<T, A, AA> = StoreMute8<T, A, AA> & {\n solid: SolidExtension<T>\n}\n\nconst options: SignalOptions<any> = {\n equals: (prev, cur) => toJson(prev) == toJson(cur)\n}\n\nexport const newStore = <T extends Object, A, AA>(store: StoreDefiniton<T, A, AA>) => {\n const extension: ProxyExtension<T, A, AA> = {\n name: \"solid\",\n init(core) {\n return {\n use() {\n const [value, setValue] = createSignal(core.s.sanp());\n const sub = core.s.sub(s => setValue(s as any))\n onCleanup(() => sub.destroy())\n return [value, (v: any) => core.s.mut(v)]\n },\n useOne<K extends keyof T>(property: K & string) {\n const [value, setValue] = createSignal((core.s.sanp() as any)[property], options);\n const sub = core.s.sub((s: any) => setValue(s[property]))\n onCleanup(() => sub.destroy())\n return [value, (v: any) => core.s.set(property, v)]\n },\n select<O>(fn: SelectFn<T, O>) {\n const [value, setValue] = createSignal(fn(core.s.sanp()));\n const obs = core.s.select(fn)\n obs.sub(s => setValue(s as any))\n onCleanup(() => obs.destroy())\n return value\n }\n }\n },\n }\n\n return buildProxy(store, extension) as Store<T, A, AA>\n}\n\nexport { SubFn, VoidFn, AsyncFn, Sub, Plugin } from \"../mute8/mute8\""]}