|
@@ -26,8 +26,42 @@ namespace StateBuilder {
|
|
|
}
|
|
|
|
|
|
interface BuildState {
|
|
|
+ state: State | undefined,
|
|
|
tree: TransientTree,
|
|
|
- editInfo: EditInfo
|
|
|
+ editInfo: EditInfo,
|
|
|
+ actions: Action[]
|
|
|
+ }
|
|
|
+
|
|
|
+ type Action =
|
|
|
+ | { kind: 'add', transform: StateTransform }
|
|
|
+ | { kind: 'update', ref: string, params: any }
|
|
|
+ | { kind: 'delete', ref: string }
|
|
|
+ | { kind: 'insert', ref: string, transform: StateTransform, initialCellState?: Partial<StateObjectCell.State> }
|
|
|
+
|
|
|
+ function buildTree(state: BuildState) {
|
|
|
+ if (!state.state || state.state.tree === state.editInfo.sourceTree) {
|
|
|
+ return state.tree.asImmutable();
|
|
|
+ }
|
|
|
+
|
|
|
+ // The tree has changed in the meantime, we need to reapply the changes!
|
|
|
+ const tree = state.state.tree.asTransient();
|
|
|
+ for (const a of state.actions) {
|
|
|
+ switch (a.kind) {
|
|
|
+ case 'add': tree.add(a.transform); break;
|
|
|
+ case 'update': tree.setParams(a.ref, a.params); break;
|
|
|
+ case 'delete': tree.remove(a.ref); break;
|
|
|
+ case 'insert': {
|
|
|
+ const children = tree.children.get(a.ref).toArray();
|
|
|
+ tree.add(a.transform, a.initialCellState);
|
|
|
+ for (const c of children) {
|
|
|
+ tree.changeParent(c, a.transform.ref);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ state.editInfo.sourceTree = state.tree;
|
|
|
+ return tree.asImmutable();
|
|
|
}
|
|
|
|
|
|
export function is(obj: any): obj is StateBuilder {
|
|
@@ -52,10 +86,11 @@ namespace StateBuilder {
|
|
|
delete(ref: StateTransform.Ref) {
|
|
|
this.editInfo.count++;
|
|
|
this.state.tree.remove(ref);
|
|
|
+ this.state.actions.push({ kind: 'delete', ref });
|
|
|
return this;
|
|
|
}
|
|
|
- getTree(): StateTree { return this.state.tree.asImmutable(); }
|
|
|
- constructor(tree: StateTree) { this.state = { tree: tree.asTransient(), editInfo: { sourceTree: tree, count: 0, lastUpdate: void 0 } } }
|
|
|
+ getTree(): StateTree { return buildTree(this.state); } //this.state.tree.asImmutable(); }
|
|
|
+ constructor(tree: StateTree, state?: State) { this.state = { state, tree: tree.asTransient(), actions: [], editInfo: { sourceTree: tree, count: 0, lastUpdate: void 0 } } }
|
|
|
}
|
|
|
|
|
|
export class To<A extends StateObject, T extends StateTransformer = StateTransformer> implements StateBuilder {
|
|
@@ -72,6 +107,9 @@ namespace StateBuilder {
|
|
|
this.state.tree.add(t, initialCellState);
|
|
|
this.editInfo.count++;
|
|
|
this.editInfo.lastUpdate = t.ref;
|
|
|
+
|
|
|
+ this.state.actions.push({ kind: 'add', transform: t });
|
|
|
+
|
|
|
return new To(this.state, t.ref, this.root);
|
|
|
}
|
|
|
|
|
@@ -100,30 +138,33 @@ namespace StateBuilder {
|
|
|
|
|
|
this.editInfo.count++;
|
|
|
this.editInfo.lastUpdate = t.ref;
|
|
|
+
|
|
|
+ this.state.actions.push({ kind: 'insert', ref: this.ref, transform: t, initialCellState });
|
|
|
+
|
|
|
return new To(this.state, t.ref, this.root);
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Updates a transform in an instantiated tree, passing the transform's source into the providers
|
|
|
- *
|
|
|
- * This only works if the transform source is NOT updated by the builder. Use at own discression.
|
|
|
- */
|
|
|
- updateInState<T extends StateTransformer<any, A, any>>(transformer: T, state: State, provider: (old: StateTransformer.Params<T>, a: StateTransformer.From<T>) => StateTransformer.Params<T>): Root {
|
|
|
- const old = this.state.tree.transforms.get(this.ref)!;
|
|
|
- const cell = state.cells.get(this.ref);
|
|
|
- if (!cell || !cell.sourceRef) throw new Error('Source cell is not present in the tree.');
|
|
|
- const parent = state.cells.get(cell.sourceRef);
|
|
|
- if (!parent || !parent.obj) throw new Error('Parent cell is not present or computed.');
|
|
|
+ // /**
|
|
|
+ // * Updates a transform in an instantiated tree, passing the transform's source into the providers
|
|
|
+ // *
|
|
|
+ // * This only works if the transform source is NOT updated by the builder. Use at own discression.
|
|
|
+ // */
|
|
|
+ // updateInState<T extends StateTransformer<any, A, any>>(transformer: T, state: State, provider: (old: StateTransformer.Params<T>, a: StateTransformer.From<T>) => StateTransformer.Params<T>): Root {
|
|
|
+ // const old = this.state.tree.transforms.get(this.ref)!;
|
|
|
+ // const cell = state.cells.get(this.ref);
|
|
|
+ // if (!cell || !cell.sourceRef) throw new Error('Source cell is not present in the tree.');
|
|
|
+ // const parent = state.cells.get(cell.sourceRef);
|
|
|
+ // if (!parent || !parent.obj) throw new Error('Parent cell is not present or computed.');
|
|
|
|
|
|
- const params = provider(old.params as any, parent.obj as any);
|
|
|
+ // const params = provider(old.params as any, parent.obj as any);
|
|
|
|
|
|
- if (this.state.tree.setParams(this.ref, params)) {
|
|
|
- this.editInfo.count++;
|
|
|
- this.editInfo.lastUpdate = this.ref;
|
|
|
- }
|
|
|
+ // if (this.state.tree.setParams(this.ref, params)) {
|
|
|
+ // this.editInfo.count++;
|
|
|
+ // this.editInfo.lastUpdate = this.ref;
|
|
|
+ // }
|
|
|
|
|
|
- return this.root;
|
|
|
- }
|
|
|
+ // return this.root;
|
|
|
+ // }
|
|
|
|
|
|
update<T extends StateTransformer<any, A, any>>(transformer: T, params: (old: StateTransformer.Params<T>) => StateTransformer.Params<T>): Root
|
|
|
update(params: StateTransformer.Params<T> | ((old: StateTransformer.Params<T>) => StateTransformer.Params<T>)): Root
|
|
@@ -143,6 +184,8 @@ namespace StateBuilder {
|
|
|
this.editInfo.lastUpdate = this.ref;
|
|
|
}
|
|
|
|
|
|
+ this.state.actions.push({ kind: 'update', ref: this.ref, params });
|
|
|
+
|
|
|
return this.root;
|
|
|
}
|
|
|
|
|
@@ -150,7 +193,7 @@ namespace StateBuilder {
|
|
|
toRoot<A extends StateObject>() { return this.root.toRoot<A>(); }
|
|
|
delete(ref: StateTransform.Ref) { return this.root.delete(ref); }
|
|
|
|
|
|
- getTree(): StateTree { return this.state.tree.asImmutable(); }
|
|
|
+ getTree(): StateTree { return buildTree(this.state); } //this.state.tree.asImmutable(); }
|
|
|
|
|
|
constructor(private state: BuildState, ref: StateTransform.Ref, private root: Root) {
|
|
|
this.ref = ref;
|