Files
2025-11-04 05:03:50 +08:00

119 lines
4.0 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ObjectCursor = void 0;
const optional_1 = require("../../types/optional");
const clone_1 = require("../../util/clone");
const key_path_1 = require("./key-path");
const traverse_1 = require("./traverse");
class ObjectCursor {
/**
* Create a cursor for an object.
*
* @param root - An object to traverse.
*/
constructor(root) {
this.values = [root];
this.keyPaths = [key_path_1.thisKeyPath];
this.savedDepths = [];
}
/**
* The current value this cursor is pointing at.
*/
get currentValue() {
return this.values[this.values.length - 1];
}
/**
* The key path of the value this cursor is pointing at.
*/
get currentKeyPath() {
return this.keyPaths[this.keyPaths.length - 1];
}
/**
* Advance this cursor to a given value and the key path which
* was used to reach it.
*
* Use this method to override the internal traversal logic of
* the cursor as needed. Like `moveTo`, calls to this method can
* be balanced with calls to `back`.
*
* @param value - The new value for the cursor to represent.
* @param keyPath - The key path used to reach the value.
*/
interject(value, keyPath) {
this.values.push(value);
this.keyPaths.push(keyPath);
}
/**
* Reconfigure this cursor to traverse a given object.
*
* @param newRoot - The new root object to traverse.
* @param keyPath - The key path specifying where the root object came from.
* Typically this should be `thisKeyPath` (the default value for this parameter.)
*/
reuse(newRoot, keyPath = key_path_1.thisKeyPath) {
this.values.length = 0;
this.values.push(newRoot);
this.keyPaths.length = 0;
this.keyPaths.push(keyPath);
this.savedDepths.length = 0;
}
/**
* Advance this cursor to a new position in the object it is traversing,
* saving its previous position so that the cursor may be moved back.
*
* @param keyPath - A key path referring to a location in the cursor's current value.
* @returns The new current value of the cursor.
*/
moveTo(keyPath) {
const newValue = (0, traverse_1.traverse)(this.currentValue, keyPath);
this.values.push(newValue);
this.keyPaths.push(keyPath);
return newValue;
}
/**
* Rewind this cursor to its previous position in the object it is traversing.
*/
moveBack() {
const currentDepth = this.values.length;
if (currentDepth === 1) {
throw new Error("Cannot move back past the root of a cursor");
}
const numberOfSaves = this.savedDepths.length;
if (numberOfSaves > 0 && currentDepth <= this.savedDepths[numberOfSaves - 1]) {
throw new Error("Cannot move back past the most recent saved state");
}
this.values.pop();
this.keyPaths.pop();
}
/**
* Save the current position of this cursor so that it may be restored later.
*
* Calls to this method must be balanced with a call to `restoreState`.
*/
saveState() {
this.savedDepths.push(this.values.length);
}
/**
* Restore this cursor's position to a previously saved state.
*
* Use this method to balance a previous call to `saveState`.
*/
restoreState() {
const savedLength = this.savedDepths.pop();
if ((0, optional_1.isNothing)(savedLength)) {
throw new Error("Calls to restoreState must balance previous calls to saveState");
}
this.values.length = savedLength;
this.keyPaths.length = savedLength;
}
// section Cloneable
clone() {
const copy = (0, clone_1.shallowCloneOf)(this);
copy.values = this.values.slice();
copy.keyPaths = this.keyPaths.slice();
copy.savedDepths = this.savedDepths.slice();
return copy;
}
}
exports.ObjectCursor = ObjectCursor;
//# sourceMappingURL=object-cursor.js.map