tree.ts 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. /**
  2. * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. import { Transform } from './transform';
  7. import { ImmutableTree } from './util/immutable-tree';
  8. import { Transformer } from './transformer';
  9. import { StateObject } from './object';
  10. interface StateTree extends ImmutableTree<Transform> { }
  11. namespace StateTree {
  12. export interface Transient extends ImmutableTree.Transient<Transform> { }
  13. export interface Serialized extends ImmutableTree.Serialized { }
  14. function _getRef(t: Transform) { return t.ref; }
  15. export function create() {
  16. return ImmutableTree.create<Transform>(Transform.createRoot('<:root:>'), _getRef);
  17. }
  18. export function updateParams<T extends Transformer = Transformer>(tree: StateTree, ref: Transform.Ref, params: Transformer.Params<T>): StateTree {
  19. const t = tree.nodes.get(ref)!.value;
  20. const newTransform = Transform.updateParams(t, params);
  21. const newTree = ImmutableTree.asTransient(tree);
  22. newTree.setValue(ref, newTransform);
  23. return newTree.asImmutable();
  24. }
  25. export function toJSON(tree: StateTree) {
  26. return ImmutableTree.toJSON(tree, Transform.toJSON) as Serialized;
  27. }
  28. export function fromJSON(data: Serialized): StateTree {
  29. return ImmutableTree.fromJSON(data, _getRef, Transform.fromJSON);
  30. }
  31. export interface Builder {
  32. getTree(): StateTree
  33. }
  34. export function build(tree: StateTree) {
  35. return new Builder.Root(tree);
  36. }
  37. export namespace Builder {
  38. interface State {
  39. tree: StateTree.Transient
  40. }
  41. export class Root implements Builder {
  42. private state: State;
  43. to<A extends StateObject>(ref: Transform.Ref) { return new To<A>(this.state, ref, this); }
  44. toRoot<A extends StateObject>() { return new To<A>(this.state, this.state.tree.rootRef as any, this); }
  45. delete(ref: Transform.Ref) {
  46. this.state.tree.remove(ref);
  47. return this;
  48. }
  49. getTree(): StateTree { return this.state.tree.asImmutable(); }
  50. constructor(tree: StateTree) { this.state = { tree: ImmutableTree.asTransient(tree) } }
  51. }
  52. export class To<A extends StateObject> implements Builder {
  53. apply<T extends Transformer<A, any, any>>(tr: T, params?: Transformer.Params<T>, props?: Partial<Transform.Options>): To<Transformer.To<T>> {
  54. const t = tr.apply(params, props);
  55. this.state.tree.add(this.ref, t);
  56. return new To(this.state, t.ref, this.root);
  57. }
  58. and() { return this.root; }
  59. getTree(): StateTree { return this.state.tree.asImmutable(); }
  60. constructor(private state: State, private ref: Transform.Ref, private root: Root) {
  61. if (!this.state.tree.nodes.has(ref)) {
  62. throw new Error(`Could not find node '${ref}'.`);
  63. }
  64. }
  65. }
  66. }
  67. }
  68. export { StateTree }