hexo/node_modules/@selderee/plugin-htmlparser2/lib/hp2-builder.mjs

91 lines
2.8 KiB
JavaScript

import { isTag } from 'domhandler';
import { Picker } from 'selderee';
function hp2Builder(nodes) {
return new Picker(handleArray(nodes));
}
function handleArray(nodes) {
const matchers = nodes.map(handleNode);
return (el, ...tail) => matchers.flatMap(m => m(el, ...tail));
}
function handleNode(node) {
switch (node.type) {
case 'terminal': {
const result = [node.valueContainer];
return (el, ...tail) => result;
}
case 'tagName':
return handleTagName(node);
case 'attrValue':
return handleAttrValueName(node);
case 'attrPresence':
return handleAttrPresenceName(node);
case 'pushElement':
return handlePushElementNode(node);
case 'popElement':
return handlePopElementNode(node);
}
}
function handleTagName(node) {
const variants = {};
for (const variant of node.variants) {
variants[variant.value] = handleArray(variant.cont);
}
return (el, ...tail) => {
const continuation = variants[el.name];
return (continuation) ? continuation(el, ...tail) : [];
};
}
function handleAttrPresenceName(node) {
const attrName = node.name;
const continuation = handleArray(node.cont);
return (el, ...tail) => (Object.prototype.hasOwnProperty.call(el.attribs, attrName))
? continuation(el, ...tail)
: [];
}
function handleAttrValueName(node) {
const callbacks = [];
for (const matcher of node.matchers) {
const predicate = matcher.predicate;
const continuation = handleArray(matcher.cont);
callbacks.push((attr, el, ...tail) => (predicate(attr) ? continuation(el, ...tail) : []));
}
const attrName = node.name;
return (el, ...tail) => {
const attr = el.attribs[attrName];
return (attr || attr === '')
? callbacks.flatMap(cb => cb(attr, el, ...tail))
: [];
};
}
function handlePushElementNode(node) {
const continuation = handleArray(node.cont);
const leftElementGetter = (node.combinator === '+')
? getPrecedingElement
: getParentElement;
return (el, ...tail) => {
const next = leftElementGetter(el);
if (next === null) {
return [];
}
return continuation(next, el, ...tail);
};
}
const getPrecedingElement = (el) => {
const prev = el.prev;
if (prev === null) {
return null;
}
return (isTag(prev)) ? prev : getPrecedingElement(prev);
};
const getParentElement = (el) => {
const parent = el.parent;
return (parent && isTag(parent)) ? parent : null;
};
function handlePopElementNode(node) {
const continuation = handleArray(node.cont);
return (el, next, ...tail) => continuation(next, ...tail);
}
export { hp2Builder };