UNPKG

@theia/core

Version:

Theia is a cloud & desktop IDE framework implemented in TypeScript.

221 lines • 7.67 kB
"use strict"; // ***************************************************************************** // Copyright (C) 2017 TypeFox and others. // // This program and the accompanying materials are made available under the // terms of the Eclipse Public License v. 2.0 which is available at // http://www.eclipse.org/legal/epl-2.0. // // This Source Code may also be made available under the following Secondary // Licenses when the conditions for such availability set forth in the Eclipse // Public License v. 2.0 are satisfied: GNU General Public License, version 2 // with the GNU Classpath Exception which is available at // https://www.gnu.org/software/classpath/license.html. // // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 // ***************************************************************************** Object.defineProperty(exports, "__esModule", { value: true }); exports.Iterators = exports.BottomUpTreeIterator = exports.TopDownTreeIterator = exports.BreadthFirstTreeIterator = exports.DepthFirstTreeIterator = exports.AbstractTreeIterator = exports.TreeIterator = void 0; const tree_1 = require("./tree"); const tree_expansion_1 = require("./tree-expansion"); var TreeIterator; (function (TreeIterator) { TreeIterator.DEFAULT_OPTIONS = { pruneCollapsed: false, pruneSiblings: false }; })(TreeIterator = exports.TreeIterator || (exports.TreeIterator = {})); class AbstractTreeIterator { constructor(root, options) { this.root = root; this.options = Object.assign(Object.assign({}, TreeIterator.DEFAULT_OPTIONS), options); this.delegate = this.iterator(this.root); } // tslint:disable-next-line:typedef [Symbol.iterator]() { return this.delegate; } next() { return this.delegate.next(); } children(node) { if (!tree_1.CompositeTreeNode.is(node)) { return undefined; } if (this.options.pruneCollapsed && this.isCollapsed(node)) { return undefined; } return node.children.slice(); } isCollapsed(node) { return tree_expansion_1.ExpandableTreeNode.isCollapsed(node); } isEmpty(nodes) { return nodes === undefined || nodes.length === 0; } } exports.AbstractTreeIterator = AbstractTreeIterator; class DepthFirstTreeIterator extends AbstractTreeIterator { iterator(root) { return Iterators.depthFirst(root, this.children.bind(this)); } } exports.DepthFirstTreeIterator = DepthFirstTreeIterator; class BreadthFirstTreeIterator extends AbstractTreeIterator { iterator(root) { return Iterators.breadthFirst(root, this.children.bind(this)); } } exports.BreadthFirstTreeIterator = BreadthFirstTreeIterator; /** * This tree iterator visits all nodes from top to bottom considering the following rules. * * Let assume the following tree: * ``` * R * | * +---1 * | | * | +---1.1 * | | * | +---1.2 * | | * | +---1.3 * | | | * | | +---1.3.1 * | | | * | | +---1.3.2 * | | * | +---1.4 * | * +---2 * | * +---2.1 * ``` * When selecting `1.2` as the root, the normal `DepthFirstTreeIterator` would stop on `1.2` as it does not have children, * but this iterator will visit the next sibling (`1.3` and `1.4` but **not** `1.1`) nodes. So the expected traversal order will be * `1.2`, `1.3`, `1.3.1`, `1.3.2`, and `1.4` then jumps to `2` and continues with `2.1`. */ class TopDownTreeIterator extends AbstractTreeIterator { iterator(root) { const doNext = this.doNext.bind(this); return (function* () { let next = root; while (next) { yield next; next = doNext(next); } }).bind(this)(); } doNext(node) { return this.findFirstChild(node) || this.findNextSibling(node); } findFirstChild(node) { return (this.children(node) || [])[0]; } findNextSibling(node) { if (!node) { return undefined; } if (this.options.pruneSiblings && node === this.root) { return undefined; } if (node.nextSibling) { return node.nextSibling; } return this.findNextSibling(node.parent); } } exports.TopDownTreeIterator = TopDownTreeIterator; /** * Unlike other tree iterators, this does not visit all the nodes, it stops once it reaches the root node * while traversing up the tree hierarchy in an inverse pre-order fashion. This is the counterpart of the `TopDownTreeIterator`. */ class BottomUpTreeIterator extends AbstractTreeIterator { iterator(root) { const doNext = this.doNext.bind(this); return (function* () { let next = root; while (next) { yield next; next = doNext(next); } }).bind(this)(); } doNext(node) { const previousSibling = node.previousSibling; const lastChild = this.lastChild(previousSibling); return lastChild || node.parent; } lastChild(node) { const children = node ? this.children(node) : []; if (this.isEmpty(children)) { return node; } if (tree_1.CompositeTreeNode.is(node)) { const lastChild = tree_1.CompositeTreeNode.getLastChild(node); return this.lastChild(lastChild); } return undefined; } } exports.BottomUpTreeIterator = BottomUpTreeIterator; var Iterators; (function (Iterators) { /** * Generator for depth first, pre-order tree traversal iteration. */ function* depthFirst(root, children, include = () => true) { const stack = []; stack.push(root); while (stack.length > 0) { const top = stack.pop(); yield top; stack.push(...(children(top) || []).filter(include).reverse()); } } Iterators.depthFirst = depthFirst; /** * Generator for breadth first tree traversal iteration. */ function* breadthFirst(root, children, include = () => true) { const queue = []; queue.push(root); while (queue.length > 0) { const head = queue.shift(); yield head; queue.push(...(children(head) || []).filter(include)); } } Iterators.breadthFirst = breadthFirst; /** * Returns with the iterator of the argument. */ function asIterator(elements) { return elements.slice()[Symbol.iterator](); } Iterators.asIterator = asIterator; /** * Returns an iterator that cycles indefinitely over the elements of iterable. * - If `start` is given it starts the iteration from that element. Otherwise, it starts with the first element of the array. * - If `start` is given, it must contain by the `elements` array. Otherwise, an error will be thrown. * * **Warning**: Typical uses of the resulting iterator may produce an infinite loop. You should use an explicit break. */ function* cycle(elements, start) { const copy = elements.slice(); let index = !!start ? copy.indexOf(start) : 0; if (index === -1) { throw new Error(`${start} is not contained in ${copy}.`); } while (true) { yield copy[index]; index++; if (index === copy.length) { index = 0; } } } Iterators.cycle = cycle; })(Iterators = exports.Iterators || (exports.Iterators = {})); //# sourceMappingURL=tree-iterator.js.map