From bce557cc2dc767628bed6aac87301a1be7c5431b Mon Sep 17 00:00:00 2001 From: rxliuli Date: Tue, 4 Nov 2025 05:03:50 +0800 Subject: init commit --- .../@jet/environment/json/reader/object-reader.js | 428 +++++++++++++++++++++ 1 file changed, 428 insertions(+) create mode 100644 node_modules/@jet/environment/json/reader/object-reader.js (limited to 'node_modules/@jet/environment/json/reader/object-reader.js') 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 -- cgit v1.2.3