@web/dev-server-core
Version:
140 lines (127 loc) • 4.12 kB
text/typescript
/**
* @license
* Copyright (c) 2018 The Polymer Project Authors. All rights reserved.
* This code may only be used under the BSD style license found at
* http://polymer.github.io/LICENSE.txt
* The complete set of authors may be found at
* http://polymer.github.io/AUTHORS.txt
* The complete set of contributors may be found at
* http://polymer.github.io/CONTRIBUTORS.txt
* Code distributed by Google as part of the polymer project is also
* subject to an additional IP rights grant found at
* http://polymer.github.io/PATENTS.txt
*/
import * as iteration from './iteration.js';
import { isElement, Predicate, predicates as p } from './predicates.js';
import { defaultChildNodes, GetChildNodes } from './util.js';
/**
* Applies `mapfn` to `node` and the tree below `node`, returning a flattened
* list of results.
*/
export function treeMap<U>(node: Node, mapfn: (node: Node) => U[]): U[] {
return Array.from(iteration.treeMap(node, mapfn));
}
function find<U>(iter: Iterable<U>, predicate: (u: U) => boolean) {
for (const value of iter) {
if (predicate(value)) {
return value;
}
}
return null;
}
function filter<U>(iter: Iterable<U>, predicate: (u: U) => boolean, matches: U[] = []) {
for (const value of iter) {
if (predicate(value)) {
matches.push(value);
}
}
return matches;
}
/**
* Walk the tree down from `node`, applying the `predicate` function.
* Return the first node that matches the given predicate.
*
* @returns `null` if no node matches, parse5 node object if a node matches.
*/
export function nodeWalk(
node: Node,
predicate: Predicate,
getChildNodes: GetChildNodes = defaultChildNodes,
): Node | null {
return find(iteration.depthFirst(node, getChildNodes), predicate);
}
/**
* Walk the tree down from `node`, applying the `predicate` function.
* All nodes matching the predicate function from `node` to leaves will be
* returned.
*/
export function nodeWalkAll(
node: Node,
predicate: Predicate,
matches?: Node[],
getChildNodes: GetChildNodes = defaultChildNodes,
): Node[] {
return filter(iteration.depthFirst(node, getChildNodes), predicate, matches);
}
/**
* Equivalent to `nodeWalk`, but only returns nodes that are either
* ancestors or earlier siblings in the document.
*
* Nodes are searched in reverse document order, starting from the sibling
* prior to `node`.
*/
export function nodeWalkPrior(node: Node, predicate: Predicate): Node | undefined {
const result = find(iteration.prior(node), predicate);
if (result === null) {
return undefined;
}
return result;
}
function* iteratePriorIncludingNode(node: Node) {
yield node;
yield* iteration.prior(node);
}
/**
* Equivalent to `nodeWalkAll`, but only returns nodes that are either
* ancestors or earlier cousins/siblings in the document.
*
* Nodes are returned in reverse document order, starting from `node`.
*/
export function nodeWalkAllPrior(node: Node, predicate: Predicate, matches?: Node[]): Node[] {
return filter(iteratePriorIncludingNode(node), predicate, matches);
}
/**
* Walk the tree up from the parent of `node`, to its grandparent and so on to
* the root of the tree. Return the first ancestor that matches the given
* predicate.
*/
export function nodeWalkAncestors(node: Node, predicate: Predicate): Node | undefined {
const result = find(iteration.ancestors(node), predicate);
if (result === null) {
return undefined;
}
return result;
}
/**
* Equivalent to `nodeWalk`, but only matches elements
*/
export function query(
node: any,
predicate: Predicate,
getChildNodes: GetChildNodes = defaultChildNodes,
): any | null {
const elementPredicate = p.AND(isElement, predicate);
return nodeWalk(node, elementPredicate, getChildNodes);
}
/**
* Equivalent to `nodeWalkAll`, but only matches elements
*/
export function queryAll(
node: any,
predicate: Predicate,
matches?: Node[],
getChildNodes: GetChildNodes = defaultChildNodes,
): any[] {
const elementPredicate = p.AND(isElement, predicate);
return nodeWalkAll(node, elementPredicate, matches, getChildNodes);
}