UNPKG

@odoo/o-spreadsheet

Version:
177 lines (176 loc) 5.99 kB
import { OperationSequenceNode, TransformationFactory } from "../types/history"; import { UID } from "../types/misc"; import { Branch } from "./branch"; import { Operation } from "./operation"; import { OperationSequence } from "./operation_sequence"; /** * The tree is a data structure used to maintain the different branches of the * SelectiveHistory. * * Branches can be "stacked" on each other and an execution path can be derived * from any stack of branches. The rules to derive this path is explained below. * * An operation can be cancelled/undone by inserting a new branch below * this operation. * e.g * Given the branch A B C * To undo B, a new branching branch is inserted at operation B. * ```txt * A B C D * > C' D' * ``` * A new execution path can now be derived. At each operation: * - if there is a lower branch, don't execute it and go to the operation below * - if not, execute it and go to the operation on the right. * The execution path is A C' D' * Operation C and D have been adapted (transformed) in the lower branch * since operation B is not executed in this branch. * */ export declare class Tree<T = unknown> { private readonly buildTransformation; private readonly branches; private branchingOperationIds; constructor(buildTransformation: TransformationFactory<T>, initialBranch: Branch<T>); /** * Return the last branch of the entire stack of branches. */ getLastBranch(): Branch<T>; /** * Return the sequence of operations from this branch * until the very last branch. */ execution(branch: Branch<T>): OperationSequence<T>; /** * Return the sequence of operations from this branch * to the very first branch. */ revertedExecution(branch: Branch<T>): OperationSequence<T>; /** * Append an operation to the end of the tree. * Also insert the (transformed) operation in all previous branches. * * Adding operation `D` to the last branch * ```txt * A1 B1 C1 * > B2 C2 * ``` * will give * ```txt * A1 B1 C1 D' with D' = D transformed with A1 * > B2 C2 D * ``` */ insertOperationLast(branch: Branch<T>, operation: Operation<T>): void; /** * Insert a new operation after an other operation. * The operation will be inserted in this branch, in next branches (transformed) * and in previous branches (also transformed). * * Given * ```txt * 1: A1 B1 C1 * 2: > B2 C2 * 3: > C3 * ``` * Inserting D to branch 2 gives * ```txt * 1: A1 B1 C1 D1 D1 = D transformed with A1 * 2: > B2 C2 D with D = D * 3: > C3 D2 D2 = D transformed without B2 (B2⁻¹) * ``` */ insertOperationAfter(branch: Branch<T>, operation: Operation<T>, predecessorOpId: UID): void; /** * Create a new branching branch at the given operation. * This cancels the operation from the execution path. */ undo(branch: Branch<T>, operation: Operation<T>): void; /** * Remove the branch just after this one. This un-cancels (redo) the branching * operation. Lower branches will be transformed accordingly. * * Given * ```txt * 1: A1 B1 C1 * 2: > B2 C2 * 3: > C3 * ``` * removing the next branch of 1 gives * * ```txt * 1: A1 B1 C1 * 2: > C3' with C3' = C1 transformed without B1 (B1⁻¹) * ``` */ redo(branch: Branch<T>): void; /** * Drop the operation and all following operations in every * branches */ drop(operationId: UID): void; /** * Find the operation in the execution path. */ findOperation(branch: Branch<T>, operationId: UID): OperationSequenceNode<T>; /** * Rebuild transformed operations of this branch based on the upper branch. * * Given the following structure: * ```txt * 1: A1 B1 C1 * 2: > B2 C2 * 3: > C3 * ``` * Rebasing branch "2" gives * ```txt * 1: A1 B1 C1 * 2: > B2' C2' With B2' = B1 transformed without A1 and C2' = C1 transformed without A1 * 3: > C3' C3' = C2' transformed without B2' * ``` */ private rebaseUp; private removeBranchFromTree; private insertBranchAfter; /** * Update the branching branch of this branch, either by (1) inserting the new * operation in it or (2) by transforming it. * (1) If the operation is positioned before the branching branch, the branching * branch should be transformed with this operation. * (2) If it's positioned after, the operation should be inserted in the * branching branch. */ private updateNextWith; private addToNextBranch; private getTransformedOperation; /** * Check if this branch should execute the given operation. * i.e. If the operation is not cancelled by a branching branch. */ private shouldExecute; private transform; /** * Insert a new operation in previous branches. The operations which are * positioned after the inserted operations are transformed with the newly * inserted operations. This one is also transformed, with the branching * operation. */ private insertPrevious; private findPreviousBranchingOperation; /** * Retrieve the next branch of the given branch */ private nextBranch; /** * Retrieve the previous branch of the given branch */ private previousBranch; /** * Yields the sequence of operations to execute, in reverse order. */ private _revertedExecution; /** * Yields the sequence of operations to execute */ private _execution; }