| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 | import { createNode } from '../doc/createNode.js';import { isNode, isPair, isCollection, isScalar } from './identity.js';import { NodeBase } from './Node.js';function collectionFromPath(schema, path, value) {    let v = value;    for (let i = path.length - 1; i >= 0; --i) {        const k = path[i];        if (typeof k === 'number' && Number.isInteger(k) && k >= 0) {            const a = [];            a[k] = v;            v = a;        }        else {            v = new Map([[k, v]]);        }    }    return createNode(v, undefined, {        aliasDuplicateObjects: false,        keepUndefined: false,        onAnchor: () => {            throw new Error('This should not happen, please report a bug.');        },        schema,        sourceObjects: new Map()    });}// Type guard is intentionally a little wrong so as to be more useful,// as it does not cover untypable empty non-string iterables (e.g. []).const isEmptyPath = (path) => path == null ||    (typeof path === 'object' && !!path[Symbol.iterator]().next().done);class Collection extends NodeBase {    constructor(type, schema) {        super(type);        Object.defineProperty(this, 'schema', {            value: schema,            configurable: true,            enumerable: false,            writable: true        });    }    /**     * Create a copy of this collection.     *     * @param schema - If defined, overwrites the original's schema     */    clone(schema) {        const copy = Object.create(Object.getPrototypeOf(this), Object.getOwnPropertyDescriptors(this));        if (schema)            copy.schema = schema;        copy.items = copy.items.map(it => isNode(it) || isPair(it) ? it.clone(schema) : it);        if (this.range)            copy.range = this.range.slice();        return copy;    }    /**     * Adds a value to the collection. For `!!map` and `!!omap` the value must     * be a Pair instance or a `{ key, value }` object, which may not have a key     * that already exists in the map.     */    addIn(path, value) {        if (isEmptyPath(path))            this.add(value);        else {            const [key, ...rest] = path;            const node = this.get(key, true);            if (isCollection(node))                node.addIn(rest, value);            else if (node === undefined && this.schema)                this.set(key, collectionFromPath(this.schema, rest, value));            else                throw new Error(`Expected YAML collection at ${key}. Remaining path: ${rest}`);        }    }    /**     * Removes a value from the collection.     * @returns `true` if the item was found and removed.     */    deleteIn(path) {        const [key, ...rest] = path;        if (rest.length === 0)            return this.delete(key);        const node = this.get(key, true);        if (isCollection(node))            return node.deleteIn(rest);        else            throw new Error(`Expected YAML collection at ${key}. Remaining path: ${rest}`);    }    /**     * Returns item at `key`, or `undefined` if not found. By default unwraps     * scalar values from their surrounding node; to disable set `keepScalar` to     * `true` (collections are always returned intact).     */    getIn(path, keepScalar) {        const [key, ...rest] = path;        const node = this.get(key, true);        if (rest.length === 0)            return !keepScalar && isScalar(node) ? node.value : node;        else            return isCollection(node) ? node.getIn(rest, keepScalar) : undefined;    }    hasAllNullValues(allowScalar) {        return this.items.every(node => {            if (!isPair(node))                return false;            const n = node.value;            return (n == null ||                (allowScalar &&                    isScalar(n) &&                    n.value == null &&                    !n.commentBefore &&                    !n.comment &&                    !n.tag));        });    }    /**     * Checks if the collection includes a value with the key `key`.     */    hasIn(path) {        const [key, ...rest] = path;        if (rest.length === 0)            return this.has(key);        const node = this.get(key, true);        return isCollection(node) ? node.hasIn(rest) : false;    }    /**     * Sets a value in this collection. For `!!set`, `value` needs to be a     * boolean to add/remove the item from the set.     */    setIn(path, value) {        const [key, ...rest] = path;        if (rest.length === 0) {            this.set(key, value);        }        else {            const node = this.get(key, true);            if (isCollection(node))                node.setIn(rest, value);            else if (node === undefined && this.schema)                this.set(key, collectionFromPath(this.schema, rest, value));            else                throw new Error(`Expected YAML collection at ${key}. Remaining path: ${rest}`);        }    }}Collection.maxFlowStringSingleLineLength = 60;export { Collection, collectionFromPath, isEmptyPath };
 |