/** * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal */ import { Transform } from './transform'; import { ImmutableTree } from './util/immutable-tree'; import { Transformer } from './transformer'; import { StateObject } from './object'; interface StateTree extends ImmutableTree { } namespace StateTree { export interface Transient extends ImmutableTree.Transient { } export interface Serialized extends ImmutableTree.Serialized { } function _getRef(t: Transform) { return t.ref; } export function create() { return ImmutableTree.create(Transform.createRoot('<:root:>'), _getRef); } export function updateParams(tree: StateTree, ref: Transform.Ref, params: Transformer.Params): StateTree { const t = tree.nodes.get(ref)!.value; const newTransform = Transform.updateParams(t, params); const newTree = ImmutableTree.asTransient(tree); newTree.setValue(ref, newTransform); return newTree.asImmutable(); } export function toJSON(tree: StateTree) { return ImmutableTree.toJSON(tree, Transform.toJSON) as Serialized; } export function fromJSON(data: Serialized): StateTree { return ImmutableTree.fromJSON(data, _getRef, Transform.fromJSON); } export interface Builder { getTree(): StateTree } export function build(tree: StateTree) { return new Builder.Root(tree); } export namespace Builder { interface State { tree: StateTree.Transient } export class Root implements Builder { private state: State; to(ref: Transform.Ref) { return new To(this.state, ref, this); } toRoot() { return new To(this.state, this.state.tree.rootRef as any, this); } delete(ref: Transform.Ref) { this.state.tree.remove(ref); return this; } getTree(): StateTree { return this.state.tree.asImmutable(); } constructor(tree: StateTree) { this.state = { tree: ImmutableTree.asTransient(tree) } } } export class To implements Builder { apply>(tr: T, params?: Transformer.Params, props?: Partial): To> { const t = tr.apply(params, props); this.state.tree.add(this.ref, t); return new To(this.state, t.ref, this.root); } and() { return this.root; } getTree(): StateTree { return this.state.tree.asImmutable(); } constructor(private state: State, private ref: Transform.Ref, private root: Root) { if (!this.state.tree.nodes.has(ref)) { throw new Error(`Could not find node '${ref}'.`); } } } } } export { StateTree }