summaryrefslogtreecommitdiff
path: root/node_modules/@jet/environment/json/reader/object-reader.js
diff options
context:
space:
mode:
authorrxliuli <rxliuli@gmail.com>2025-11-04 05:03:50 +0800
committerrxliuli <rxliuli@gmail.com>2025-11-04 05:03:50 +0800
commitbce557cc2dc767628bed6aac87301a1be7c5431b (patch)
treeb51a051228d01fe3306cd7626d4a96768aadb944 /node_modules/@jet/environment/json/reader/object-reader.js
init commit
Diffstat (limited to 'node_modules/@jet/environment/json/reader/object-reader.js')
-rw-r--r--node_modules/@jet/environment/json/reader/object-reader.js428
1 files changed, 428 insertions, 0 deletions
diff --git a/node_modules/@jet/environment/json/reader/object-reader.js b/node_modules/@jet/environment/json/reader/object-reader.js
new file mode 100644
index 0000000..f31a222
--- /dev/null
+++ b/node_modules/@jet/environment/json/reader/object-reader.js
@@ -0,0 +1,428 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.ObjectReader = void 0;
+const optional_1 = require("../../types/optional");
+const clone_1 = require("../../util/clone");
+const coercion_1 = require("./coercion");
+const key_path_1 = require("./key-path");
+const object_cursor_1 = require("./object-cursor");
+const traverse_1 = require("./traverse");
+/* eslint-disable no-underscore-dangle */
+/**
+ * Map which holds any object readers recycled, divided by constructor.
+ */
+// eslint-disable-next-line @typescript-eslint/ban-types
+const scrapReaders = new Map();
+/**
+ * A type which allows efficient and type-safe traversal of untyped objects.
+ */
+class ObjectReader {
+ /**
+ * Create a reader to traverse the contents of an untyped
+ * object safely and efficiently.
+ *
+ * @param object - An object to efficiently traverse with a reader.
+ */
+ constructor(object) {
+ this._cursor = new object_cursor_1.ObjectCursor(object);
+ }
+ // endsection
+ // section Structure
+ /**
+ * Current key path which operations on this reader are relative to.
+ */
+ get currentKeyPath() {
+ return this._cursor.currentKeyPath;
+ }
+ /**
+ * Determines whether a value exists for a given key
+ * relative to the reader's current location.
+ *
+ * @param key - The key to test for the existence of.
+ * @returns `true` if a value exists for `key`; `false` otherwise.
+ */
+ has(key) {
+ return (0, key_path_1.keyPathEndsWith)(this._cursor.currentKeyPath, key) || (0, optional_1.isSome)(this.get(key));
+ }
+ /**
+ * Make all operations on this reader be relative to a given key path.
+ *
+ * Consecutive calls to `select` with the same key path are idempotent.
+ * You may repeatedly call this method with the same key path and only
+ * the first call will change what operations are relative to on this reader.
+ *
+ * To allow repeated paths in consecutive `select` calls set the optional
+ * `allowRepeatedKeyPath` argument to `true`.
+ *
+ * You must balance calls to this method with matching calls to `deselect`.
+ *
+ * @param keyPath - The key path to make this reader's operations relative to.
+ * @param allowRepeatedKeyPath - The Boolean indicating whether repeated key path
+ * like 'value.value' should be accepted by the reader.
+ * Some JSON objects can have nested properties stored under the same key path.
+ * @returns The reader this method was called on.
+ */
+ select(keyPath, allowRepeatedKeyPath = false) {
+ if (allowRepeatedKeyPath || !(0, key_path_1.keyPathsEqual)(this._cursor.currentKeyPath, keyPath)) {
+ this._cursor.moveTo(keyPath);
+ }
+ return this;
+ }
+ /**
+ * Make all operations on this reader be relative to the previously selected key path.
+ *
+ * If no key path was previously selected, this method has the effect of making
+ * operations relative to the media response the reader was created to work on.
+ *
+ * Use this method to balance previous calls to a method in the `select` family.
+ *
+ * @returns The reader this method was called on.
+ */
+ deselect() {
+ this._cursor.moveBack();
+ return this;
+ }
+ /**
+ * Save the current selection of this reader so that it can be restored later.
+ *
+ * Calls to this method should be balanced with a call to `restoreSelection`.
+ */
+ saveSelection() {
+ this._cursor.saveState();
+ return this;
+ }
+ /**
+ * Restore a previous selection of this reader.
+ *
+ * Use this method to balance a previous call to `saveSelection`.
+ */
+ restoreSelection() {
+ this._cursor.restoreState();
+ return this;
+ }
+ // endsection
+ // section Scalars
+ /**
+ * Access an untyped value in this reader's contents.
+ *
+ * @param keyPath - A key path specifying where to find the value in this reader's contents.
+ * @returns An optional untyped value.
+ */
+ get(keyPath = key_path_1.thisKeyPath) {
+ if ((0, key_path_1.isKeyPathThis)(keyPath)) {
+ return this._cursor.currentValue;
+ }
+ else {
+ return (0, traverse_1.traverse)(this._cursor.currentValue, keyPath);
+ }
+ }
+ /**
+ * Access a boolean value in this reader's contents.
+ *
+ * @param keyPath - A key path specifying where to find the value in this reader's contents.
+ * @returns An optional boolean value.
+ */
+ asBoolean(keyPath = key_path_1.thisKeyPath, policy = "coercible") {
+ return (0, coercion_1.valueAsBoolean)(this.get(keyPath), policy, String(keyPath));
+ }
+ /**
+ * Access a number value in this reader's contents.
+ *
+ * @param keyPath - A key path specifying where to find the value in this reader's contents.
+ * @returns An optional number value.
+ */
+ asNumber(keyPath = key_path_1.thisKeyPath, policy = "coercible") {
+ return (0, coercion_1.valueAsNumber)(this.get(keyPath), policy, String(keyPath));
+ }
+ /**
+ * Access a string value in this reader's contents.
+ *
+ * @param keyPath - A key path specifying where to find the value in this reader's contents.
+ * @returns An optional string value.
+ */
+ asString(keyPath = key_path_1.thisKeyPath, policy = "coercible") {
+ return (0, coercion_1.valueAsString)(this.get(keyPath), policy, String(keyPath));
+ }
+ // endsection
+ // section Sequences
+ /**
+ * Create an iterator for the contents of this reader.
+ *
+ * If the current reader's contents are `undefined` or `null`,
+ * the returned iterator yields nothing.
+ *
+ * If the current reader's contents is an array, the returned
+ * iterator will yield a reader for each element in that array.
+ *
+ * Otherwise, the iterator will yield a single reader for
+ * the current reader's contents.
+ *
+ * __Important:__ The readers yielded by this iterator must not
+ * be allowed to escape your `for`-loop. For efficiency, readers
+ * may be reused.
+ *
+ * An iterator consumer (`for...of` loop) may safely call select
+ * methods on the reader without balancing them with deselect
+ * calls before the getting the next reader from the iterator.
+ */
+ *[Symbol.iterator]() {
+ const iteratee = this.get();
+ if ((0, optional_1.isNothing)(iteratee)) {
+ return;
+ }
+ const iterationReader = ObjectReader._clone(this);
+ if (Array.isArray(iteratee)) {
+ let index = 0;
+ for (const value of iteratee) {
+ iterationReader.saveSelection();
+ iterationReader._cursor.interject(value, index);
+ yield iterationReader;
+ iterationReader.restoreSelection();
+ index += 1;
+ }
+ }
+ else {
+ yield iterationReader;
+ }
+ ObjectReader._recycle(iterationReader);
+ }
+ /**
+ * Returns the result of combining the contents of this reader
+ * using a given function.
+ *
+ * If the current reader's contents are `undefined` or `null`,
+ * the `initialValue` is returned unchanged.
+ *
+ * If the current reader's contents is an array, the `reducer`
+ * will be called with a reader for each element in that array.
+ *
+ * Otherwise, the `reducer` function will be called once with
+ * a reader for the current reader's contents.
+ *
+ * __Important:__ The `reducer` function must not allow the passed in
+ * reader to escape its body. For efficiency, readers may be reused.
+ * The function may safely perform call select methods without balancing
+ * them with matching deselect calls.
+ *
+ * @param initialValue - The value to use as the initial accumulating value.
+ * @param reducer - A function that combines an accumulating value and an element from this reader's contents
+ * into a new accumulating value, to be used in the next call of this function or returned to the caller.
+ */
+ reduce(initialValue, reducer) {
+ const iteratee = this.get();
+ if ((0, optional_1.isNothing)(iteratee)) {
+ return initialValue;
+ }
+ if (Array.isArray(iteratee)) {
+ try {
+ let value = initialValue;
+ for (let index = 0, length = iteratee.length; index < length; index += 1) {
+ this.saveSelection();
+ this._cursor.interject(iteratee[index], index);
+ value = reducer(value, this);
+ this.restoreSelection();
+ }
+ return value;
+ }
+ catch (e) {
+ this.restoreSelection();
+ throw e;
+ }
+ }
+ else {
+ return reducer(initialValue, this);
+ }
+ }
+ /**
+ * Create an array by applying a function to the contents of this reader.
+ *
+ * If the current reader's contents are `undefined` or `null`,
+ * an empty array will be returned without calling `transformer`.
+ *
+ * If the current reader's contents is an array, the function will
+ * be called with a reader for each element from that array.
+ *
+ * Otherwise, the function will be called once with a reader for
+ * the current reader's contents.
+ *
+ * __Important:__ The function must not allow the passed in reader
+ * to escape its body. For efficiency, readers may be reused.
+ * The function may safely perform call select methods without balancing
+ * them with matching deselect calls.
+ *
+ * @param transformer - A function which derives a value from a reader.
+ * @returns An array containing the accumulated results of calling `transformer`.
+ */
+ map(transformer) {
+ return this.reduce(new Array(), (acc, reader) => {
+ acc.push(transformer(reader));
+ return acc;
+ });
+ }
+ /**
+ * Create an array by applying a function to the contents of this reader,
+ * discarding `undefined` and `null` values returned by the function.
+ *
+ * If the current reader's contents are `undefined` or `null`,
+ * an empty array will be returned without calling `transformer`.
+ *
+ * If the current reader's contents is an array, the function will
+ * be called with a reader for each element from that array.
+ *
+ * Otherwise, the function will be called once with a reader for
+ * the current reader's contents.
+ *
+ * __Important:__ The function must not allow the passed in reader
+ * to escape its body. For efficiency, readers may be reused.
+ * The function may safely perform call select methods without balancing
+ * them with matching deselect calls.
+ *
+ * @param transformer - A function which derives a value from a reader,
+ * or returns a nully value if none can be derived.
+ * @returns An array containing the accumulated results of calling `transformer`.
+ */
+ compactMap(transformer) {
+ return this.reduce(new Array(), (acc, reader) => {
+ const value = transformer(reader);
+ if ((0, optional_1.isSome)(value)) {
+ acc.push(value);
+ }
+ return acc;
+ });
+ }
+ // endsection
+ // section Builders
+ /**
+ * Call a function with this reader and any number of additional parameters,
+ * rolling back any reader selection changes the function makes.
+ *
+ * Use this method to work with closures and top level functions which use
+ * an object reader to do work. Prefer `#callOn` for object methods.
+ *
+ * @param body - A function which takes a reader and any number of additional parameters.
+ * @param rest - The parameters to pass to `body` after this reader.
+ * @returns The result of `body`, if any.
+ */
+ applyTo(body, ...rest) {
+ this.saveSelection();
+ try {
+ const result = body(this, ...rest);
+ this.restoreSelection();
+ return result;
+ }
+ catch (e) {
+ this.restoreSelection();
+ throw e;
+ }
+ }
+ /**
+ * Call an object method with this reader and any number of additional parameters,
+ * rolling back any reader selection changes the method makes.
+ *
+ * Use this method to work with object methods which use an object reader to do work.
+ * Prefer `#applyTo` for closures and top level functions.
+ *
+ * @param method - A method which takes a reader and any number of additional parameters.
+ * @param thisArg - The object to be used as the current object.
+ * @param rest - The parameters to pass to `method` after this reader.
+ * @returns The result of `method`, if any.
+ */
+ callOn(method, thisArg, ...rest) {
+ this.saveSelection();
+ try {
+ const result = method.call(thisArg, this, ...rest);
+ this.restoreSelection();
+ return result;
+ }
+ catch (e) {
+ this.restoreSelection();
+ throw e;
+ }
+ }
+ // endsection
+ // section Cloneable
+ clone() {
+ const copy = (0, clone_1.shallowCloneOf)(this);
+ copy._cursor = this._cursor.clone();
+ return copy;
+ }
+ // endsection
+ // section Reuse
+ /**
+ * Reduce allocations required when iterating with this object reader
+ * up to a specified depth.
+ *
+ * Each subclass of `ObjectReader` should call this method on itself
+ * after the module containing the subclass is loaded.
+ *
+ * @param depth - The expected iteration depth of this object reader type.
+ */
+ static optimizeIterationUpToDepth(depth) {
+ for (let index = 0; index < depth; index += 1) {
+ ObjectReader._recycle(new ObjectReader(undefined));
+ }
+ }
+ /**
+ * Clone a given object reader, reusing a previously created instance
+ * of the same constructor if one is available.
+ *
+ * @param reader - The object reader to efficiently clone.
+ * @returns A new reader which can be treated as clone of `reader`.
+ */
+ static _clone(reader) {
+ const scrap = scrapReaders.get(reader.constructor);
+ if ((0, optional_1.isSome)(scrap)) {
+ const reclaimedReader = scrap.pop();
+ if ((0, optional_1.isSome)(reclaimedReader)) {
+ reclaimedReader.onReuseToIterate(reader);
+ return reclaimedReader;
+ }
+ }
+ return reader.clone();
+ }
+ /**
+ * Informs an object reader it is about to be reused as the value
+ * of another object reader which is being treated as an iterator.
+ *
+ * Subclasses _must_ call `super` when overriding this method.
+ *
+ * @param other - The reader this instance is being used to assist.
+ */
+ onReuseToIterate(other) {
+ const cursorToMirror = other._cursor;
+ this._cursor.reuse(cursorToMirror.currentValue, cursorToMirror.currentKeyPath);
+ }
+ /**
+ * Recycle an object reader which was used as the value of another
+ * object reader being treated as an iterator.
+ *
+ * @param reader - A reader which was used for iteration and is no longer
+ * needed for that role.
+ */
+ static _recycle(reader) {
+ const ctor = reader.constructor;
+ const existingScrap = scrapReaders.get(ctor);
+ if ((0, optional_1.isSome)(existingScrap)) {
+ if (existingScrap.length >= 5) {
+ return;
+ }
+ reader.onRecycleForIteration();
+ existingScrap.push(reader);
+ }
+ else {
+ reader.onRecycleForIteration();
+ scrapReaders.set(ctor, [reader]);
+ }
+ }
+ /**
+ * Informs an object reader it is being recycled after being used as
+ * the value of another object reader which was treated as an iterator.
+ *
+ * Subclasses _must_ call `super` when overriding this method.
+ */
+ onRecycleForIteration() {
+ this._cursor.reuse(undefined);
+ }
+}
+exports.ObjectReader = ObjectReader;
+//# sourceMappingURL=object-reader.js.map \ No newline at end of file