UNPKG

@foblex/mutator

Version:

Angular Signals state engine with deep patch + undo/redo and notifier.

1 lines 11.4 kB
{"version":3,"file":"foblex-mutator.mjs","sources":["../../../projects/mutator/src/lib/utils/deep-delete.ts","../../../projects/mutator/src/lib/utils/deep-merge.ts","../../../projects/mutator/src/lib/provide-mutator.ts","../../../projects/mutator/src/lib/mutator.ts","../../../projects/mutator/src/foblex-mutator.ts"],"sourcesContent":["import {DeepPartial} from './deep-partial';\n\nexport function deepDelete<T>(target: T, patch: DeepPartial<T>): T {\n const out: any = Array.isArray(target) ? [...target] : { ...target };\n\n for (const k in patch) {\n const pv: any = (patch as any)[k];\n\n if (pv && typeof pv === 'object' && !Array.isArray(pv)) {\n if (out[k]) out[k] = deepDelete(out[k], pv);\n } else {\n delete out[k];\n }\n }\n return out;\n}\n","import {DeepPartial} from './deep-partial';\n\nexport function deepMerge<T>(target: T, patch: DeepPartial<T>): T {\n if (typeof target !== 'object' || target === null) return patch as T;\n if (typeof patch !== 'object' || patch === null) return target;\n\n const out: any = Array.isArray(target)\n ? [...target]\n : { ...target };\n\n for (const key in patch) {\n if (!Object.prototype.hasOwnProperty.call(patch, key)) continue;\n\n const patchValue = patch[key];\n const targetValue = (target as any)[key];\n\n if (isPlainObject(patchValue) && isPlainObject(targetValue)) {\n out[key] = deepMerge(targetValue, patchValue as any);\n } else {\n out[key] = patchValue;\n }\n }\n\n return out;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, any> {\n return (\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n Object.prototype.toString.call(value) === '[object Object]'\n );\n}\n","import {InjectionToken, Provider} from '@angular/core';\n\nexport interface MutatorConfig {\n limit?: number;\n}\n\nexport const MUTATOR_CONFIG = new InjectionToken<MutatorConfig>('F_MUTATOR_CONFIG');\n\nexport function provideMutator(config: MutatorConfig = {}): Provider[] {\n return [\n {\n provide: MUTATOR_CONFIG,\n useValue: config,\n }\n ];\n}\n","import {inject, Signal, signal} from '@angular/core';\nimport {deepMerge, deepDelete, DeepPartial} from './utils';\nimport {IMutatorChange} from './i-mutator-change';\nimport {MUTATOR_CONFIG} from './provide-mutator';\n\nfunction deepClone<T>(value: T): T {\n if (typeof structuredClone === 'function') {\n return structuredClone(value);\n }\n return JSON.parse(JSON.stringify(value));\n}\n\ninterface Changes<T> {\n value: DeepPartial<T>;\n action: 'create' | 'update' | 'delete';\n}\n\nexport abstract class Mutator<T extends object> {\n private _base: T = {} as T;\n private readonly _undoStack: Changes<T>[] = [];\n private readonly _redoStack: Changes<T>[] = [];\n\n private readonly _config = inject(MUTATOR_CONFIG, {optional: true});\n\n private readonly _limit = this._config?.limit || 50;\n\n private readonly _change = signal<IMutatorChange>({\n version: 0,\n notifier: null\n });\n\n private readonly _canUndo = signal(false);\n private readonly _canRedo = signal(false);\n\n public get changes(): Signal<IMutatorChange> {\n return this._change.asReadonly();\n }\n\n public get canUndo(): Signal<boolean> {\n return this._canUndo.asReadonly();\n }\n\n public get canRedo(): Signal<boolean> {\n return this._canRedo.asReadonly();\n }\n\n public get base(): T {\n return deepClone(this._base);\n }\n\n public initialize(value: T): void {\n this._base = value;\n this._undoStack.length = 0;\n this._redoStack.length = 0;\n this._updateSignals();\n this._change.set({version: 0, notifier: null});\n }\n\n public create(patch: DeepPartial<T>, notifier?: string): void {\n this._addChanges({\n value: patch,\n action: 'create'\n }, notifier || null);\n }\n\n public update(patch: DeepPartial<T>, notifier?: string): void {\n this._addChanges({\n value: patch,\n action: 'update'\n }, notifier || null);\n }\n\n public delete(patch: DeepPartial<T>, notifier?: string): void {\n this._addChanges({\n value: patch,\n action: 'delete'\n }, notifier || null);\n }\n\n public _addChanges(changes: Changes<T>, notifier: string | null): void {\n this._undoStack.push(deepClone(changes));\n\n if (this._undoStack.length > this._limit) {\n const oldest = this._undoStack.shift()!;\n this._base = this._applyChange(this._base, oldest);\n }\n\n this._redoStack.length = 0;\n this._updateSignals();\n\n this._setChangeObject(notifier);\n }\n\n private _setChangeObject(notifier: string | null): void {\n this._change.set({version: this._change().version + 1, notifier});\n }\n\n public getSnapshot(): T {\n let result: T = deepClone(this._base);\n\n for (const change of this._undoStack) {\n result = this._applyChange(result, change);\n }\n\n return result;\n }\n\n private _applyChange(result: T, change: Changes<T>): T {\n switch (change.action) {\n case 'create':\n case 'update':\n return deepMerge(result, change.value);\n case 'delete':\n return deepDelete(result, change.value);\n default:\n throw new Error(`Unknown action: ${change.action}`);\n }\n }\n\n public undo(): void {\n const last = this._undoStack.pop();\n if (last) {\n this._redoStack.push(last);\n this._updateSignals();\n this._setChangeObject(null);\n }\n }\n\n public redo(): void {\n const restored = this._redoStack.pop();\n if (restored) {\n this._undoStack.push(restored);\n this._updateSignals();\n this._setChangeObject(null);\n }\n }\n\n public patchBase(patch: DeepPartial<T>): void {\n this._base = deepMerge(this._base, deepClone(patch));\n }\n\n public deleteFromBase(patch: DeepPartial<T>): void {\n this._base = deepDelete(this._base, deepClone(patch));\n }\n\n private _updateSignals(): void {\n this._canUndo.set(this._undoStack.length > 0);\n this._canRedo.set(this._redoStack.length > 0);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}