import { $CONSTRUCTOR, MetaContext, MetaObject } from '../../MetaContext'; import { $CONSTRUCT } from './$construct'; export const $RESTORE = '$restore'; export type Restore = (value: T, state: any) => T; export type $Restore = { [$RESTORE]: Restore }; export const $CREATE = '$create'; export type Create = (state: any) => T; export type $Create = { [$CREATE]: Create }; export const withRestore = MetaContext>(MetaContextBase: TMetaContextBase) => class extends MetaContextBase { getState(state: any) { return [this.getValue(state), state] as [MetaObject, any]; } resolveState(state: any) { const ret = this.getState(state); if (ret[0] === undefined) throw new TypeError(`MetaContext.resolveState(): ${state} is not found`); return ret; } [$RESTORE](value: T, state: any) { const [stateMetaObject, resolvedState] = this.resolveState(state); if (stateMetaObject !== this.getValue(value)) return stateMetaObject[$CREATE](resolvedState, this) as T; return stateMetaObject[$RESTORE](value, resolvedState, this) as T; } [$CREATE](state: any) { const [stateMetaObject, resolvedState] = this.resolveState(state); return stateMetaObject[$CREATE](resolvedState, this) as T; } }; export type GenericRestore = (value: T, state: any, restorefn: Restore, createfn: Create, context: any) => T; export function primitiveRestore(_: T, state: any) { return primitiveCreate(state) as T; } export function primitiveWrapperRestore(this: MetaObject, _: T, state: any) { return primitiveWrapperCreate.call(this, state) as T; } export function deepRestore(genericRestore: GenericRestore) { return function $restore(this: MetaObject, value: T, state: any, context: MetaContext & $Restore & $Create) { const restorefn = context[$RESTORE]; const createfn = context[$CREATE]; return (this[$RESTORE] = function $restore(value: T, state: any, context: MetaContext) { return genericRestore(value, state, restorefn, createfn, context); })(value, state, context); }; } export function genericCreate(this: MetaObject, state: any, context: any, ...args: any[]) { return this[$RESTORE](this[$CONSTRUCT](...args), state, context) as T; } export function primitiveCreate(state: any) { return state as T; } export function primitiveWrapperCreate(this: MetaObject, state: any) { return new this[$CONSTRUCTOR]!(state) as T; }