UNPKG

dom5

Version:
184 lines (161 loc) 4.52 kB
/** * @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 {ASTNode as Node} from 'parse5'; import {getAttribute, getAttributeIndex, getTextContent} from './util'; export {ASTNode as Node} from 'parse5'; /** * Match the text inside an element, textnode, or comment * * Note: nodeWalkAll with hasTextValue may return an textnode and its parent if * the textnode is the only child in that parent. */ function hasTextValue(value: string): Predicate { return function(node) { return getTextContent(node) === value; }; } export type Predicate = (node: Node) => boolean; /** * OR an array of predicates */ function OR(...predicates: Predicate[]): Predicate; function OR(/* ...rules */): Predicate { const rules = new Array<Predicate>(arguments.length); for (let i = 0; i < arguments.length; i++) { rules[i] = arguments[i]; } return function(node) { for (let i = 0; i < rules.length; i++) { if (rules[i](node)) { return true; } } return false; }; } /** * AND an array of predicates */ function AND(...predicates: Predicate[]): Predicate; function AND(/* ...rules */): Predicate { const rules = new Array<Predicate>(arguments.length); for (let i = 0; i < arguments.length; i++) { rules[i] = arguments[i]; } return function(node) { for (let i = 0; i < rules.length; i++) { if (!rules[i](node)) { return false; } } return true; }; } /** * negate an individual predicate, or a group with AND or OR */ function NOT(predicateFn: Predicate): Predicate { return function(node) { return !predicateFn(node); }; } /** * Returns a predicate that matches any node with a parent matching * `predicateFn`. */ function parentMatches(predicateFn: Predicate): Predicate { return function(node) { let parent = node.parentNode; while (parent !== undefined) { if (predicateFn(parent)) { return true; } parent = parent.parentNode; } return false; }; } function hasAttr(attr: string): Predicate { return function(node) { return getAttributeIndex(node, attr) > -1; }; } function hasAttrValue(attr: string, value: string): Predicate { return function(node) { return getAttribute(node, attr) === value; }; } function hasClass(name: string): Predicate { return hasSpaceSeparatedAttrValue('class', name); } function hasTagName(name: string): Predicate { const n = name.toLowerCase(); return function(node) { if (!node.tagName) { return false; } return node.tagName.toLowerCase() === n; }; } /** * Returns true if `regex.match(tagName)` finds a match. * * This will use the lowercased tagName for comparison. */ function hasMatchingTagName(regex: RegExp): Predicate { return function(node) { if (!node.tagName) { return false; } return regex.test(node.tagName.toLowerCase()); }; } export function hasSpaceSeparatedAttrValue( name: string, value: string): Predicate { return function(element: Node) { const attributeValue = getAttribute(element, name); if (typeof attributeValue !== 'string') { return false; } return attributeValue.split(' ').indexOf(value) !== -1; }; } export function isDocument(node: Node): boolean { return node.nodeName === '#document'; } export function isDocumentFragment(node: Node): boolean { return node.nodeName === '#document-fragment'; } export function isElement(node: Node): boolean { return node.nodeName === node.tagName; } export function isTextNode(node: Node): boolean { return node.nodeName === '#text'; } export function isCommentNode(node: Node): boolean { return node.nodeName === '#comment'; } export const predicates = { hasClass: hasClass, hasAttr: hasAttr, hasAttrValue: hasAttrValue, hasMatchingTagName: hasMatchingTagName, hasSpaceSeparatedAttrValue: hasSpaceSeparatedAttrValue, hasTagName: hasTagName, hasTextValue: hasTextValue, AND: AND, OR: OR, NOT: NOT, parentMatches: parentMatches, };