6001 lines
210 KiB
JavaScript
6001 lines
210 KiB
JavaScript
|
|
import { walkTree } from "markmap-common";
|
|||
|
|
const defaultOpts$1 = {
|
|||
|
|
_useHtmlParser2: false
|
|||
|
|
};
|
|||
|
|
function flattenOptions(options, baseOptions) {
|
|||
|
|
if (!options) {
|
|||
|
|
return baseOptions !== null && baseOptions !== void 0 ? baseOptions : defaultOpts$1;
|
|||
|
|
}
|
|||
|
|
const opts = {
|
|||
|
|
_useHtmlParser2: !!options.xmlMode,
|
|||
|
|
...baseOptions,
|
|||
|
|
...options
|
|||
|
|
};
|
|||
|
|
if (options.xml) {
|
|||
|
|
opts._useHtmlParser2 = true;
|
|||
|
|
opts.xmlMode = true;
|
|||
|
|
if (options.xml !== true) {
|
|||
|
|
Object.assign(opts, options.xml);
|
|||
|
|
}
|
|||
|
|
} else if (options.xmlMode) {
|
|||
|
|
opts._useHtmlParser2 = true;
|
|||
|
|
}
|
|||
|
|
return opts;
|
|||
|
|
}
|
|||
|
|
var ElementType;
|
|||
|
|
(function(ElementType2) {
|
|||
|
|
ElementType2["Root"] = "root";
|
|||
|
|
ElementType2["Text"] = "text";
|
|||
|
|
ElementType2["Directive"] = "directive";
|
|||
|
|
ElementType2["Comment"] = "comment";
|
|||
|
|
ElementType2["Script"] = "script";
|
|||
|
|
ElementType2["Style"] = "style";
|
|||
|
|
ElementType2["Tag"] = "tag";
|
|||
|
|
ElementType2["CDATA"] = "cdata";
|
|||
|
|
ElementType2["Doctype"] = "doctype";
|
|||
|
|
})(ElementType || (ElementType = {}));
|
|||
|
|
function isTag$1(elem) {
|
|||
|
|
return elem.type === ElementType.Tag || elem.type === ElementType.Script || elem.type === ElementType.Style;
|
|||
|
|
}
|
|||
|
|
const Root = ElementType.Root;
|
|||
|
|
const Text$1 = ElementType.Text;
|
|||
|
|
const Directive = ElementType.Directive;
|
|||
|
|
const Comment$1 = ElementType.Comment;
|
|||
|
|
const Script = ElementType.Script;
|
|||
|
|
const Style = ElementType.Style;
|
|||
|
|
const Tag = ElementType.Tag;
|
|||
|
|
const CDATA$1 = ElementType.CDATA;
|
|||
|
|
const Doctype = ElementType.Doctype;
|
|||
|
|
class Node {
|
|||
|
|
constructor() {
|
|||
|
|
this.parent = null;
|
|||
|
|
this.prev = null;
|
|||
|
|
this.next = null;
|
|||
|
|
this.startIndex = null;
|
|||
|
|
this.endIndex = null;
|
|||
|
|
}
|
|||
|
|
// Read-write aliases for properties
|
|||
|
|
/**
|
|||
|
|
* Same as {@link parent}.
|
|||
|
|
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
|
|||
|
|
*/
|
|||
|
|
get parentNode() {
|
|||
|
|
return this.parent;
|
|||
|
|
}
|
|||
|
|
set parentNode(parent2) {
|
|||
|
|
this.parent = parent2;
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Same as {@link prev}.
|
|||
|
|
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
|
|||
|
|
*/
|
|||
|
|
get previousSibling() {
|
|||
|
|
return this.prev;
|
|||
|
|
}
|
|||
|
|
set previousSibling(prev2) {
|
|||
|
|
this.prev = prev2;
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Same as {@link next}.
|
|||
|
|
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
|
|||
|
|
*/
|
|||
|
|
get nextSibling() {
|
|||
|
|
return this.next;
|
|||
|
|
}
|
|||
|
|
set nextSibling(next2) {
|
|||
|
|
this.next = next2;
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Clone this node, and optionally its children.
|
|||
|
|
*
|
|||
|
|
* @param recursive Clone child nodes as well.
|
|||
|
|
* @returns A clone of the node.
|
|||
|
|
*/
|
|||
|
|
cloneNode(recursive = false) {
|
|||
|
|
return cloneNode(this, recursive);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
class DataNode extends Node {
|
|||
|
|
/**
|
|||
|
|
* @param data The content of the data node
|
|||
|
|
*/
|
|||
|
|
constructor(data2) {
|
|||
|
|
super();
|
|||
|
|
this.data = data2;
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Same as {@link data}.
|
|||
|
|
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
|
|||
|
|
*/
|
|||
|
|
get nodeValue() {
|
|||
|
|
return this.data;
|
|||
|
|
}
|
|||
|
|
set nodeValue(data2) {
|
|||
|
|
this.data = data2;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
class Text extends DataNode {
|
|||
|
|
constructor() {
|
|||
|
|
super(...arguments);
|
|||
|
|
this.type = ElementType.Text;
|
|||
|
|
}
|
|||
|
|
get nodeType() {
|
|||
|
|
return 3;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
class Comment extends DataNode {
|
|||
|
|
constructor() {
|
|||
|
|
super(...arguments);
|
|||
|
|
this.type = ElementType.Comment;
|
|||
|
|
}
|
|||
|
|
get nodeType() {
|
|||
|
|
return 8;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
class ProcessingInstruction extends DataNode {
|
|||
|
|
constructor(name, data2) {
|
|||
|
|
super(data2);
|
|||
|
|
this.name = name;
|
|||
|
|
this.type = ElementType.Directive;
|
|||
|
|
}
|
|||
|
|
get nodeType() {
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
class NodeWithChildren extends Node {
|
|||
|
|
/**
|
|||
|
|
* @param children Children of the node. Only certain node types can have children.
|
|||
|
|
*/
|
|||
|
|
constructor(children2) {
|
|||
|
|
super();
|
|||
|
|
this.children = children2;
|
|||
|
|
}
|
|||
|
|
// Aliases
|
|||
|
|
/** First child of the node. */
|
|||
|
|
get firstChild() {
|
|||
|
|
var _a2;
|
|||
|
|
return (_a2 = this.children[0]) !== null && _a2 !== void 0 ? _a2 : null;
|
|||
|
|
}
|
|||
|
|
/** Last child of the node. */
|
|||
|
|
get lastChild() {
|
|||
|
|
return this.children.length > 0 ? this.children[this.children.length - 1] : null;
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Same as {@link children}.
|
|||
|
|
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
|
|||
|
|
*/
|
|||
|
|
get childNodes() {
|
|||
|
|
return this.children;
|
|||
|
|
}
|
|||
|
|
set childNodes(children2) {
|
|||
|
|
this.children = children2;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
class CDATA extends NodeWithChildren {
|
|||
|
|
constructor() {
|
|||
|
|
super(...arguments);
|
|||
|
|
this.type = ElementType.CDATA;
|
|||
|
|
}
|
|||
|
|
get nodeType() {
|
|||
|
|
return 4;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
class Document extends NodeWithChildren {
|
|||
|
|
constructor() {
|
|||
|
|
super(...arguments);
|
|||
|
|
this.type = ElementType.Root;
|
|||
|
|
}
|
|||
|
|
get nodeType() {
|
|||
|
|
return 9;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
class Element extends NodeWithChildren {
|
|||
|
|
/**
|
|||
|
|
* @param name Name of the tag, eg. `div`, `span`.
|
|||
|
|
* @param attribs Object mapping attribute names to attribute values.
|
|||
|
|
* @param children Children of the node.
|
|||
|
|
*/
|
|||
|
|
constructor(name, attribs, children2 = [], type = name === "script" ? ElementType.Script : name === "style" ? ElementType.Style : ElementType.Tag) {
|
|||
|
|
super(children2);
|
|||
|
|
this.name = name;
|
|||
|
|
this.attribs = attribs;
|
|||
|
|
this.type = type;
|
|||
|
|
}
|
|||
|
|
get nodeType() {
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
// DOM Level 1 aliases
|
|||
|
|
/**
|
|||
|
|
* Same as {@link name}.
|
|||
|
|
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
|
|||
|
|
*/
|
|||
|
|
get tagName() {
|
|||
|
|
return this.name;
|
|||
|
|
}
|
|||
|
|
set tagName(name) {
|
|||
|
|
this.name = name;
|
|||
|
|
}
|
|||
|
|
get attributes() {
|
|||
|
|
return Object.keys(this.attribs).map((name) => {
|
|||
|
|
var _a2, _b;
|
|||
|
|
return {
|
|||
|
|
name,
|
|||
|
|
value: this.attribs[name],
|
|||
|
|
namespace: (_a2 = this["x-attribsNamespace"]) === null || _a2 === void 0 ? void 0 : _a2[name],
|
|||
|
|
prefix: (_b = this["x-attribsPrefix"]) === null || _b === void 0 ? void 0 : _b[name]
|
|||
|
|
};
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function isTag(node) {
|
|||
|
|
return isTag$1(node);
|
|||
|
|
}
|
|||
|
|
function isCDATA(node) {
|
|||
|
|
return node.type === ElementType.CDATA;
|
|||
|
|
}
|
|||
|
|
function isText(node) {
|
|||
|
|
return node.type === ElementType.Text;
|
|||
|
|
}
|
|||
|
|
function isComment(node) {
|
|||
|
|
return node.type === ElementType.Comment;
|
|||
|
|
}
|
|||
|
|
function isDirective(node) {
|
|||
|
|
return node.type === ElementType.Directive;
|
|||
|
|
}
|
|||
|
|
function isDocument(node) {
|
|||
|
|
return node.type === ElementType.Root;
|
|||
|
|
}
|
|||
|
|
function hasChildren(node) {
|
|||
|
|
return Object.prototype.hasOwnProperty.call(node, "children");
|
|||
|
|
}
|
|||
|
|
function cloneNode(node, recursive = false) {
|
|||
|
|
let result;
|
|||
|
|
if (isText(node)) {
|
|||
|
|
result = new Text(node.data);
|
|||
|
|
} else if (isComment(node)) {
|
|||
|
|
result = new Comment(node.data);
|
|||
|
|
} else if (isTag(node)) {
|
|||
|
|
const children2 = recursive ? cloneChildren(node.children) : [];
|
|||
|
|
const clone2 = new Element(node.name, { ...node.attribs }, children2);
|
|||
|
|
children2.forEach((child) => child.parent = clone2);
|
|||
|
|
if (node.namespace != null) {
|
|||
|
|
clone2.namespace = node.namespace;
|
|||
|
|
}
|
|||
|
|
if (node["x-attribsNamespace"]) {
|
|||
|
|
clone2["x-attribsNamespace"] = { ...node["x-attribsNamespace"] };
|
|||
|
|
}
|
|||
|
|
if (node["x-attribsPrefix"]) {
|
|||
|
|
clone2["x-attribsPrefix"] = { ...node["x-attribsPrefix"] };
|
|||
|
|
}
|
|||
|
|
result = clone2;
|
|||
|
|
} else if (isCDATA(node)) {
|
|||
|
|
const children2 = recursive ? cloneChildren(node.children) : [];
|
|||
|
|
const clone2 = new CDATA(children2);
|
|||
|
|
children2.forEach((child) => child.parent = clone2);
|
|||
|
|
result = clone2;
|
|||
|
|
} else if (isDocument(node)) {
|
|||
|
|
const children2 = recursive ? cloneChildren(node.children) : [];
|
|||
|
|
const clone2 = new Document(children2);
|
|||
|
|
children2.forEach((child) => child.parent = clone2);
|
|||
|
|
if (node["x-mode"]) {
|
|||
|
|
clone2["x-mode"] = node["x-mode"];
|
|||
|
|
}
|
|||
|
|
result = clone2;
|
|||
|
|
} else if (isDirective(node)) {
|
|||
|
|
const instruction = new ProcessingInstruction(node.name, node.data);
|
|||
|
|
if (node["x-name"] != null) {
|
|||
|
|
instruction["x-name"] = node["x-name"];
|
|||
|
|
instruction["x-publicId"] = node["x-publicId"];
|
|||
|
|
instruction["x-systemId"] = node["x-systemId"];
|
|||
|
|
}
|
|||
|
|
result = instruction;
|
|||
|
|
} else {
|
|||
|
|
throw new Error(`Not implemented yet: ${node.type}`);
|
|||
|
|
}
|
|||
|
|
result.startIndex = node.startIndex;
|
|||
|
|
result.endIndex = node.endIndex;
|
|||
|
|
if (node.sourceCodeLocation != null) {
|
|||
|
|
result.sourceCodeLocation = node.sourceCodeLocation;
|
|||
|
|
}
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
function cloneChildren(childs) {
|
|||
|
|
const children2 = childs.map((child) => cloneNode(child, true));
|
|||
|
|
for (let i = 1; i < children2.length; i++) {
|
|||
|
|
children2[i].prev = children2[i - 1];
|
|||
|
|
children2[i - 1].next = children2[i];
|
|||
|
|
}
|
|||
|
|
return children2;
|
|||
|
|
}
|
|||
|
|
const defaultOpts = {
|
|||
|
|
withStartIndices: false,
|
|||
|
|
withEndIndices: false,
|
|||
|
|
xmlMode: false
|
|||
|
|
};
|
|||
|
|
class DomHandler {
|
|||
|
|
/**
|
|||
|
|
* @param callback Called once parsing has completed.
|
|||
|
|
* @param options Settings for the handler.
|
|||
|
|
* @param elementCB Callback whenever a tag is closed.
|
|||
|
|
*/
|
|||
|
|
constructor(callback, options, elementCB) {
|
|||
|
|
this.dom = [];
|
|||
|
|
this.root = new Document(this.dom);
|
|||
|
|
this.done = false;
|
|||
|
|
this.tagStack = [this.root];
|
|||
|
|
this.lastNode = null;
|
|||
|
|
this.parser = null;
|
|||
|
|
if (typeof options === "function") {
|
|||
|
|
elementCB = options;
|
|||
|
|
options = defaultOpts;
|
|||
|
|
}
|
|||
|
|
if (typeof callback === "object") {
|
|||
|
|
options = callback;
|
|||
|
|
callback = void 0;
|
|||
|
|
}
|
|||
|
|
this.callback = callback !== null && callback !== void 0 ? callback : null;
|
|||
|
|
this.options = options !== null && options !== void 0 ? options : defaultOpts;
|
|||
|
|
this.elementCB = elementCB !== null && elementCB !== void 0 ? elementCB : null;
|
|||
|
|
}
|
|||
|
|
onparserinit(parser) {
|
|||
|
|
this.parser = parser;
|
|||
|
|
}
|
|||
|
|
// Resets the handler back to starting state
|
|||
|
|
onreset() {
|
|||
|
|
this.dom = [];
|
|||
|
|
this.root = new Document(this.dom);
|
|||
|
|
this.done = false;
|
|||
|
|
this.tagStack = [this.root];
|
|||
|
|
this.lastNode = null;
|
|||
|
|
this.parser = null;
|
|||
|
|
}
|
|||
|
|
// Signals the handler that parsing is done
|
|||
|
|
onend() {
|
|||
|
|
if (this.done)
|
|||
|
|
return;
|
|||
|
|
this.done = true;
|
|||
|
|
this.parser = null;
|
|||
|
|
this.handleCallback(null);
|
|||
|
|
}
|
|||
|
|
onerror(error) {
|
|||
|
|
this.handleCallback(error);
|
|||
|
|
}
|
|||
|
|
onclosetag() {
|
|||
|
|
this.lastNode = null;
|
|||
|
|
const elem = this.tagStack.pop();
|
|||
|
|
if (this.options.withEndIndices) {
|
|||
|
|
elem.endIndex = this.parser.endIndex;
|
|||
|
|
}
|
|||
|
|
if (this.elementCB)
|
|||
|
|
this.elementCB(elem);
|
|||
|
|
}
|
|||
|
|
onopentag(name, attribs) {
|
|||
|
|
const type = this.options.xmlMode ? ElementType.Tag : void 0;
|
|||
|
|
const element = new Element(name, attribs, void 0, type);
|
|||
|
|
this.addNode(element);
|
|||
|
|
this.tagStack.push(element);
|
|||
|
|
}
|
|||
|
|
ontext(data2) {
|
|||
|
|
const { lastNode } = this;
|
|||
|
|
if (lastNode && lastNode.type === ElementType.Text) {
|
|||
|
|
lastNode.data += data2;
|
|||
|
|
if (this.options.withEndIndices) {
|
|||
|
|
lastNode.endIndex = this.parser.endIndex;
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
const node = new Text(data2);
|
|||
|
|
this.addNode(node);
|
|||
|
|
this.lastNode = node;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
oncomment(data2) {
|
|||
|
|
if (this.lastNode && this.lastNode.type === ElementType.Comment) {
|
|||
|
|
this.lastNode.data += data2;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
const node = new Comment(data2);
|
|||
|
|
this.addNode(node);
|
|||
|
|
this.lastNode = node;
|
|||
|
|
}
|
|||
|
|
oncommentend() {
|
|||
|
|
this.lastNode = null;
|
|||
|
|
}
|
|||
|
|
oncdatastart() {
|
|||
|
|
const text2 = new Text("");
|
|||
|
|
const node = new CDATA([text2]);
|
|||
|
|
this.addNode(node);
|
|||
|
|
text2.parent = node;
|
|||
|
|
this.lastNode = text2;
|
|||
|
|
}
|
|||
|
|
oncdataend() {
|
|||
|
|
this.lastNode = null;
|
|||
|
|
}
|
|||
|
|
onprocessinginstruction(name, data2) {
|
|||
|
|
const node = new ProcessingInstruction(name, data2);
|
|||
|
|
this.addNode(node);
|
|||
|
|
}
|
|||
|
|
handleCallback(error) {
|
|||
|
|
if (typeof this.callback === "function") {
|
|||
|
|
this.callback(error, this.dom);
|
|||
|
|
} else if (error) {
|
|||
|
|
throw error;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
addNode(node) {
|
|||
|
|
const parent2 = this.tagStack[this.tagStack.length - 1];
|
|||
|
|
const previousSibling = parent2.children[parent2.children.length - 1];
|
|||
|
|
if (this.options.withStartIndices) {
|
|||
|
|
node.startIndex = this.parser.startIndex;
|
|||
|
|
}
|
|||
|
|
if (this.options.withEndIndices) {
|
|||
|
|
node.endIndex = this.parser.endIndex;
|
|||
|
|
}
|
|||
|
|
parent2.children.push(node);
|
|||
|
|
if (previousSibling) {
|
|||
|
|
node.prev = previousSibling;
|
|||
|
|
previousSibling.next = node;
|
|||
|
|
}
|
|||
|
|
node.parent = parent2;
|
|||
|
|
this.lastNode = null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
const htmlDecodeTree = new Uint16Array(
|
|||
|
|
// prettier-ignore
|
|||
|
|
'ᵁ<Õıʊҝջאٵ۞ޢߖࠏઑඡ༉༦ረዡᐕᒝᓃᓟᔥ\0\0\0\0\0\0ᕫᛍᦍᰒᷝ↰⊍⏀⏻⑂⠤⤒ⴈ⹈⿎〖㊺㘹㞬㣾㨨㩱㫠㬮ࠀEMabcfglmnoprstu\\bfms¦³¹ÈÏlig耻Æ䃆P耻&䀦cute耻Á䃁reve;䄂Āiyx}rc耻Â䃂;䐐r;쀀𝔄rave耻À䃀pha;䎑acr;䄀d;橓Āgp¡on;䄄f;쀀𝔸plyFunction;恡ing耻Å䃅Ācs¾Ãr;쀀𝒜ign;扔ilde耻Ã䃃ml耻Ä䃄ЀaceforsuåûþėĜĢħĪĀcrêòkslash;或Ŷöø;櫧ed;挆y;䐑ƀcrtąċĔause;戵noullis;愬a;䎒r;쀀𝔅pf;쀀𝔹eve;䋘còēmpeq;扎܀HOacdefhilorsuōőŖƀƞƢƵƷƺǜȕɳɸɾcy;䐧PY耻©䂩ƀcpyŝŢźute;䄆Ā;iŧŨ拒talDifferentialD;慅leys;愭ȀaeioƉƎƔƘron;䄌dil耻Ç䃇rc;䄈nint;戰ot;䄊ĀdnƧƭilla;䂸terDot;䂷òſi;䎧rcleȀDMPTLJNjǑǖot;抙inus;抖lus;投imes;抗oĀcsǢǸkwiseContourIntegral;戲eCurlyĀDQȃȏoubleQuote;思uote;怙ȀlnpuȞȨɇɕonĀ;eȥȦ户;橴ƀgitȯȶȺruent;扡nt;戯ourIntegral;戮ĀfrɌɎ;愂oduct;成nterClockwiseContourIntegral;戳oss;樯cr;쀀𝒞pĀ;Cʄʅ拓ap;才րDJSZacefiosʠʬʰʴʸˋ˗ˡ˦̳ҍĀ;oŹʥtrahd;椑cy;䐂cy;䐅cy;䐏ƀgrsʿ˄ˇger;怡r;憡hv;櫤Āayː˕ron;䄎;䐔lĀ;t˝˞戇a;䎔r;쀀𝔇Āaf˫̧Ācm˰̢riticalȀADGT̖̜̀̆cute;䂴oŴ̋̍;䋙bleAcute;䋝rave;䁠ilde;䋜ond;拄ferentialD;慆Ѱ̽\0\0\0͔͂\0Ѕf;쀀𝔻ƀ;DE͈͉͍䂨ot;惜qual;扐blèCDLRUVͣͲϏϢϸontourIntegraìȹoɴ\0\0ͻ»͉nArrow;懓Āeo·ΤftƀARTΐΖΡrrow;懐ightArrow;懔eåˊngĀLRΫτeftĀARγιrrow;柸ightArrow;柺ightArrow;柹ightĀATϘϞrrow;懒ee;抨pɁϩ\0\0ϯrrow;懑ownArrow;懕erticalBar;戥ǹABLRTaВЪаўѿͼrrowƀ;BUНОТ憓ar;椓pArrow;懵reve;䌑eft˒к\0ц\0ѐightVector;楐eeVector;楞ectorĀ;Bљњ憽ar;楖ightǔѧ\0ѱeeVector;楟ectorĀ;BѺѻ懁ar;楗eeĀ;A҆҇护rrow;憧ĀctҒҗr;쀀𝒟rok;䄐ࠀNTacdfglmopqstuxҽӀӄӋӞӢӧӮӵԡԯԶՒ՝ՠեG;䅊H耻Ð䃐cute耻É䃉ƀaiyӒӗӜron;䄚rc耻Ê䃊;䐭ot;䄖r;쀀𝔈rave耻È䃈ement;戈ĀapӺӾcr;䄒tyɓԆ\0\0ԒmallSquare;旻erySmallSquare;斫ĀgpԦԪon;䄘f;쀀𝔼silon;䎕uĀaiԼՉlĀ;TՂՃ橵ilde;扂librium;懌Āci՚r;愰m;橳a;䎗ml耻Ë䃋Āipժկsts;戃onentialE;慇ʀcfiosօֈ֍ֲy;䐤r;쀀𝔉lledɓ֗\0\0֣mallSquare;旼erySmallSquare;斪Ͱֺ\0ֿ\0\0ׄf;쀀𝔽All;戀riertrf;愱còJTabcdfgorstרׯؒؖ؛؝أ٬ٲcy;䐃耻>䀾mmaĀ;d䎓;䏜reve;䄞ƀeiy؇،ؐdil;䄢rc;䄜;䐓ot;䄠r;쀀𝔊;拙pf;쀀𝔾eater̀EFGLSTصلَٖٛ٦qualĀ;Lؾؿ扥ess;招ullEqual;执reater;檢ess;扷lantEqual;橾ilde;扳cr;쀀𝒢;扫ЀAacfiosuڅڋږڛڞڪھۊRDcy;䐪Āctڐڔek;䋇;䁞irc;䄤r;愌lbertSpace;愋ǰگ\0ڲf;愍izontalLine;攀Āctۃۅòکrok;䄦mpńېۘownHumðįqual;扏܀EJOacdfgmnostuۺ۾܃܇ܚܞܡܨ݄ݸދޏޕcy;䐕lig;䄲cy;䐁cute耻Í䃍Āiyܓܘrc耻Î䃎;䐘ot;䄰r;愑rave耻Ì䃌ƀ;apܠܯܿĀcgܴܷr;䄪inaryI;慈lieóϝǴ݉\0ݢĀ;eݍݎ戬Āgrݓݘral;戫section;拂isibleĀCTݬݲomma;恣imes;恢ƀgptݿރވon;䄮f;쀀𝕀a;䎙cr;愐ilde;䄨ǫޚ\0ޞcy;䐆l耻Ï䃏ʀcfosuެ߂ߐĀiyޱrc;䄴;䐙r;쀀𝔍pf;쀀𝕁ǣ߇\0ߌr;쀀𝒥rcy;䐈kcy;䐄HJacfosߤߨ߽߬߱ࠂࠈcy;䐥cy;䐌ppa;䎚Āey߶dil;䄶;䐚r;쀀𝔎pf;쀀𝕂cr;쀀𝒦րJTaceflmostࠥࠩࠬࡐࡣসে্ੇcy;䐉耻<䀼ʀcmnpr࠷࠼ࡁࡄࡍute;䄹bda;䎛g;柪lacetrf;愒r;憞ƀaeyࡗࡡron;䄽dil;䄻;䐛Āfsࡨ॰tԀACDFRTUVarࡾࢩࢱࣦ࣠ࣼयज़ΐ४ĀnrࢃgleBracket;柨rowƀ;BR࢙࢚࢞憐ar;懤ightArrow;懆eiling;挈oǵࢷ\0ࣃbleBracket;柦nǔࣈ\0࣒eeVector;楡ectorĀ;Bࣛࣜ懃ar;楙loor;挊ightĀAV࣯ࣵrrow;憔ector;楎Āerँगeƀ;AVउऊऐ抣rrow;憤ector;楚iangleƀ;BEतथऩ抲ar;槏qual;抴pƀDTVषूौownVector;楑eeVector;楠ectorĀ;Bॖॗ憿ar;楘ectorĀ;B॥०憼ar;楒ightáΜs̀EFGLSTॾঋকঝঢভqualGreater;拚ullEqual;扦reater;扶ess;檡lantEqual;橽ilde;扲r;쀀𝔏Ā;eঽা拘ftarrow;懚idot;䄿ƀnpwਖਛgȀLRlr৷ਂਐeftĀAR০৬rrow;柵ightArrow;柷ightArrow;柶eftĀarγਊightáοightáϊf;쀀𝕃erĀLRਢਬeftArrow;憙ightArrow;憘ƀchtਾੀੂòࡌ;憰rok;䅁;扪Ѐacefiosuਗ਼અઋp;椅y;䐜Ādl੯iumSpace;恟lintrf;愳r;쀀𝔐nusPlus;戓
|
|||
|
|
);
|
|||
|
|
const xmlDecodeTree = new Uint16Array(
|
|||
|
|
// prettier-ignore
|
|||
|
|
"Ȁaglq \x1Bɭ\0\0p;䀦os;䀧t;䀾t;䀼uot;䀢".split("").map((c) => c.charCodeAt(0))
|
|||
|
|
);
|
|||
|
|
var _a;
|
|||
|
|
const decodeMap = /* @__PURE__ */ new Map([
|
|||
|
|
[0, 65533],
|
|||
|
|
// C1 Unicode control character reference replacements
|
|||
|
|
[128, 8364],
|
|||
|
|
[130, 8218],
|
|||
|
|
[131, 402],
|
|||
|
|
[132, 8222],
|
|||
|
|
[133, 8230],
|
|||
|
|
[134, 8224],
|
|||
|
|
[135, 8225],
|
|||
|
|
[136, 710],
|
|||
|
|
[137, 8240],
|
|||
|
|
[138, 352],
|
|||
|
|
[139, 8249],
|
|||
|
|
[140, 338],
|
|||
|
|
[142, 381],
|
|||
|
|
[145, 8216],
|
|||
|
|
[146, 8217],
|
|||
|
|
[147, 8220],
|
|||
|
|
[148, 8221],
|
|||
|
|
[149, 8226],
|
|||
|
|
[150, 8211],
|
|||
|
|
[151, 8212],
|
|||
|
|
[152, 732],
|
|||
|
|
[153, 8482],
|
|||
|
|
[154, 353],
|
|||
|
|
[155, 8250],
|
|||
|
|
[156, 339],
|
|||
|
|
[158, 382],
|
|||
|
|
[159, 376]
|
|||
|
|
]);
|
|||
|
|
const fromCodePoint = (
|
|||
|
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, node/no-unsupported-features/es-builtins
|
|||
|
|
(_a = String.fromCodePoint) !== null && _a !== void 0 ? _a : function(codePoint) {
|
|||
|
|
let output = "";
|
|||
|
|
if (codePoint > 65535) {
|
|||
|
|
codePoint -= 65536;
|
|||
|
|
output += String.fromCharCode(codePoint >>> 10 & 1023 | 55296);
|
|||
|
|
codePoint = 56320 | codePoint & 1023;
|
|||
|
|
}
|
|||
|
|
output += String.fromCharCode(codePoint);
|
|||
|
|
return output;
|
|||
|
|
}
|
|||
|
|
);
|
|||
|
|
function replaceCodePoint(codePoint) {
|
|||
|
|
var _a2;
|
|||
|
|
if (codePoint >= 55296 && codePoint <= 57343 || codePoint > 1114111) {
|
|||
|
|
return 65533;
|
|||
|
|
}
|
|||
|
|
return (_a2 = decodeMap.get(codePoint)) !== null && _a2 !== void 0 ? _a2 : codePoint;
|
|||
|
|
}
|
|||
|
|
var CharCodes$1;
|
|||
|
|
(function(CharCodes2) {
|
|||
|
|
CharCodes2[CharCodes2["NUM"] = 35] = "NUM";
|
|||
|
|
CharCodes2[CharCodes2["SEMI"] = 59] = "SEMI";
|
|||
|
|
CharCodes2[CharCodes2["EQUALS"] = 61] = "EQUALS";
|
|||
|
|
CharCodes2[CharCodes2["ZERO"] = 48] = "ZERO";
|
|||
|
|
CharCodes2[CharCodes2["NINE"] = 57] = "NINE";
|
|||
|
|
CharCodes2[CharCodes2["LOWER_A"] = 97] = "LOWER_A";
|
|||
|
|
CharCodes2[CharCodes2["LOWER_F"] = 102] = "LOWER_F";
|
|||
|
|
CharCodes2[CharCodes2["LOWER_X"] = 120] = "LOWER_X";
|
|||
|
|
CharCodes2[CharCodes2["LOWER_Z"] = 122] = "LOWER_Z";
|
|||
|
|
CharCodes2[CharCodes2["UPPER_A"] = 65] = "UPPER_A";
|
|||
|
|
CharCodes2[CharCodes2["UPPER_F"] = 70] = "UPPER_F";
|
|||
|
|
CharCodes2[CharCodes2["UPPER_Z"] = 90] = "UPPER_Z";
|
|||
|
|
})(CharCodes$1 || (CharCodes$1 = {}));
|
|||
|
|
const TO_LOWER_BIT = 32;
|
|||
|
|
var BinTrieFlags;
|
|||
|
|
(function(BinTrieFlags2) {
|
|||
|
|
BinTrieFlags2[BinTrieFlags2["VALUE_LENGTH"] = 49152] = "VALUE_LENGTH";
|
|||
|
|
BinTrieFlags2[BinTrieFlags2["BRANCH_LENGTH"] = 16256] = "BRANCH_LENGTH";
|
|||
|
|
BinTrieFlags2[BinTrieFlags2["JUMP_TABLE"] = 127] = "JUMP_TABLE";
|
|||
|
|
})(BinTrieFlags || (BinTrieFlags = {}));
|
|||
|
|
function isNumber(code) {
|
|||
|
|
return code >= CharCodes$1.ZERO && code <= CharCodes$1.NINE;
|
|||
|
|
}
|
|||
|
|
function isHexadecimalCharacter(code) {
|
|||
|
|
return code >= CharCodes$1.UPPER_A && code <= CharCodes$1.UPPER_F || code >= CharCodes$1.LOWER_A && code <= CharCodes$1.LOWER_F;
|
|||
|
|
}
|
|||
|
|
function isAsciiAlphaNumeric(code) {
|
|||
|
|
return code >= CharCodes$1.UPPER_A && code <= CharCodes$1.UPPER_Z || code >= CharCodes$1.LOWER_A && code <= CharCodes$1.LOWER_Z || isNumber(code);
|
|||
|
|
}
|
|||
|
|
function isEntityInAttributeInvalidEnd(code) {
|
|||
|
|
return code === CharCodes$1.EQUALS || isAsciiAlphaNumeric(code);
|
|||
|
|
}
|
|||
|
|
var EntityDecoderState;
|
|||
|
|
(function(EntityDecoderState2) {
|
|||
|
|
EntityDecoderState2[EntityDecoderState2["EntityStart"] = 0] = "EntityStart";
|
|||
|
|
EntityDecoderState2[EntityDecoderState2["NumericStart"] = 1] = "NumericStart";
|
|||
|
|
EntityDecoderState2[EntityDecoderState2["NumericDecimal"] = 2] = "NumericDecimal";
|
|||
|
|
EntityDecoderState2[EntityDecoderState2["NumericHex"] = 3] = "NumericHex";
|
|||
|
|
EntityDecoderState2[EntityDecoderState2["NamedEntity"] = 4] = "NamedEntity";
|
|||
|
|
})(EntityDecoderState || (EntityDecoderState = {}));
|
|||
|
|
var DecodingMode;
|
|||
|
|
(function(DecodingMode2) {
|
|||
|
|
DecodingMode2[DecodingMode2["Legacy"] = 0] = "Legacy";
|
|||
|
|
DecodingMode2[DecodingMode2["Strict"] = 1] = "Strict";
|
|||
|
|
DecodingMode2[DecodingMode2["Attribute"] = 2] = "Attribute";
|
|||
|
|
})(DecodingMode || (DecodingMode = {}));
|
|||
|
|
class EntityDecoder {
|
|||
|
|
constructor(decodeTree, emitCodePoint, errors) {
|
|||
|
|
this.decodeTree = decodeTree;
|
|||
|
|
this.emitCodePoint = emitCodePoint;
|
|||
|
|
this.errors = errors;
|
|||
|
|
this.state = EntityDecoderState.EntityStart;
|
|||
|
|
this.consumed = 1;
|
|||
|
|
this.result = 0;
|
|||
|
|
this.treeIndex = 0;
|
|||
|
|
this.excess = 1;
|
|||
|
|
this.decodeMode = DecodingMode.Strict;
|
|||
|
|
}
|
|||
|
|
/** Resets the instance to make it reusable. */
|
|||
|
|
startEntity(decodeMode) {
|
|||
|
|
this.decodeMode = decodeMode;
|
|||
|
|
this.state = EntityDecoderState.EntityStart;
|
|||
|
|
this.result = 0;
|
|||
|
|
this.treeIndex = 0;
|
|||
|
|
this.excess = 1;
|
|||
|
|
this.consumed = 1;
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Write an entity to the decoder. This can be called multiple times with partial entities.
|
|||
|
|
* If the entity is incomplete, the decoder will return -1.
|
|||
|
|
*
|
|||
|
|
* Mirrors the implementation of `getDecoder`, but with the ability to stop decoding if the
|
|||
|
|
* entity is incomplete, and resume when the next string is written.
|
|||
|
|
*
|
|||
|
|
* @param string The string containing the entity (or a continuation of the entity).
|
|||
|
|
* @param offset The offset at which the entity begins. Should be 0 if this is not the first call.
|
|||
|
|
* @returns The number of characters that were consumed, or -1 if the entity is incomplete.
|
|||
|
|
*/
|
|||
|
|
write(str, offset) {
|
|||
|
|
switch (this.state) {
|
|||
|
|
case EntityDecoderState.EntityStart: {
|
|||
|
|
if (str.charCodeAt(offset) === CharCodes$1.NUM) {
|
|||
|
|
this.state = EntityDecoderState.NumericStart;
|
|||
|
|
this.consumed += 1;
|
|||
|
|
return this.stateNumericStart(str, offset + 1);
|
|||
|
|
}
|
|||
|
|
this.state = EntityDecoderState.NamedEntity;
|
|||
|
|
return this.stateNamedEntity(str, offset);
|
|||
|
|
}
|
|||
|
|
case EntityDecoderState.NumericStart: {
|
|||
|
|
return this.stateNumericStart(str, offset);
|
|||
|
|
}
|
|||
|
|
case EntityDecoderState.NumericDecimal: {
|
|||
|
|
return this.stateNumericDecimal(str, offset);
|
|||
|
|
}
|
|||
|
|
case EntityDecoderState.NumericHex: {
|
|||
|
|
return this.stateNumericHex(str, offset);
|
|||
|
|
}
|
|||
|
|
case EntityDecoderState.NamedEntity: {
|
|||
|
|
return this.stateNamedEntity(str, offset);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Switches between the numeric decimal and hexadecimal states.
|
|||
|
|
*
|
|||
|
|
* Equivalent to the `Numeric character reference state` in the HTML spec.
|
|||
|
|
*
|
|||
|
|
* @param str The string containing the entity (or a continuation of the entity).
|
|||
|
|
* @param offset The current offset.
|
|||
|
|
* @returns The number of characters that were consumed, or -1 if the entity is incomplete.
|
|||
|
|
*/
|
|||
|
|
stateNumericStart(str, offset) {
|
|||
|
|
if (offset >= str.length) {
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
if ((str.charCodeAt(offset) | TO_LOWER_BIT) === CharCodes$1.LOWER_X) {
|
|||
|
|
this.state = EntityDecoderState.NumericHex;
|
|||
|
|
this.consumed += 1;
|
|||
|
|
return this.stateNumericHex(str, offset + 1);
|
|||
|
|
}
|
|||
|
|
this.state = EntityDecoderState.NumericDecimal;
|
|||
|
|
return this.stateNumericDecimal(str, offset);
|
|||
|
|
}
|
|||
|
|
addToNumericResult(str, start, end2, base) {
|
|||
|
|
if (start !== end2) {
|
|||
|
|
const digitCount = end2 - start;
|
|||
|
|
this.result = this.result * Math.pow(base, digitCount) + parseInt(str.substr(start, digitCount), base);
|
|||
|
|
this.consumed += digitCount;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Parses a hexadecimal numeric entity.
|
|||
|
|
*
|
|||
|
|
* Equivalent to the `Hexademical character reference state` in the HTML spec.
|
|||
|
|
*
|
|||
|
|
* @param str The string containing the entity (or a continuation of the entity).
|
|||
|
|
* @param offset The current offset.
|
|||
|
|
* @returns The number of characters that were consumed, or -1 if the entity is incomplete.
|
|||
|
|
*/
|
|||
|
|
stateNumericHex(str, offset) {
|
|||
|
|
const startIdx = offset;
|
|||
|
|
while (offset < str.length) {
|
|||
|
|
const char = str.charCodeAt(offset);
|
|||
|
|
if (isNumber(char) || isHexadecimalCharacter(char)) {
|
|||
|
|
offset += 1;
|
|||
|
|
} else {
|
|||
|
|
this.addToNumericResult(str, startIdx, offset, 16);
|
|||
|
|
return this.emitNumericEntity(char, 3);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
this.addToNumericResult(str, startIdx, offset, 16);
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Parses a decimal numeric entity.
|
|||
|
|
*
|
|||
|
|
* Equivalent to the `Decimal character reference state` in the HTML spec.
|
|||
|
|
*
|
|||
|
|
* @param str The string containing the entity (or a continuation of the entity).
|
|||
|
|
* @param offset The current offset.
|
|||
|
|
* @returns The number of characters that were consumed, or -1 if the entity is incomplete.
|
|||
|
|
*/
|
|||
|
|
stateNumericDecimal(str, offset) {
|
|||
|
|
const startIdx = offset;
|
|||
|
|
while (offset < str.length) {
|
|||
|
|
const char = str.charCodeAt(offset);
|
|||
|
|
if (isNumber(char)) {
|
|||
|
|
offset += 1;
|
|||
|
|
} else {
|
|||
|
|
this.addToNumericResult(str, startIdx, offset, 10);
|
|||
|
|
return this.emitNumericEntity(char, 2);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
this.addToNumericResult(str, startIdx, offset, 10);
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Validate and emit a numeric entity.
|
|||
|
|
*
|
|||
|
|
* Implements the logic from the `Hexademical character reference start
|
|||
|
|
* state` and `Numeric character reference end state` in the HTML spec.
|
|||
|
|
*
|
|||
|
|
* @param lastCp The last code point of the entity. Used to see if the
|
|||
|
|
* entity was terminated with a semicolon.
|
|||
|
|
* @param expectedLength The minimum number of characters that should be
|
|||
|
|
* consumed. Used to validate that at least one digit
|
|||
|
|
* was consumed.
|
|||
|
|
* @returns The number of characters that were consumed.
|
|||
|
|
*/
|
|||
|
|
emitNumericEntity(lastCp, expectedLength) {
|
|||
|
|
var _a2;
|
|||
|
|
if (this.consumed <= expectedLength) {
|
|||
|
|
(_a2 = this.errors) === null || _a2 === void 0 ? void 0 : _a2.absenceOfDigitsInNumericCharacterReference(this.consumed);
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
if (lastCp === CharCodes$1.SEMI) {
|
|||
|
|
this.consumed += 1;
|
|||
|
|
} else if (this.decodeMode === DecodingMode.Strict) {
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
this.emitCodePoint(replaceCodePoint(this.result), this.consumed);
|
|||
|
|
if (this.errors) {
|
|||
|
|
if (lastCp !== CharCodes$1.SEMI) {
|
|||
|
|
this.errors.missingSemicolonAfterCharacterReference();
|
|||
|
|
}
|
|||
|
|
this.errors.validateNumericCharacterReference(this.result);
|
|||
|
|
}
|
|||
|
|
return this.consumed;
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Parses a named entity.
|
|||
|
|
*
|
|||
|
|
* Equivalent to the `Named character reference state` in the HTML spec.
|
|||
|
|
*
|
|||
|
|
* @param str The string containing the entity (or a continuation of the entity).
|
|||
|
|
* @param offset The current offset.
|
|||
|
|
* @returns The number of characters that were consumed, or -1 if the entity is incomplete.
|
|||
|
|
*/
|
|||
|
|
stateNamedEntity(str, offset) {
|
|||
|
|
const { decodeTree } = this;
|
|||
|
|
let current = decodeTree[this.treeIndex];
|
|||
|
|
let valueLength = (current & BinTrieFlags.VALUE_LENGTH) >> 14;
|
|||
|
|
for (; offset < str.length; offset++, this.excess++) {
|
|||
|
|
const char = str.charCodeAt(offset);
|
|||
|
|
this.treeIndex = determineBranch(decodeTree, current, this.treeIndex + Math.max(1, valueLength), char);
|
|||
|
|
if (this.treeIndex < 0) {
|
|||
|
|
return this.result === 0 || // If we are parsing an attribute
|
|||
|
|
this.decodeMode === DecodingMode.Attribute && // We shouldn't have consumed any characters after the entity,
|
|||
|
|
(valueLength === 0 || // And there should be no invalid characters.
|
|||
|
|
isEntityInAttributeInvalidEnd(char)) ? 0 : this.emitNotTerminatedNamedEntity();
|
|||
|
|
}
|
|||
|
|
current = decodeTree[this.treeIndex];
|
|||
|
|
valueLength = (current & BinTrieFlags.VALUE_LENGTH) >> 14;
|
|||
|
|
if (valueLength !== 0) {
|
|||
|
|
if (char === CharCodes$1.SEMI) {
|
|||
|
|
return this.emitNamedEntityData(this.treeIndex, valueLength, this.consumed + this.excess);
|
|||
|
|
}
|
|||
|
|
if (this.decodeMode !== DecodingMode.Strict) {
|
|||
|
|
this.result = this.treeIndex;
|
|||
|
|
this.consumed += this.excess;
|
|||
|
|
this.excess = 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Emit a named entity that was not terminated with a semicolon.
|
|||
|
|
*
|
|||
|
|
* @returns The number of characters consumed.
|
|||
|
|
*/
|
|||
|
|
emitNotTerminatedNamedEntity() {
|
|||
|
|
var _a2;
|
|||
|
|
const { result, decodeTree } = this;
|
|||
|
|
const valueLength = (decodeTree[result] & BinTrieFlags.VALUE_LENGTH) >> 14;
|
|||
|
|
this.emitNamedEntityData(result, valueLength, this.consumed);
|
|||
|
|
(_a2 = this.errors) === null || _a2 === void 0 ? void 0 : _a2.missingSemicolonAfterCharacterReference();
|
|||
|
|
return this.consumed;
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Emit a named entity.
|
|||
|
|
*
|
|||
|
|
* @param result The index of the entity in the decode tree.
|
|||
|
|
* @param valueLength The number of bytes in the entity.
|
|||
|
|
* @param consumed The number of characters consumed.
|
|||
|
|
*
|
|||
|
|
* @returns The number of characters consumed.
|
|||
|
|
*/
|
|||
|
|
emitNamedEntityData(result, valueLength, consumed) {
|
|||
|
|
const { decodeTree } = this;
|
|||
|
|
this.emitCodePoint(valueLength === 1 ? decodeTree[result] & ~BinTrieFlags.VALUE_LENGTH : decodeTree[result + 1], consumed);
|
|||
|
|
if (valueLength === 3) {
|
|||
|
|
this.emitCodePoint(decodeTree[result + 2], consumed);
|
|||
|
|
}
|
|||
|
|
return consumed;
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Signal to the parser that the end of the input was reached.
|
|||
|
|
*
|
|||
|
|
* Remaining data will be emitted and relevant errors will be produced.
|
|||
|
|
*
|
|||
|
|
* @returns The number of characters consumed.
|
|||
|
|
*/
|
|||
|
|
end() {
|
|||
|
|
var _a2;
|
|||
|
|
switch (this.state) {
|
|||
|
|
case EntityDecoderState.NamedEntity: {
|
|||
|
|
return this.result !== 0 && (this.decodeMode !== DecodingMode.Attribute || this.result === this.treeIndex) ? this.emitNotTerminatedNamedEntity() : 0;
|
|||
|
|
}
|
|||
|
|
// Otherwise, emit a numeric entity if we have one.
|
|||
|
|
case EntityDecoderState.NumericDecimal: {
|
|||
|
|
return this.emitNumericEntity(0, 2);
|
|||
|
|
}
|
|||
|
|
case EntityDecoderState.NumericHex: {
|
|||
|
|
return this.emitNumericEntity(0, 3);
|
|||
|
|
}
|
|||
|
|
case EntityDecoderState.NumericStart: {
|
|||
|
|
(_a2 = this.errors) === null || _a2 === void 0 ? void 0 : _a2.absenceOfDigitsInNumericCharacterReference(this.consumed);
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
case EntityDecoderState.EntityStart: {
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function getDecoder(decodeTree) {
|
|||
|
|
let ret = "";
|
|||
|
|
const decoder = new EntityDecoder(decodeTree, (str) => ret += fromCodePoint(str));
|
|||
|
|
return function decodeWithTrie(str, decodeMode) {
|
|||
|
|
let lastIndex = 0;
|
|||
|
|
let offset = 0;
|
|||
|
|
while ((offset = str.indexOf("&", offset)) >= 0) {
|
|||
|
|
ret += str.slice(lastIndex, offset);
|
|||
|
|
decoder.startEntity(decodeMode);
|
|||
|
|
const len = decoder.write(
|
|||
|
|
str,
|
|||
|
|
// Skip the "&"
|
|||
|
|
offset + 1
|
|||
|
|
);
|
|||
|
|
if (len < 0) {
|
|||
|
|
lastIndex = offset + decoder.end();
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
lastIndex = offset + len;
|
|||
|
|
offset = len === 0 ? lastIndex + 1 : lastIndex;
|
|||
|
|
}
|
|||
|
|
const result = ret + str.slice(lastIndex);
|
|||
|
|
ret = "";
|
|||
|
|
return result;
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
function determineBranch(decodeTree, current, nodeIdx, char) {
|
|||
|
|
const branchCount = (current & BinTrieFlags.BRANCH_LENGTH) >> 7;
|
|||
|
|
const jumpOffset = current & BinTrieFlags.JUMP_TABLE;
|
|||
|
|
if (branchCount === 0) {
|
|||
|
|
return jumpOffset !== 0 && char === jumpOffset ? nodeIdx : -1;
|
|||
|
|
}
|
|||
|
|
if (jumpOffset) {
|
|||
|
|
const value = char - jumpOffset;
|
|||
|
|
return value < 0 || value >= branchCount ? -1 : decodeTree[nodeIdx + value] - 1;
|
|||
|
|
}
|
|||
|
|
let lo = nodeIdx;
|
|||
|
|
let hi = lo + branchCount - 1;
|
|||
|
|
while (lo <= hi) {
|
|||
|
|
const mid = lo + hi >>> 1;
|
|||
|
|
const midVal = decodeTree[mid];
|
|||
|
|
if (midVal < char) {
|
|||
|
|
lo = mid + 1;
|
|||
|
|
} else if (midVal > char) {
|
|||
|
|
hi = mid - 1;
|
|||
|
|
} else {
|
|||
|
|
return decodeTree[mid + branchCount];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
getDecoder(htmlDecodeTree);
|
|||
|
|
getDecoder(xmlDecodeTree);
|
|||
|
|
const xmlReplacer = /["&'<>$\x80-\uFFFF]/g;
|
|||
|
|
const xmlCodeMap = /* @__PURE__ */ new Map([
|
|||
|
|
[34, """],
|
|||
|
|
[38, "&"],
|
|||
|
|
[39, "'"],
|
|||
|
|
[60, "<"],
|
|||
|
|
[62, ">"]
|
|||
|
|
]);
|
|||
|
|
const getCodePoint = (
|
|||
|
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|||
|
|
String.prototype.codePointAt != null ? (str, index2) => str.codePointAt(index2) : (
|
|||
|
|
// http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
|
|||
|
|
(c, index2) => (c.charCodeAt(index2) & 64512) === 55296 ? (c.charCodeAt(index2) - 55296) * 1024 + c.charCodeAt(index2 + 1) - 56320 + 65536 : c.charCodeAt(index2)
|
|||
|
|
)
|
|||
|
|
);
|
|||
|
|
function encodeXML(str) {
|
|||
|
|
let ret = "";
|
|||
|
|
let lastIdx = 0;
|
|||
|
|
let match;
|
|||
|
|
while ((match = xmlReplacer.exec(str)) !== null) {
|
|||
|
|
const i = match.index;
|
|||
|
|
const char = str.charCodeAt(i);
|
|||
|
|
const next2 = xmlCodeMap.get(char);
|
|||
|
|
if (next2 !== void 0) {
|
|||
|
|
ret += str.substring(lastIdx, i) + next2;
|
|||
|
|
lastIdx = i + 1;
|
|||
|
|
} else {
|
|||
|
|
ret += `${str.substring(lastIdx, i)}&#x${getCodePoint(str, i).toString(16)};`;
|
|||
|
|
lastIdx = xmlReplacer.lastIndex += Number((char & 64512) === 55296);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return ret + str.substr(lastIdx);
|
|||
|
|
}
|
|||
|
|
function getEscaper(regex, map2) {
|
|||
|
|
return function escape(data2) {
|
|||
|
|
let match;
|
|||
|
|
let lastIdx = 0;
|
|||
|
|
let result = "";
|
|||
|
|
while (match = regex.exec(data2)) {
|
|||
|
|
if (lastIdx !== match.index) {
|
|||
|
|
result += data2.substring(lastIdx, match.index);
|
|||
|
|
}
|
|||
|
|
result += map2.get(match[0].charCodeAt(0));
|
|||
|
|
lastIdx = match.index + 1;
|
|||
|
|
}
|
|||
|
|
return result + data2.substring(lastIdx);
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
const escapeAttribute = getEscaper(/["&\u00A0]/g, /* @__PURE__ */ new Map([
|
|||
|
|
[34, """],
|
|||
|
|
[38, "&"],
|
|||
|
|
[160, " "]
|
|||
|
|
]));
|
|||
|
|
const escapeText = getEscaper(/[&<>\u00A0]/g, /* @__PURE__ */ new Map([
|
|||
|
|
[38, "&"],
|
|||
|
|
[60, "<"],
|
|||
|
|
[62, ">"],
|
|||
|
|
[160, " "]
|
|||
|
|
]));
|
|||
|
|
const elementNames = new Map([
|
|||
|
|
"altGlyph",
|
|||
|
|
"altGlyphDef",
|
|||
|
|
"altGlyphItem",
|
|||
|
|
"animateColor",
|
|||
|
|
"animateMotion",
|
|||
|
|
"animateTransform",
|
|||
|
|
"clipPath",
|
|||
|
|
"feBlend",
|
|||
|
|
"feColorMatrix",
|
|||
|
|
"feComponentTransfer",
|
|||
|
|
"feComposite",
|
|||
|
|
"feConvolveMatrix",
|
|||
|
|
"feDiffuseLighting",
|
|||
|
|
"feDisplacementMap",
|
|||
|
|
"feDistantLight",
|
|||
|
|
"feDropShadow",
|
|||
|
|
"feFlood",
|
|||
|
|
"feFuncA",
|
|||
|
|
"feFuncB",
|
|||
|
|
"feFuncG",
|
|||
|
|
"feFuncR",
|
|||
|
|
"feGaussianBlur",
|
|||
|
|
"feImage",
|
|||
|
|
"feMerge",
|
|||
|
|
"feMergeNode",
|
|||
|
|
"feMorphology",
|
|||
|
|
"feOffset",
|
|||
|
|
"fePointLight",
|
|||
|
|
"feSpecularLighting",
|
|||
|
|
"feSpotLight",
|
|||
|
|
"feTile",
|
|||
|
|
"feTurbulence",
|
|||
|
|
"foreignObject",
|
|||
|
|
"glyphRef",
|
|||
|
|
"linearGradient",
|
|||
|
|
"radialGradient",
|
|||
|
|
"textPath"
|
|||
|
|
].map((val2) => [val2.toLowerCase(), val2]));
|
|||
|
|
const attributeNames = new Map([
|
|||
|
|
"definitionURL",
|
|||
|
|
"attributeName",
|
|||
|
|
"attributeType",
|
|||
|
|
"baseFrequency",
|
|||
|
|
"baseProfile",
|
|||
|
|
"calcMode",
|
|||
|
|
"clipPathUnits",
|
|||
|
|
"diffuseConstant",
|
|||
|
|
"edgeMode",
|
|||
|
|
"filterUnits",
|
|||
|
|
"glyphRef",
|
|||
|
|
"gradientTransform",
|
|||
|
|
"gradientUnits",
|
|||
|
|
"kernelMatrix",
|
|||
|
|
"kernelUnitLength",
|
|||
|
|
"keyPoints",
|
|||
|
|
"keySplines",
|
|||
|
|
"keyTimes",
|
|||
|
|
"lengthAdjust",
|
|||
|
|
"limitingConeAngle",
|
|||
|
|
"markerHeight",
|
|||
|
|
"markerUnits",
|
|||
|
|
"markerWidth",
|
|||
|
|
"maskContentUnits",
|
|||
|
|
"maskUnits",
|
|||
|
|
"numOctaves",
|
|||
|
|
"pathLength",
|
|||
|
|
"patternContentUnits",
|
|||
|
|
"patternTransform",
|
|||
|
|
"patternUnits",
|
|||
|
|
"pointsAtX",
|
|||
|
|
"pointsAtY",
|
|||
|
|
"pointsAtZ",
|
|||
|
|
"preserveAlpha",
|
|||
|
|
"preserveAspectRatio",
|
|||
|
|
"primitiveUnits",
|
|||
|
|
"refX",
|
|||
|
|
"refY",
|
|||
|
|
"repeatCount",
|
|||
|
|
"repeatDur",
|
|||
|
|
"requiredExtensions",
|
|||
|
|
"requiredFeatures",
|
|||
|
|
"specularConstant",
|
|||
|
|
"specularExponent",
|
|||
|
|
"spreadMethod",
|
|||
|
|
"startOffset",
|
|||
|
|
"stdDeviation",
|
|||
|
|
"stitchTiles",
|
|||
|
|
"surfaceScale",
|
|||
|
|
"systemLanguage",
|
|||
|
|
"tableValues",
|
|||
|
|
"targetX",
|
|||
|
|
"targetY",
|
|||
|
|
"textLength",
|
|||
|
|
"viewBox",
|
|||
|
|
"viewTarget",
|
|||
|
|
"xChannelSelector",
|
|||
|
|
"yChannelSelector",
|
|||
|
|
"zoomAndPan"
|
|||
|
|
].map((val2) => [val2.toLowerCase(), val2]));
|
|||
|
|
const unencodedElements = /* @__PURE__ */ new Set([
|
|||
|
|
"style",
|
|||
|
|
"script",
|
|||
|
|
"xmp",
|
|||
|
|
"iframe",
|
|||
|
|
"noembed",
|
|||
|
|
"noframes",
|
|||
|
|
"plaintext",
|
|||
|
|
"noscript"
|
|||
|
|
]);
|
|||
|
|
function replaceQuotes(value) {
|
|||
|
|
return value.replace(/"/g, """);
|
|||
|
|
}
|
|||
|
|
function formatAttributes(attributes2, opts) {
|
|||
|
|
var _a2;
|
|||
|
|
if (!attributes2)
|
|||
|
|
return;
|
|||
|
|
const encode = ((_a2 = opts.encodeEntities) !== null && _a2 !== void 0 ? _a2 : opts.decodeEntities) === false ? replaceQuotes : opts.xmlMode || opts.encodeEntities !== "utf8" ? encodeXML : escapeAttribute;
|
|||
|
|
return Object.keys(attributes2).map((key) => {
|
|||
|
|
var _a3, _b;
|
|||
|
|
const value = (_a3 = attributes2[key]) !== null && _a3 !== void 0 ? _a3 : "";
|
|||
|
|
if (opts.xmlMode === "foreign") {
|
|||
|
|
key = (_b = attributeNames.get(key)) !== null && _b !== void 0 ? _b : key;
|
|||
|
|
}
|
|||
|
|
if (!opts.emptyAttrs && !opts.xmlMode && value === "") {
|
|||
|
|
return key;
|
|||
|
|
}
|
|||
|
|
return `${key}="${encode(value)}"`;
|
|||
|
|
}).join(" ");
|
|||
|
|
}
|
|||
|
|
const singleTag = /* @__PURE__ */ new Set([
|
|||
|
|
"area",
|
|||
|
|
"base",
|
|||
|
|
"basefont",
|
|||
|
|
"br",
|
|||
|
|
"col",
|
|||
|
|
"command",
|
|||
|
|
"embed",
|
|||
|
|
"frame",
|
|||
|
|
"hr",
|
|||
|
|
"img",
|
|||
|
|
"input",
|
|||
|
|
"isindex",
|
|||
|
|
"keygen",
|
|||
|
|
"link",
|
|||
|
|
"meta",
|
|||
|
|
"param",
|
|||
|
|
"source",
|
|||
|
|
"track",
|
|||
|
|
"wbr"
|
|||
|
|
]);
|
|||
|
|
function render$1(node, options = {}) {
|
|||
|
|
const nodes = "length" in node ? node : [node];
|
|||
|
|
let output = "";
|
|||
|
|
for (let i = 0; i < nodes.length; i++) {
|
|||
|
|
output += renderNode(nodes[i], options);
|
|||
|
|
}
|
|||
|
|
return output;
|
|||
|
|
}
|
|||
|
|
function renderNode(node, options) {
|
|||
|
|
switch (node.type) {
|
|||
|
|
case Root:
|
|||
|
|
return render$1(node.children, options);
|
|||
|
|
// @ts-expect-error We don't use `Doctype` yet
|
|||
|
|
case Doctype:
|
|||
|
|
case Directive:
|
|||
|
|
return renderDirective(node);
|
|||
|
|
case Comment$1:
|
|||
|
|
return renderComment(node);
|
|||
|
|
case CDATA$1:
|
|||
|
|
return renderCdata(node);
|
|||
|
|
case Script:
|
|||
|
|
case Style:
|
|||
|
|
case Tag:
|
|||
|
|
return renderTag(node, options);
|
|||
|
|
case Text$1:
|
|||
|
|
return renderText(node, options);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
const foreignModeIntegrationPoints = /* @__PURE__ */ new Set([
|
|||
|
|
"mi",
|
|||
|
|
"mo",
|
|||
|
|
"mn",
|
|||
|
|
"ms",
|
|||
|
|
"mtext",
|
|||
|
|
"annotation-xml",
|
|||
|
|
"foreignObject",
|
|||
|
|
"desc",
|
|||
|
|
"title"
|
|||
|
|
]);
|
|||
|
|
const foreignElements = /* @__PURE__ */ new Set(["svg", "math"]);
|
|||
|
|
function renderTag(elem, opts) {
|
|||
|
|
var _a2;
|
|||
|
|
if (opts.xmlMode === "foreign") {
|
|||
|
|
elem.name = (_a2 = elementNames.get(elem.name)) !== null && _a2 !== void 0 ? _a2 : elem.name;
|
|||
|
|
if (elem.parent && foreignModeIntegrationPoints.has(elem.parent.name)) {
|
|||
|
|
opts = { ...opts, xmlMode: false };
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (!opts.xmlMode && foreignElements.has(elem.name)) {
|
|||
|
|
opts = { ...opts, xmlMode: "foreign" };
|
|||
|
|
}
|
|||
|
|
let tag = `<${elem.name}`;
|
|||
|
|
const attribs = formatAttributes(elem.attribs, opts);
|
|||
|
|
if (attribs) {
|
|||
|
|
tag += ` ${attribs}`;
|
|||
|
|
}
|
|||
|
|
if (elem.children.length === 0 && (opts.xmlMode ? (
|
|||
|
|
// In XML mode or foreign mode, and user hasn't explicitly turned off self-closing tags
|
|||
|
|
opts.selfClosingTags !== false
|
|||
|
|
) : (
|
|||
|
|
// User explicitly asked for self-closing tags, even in HTML mode
|
|||
|
|
opts.selfClosingTags && singleTag.has(elem.name)
|
|||
|
|
))) {
|
|||
|
|
if (!opts.xmlMode)
|
|||
|
|
tag += " ";
|
|||
|
|
tag += "/>";
|
|||
|
|
} else {
|
|||
|
|
tag += ">";
|
|||
|
|
if (elem.children.length > 0) {
|
|||
|
|
tag += render$1(elem.children, opts);
|
|||
|
|
}
|
|||
|
|
if (opts.xmlMode || !singleTag.has(elem.name)) {
|
|||
|
|
tag += `</${elem.name}>`;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return tag;
|
|||
|
|
}
|
|||
|
|
function renderDirective(elem) {
|
|||
|
|
return `<${elem.data}>`;
|
|||
|
|
}
|
|||
|
|
function renderText(elem, opts) {
|
|||
|
|
var _a2;
|
|||
|
|
let data2 = elem.data || "";
|
|||
|
|
if (((_a2 = opts.encodeEntities) !== null && _a2 !== void 0 ? _a2 : opts.decodeEntities) !== false && !(!opts.xmlMode && elem.parent && unencodedElements.has(elem.parent.name))) {
|
|||
|
|
data2 = opts.xmlMode || opts.encodeEntities !== "utf8" ? encodeXML(data2) : escapeText(data2);
|
|||
|
|
}
|
|||
|
|
return data2;
|
|||
|
|
}
|
|||
|
|
function renderCdata(elem) {
|
|||
|
|
return `<![CDATA[${elem.children[0].data}]]>`;
|
|||
|
|
}
|
|||
|
|
function renderComment(elem) {
|
|||
|
|
return `<!--${elem.data}-->`;
|
|||
|
|
}
|
|||
|
|
function getOuterHTML(node, options) {
|
|||
|
|
return render$1(node, options);
|
|||
|
|
}
|
|||
|
|
function getInnerHTML(node, options) {
|
|||
|
|
return hasChildren(node) ? node.children.map((node2) => getOuterHTML(node2, options)).join("") : "";
|
|||
|
|
}
|
|||
|
|
function getText(node) {
|
|||
|
|
if (Array.isArray(node))
|
|||
|
|
return node.map(getText).join("");
|
|||
|
|
if (isTag(node))
|
|||
|
|
return node.name === "br" ? "\n" : getText(node.children);
|
|||
|
|
if (isCDATA(node))
|
|||
|
|
return getText(node.children);
|
|||
|
|
if (isText(node))
|
|||
|
|
return node.data;
|
|||
|
|
return "";
|
|||
|
|
}
|
|||
|
|
function textContent(node) {
|
|||
|
|
if (Array.isArray(node))
|
|||
|
|
return node.map(textContent).join("");
|
|||
|
|
if (hasChildren(node) && !isComment(node)) {
|
|||
|
|
return textContent(node.children);
|
|||
|
|
}
|
|||
|
|
if (isText(node))
|
|||
|
|
return node.data;
|
|||
|
|
return "";
|
|||
|
|
}
|
|||
|
|
function innerText(node) {
|
|||
|
|
if (Array.isArray(node))
|
|||
|
|
return node.map(innerText).join("");
|
|||
|
|
if (hasChildren(node) && (node.type === ElementType.Tag || isCDATA(node))) {
|
|||
|
|
return innerText(node.children);
|
|||
|
|
}
|
|||
|
|
if (isText(node))
|
|||
|
|
return node.data;
|
|||
|
|
return "";
|
|||
|
|
}
|
|||
|
|
function getChildren(elem) {
|
|||
|
|
return hasChildren(elem) ? elem.children : [];
|
|||
|
|
}
|
|||
|
|
function getParent(elem) {
|
|||
|
|
return elem.parent || null;
|
|||
|
|
}
|
|||
|
|
function getSiblings(elem) {
|
|||
|
|
const parent2 = getParent(elem);
|
|||
|
|
if (parent2 != null)
|
|||
|
|
return getChildren(parent2);
|
|||
|
|
const siblings2 = [elem];
|
|||
|
|
let { prev: prev2, next: next2 } = elem;
|
|||
|
|
while (prev2 != null) {
|
|||
|
|
siblings2.unshift(prev2);
|
|||
|
|
({ prev: prev2 } = prev2);
|
|||
|
|
}
|
|||
|
|
while (next2 != null) {
|
|||
|
|
siblings2.push(next2);
|
|||
|
|
({ next: next2 } = next2);
|
|||
|
|
}
|
|||
|
|
return siblings2;
|
|||
|
|
}
|
|||
|
|
function getAttributeValue(elem, name) {
|
|||
|
|
var _a2;
|
|||
|
|
return (_a2 = elem.attribs) === null || _a2 === void 0 ? void 0 : _a2[name];
|
|||
|
|
}
|
|||
|
|
function hasAttrib(elem, name) {
|
|||
|
|
return elem.attribs != null && Object.prototype.hasOwnProperty.call(elem.attribs, name) && elem.attribs[name] != null;
|
|||
|
|
}
|
|||
|
|
function getName(elem) {
|
|||
|
|
return elem.name;
|
|||
|
|
}
|
|||
|
|
function nextElementSibling(elem) {
|
|||
|
|
let { next: next2 } = elem;
|
|||
|
|
while (next2 !== null && !isTag(next2))
|
|||
|
|
({ next: next2 } = next2);
|
|||
|
|
return next2;
|
|||
|
|
}
|
|||
|
|
function prevElementSibling(elem) {
|
|||
|
|
let { prev: prev2 } = elem;
|
|||
|
|
while (prev2 !== null && !isTag(prev2))
|
|||
|
|
({ prev: prev2 } = prev2);
|
|||
|
|
return prev2;
|
|||
|
|
}
|
|||
|
|
function removeElement(elem) {
|
|||
|
|
if (elem.prev)
|
|||
|
|
elem.prev.next = elem.next;
|
|||
|
|
if (elem.next)
|
|||
|
|
elem.next.prev = elem.prev;
|
|||
|
|
if (elem.parent) {
|
|||
|
|
const childs = elem.parent.children;
|
|||
|
|
const childsIndex = childs.lastIndexOf(elem);
|
|||
|
|
if (childsIndex >= 0) {
|
|||
|
|
childs.splice(childsIndex, 1);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
elem.next = null;
|
|||
|
|
elem.prev = null;
|
|||
|
|
elem.parent = null;
|
|||
|
|
}
|
|||
|
|
function replaceElement(elem, replacement) {
|
|||
|
|
const prev2 = replacement.prev = elem.prev;
|
|||
|
|
if (prev2) {
|
|||
|
|
prev2.next = replacement;
|
|||
|
|
}
|
|||
|
|
const next2 = replacement.next = elem.next;
|
|||
|
|
if (next2) {
|
|||
|
|
next2.prev = replacement;
|
|||
|
|
}
|
|||
|
|
const parent2 = replacement.parent = elem.parent;
|
|||
|
|
if (parent2) {
|
|||
|
|
const childs = parent2.children;
|
|||
|
|
childs[childs.lastIndexOf(elem)] = replacement;
|
|||
|
|
elem.parent = null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function appendChild(parent2, child) {
|
|||
|
|
removeElement(child);
|
|||
|
|
child.next = null;
|
|||
|
|
child.parent = parent2;
|
|||
|
|
if (parent2.children.push(child) > 1) {
|
|||
|
|
const sibling = parent2.children[parent2.children.length - 2];
|
|||
|
|
sibling.next = child;
|
|||
|
|
child.prev = sibling;
|
|||
|
|
} else {
|
|||
|
|
child.prev = null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function append$1(elem, next2) {
|
|||
|
|
removeElement(next2);
|
|||
|
|
const { parent: parent2 } = elem;
|
|||
|
|
const currNext = elem.next;
|
|||
|
|
next2.next = currNext;
|
|||
|
|
next2.prev = elem;
|
|||
|
|
elem.next = next2;
|
|||
|
|
next2.parent = parent2;
|
|||
|
|
if (currNext) {
|
|||
|
|
currNext.prev = next2;
|
|||
|
|
if (parent2) {
|
|||
|
|
const childs = parent2.children;
|
|||
|
|
childs.splice(childs.lastIndexOf(currNext), 0, next2);
|
|||
|
|
}
|
|||
|
|
} else if (parent2) {
|
|||
|
|
parent2.children.push(next2);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function prependChild(parent2, child) {
|
|||
|
|
removeElement(child);
|
|||
|
|
child.parent = parent2;
|
|||
|
|
child.prev = null;
|
|||
|
|
if (parent2.children.unshift(child) !== 1) {
|
|||
|
|
const sibling = parent2.children[1];
|
|||
|
|
sibling.prev = child;
|
|||
|
|
child.next = sibling;
|
|||
|
|
} else {
|
|||
|
|
child.next = null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function prepend$1(elem, prev2) {
|
|||
|
|
removeElement(prev2);
|
|||
|
|
const { parent: parent2 } = elem;
|
|||
|
|
if (parent2) {
|
|||
|
|
const childs = parent2.children;
|
|||
|
|
childs.splice(childs.indexOf(elem), 0, prev2);
|
|||
|
|
}
|
|||
|
|
if (elem.prev) {
|
|||
|
|
elem.prev.next = prev2;
|
|||
|
|
}
|
|||
|
|
prev2.parent = parent2;
|
|||
|
|
prev2.prev = elem.prev;
|
|||
|
|
prev2.next = elem;
|
|||
|
|
elem.prev = prev2;
|
|||
|
|
}
|
|||
|
|
function filter$2(test, node, recurse = true, limit = Infinity) {
|
|||
|
|
return find$2(test, Array.isArray(node) ? node : [node], recurse, limit);
|
|||
|
|
}
|
|||
|
|
function find$2(test, nodes, recurse, limit) {
|
|||
|
|
const result = [];
|
|||
|
|
const nodeStack = [nodes];
|
|||
|
|
const indexStack = [0];
|
|||
|
|
for (; ; ) {
|
|||
|
|
if (indexStack[0] >= nodeStack[0].length) {
|
|||
|
|
if (indexStack.length === 1) {
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
nodeStack.shift();
|
|||
|
|
indexStack.shift();
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
const elem = nodeStack[0][indexStack[0]++];
|
|||
|
|
if (test(elem)) {
|
|||
|
|
result.push(elem);
|
|||
|
|
if (--limit <= 0)
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
if (recurse && hasChildren(elem) && elem.children.length > 0) {
|
|||
|
|
indexStack.unshift(0);
|
|||
|
|
nodeStack.unshift(elem.children);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function findOneChild(test, nodes) {
|
|||
|
|
return nodes.find(test);
|
|||
|
|
}
|
|||
|
|
function findOne(test, nodes, recurse = true) {
|
|||
|
|
let elem = null;
|
|||
|
|
for (let i = 0; i < nodes.length && !elem; i++) {
|
|||
|
|
const node = nodes[i];
|
|||
|
|
if (!isTag(node)) {
|
|||
|
|
continue;
|
|||
|
|
} else if (test(node)) {
|
|||
|
|
elem = node;
|
|||
|
|
} else if (recurse && node.children.length > 0) {
|
|||
|
|
elem = findOne(test, node.children, true);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return elem;
|
|||
|
|
}
|
|||
|
|
function existsOne(test, nodes) {
|
|||
|
|
return nodes.some((checked) => isTag(checked) && (test(checked) || existsOne(test, checked.children)));
|
|||
|
|
}
|
|||
|
|
function findAll(test, nodes) {
|
|||
|
|
const result = [];
|
|||
|
|
const nodeStack = [nodes];
|
|||
|
|
const indexStack = [0];
|
|||
|
|
for (; ; ) {
|
|||
|
|
if (indexStack[0] >= nodeStack[0].length) {
|
|||
|
|
if (nodeStack.length === 1) {
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
nodeStack.shift();
|
|||
|
|
indexStack.shift();
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
const elem = nodeStack[0][indexStack[0]++];
|
|||
|
|
if (!isTag(elem))
|
|||
|
|
continue;
|
|||
|
|
if (test(elem))
|
|||
|
|
result.push(elem);
|
|||
|
|
if (elem.children.length > 0) {
|
|||
|
|
indexStack.unshift(0);
|
|||
|
|
nodeStack.unshift(elem.children);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
const Checks = {
|
|||
|
|
tag_name(name) {
|
|||
|
|
if (typeof name === "function") {
|
|||
|
|
return (elem) => isTag(elem) && name(elem.name);
|
|||
|
|
} else if (name === "*") {
|
|||
|
|
return isTag;
|
|||
|
|
}
|
|||
|
|
return (elem) => isTag(elem) && elem.name === name;
|
|||
|
|
},
|
|||
|
|
tag_type(type) {
|
|||
|
|
if (typeof type === "function") {
|
|||
|
|
return (elem) => type(elem.type);
|
|||
|
|
}
|
|||
|
|
return (elem) => elem.type === type;
|
|||
|
|
},
|
|||
|
|
tag_contains(data2) {
|
|||
|
|
if (typeof data2 === "function") {
|
|||
|
|
return (elem) => isText(elem) && data2(elem.data);
|
|||
|
|
}
|
|||
|
|
return (elem) => isText(elem) && elem.data === data2;
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
function getAttribCheck(attrib, value) {
|
|||
|
|
if (typeof value === "function") {
|
|||
|
|
return (elem) => isTag(elem) && value(elem.attribs[attrib]);
|
|||
|
|
}
|
|||
|
|
return (elem) => isTag(elem) && elem.attribs[attrib] === value;
|
|||
|
|
}
|
|||
|
|
function combineFuncs(a, b) {
|
|||
|
|
return (elem) => a(elem) || b(elem);
|
|||
|
|
}
|
|||
|
|
function compileTest(options) {
|
|||
|
|
const funcs = Object.keys(options).map((key) => {
|
|||
|
|
const value = options[key];
|
|||
|
|
return Object.prototype.hasOwnProperty.call(Checks, key) ? Checks[key](value) : getAttribCheck(key, value);
|
|||
|
|
});
|
|||
|
|
return funcs.length === 0 ? null : funcs.reduce(combineFuncs);
|
|||
|
|
}
|
|||
|
|
function testElement(options, node) {
|
|||
|
|
const test = compileTest(options);
|
|||
|
|
return test ? test(node) : true;
|
|||
|
|
}
|
|||
|
|
function getElements(options, nodes, recurse, limit = Infinity) {
|
|||
|
|
const test = compileTest(options);
|
|||
|
|
return test ? filter$2(test, nodes, recurse, limit) : [];
|
|||
|
|
}
|
|||
|
|
function getElementById(id, nodes, recurse = true) {
|
|||
|
|
if (!Array.isArray(nodes))
|
|||
|
|
nodes = [nodes];
|
|||
|
|
return findOne(getAttribCheck("id", id), nodes, recurse);
|
|||
|
|
}
|
|||
|
|
function getElementsByTagName(tagName, nodes, recurse = true, limit = Infinity) {
|
|||
|
|
return filter$2(Checks["tag_name"](tagName), nodes, recurse, limit);
|
|||
|
|
}
|
|||
|
|
function getElementsByTagType(type, nodes, recurse = true, limit = Infinity) {
|
|||
|
|
return filter$2(Checks["tag_type"](type), nodes, recurse, limit);
|
|||
|
|
}
|
|||
|
|
function removeSubsets(nodes) {
|
|||
|
|
let idx = nodes.length;
|
|||
|
|
while (--idx >= 0) {
|
|||
|
|
const node = nodes[idx];
|
|||
|
|
if (idx > 0 && nodes.lastIndexOf(node, idx - 1) >= 0) {
|
|||
|
|
nodes.splice(idx, 1);
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
for (let ancestor = node.parent; ancestor; ancestor = ancestor.parent) {
|
|||
|
|
if (nodes.includes(ancestor)) {
|
|||
|
|
nodes.splice(idx, 1);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return nodes;
|
|||
|
|
}
|
|||
|
|
var DocumentPosition;
|
|||
|
|
(function(DocumentPosition2) {
|
|||
|
|
DocumentPosition2[DocumentPosition2["DISCONNECTED"] = 1] = "DISCONNECTED";
|
|||
|
|
DocumentPosition2[DocumentPosition2["PRECEDING"] = 2] = "PRECEDING";
|
|||
|
|
DocumentPosition2[DocumentPosition2["FOLLOWING"] = 4] = "FOLLOWING";
|
|||
|
|
DocumentPosition2[DocumentPosition2["CONTAINS"] = 8] = "CONTAINS";
|
|||
|
|
DocumentPosition2[DocumentPosition2["CONTAINED_BY"] = 16] = "CONTAINED_BY";
|
|||
|
|
})(DocumentPosition || (DocumentPosition = {}));
|
|||
|
|
function compareDocumentPosition(nodeA, nodeB) {
|
|||
|
|
const aParents = [];
|
|||
|
|
const bParents = [];
|
|||
|
|
if (nodeA === nodeB) {
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
let current = hasChildren(nodeA) ? nodeA : nodeA.parent;
|
|||
|
|
while (current) {
|
|||
|
|
aParents.unshift(current);
|
|||
|
|
current = current.parent;
|
|||
|
|
}
|
|||
|
|
current = hasChildren(nodeB) ? nodeB : nodeB.parent;
|
|||
|
|
while (current) {
|
|||
|
|
bParents.unshift(current);
|
|||
|
|
current = current.parent;
|
|||
|
|
}
|
|||
|
|
const maxIdx = Math.min(aParents.length, bParents.length);
|
|||
|
|
let idx = 0;
|
|||
|
|
while (idx < maxIdx && aParents[idx] === bParents[idx]) {
|
|||
|
|
idx++;
|
|||
|
|
}
|
|||
|
|
if (idx === 0) {
|
|||
|
|
return DocumentPosition.DISCONNECTED;
|
|||
|
|
}
|
|||
|
|
const sharedParent = aParents[idx - 1];
|
|||
|
|
const siblings2 = sharedParent.children;
|
|||
|
|
const aSibling = aParents[idx];
|
|||
|
|
const bSibling = bParents[idx];
|
|||
|
|
if (siblings2.indexOf(aSibling) > siblings2.indexOf(bSibling)) {
|
|||
|
|
if (sharedParent === nodeB) {
|
|||
|
|
return DocumentPosition.FOLLOWING | DocumentPosition.CONTAINED_BY;
|
|||
|
|
}
|
|||
|
|
return DocumentPosition.FOLLOWING;
|
|||
|
|
}
|
|||
|
|
if (sharedParent === nodeA) {
|
|||
|
|
return DocumentPosition.PRECEDING | DocumentPosition.CONTAINS;
|
|||
|
|
}
|
|||
|
|
return DocumentPosition.PRECEDING;
|
|||
|
|
}
|
|||
|
|
function uniqueSort(nodes) {
|
|||
|
|
nodes = nodes.filter((node, i, arr) => !arr.includes(node, i + 1));
|
|||
|
|
nodes.sort((a, b) => {
|
|||
|
|
const relative = compareDocumentPosition(a, b);
|
|||
|
|
if (relative & DocumentPosition.PRECEDING) {
|
|||
|
|
return -1;
|
|||
|
|
} else if (relative & DocumentPosition.FOLLOWING) {
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
return 0;
|
|||
|
|
});
|
|||
|
|
return nodes;
|
|||
|
|
}
|
|||
|
|
function getFeed(doc) {
|
|||
|
|
const feedRoot = getOneElement(isValidFeed, doc);
|
|||
|
|
return !feedRoot ? null : feedRoot.name === "feed" ? getAtomFeed(feedRoot) : getRssFeed(feedRoot);
|
|||
|
|
}
|
|||
|
|
function getAtomFeed(feedRoot) {
|
|||
|
|
var _a2;
|
|||
|
|
const childs = feedRoot.children;
|
|||
|
|
const feed = {
|
|||
|
|
type: "atom",
|
|||
|
|
items: getElementsByTagName("entry", childs).map((item) => {
|
|||
|
|
var _a3;
|
|||
|
|
const { children: children2 } = item;
|
|||
|
|
const entry = { media: getMediaElements(children2) };
|
|||
|
|
addConditionally(entry, "id", "id", children2);
|
|||
|
|
addConditionally(entry, "title", "title", children2);
|
|||
|
|
const href2 = (_a3 = getOneElement("link", children2)) === null || _a3 === void 0 ? void 0 : _a3.attribs["href"];
|
|||
|
|
if (href2) {
|
|||
|
|
entry.link = href2;
|
|||
|
|
}
|
|||
|
|
const description = fetch("summary", children2) || fetch("content", children2);
|
|||
|
|
if (description) {
|
|||
|
|
entry.description = description;
|
|||
|
|
}
|
|||
|
|
const pubDate = fetch("updated", children2);
|
|||
|
|
if (pubDate) {
|
|||
|
|
entry.pubDate = new Date(pubDate);
|
|||
|
|
}
|
|||
|
|
return entry;
|
|||
|
|
})
|
|||
|
|
};
|
|||
|
|
addConditionally(feed, "id", "id", childs);
|
|||
|
|
addConditionally(feed, "title", "title", childs);
|
|||
|
|
const href = (_a2 = getOneElement("link", childs)) === null || _a2 === void 0 ? void 0 : _a2.attribs["href"];
|
|||
|
|
if (href) {
|
|||
|
|
feed.link = href;
|
|||
|
|
}
|
|||
|
|
addConditionally(feed, "description", "subtitle", childs);
|
|||
|
|
const updated = fetch("updated", childs);
|
|||
|
|
if (updated) {
|
|||
|
|
feed.updated = new Date(updated);
|
|||
|
|
}
|
|||
|
|
addConditionally(feed, "author", "email", childs, true);
|
|||
|
|
return feed;
|
|||
|
|
}
|
|||
|
|
function getRssFeed(feedRoot) {
|
|||
|
|
var _a2, _b;
|
|||
|
|
const childs = (_b = (_a2 = getOneElement("channel", feedRoot.children)) === null || _a2 === void 0 ? void 0 : _a2.children) !== null && _b !== void 0 ? _b : [];
|
|||
|
|
const feed = {
|
|||
|
|
type: feedRoot.name.substr(0, 3),
|
|||
|
|
id: "",
|
|||
|
|
items: getElementsByTagName("item", feedRoot.children).map((item) => {
|
|||
|
|
const { children: children2 } = item;
|
|||
|
|
const entry = { media: getMediaElements(children2) };
|
|||
|
|
addConditionally(entry, "id", "guid", children2);
|
|||
|
|
addConditionally(entry, "title", "title", children2);
|
|||
|
|
addConditionally(entry, "link", "link", children2);
|
|||
|
|
addConditionally(entry, "description", "description", children2);
|
|||
|
|
const pubDate = fetch("pubDate", children2) || fetch("dc:date", children2);
|
|||
|
|
if (pubDate)
|
|||
|
|
entry.pubDate = new Date(pubDate);
|
|||
|
|
return entry;
|
|||
|
|
})
|
|||
|
|
};
|
|||
|
|
addConditionally(feed, "title", "title", childs);
|
|||
|
|
addConditionally(feed, "link", "link", childs);
|
|||
|
|
addConditionally(feed, "description", "description", childs);
|
|||
|
|
const updated = fetch("lastBuildDate", childs);
|
|||
|
|
if (updated) {
|
|||
|
|
feed.updated = new Date(updated);
|
|||
|
|
}
|
|||
|
|
addConditionally(feed, "author", "managingEditor", childs, true);
|
|||
|
|
return feed;
|
|||
|
|
}
|
|||
|
|
const MEDIA_KEYS_STRING = ["url", "type", "lang"];
|
|||
|
|
const MEDIA_KEYS_INT = [
|
|||
|
|
"fileSize",
|
|||
|
|
"bitrate",
|
|||
|
|
"framerate",
|
|||
|
|
"samplingrate",
|
|||
|
|
"channels",
|
|||
|
|
"duration",
|
|||
|
|
"height",
|
|||
|
|
"width"
|
|||
|
|
];
|
|||
|
|
function getMediaElements(where) {
|
|||
|
|
return getElementsByTagName("media:content", where).map((elem) => {
|
|||
|
|
const { attribs } = elem;
|
|||
|
|
const media = {
|
|||
|
|
medium: attribs["medium"],
|
|||
|
|
isDefault: !!attribs["isDefault"]
|
|||
|
|
};
|
|||
|
|
for (const attrib of MEDIA_KEYS_STRING) {
|
|||
|
|
if (attribs[attrib]) {
|
|||
|
|
media[attrib] = attribs[attrib];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
for (const attrib of MEDIA_KEYS_INT) {
|
|||
|
|
if (attribs[attrib]) {
|
|||
|
|
media[attrib] = parseInt(attribs[attrib], 10);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (attribs["expression"]) {
|
|||
|
|
media.expression = attribs["expression"];
|
|||
|
|
}
|
|||
|
|
return media;
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
function getOneElement(tagName, node) {
|
|||
|
|
return getElementsByTagName(tagName, node, true, 1)[0];
|
|||
|
|
}
|
|||
|
|
function fetch(tagName, where, recurse = false) {
|
|||
|
|
return textContent(getElementsByTagName(tagName, where, recurse, 1)).trim();
|
|||
|
|
}
|
|||
|
|
function addConditionally(obj, prop2, tagName, where, recurse = false) {
|
|||
|
|
const val2 = fetch(tagName, where, recurse);
|
|||
|
|
if (val2)
|
|||
|
|
obj[prop2] = val2;
|
|||
|
|
}
|
|||
|
|
function isValidFeed(value) {
|
|||
|
|
return value === "rss" || value === "feed" || value === "rdf:RDF";
|
|||
|
|
}
|
|||
|
|
const DomUtils = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|||
|
|
__proto__: null,
|
|||
|
|
get DocumentPosition() {
|
|||
|
|
return DocumentPosition;
|
|||
|
|
},
|
|||
|
|
append: append$1,
|
|||
|
|
appendChild,
|
|||
|
|
compareDocumentPosition,
|
|||
|
|
existsOne,
|
|||
|
|
filter: filter$2,
|
|||
|
|
find: find$2,
|
|||
|
|
findAll,
|
|||
|
|
findOne,
|
|||
|
|
findOneChild,
|
|||
|
|
getAttributeValue,
|
|||
|
|
getChildren,
|
|||
|
|
getElementById,
|
|||
|
|
getElements,
|
|||
|
|
getElementsByTagName,
|
|||
|
|
getElementsByTagType,
|
|||
|
|
getFeed,
|
|||
|
|
getInnerHTML,
|
|||
|
|
getName,
|
|||
|
|
getOuterHTML,
|
|||
|
|
getParent,
|
|||
|
|
getSiblings,
|
|||
|
|
getText,
|
|||
|
|
hasAttrib,
|
|||
|
|
hasChildren,
|
|||
|
|
innerText,
|
|||
|
|
isCDATA,
|
|||
|
|
isComment,
|
|||
|
|
isDocument,
|
|||
|
|
isTag,
|
|||
|
|
isText,
|
|||
|
|
nextElementSibling,
|
|||
|
|
prepend: prepend$1,
|
|||
|
|
prependChild,
|
|||
|
|
prevElementSibling,
|
|||
|
|
removeElement,
|
|||
|
|
removeSubsets,
|
|||
|
|
replaceElement,
|
|||
|
|
testElement,
|
|||
|
|
textContent,
|
|||
|
|
uniqueSort
|
|||
|
|
}, Symbol.toStringTag, { value: "Module" }));
|
|||
|
|
function render(that, dom, options) {
|
|||
|
|
if (!that)
|
|||
|
|
return "";
|
|||
|
|
return that(dom !== null && dom !== void 0 ? dom : that._root.children, null, void 0, options).toString();
|
|||
|
|
}
|
|||
|
|
function isOptions(dom, options) {
|
|||
|
|
return typeof dom === "object" && dom != null && !("length" in dom) && !("type" in dom);
|
|||
|
|
}
|
|||
|
|
function html$1(dom, options) {
|
|||
|
|
const toRender = isOptions(dom) ? (options = dom, void 0) : dom;
|
|||
|
|
const opts = {
|
|||
|
|
...this === null || this === void 0 ? void 0 : this._options,
|
|||
|
|
...flattenOptions(options)
|
|||
|
|
};
|
|||
|
|
return render(this, toRender, opts);
|
|||
|
|
}
|
|||
|
|
function xml(dom) {
|
|||
|
|
const options = { ...this._options, xmlMode: true };
|
|||
|
|
return render(this, dom, options);
|
|||
|
|
}
|
|||
|
|
function text$1(elements) {
|
|||
|
|
const elems = elements !== null && elements !== void 0 ? elements : this ? this.root() : [];
|
|||
|
|
let ret = "";
|
|||
|
|
for (let i = 0; i < elems.length; i++) {
|
|||
|
|
ret += textContent(elems[i]);
|
|||
|
|
}
|
|||
|
|
return ret;
|
|||
|
|
}
|
|||
|
|
function parseHTML(data2, context, keepScripts = typeof context === "boolean" ? context : false) {
|
|||
|
|
if (!data2 || typeof data2 !== "string") {
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
if (typeof context === "boolean") {
|
|||
|
|
keepScripts = context;
|
|||
|
|
}
|
|||
|
|
const parsed = this.load(data2, this._options, false);
|
|||
|
|
if (!keepScripts) {
|
|||
|
|
parsed("script").remove();
|
|||
|
|
}
|
|||
|
|
return [...parsed.root()[0].children];
|
|||
|
|
}
|
|||
|
|
function root() {
|
|||
|
|
return this(this._root);
|
|||
|
|
}
|
|||
|
|
function contains(container, contained) {
|
|||
|
|
if (contained === container) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
let next2 = contained;
|
|||
|
|
while (next2 && next2 !== next2.parent) {
|
|||
|
|
next2 = next2.parent;
|
|||
|
|
if (next2 === container) {
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
function extract$1(map2) {
|
|||
|
|
return this.root().extract(map2);
|
|||
|
|
}
|
|||
|
|
function merge(arr1, arr2) {
|
|||
|
|
if (!isArrayLike(arr1) || !isArrayLike(arr2)) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
let newLength = arr1.length;
|
|||
|
|
const len = +arr2.length;
|
|||
|
|
for (let i = 0; i < len; i++) {
|
|||
|
|
arr1[newLength++] = arr2[i];
|
|||
|
|
}
|
|||
|
|
arr1.length = newLength;
|
|||
|
|
return arr1;
|
|||
|
|
}
|
|||
|
|
function isArrayLike(item) {
|
|||
|
|
if (Array.isArray(item)) {
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
if (typeof item !== "object" || item === null || !("length" in item) || typeof item.length !== "number" || item.length < 0) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
for (let i = 0; i < item.length; i++) {
|
|||
|
|
if (!(i in item)) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
const staticMethods = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|||
|
|
__proto__: null,
|
|||
|
|
contains,
|
|||
|
|
extract: extract$1,
|
|||
|
|
html: html$1,
|
|||
|
|
merge,
|
|||
|
|
parseHTML,
|
|||
|
|
root,
|
|||
|
|
text: text$1,
|
|||
|
|
xml
|
|||
|
|
}, Symbol.toStringTag, { value: "Module" }));
|
|||
|
|
function isCheerio(maybeCheerio) {
|
|||
|
|
return maybeCheerio.cheerio != null;
|
|||
|
|
}
|
|||
|
|
function camelCase(str) {
|
|||
|
|
return str.replace(/[._-](\w|$)/g, (_, x) => x.toUpperCase());
|
|||
|
|
}
|
|||
|
|
function cssCase(str) {
|
|||
|
|
return str.replace(/[A-Z]/g, "-$&").toLowerCase();
|
|||
|
|
}
|
|||
|
|
function domEach(array, fn) {
|
|||
|
|
const len = array.length;
|
|||
|
|
for (let i = 0; i < len; i++)
|
|||
|
|
fn(array[i], i);
|
|||
|
|
return array;
|
|||
|
|
}
|
|||
|
|
var CharacterCodes;
|
|||
|
|
(function(CharacterCodes2) {
|
|||
|
|
CharacterCodes2[CharacterCodes2["LowerA"] = 97] = "LowerA";
|
|||
|
|
CharacterCodes2[CharacterCodes2["LowerZ"] = 122] = "LowerZ";
|
|||
|
|
CharacterCodes2[CharacterCodes2["UpperA"] = 65] = "UpperA";
|
|||
|
|
CharacterCodes2[CharacterCodes2["UpperZ"] = 90] = "UpperZ";
|
|||
|
|
CharacterCodes2[CharacterCodes2["Exclamation"] = 33] = "Exclamation";
|
|||
|
|
})(CharacterCodes || (CharacterCodes = {}));
|
|||
|
|
function isHtml(str) {
|
|||
|
|
const tagStart = str.indexOf("<");
|
|||
|
|
if (tagStart < 0 || tagStart > str.length - 3)
|
|||
|
|
return false;
|
|||
|
|
const tagChar = str.charCodeAt(tagStart + 1);
|
|||
|
|
return (tagChar >= CharacterCodes.LowerA && tagChar <= CharacterCodes.LowerZ || tagChar >= CharacterCodes.UpperA && tagChar <= CharacterCodes.UpperZ || tagChar === CharacterCodes.Exclamation) && str.includes(">", tagStart + 2);
|
|||
|
|
}
|
|||
|
|
const hasOwn = Object.prototype.hasOwnProperty;
|
|||
|
|
const rspace = /\s+/;
|
|||
|
|
const dataAttrPrefix = "data-";
|
|||
|
|
const rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i;
|
|||
|
|
const rbrace = /^{[^]*}$|^\[[^]*]$/;
|
|||
|
|
function getAttr(elem, name, xmlMode) {
|
|||
|
|
var _a2;
|
|||
|
|
if (!elem || !isTag(elem))
|
|||
|
|
return void 0;
|
|||
|
|
(_a2 = elem.attribs) !== null && _a2 !== void 0 ? _a2 : elem.attribs = {};
|
|||
|
|
if (!name) {
|
|||
|
|
return elem.attribs;
|
|||
|
|
}
|
|||
|
|
if (hasOwn.call(elem.attribs, name)) {
|
|||
|
|
return !xmlMode && rboolean.test(name) ? name : elem.attribs[name];
|
|||
|
|
}
|
|||
|
|
if (elem.name === "option" && name === "value") {
|
|||
|
|
return text$1(elem.children);
|
|||
|
|
}
|
|||
|
|
if (elem.name === "input" && (elem.attribs["type"] === "radio" || elem.attribs["type"] === "checkbox") && name === "value") {
|
|||
|
|
return "on";
|
|||
|
|
}
|
|||
|
|
return void 0;
|
|||
|
|
}
|
|||
|
|
function setAttr(el, name, value) {
|
|||
|
|
if (value === null) {
|
|||
|
|
removeAttribute(el, name);
|
|||
|
|
} else {
|
|||
|
|
el.attribs[name] = `${value}`;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function attr(name, value) {
|
|||
|
|
if (typeof name === "object" || value !== void 0) {
|
|||
|
|
if (typeof value === "function") {
|
|||
|
|
if (typeof name !== "string") {
|
|||
|
|
{
|
|||
|
|
throw new Error("Bad combination of arguments.");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return domEach(this, (el, i) => {
|
|||
|
|
if (isTag(el))
|
|||
|
|
setAttr(el, name, value.call(el, i, el.attribs[name]));
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
return domEach(this, (el) => {
|
|||
|
|
if (!isTag(el))
|
|||
|
|
return;
|
|||
|
|
if (typeof name === "object") {
|
|||
|
|
for (const objName of Object.keys(name)) {
|
|||
|
|
const objValue = name[objName];
|
|||
|
|
setAttr(el, objName, objValue);
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
setAttr(el, name, value);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
return arguments.length > 1 ? this : getAttr(this[0], name, this.options.xmlMode);
|
|||
|
|
}
|
|||
|
|
function getProp(el, name, xmlMode) {
|
|||
|
|
return name in el ? (
|
|||
|
|
// @ts-expect-error TS doesn't like us accessing the value directly here.
|
|||
|
|
el[name]
|
|||
|
|
) : !xmlMode && rboolean.test(name) ? getAttr(el, name, false) !== void 0 : getAttr(el, name, xmlMode);
|
|||
|
|
}
|
|||
|
|
function setProp(el, name, value, xmlMode) {
|
|||
|
|
if (name in el) {
|
|||
|
|
el[name] = value;
|
|||
|
|
} else {
|
|||
|
|
setAttr(el, name, !xmlMode && rboolean.test(name) ? value ? "" : null : `${value}`);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function prop(name, value) {
|
|||
|
|
var _a2;
|
|||
|
|
if (typeof name === "string" && value === void 0) {
|
|||
|
|
const el = this[0];
|
|||
|
|
if (!el || !isTag(el))
|
|||
|
|
return void 0;
|
|||
|
|
switch (name) {
|
|||
|
|
case "style": {
|
|||
|
|
const property = this.css();
|
|||
|
|
const keys = Object.keys(property);
|
|||
|
|
for (let i = 0; i < keys.length; i++) {
|
|||
|
|
property[i] = keys[i];
|
|||
|
|
}
|
|||
|
|
property.length = keys.length;
|
|||
|
|
return property;
|
|||
|
|
}
|
|||
|
|
case "tagName":
|
|||
|
|
case "nodeName": {
|
|||
|
|
return el.name.toUpperCase();
|
|||
|
|
}
|
|||
|
|
case "href":
|
|||
|
|
case "src": {
|
|||
|
|
const prop2 = (_a2 = el.attribs) === null || _a2 === void 0 ? void 0 : _a2[name];
|
|||
|
|
if (typeof URL !== "undefined" && (name === "href" && (el.tagName === "a" || el.tagName === "link") || name === "src" && (el.tagName === "img" || el.tagName === "iframe" || el.tagName === "audio" || el.tagName === "video" || el.tagName === "source")) && prop2 !== void 0 && this.options.baseURI) {
|
|||
|
|
return new URL(prop2, this.options.baseURI).href;
|
|||
|
|
}
|
|||
|
|
return prop2;
|
|||
|
|
}
|
|||
|
|
case "innerText": {
|
|||
|
|
return innerText(el);
|
|||
|
|
}
|
|||
|
|
case "textContent": {
|
|||
|
|
return textContent(el);
|
|||
|
|
}
|
|||
|
|
case "outerHTML": {
|
|||
|
|
return this.clone().wrap("<container />").parent().html();
|
|||
|
|
}
|
|||
|
|
case "innerHTML": {
|
|||
|
|
return this.html();
|
|||
|
|
}
|
|||
|
|
default: {
|
|||
|
|
return getProp(el, name, this.options.xmlMode);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (typeof name === "object" || value !== void 0) {
|
|||
|
|
if (typeof value === "function") {
|
|||
|
|
if (typeof name === "object") {
|
|||
|
|
throw new TypeError("Bad combination of arguments.");
|
|||
|
|
}
|
|||
|
|
return domEach(this, (el, i) => {
|
|||
|
|
if (isTag(el)) {
|
|||
|
|
setProp(el, name, value.call(el, i, getProp(el, name, this.options.xmlMode)), this.options.xmlMode);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
return domEach(this, (el) => {
|
|||
|
|
if (!isTag(el))
|
|||
|
|
return;
|
|||
|
|
if (typeof name === "object") {
|
|||
|
|
for (const key of Object.keys(name)) {
|
|||
|
|
const val2 = name[key];
|
|||
|
|
setProp(el, key, val2, this.options.xmlMode);
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
setProp(el, name, value, this.options.xmlMode);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
return void 0;
|
|||
|
|
}
|
|||
|
|
function setData(elem, name, value) {
|
|||
|
|
var _a2;
|
|||
|
|
(_a2 = elem.data) !== null && _a2 !== void 0 ? _a2 : elem.data = {};
|
|||
|
|
if (typeof name === "object")
|
|||
|
|
Object.assign(elem.data, name);
|
|||
|
|
else if (typeof name === "string" && value !== void 0) {
|
|||
|
|
elem.data[name] = value;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function readAllData(el) {
|
|||
|
|
for (const domName of Object.keys(el.attribs)) {
|
|||
|
|
if (!domName.startsWith(dataAttrPrefix)) {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
const jsName = camelCase(domName.slice(dataAttrPrefix.length));
|
|||
|
|
if (!hasOwn.call(el.data, jsName)) {
|
|||
|
|
el.data[jsName] = parseDataValue(el.attribs[domName]);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return el.data;
|
|||
|
|
}
|
|||
|
|
function readData(el, name) {
|
|||
|
|
const domName = dataAttrPrefix + cssCase(name);
|
|||
|
|
const data2 = el.data;
|
|||
|
|
if (hasOwn.call(data2, name)) {
|
|||
|
|
return data2[name];
|
|||
|
|
}
|
|||
|
|
if (hasOwn.call(el.attribs, domName)) {
|
|||
|
|
return data2[name] = parseDataValue(el.attribs[domName]);
|
|||
|
|
}
|
|||
|
|
return void 0;
|
|||
|
|
}
|
|||
|
|
function parseDataValue(value) {
|
|||
|
|
if (value === "null")
|
|||
|
|
return null;
|
|||
|
|
if (value === "true")
|
|||
|
|
return true;
|
|||
|
|
if (value === "false")
|
|||
|
|
return false;
|
|||
|
|
const num = Number(value);
|
|||
|
|
if (value === String(num))
|
|||
|
|
return num;
|
|||
|
|
if (rbrace.test(value)) {
|
|||
|
|
try {
|
|||
|
|
return JSON.parse(value);
|
|||
|
|
} catch {
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return value;
|
|||
|
|
}
|
|||
|
|
function data(name, value) {
|
|||
|
|
var _a2;
|
|||
|
|
const elem = this[0];
|
|||
|
|
if (!elem || !isTag(elem))
|
|||
|
|
return;
|
|||
|
|
const dataEl = elem;
|
|||
|
|
(_a2 = dataEl.data) !== null && _a2 !== void 0 ? _a2 : dataEl.data = {};
|
|||
|
|
if (name == null) {
|
|||
|
|
return readAllData(dataEl);
|
|||
|
|
}
|
|||
|
|
if (typeof name === "object" || value !== void 0) {
|
|||
|
|
domEach(this, (el) => {
|
|||
|
|
if (isTag(el)) {
|
|||
|
|
if (typeof name === "object")
|
|||
|
|
setData(el, name);
|
|||
|
|
else
|
|||
|
|
setData(el, name, value);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
return this;
|
|||
|
|
}
|
|||
|
|
return readData(dataEl, name);
|
|||
|
|
}
|
|||
|
|
function val(value) {
|
|||
|
|
const querying = arguments.length === 0;
|
|||
|
|
const element = this[0];
|
|||
|
|
if (!element || !isTag(element))
|
|||
|
|
return querying ? void 0 : this;
|
|||
|
|
switch (element.name) {
|
|||
|
|
case "textarea": {
|
|||
|
|
return this.text(value);
|
|||
|
|
}
|
|||
|
|
case "select": {
|
|||
|
|
const option = this.find("option:selected");
|
|||
|
|
if (!querying) {
|
|||
|
|
if (this.attr("multiple") == null && typeof value === "object") {
|
|||
|
|
return this;
|
|||
|
|
}
|
|||
|
|
this.find("option").removeAttr("selected");
|
|||
|
|
const values = typeof value === "object" ? value : [value];
|
|||
|
|
for (const val2 of values) {
|
|||
|
|
this.find(`option[value="${val2}"]`).attr("selected", "");
|
|||
|
|
}
|
|||
|
|
return this;
|
|||
|
|
}
|
|||
|
|
return this.attr("multiple") ? option.toArray().map((el) => text$1(el.children)) : option.attr("value");
|
|||
|
|
}
|
|||
|
|
case "input":
|
|||
|
|
case "option": {
|
|||
|
|
return querying ? this.attr("value") : this.attr("value", value);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return void 0;
|
|||
|
|
}
|
|||
|
|
function removeAttribute(elem, name) {
|
|||
|
|
if (!elem.attribs || !hasOwn.call(elem.attribs, name))
|
|||
|
|
return;
|
|||
|
|
delete elem.attribs[name];
|
|||
|
|
}
|
|||
|
|
function splitNames(names) {
|
|||
|
|
return names ? names.trim().split(rspace) : [];
|
|||
|
|
}
|
|||
|
|
function removeAttr(name) {
|
|||
|
|
const attrNames = splitNames(name);
|
|||
|
|
for (const attrName of attrNames) {
|
|||
|
|
domEach(this, (elem) => {
|
|||
|
|
if (isTag(elem))
|
|||
|
|
removeAttribute(elem, attrName);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
return this;
|
|||
|
|
}
|
|||
|
|
function hasClass(className) {
|
|||
|
|
return this.toArray().some((elem) => {
|
|||
|
|
const clazz = isTag(elem) && elem.attribs["class"];
|
|||
|
|
let idx = -1;
|
|||
|
|
if (clazz && className.length > 0) {
|
|||
|
|
while ((idx = clazz.indexOf(className, idx + 1)) > -1) {
|
|||
|
|
const end2 = idx + className.length;
|
|||
|
|
if ((idx === 0 || rspace.test(clazz[idx - 1])) && (end2 === clazz.length || rspace.test(clazz[end2]))) {
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return false;
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
function addClass(value) {
|
|||
|
|
if (typeof value === "function") {
|
|||
|
|
return domEach(this, (el, i) => {
|
|||
|
|
if (isTag(el)) {
|
|||
|
|
const className = el.attribs["class"] || "";
|
|||
|
|
addClass.call([el], value.call(el, i, className));
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
if (!value || typeof value !== "string")
|
|||
|
|
return this;
|
|||
|
|
const classNames = value.split(rspace);
|
|||
|
|
const numElements = this.length;
|
|||
|
|
for (let i = 0; i < numElements; i++) {
|
|||
|
|
const el = this[i];
|
|||
|
|
if (!isTag(el))
|
|||
|
|
continue;
|
|||
|
|
const className = getAttr(el, "class", false);
|
|||
|
|
if (className) {
|
|||
|
|
let setClass = ` ${className} `;
|
|||
|
|
for (const cn of classNames) {
|
|||
|
|
const appendClass = `${cn} `;
|
|||
|
|
if (!setClass.includes(` ${appendClass}`))
|
|||
|
|
setClass += appendClass;
|
|||
|
|
}
|
|||
|
|
setAttr(el, "class", setClass.trim());
|
|||
|
|
} else {
|
|||
|
|
setAttr(el, "class", classNames.join(" ").trim());
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return this;
|
|||
|
|
}
|
|||
|
|
function removeClass(name) {
|
|||
|
|
if (typeof name === "function") {
|
|||
|
|
return domEach(this, (el, i) => {
|
|||
|
|
if (isTag(el)) {
|
|||
|
|
removeClass.call([el], name.call(el, i, el.attribs["class"] || ""));
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
const classes = splitNames(name);
|
|||
|
|
const numClasses = classes.length;
|
|||
|
|
const removeAll = arguments.length === 0;
|
|||
|
|
return domEach(this, (el) => {
|
|||
|
|
if (!isTag(el))
|
|||
|
|
return;
|
|||
|
|
if (removeAll) {
|
|||
|
|
el.attribs["class"] = "";
|
|||
|
|
} else {
|
|||
|
|
const elClasses = splitNames(el.attribs["class"]);
|
|||
|
|
let changed = false;
|
|||
|
|
for (let j = 0; j < numClasses; j++) {
|
|||
|
|
const index2 = elClasses.indexOf(classes[j]);
|
|||
|
|
if (index2 >= 0) {
|
|||
|
|
elClasses.splice(index2, 1);
|
|||
|
|
changed = true;
|
|||
|
|
j--;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (changed) {
|
|||
|
|
el.attribs["class"] = elClasses.join(" ");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
function toggleClass(value, stateVal) {
|
|||
|
|
if (typeof value === "function") {
|
|||
|
|
return domEach(this, (el, i) => {
|
|||
|
|
if (isTag(el)) {
|
|||
|
|
toggleClass.call([el], value.call(el, i, el.attribs["class"] || "", stateVal), stateVal);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
if (!value || typeof value !== "string")
|
|||
|
|
return this;
|
|||
|
|
const classNames = value.split(rspace);
|
|||
|
|
const numClasses = classNames.length;
|
|||
|
|
const state = typeof stateVal === "boolean" ? stateVal ? 1 : -1 : 0;
|
|||
|
|
const numElements = this.length;
|
|||
|
|
for (let i = 0; i < numElements; i++) {
|
|||
|
|
const el = this[i];
|
|||
|
|
if (!isTag(el))
|
|||
|
|
continue;
|
|||
|
|
const elementClasses = splitNames(el.attribs["class"]);
|
|||
|
|
for (let j = 0; j < numClasses; j++) {
|
|||
|
|
const index2 = elementClasses.indexOf(classNames[j]);
|
|||
|
|
if (state >= 0 && index2 < 0) {
|
|||
|
|
elementClasses.push(classNames[j]);
|
|||
|
|
} else if (state <= 0 && index2 >= 0) {
|
|||
|
|
elementClasses.splice(index2, 1);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
el.attribs["class"] = elementClasses.join(" ");
|
|||
|
|
}
|
|||
|
|
return this;
|
|||
|
|
}
|
|||
|
|
const Attributes = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|||
|
|
__proto__: null,
|
|||
|
|
addClass,
|
|||
|
|
attr,
|
|||
|
|
data,
|
|||
|
|
hasClass,
|
|||
|
|
prop,
|
|||
|
|
removeAttr,
|
|||
|
|
removeClass,
|
|||
|
|
toggleClass,
|
|||
|
|
val
|
|||
|
|
}, Symbol.toStringTag, { value: "Module" }));
|
|||
|
|
var SelectorType;
|
|||
|
|
(function(SelectorType2) {
|
|||
|
|
SelectorType2["Attribute"] = "attribute";
|
|||
|
|
SelectorType2["Pseudo"] = "pseudo";
|
|||
|
|
SelectorType2["PseudoElement"] = "pseudo-element";
|
|||
|
|
SelectorType2["Tag"] = "tag";
|
|||
|
|
SelectorType2["Universal"] = "universal";
|
|||
|
|
SelectorType2["Adjacent"] = "adjacent";
|
|||
|
|
SelectorType2["Child"] = "child";
|
|||
|
|
SelectorType2["Descendant"] = "descendant";
|
|||
|
|
SelectorType2["Parent"] = "parent";
|
|||
|
|
SelectorType2["Sibling"] = "sibling";
|
|||
|
|
SelectorType2["ColumnCombinator"] = "column-combinator";
|
|||
|
|
})(SelectorType || (SelectorType = {}));
|
|||
|
|
var AttributeAction;
|
|||
|
|
(function(AttributeAction2) {
|
|||
|
|
AttributeAction2["Any"] = "any";
|
|||
|
|
AttributeAction2["Element"] = "element";
|
|||
|
|
AttributeAction2["End"] = "end";
|
|||
|
|
AttributeAction2["Equals"] = "equals";
|
|||
|
|
AttributeAction2["Exists"] = "exists";
|
|||
|
|
AttributeAction2["Hyphen"] = "hyphen";
|
|||
|
|
AttributeAction2["Not"] = "not";
|
|||
|
|
AttributeAction2["Start"] = "start";
|
|||
|
|
})(AttributeAction || (AttributeAction = {}));
|
|||
|
|
const reName = /^[^\\#]?(?:\\(?:[\da-f]{1,6}\s?|.)|[\w\-\u00b0-\uFFFF])+/;
|
|||
|
|
const reEscape = /\\([\da-f]{1,6}\s?|(\s)|.)/gi;
|
|||
|
|
const actionTypes = /* @__PURE__ */ new Map([
|
|||
|
|
[126, AttributeAction.Element],
|
|||
|
|
[94, AttributeAction.Start],
|
|||
|
|
[36, AttributeAction.End],
|
|||
|
|
[42, AttributeAction.Any],
|
|||
|
|
[33, AttributeAction.Not],
|
|||
|
|
[124, AttributeAction.Hyphen]
|
|||
|
|
]);
|
|||
|
|
const unpackPseudos = /* @__PURE__ */ new Set([
|
|||
|
|
"has",
|
|||
|
|
"not",
|
|||
|
|
"matches",
|
|||
|
|
"is",
|
|||
|
|
"where",
|
|||
|
|
"host",
|
|||
|
|
"host-context"
|
|||
|
|
]);
|
|||
|
|
function isTraversal$1(selector) {
|
|||
|
|
switch (selector.type) {
|
|||
|
|
case SelectorType.Adjacent:
|
|||
|
|
case SelectorType.Child:
|
|||
|
|
case SelectorType.Descendant:
|
|||
|
|
case SelectorType.Parent:
|
|||
|
|
case SelectorType.Sibling:
|
|||
|
|
case SelectorType.ColumnCombinator:
|
|||
|
|
return true;
|
|||
|
|
default:
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
const stripQuotesFromPseudos = /* @__PURE__ */ new Set(["contains", "icontains"]);
|
|||
|
|
function funescape(_, escaped, escapedWhitespace) {
|
|||
|
|
const high = parseInt(escaped, 16) - 65536;
|
|||
|
|
return high !== high || escapedWhitespace ? escaped : high < 0 ? (
|
|||
|
|
// BMP codepoint
|
|||
|
|
String.fromCharCode(high + 65536)
|
|||
|
|
) : (
|
|||
|
|
// Supplemental Plane codepoint (surrogate pair)
|
|||
|
|
String.fromCharCode(high >> 10 | 55296, high & 1023 | 56320)
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
function unescapeCSS(str) {
|
|||
|
|
return str.replace(reEscape, funescape);
|
|||
|
|
}
|
|||
|
|
function isQuote(c) {
|
|||
|
|
return c === 39 || c === 34;
|
|||
|
|
}
|
|||
|
|
function isWhitespace$1(c) {
|
|||
|
|
return c === 32 || c === 9 || c === 10 || c === 12 || c === 13;
|
|||
|
|
}
|
|||
|
|
function parse$2(selector) {
|
|||
|
|
const subselects2 = [];
|
|||
|
|
const endIndex = parseSelector(subselects2, `${selector}`, 0);
|
|||
|
|
if (endIndex < selector.length) {
|
|||
|
|
throw new Error(`Unmatched selector: ${selector.slice(endIndex)}`);
|
|||
|
|
}
|
|||
|
|
return subselects2;
|
|||
|
|
}
|
|||
|
|
function parseSelector(subselects2, selector, selectorIndex) {
|
|||
|
|
let tokens = [];
|
|||
|
|
function getName2(offset) {
|
|||
|
|
const match = selector.slice(selectorIndex + offset).match(reName);
|
|||
|
|
if (!match) {
|
|||
|
|
throw new Error(`Expected name, found ${selector.slice(selectorIndex)}`);
|
|||
|
|
}
|
|||
|
|
const [name] = match;
|
|||
|
|
selectorIndex += offset + name.length;
|
|||
|
|
return unescapeCSS(name);
|
|||
|
|
}
|
|||
|
|
function stripWhitespace(offset) {
|
|||
|
|
selectorIndex += offset;
|
|||
|
|
while (selectorIndex < selector.length && isWhitespace$1(selector.charCodeAt(selectorIndex))) {
|
|||
|
|
selectorIndex++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function readValueWithParenthesis() {
|
|||
|
|
selectorIndex += 1;
|
|||
|
|
const start = selectorIndex;
|
|||
|
|
let counter = 1;
|
|||
|
|
for (; counter > 0 && selectorIndex < selector.length; selectorIndex++) {
|
|||
|
|
if (selector.charCodeAt(selectorIndex) === 40 && !isEscaped(selectorIndex)) {
|
|||
|
|
counter++;
|
|||
|
|
} else if (selector.charCodeAt(selectorIndex) === 41 && !isEscaped(selectorIndex)) {
|
|||
|
|
counter--;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (counter) {
|
|||
|
|
throw new Error("Parenthesis not matched");
|
|||
|
|
}
|
|||
|
|
return unescapeCSS(selector.slice(start, selectorIndex - 1));
|
|||
|
|
}
|
|||
|
|
function isEscaped(pos) {
|
|||
|
|
let slashCount = 0;
|
|||
|
|
while (selector.charCodeAt(--pos) === 92)
|
|||
|
|
slashCount++;
|
|||
|
|
return (slashCount & 1) === 1;
|
|||
|
|
}
|
|||
|
|
function ensureNotTraversal() {
|
|||
|
|
if (tokens.length > 0 && isTraversal$1(tokens[tokens.length - 1])) {
|
|||
|
|
throw new Error("Did not expect successive traversals.");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function addTraversal(type) {
|
|||
|
|
if (tokens.length > 0 && tokens[tokens.length - 1].type === SelectorType.Descendant) {
|
|||
|
|
tokens[tokens.length - 1].type = type;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
ensureNotTraversal();
|
|||
|
|
tokens.push({ type });
|
|||
|
|
}
|
|||
|
|
function addSpecialAttribute(name, action) {
|
|||
|
|
tokens.push({
|
|||
|
|
type: SelectorType.Attribute,
|
|||
|
|
name,
|
|||
|
|
action,
|
|||
|
|
value: getName2(1),
|
|||
|
|
namespace: null,
|
|||
|
|
ignoreCase: "quirks"
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
function finalizeSubselector() {
|
|||
|
|
if (tokens.length && tokens[tokens.length - 1].type === SelectorType.Descendant) {
|
|||
|
|
tokens.pop();
|
|||
|
|
}
|
|||
|
|
if (tokens.length === 0) {
|
|||
|
|
throw new Error("Empty sub-selector");
|
|||
|
|
}
|
|||
|
|
subselects2.push(tokens);
|
|||
|
|
}
|
|||
|
|
stripWhitespace(0);
|
|||
|
|
if (selector.length === selectorIndex) {
|
|||
|
|
return selectorIndex;
|
|||
|
|
}
|
|||
|
|
loop: while (selectorIndex < selector.length) {
|
|||
|
|
const firstChar = selector.charCodeAt(selectorIndex);
|
|||
|
|
switch (firstChar) {
|
|||
|
|
// Whitespace
|
|||
|
|
case 32:
|
|||
|
|
case 9:
|
|||
|
|
case 10:
|
|||
|
|
case 12:
|
|||
|
|
case 13: {
|
|||
|
|
if (tokens.length === 0 || tokens[0].type !== SelectorType.Descendant) {
|
|||
|
|
ensureNotTraversal();
|
|||
|
|
tokens.push({ type: SelectorType.Descendant });
|
|||
|
|
}
|
|||
|
|
stripWhitespace(1);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
// Traversals
|
|||
|
|
case 62: {
|
|||
|
|
addTraversal(SelectorType.Child);
|
|||
|
|
stripWhitespace(1);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case 60: {
|
|||
|
|
addTraversal(SelectorType.Parent);
|
|||
|
|
stripWhitespace(1);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case 126: {
|
|||
|
|
addTraversal(SelectorType.Sibling);
|
|||
|
|
stripWhitespace(1);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case 43: {
|
|||
|
|
addTraversal(SelectorType.Adjacent);
|
|||
|
|
stripWhitespace(1);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
// Special attribute selectors: .class, #id
|
|||
|
|
case 46: {
|
|||
|
|
addSpecialAttribute("class", AttributeAction.Element);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case 35: {
|
|||
|
|
addSpecialAttribute("id", AttributeAction.Equals);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case 91: {
|
|||
|
|
stripWhitespace(1);
|
|||
|
|
let name;
|
|||
|
|
let namespace = null;
|
|||
|
|
if (selector.charCodeAt(selectorIndex) === 124) {
|
|||
|
|
name = getName2(1);
|
|||
|
|
} else if (selector.startsWith("*|", selectorIndex)) {
|
|||
|
|
namespace = "*";
|
|||
|
|
name = getName2(2);
|
|||
|
|
} else {
|
|||
|
|
name = getName2(0);
|
|||
|
|
if (selector.charCodeAt(selectorIndex) === 124 && selector.charCodeAt(selectorIndex + 1) !== 61) {
|
|||
|
|
namespace = name;
|
|||
|
|
name = getName2(1);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
stripWhitespace(0);
|
|||
|
|
let action = AttributeAction.Exists;
|
|||
|
|
const possibleAction = actionTypes.get(selector.charCodeAt(selectorIndex));
|
|||
|
|
if (possibleAction) {
|
|||
|
|
action = possibleAction;
|
|||
|
|
if (selector.charCodeAt(selectorIndex + 1) !== 61) {
|
|||
|
|
throw new Error("Expected `=`");
|
|||
|
|
}
|
|||
|
|
stripWhitespace(2);
|
|||
|
|
} else if (selector.charCodeAt(selectorIndex) === 61) {
|
|||
|
|
action = AttributeAction.Equals;
|
|||
|
|
stripWhitespace(1);
|
|||
|
|
}
|
|||
|
|
let value = "";
|
|||
|
|
let ignoreCase = null;
|
|||
|
|
if (action !== "exists") {
|
|||
|
|
if (isQuote(selector.charCodeAt(selectorIndex))) {
|
|||
|
|
const quote = selector.charCodeAt(selectorIndex);
|
|||
|
|
let sectionEnd = selectorIndex + 1;
|
|||
|
|
while (sectionEnd < selector.length && (selector.charCodeAt(sectionEnd) !== quote || isEscaped(sectionEnd))) {
|
|||
|
|
sectionEnd += 1;
|
|||
|
|
}
|
|||
|
|
if (selector.charCodeAt(sectionEnd) !== quote) {
|
|||
|
|
throw new Error("Attribute value didn't end");
|
|||
|
|
}
|
|||
|
|
value = unescapeCSS(selector.slice(selectorIndex + 1, sectionEnd));
|
|||
|
|
selectorIndex = sectionEnd + 1;
|
|||
|
|
} else {
|
|||
|
|
const valueStart = selectorIndex;
|
|||
|
|
while (selectorIndex < selector.length && (!isWhitespace$1(selector.charCodeAt(selectorIndex)) && selector.charCodeAt(selectorIndex) !== 93 || isEscaped(selectorIndex))) {
|
|||
|
|
selectorIndex += 1;
|
|||
|
|
}
|
|||
|
|
value = unescapeCSS(selector.slice(valueStart, selectorIndex));
|
|||
|
|
}
|
|||
|
|
stripWhitespace(0);
|
|||
|
|
const forceIgnore = selector.charCodeAt(selectorIndex) | 32;
|
|||
|
|
if (forceIgnore === 115) {
|
|||
|
|
ignoreCase = false;
|
|||
|
|
stripWhitespace(1);
|
|||
|
|
} else if (forceIgnore === 105) {
|
|||
|
|
ignoreCase = true;
|
|||
|
|
stripWhitespace(1);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (selector.charCodeAt(selectorIndex) !== 93) {
|
|||
|
|
throw new Error("Attribute selector didn't terminate");
|
|||
|
|
}
|
|||
|
|
selectorIndex += 1;
|
|||
|
|
const attributeSelector = {
|
|||
|
|
type: SelectorType.Attribute,
|
|||
|
|
name,
|
|||
|
|
action,
|
|||
|
|
value,
|
|||
|
|
namespace,
|
|||
|
|
ignoreCase
|
|||
|
|
};
|
|||
|
|
tokens.push(attributeSelector);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case 58: {
|
|||
|
|
if (selector.charCodeAt(selectorIndex + 1) === 58) {
|
|||
|
|
tokens.push({
|
|||
|
|
type: SelectorType.PseudoElement,
|
|||
|
|
name: getName2(2).toLowerCase(),
|
|||
|
|
data: selector.charCodeAt(selectorIndex) === 40 ? readValueWithParenthesis() : null
|
|||
|
|
});
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
const name = getName2(1).toLowerCase();
|
|||
|
|
let data2 = null;
|
|||
|
|
if (selector.charCodeAt(selectorIndex) === 40) {
|
|||
|
|
if (unpackPseudos.has(name)) {
|
|||
|
|
if (isQuote(selector.charCodeAt(selectorIndex + 1))) {
|
|||
|
|
throw new Error(`Pseudo-selector ${name} cannot be quoted`);
|
|||
|
|
}
|
|||
|
|
data2 = [];
|
|||
|
|
selectorIndex = parseSelector(data2, selector, selectorIndex + 1);
|
|||
|
|
if (selector.charCodeAt(selectorIndex) !== 41) {
|
|||
|
|
throw new Error(`Missing closing parenthesis in :${name} (${selector})`);
|
|||
|
|
}
|
|||
|
|
selectorIndex += 1;
|
|||
|
|
} else {
|
|||
|
|
data2 = readValueWithParenthesis();
|
|||
|
|
if (stripQuotesFromPseudos.has(name)) {
|
|||
|
|
const quot = data2.charCodeAt(0);
|
|||
|
|
if (quot === data2.charCodeAt(data2.length - 1) && isQuote(quot)) {
|
|||
|
|
data2 = data2.slice(1, -1);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
data2 = unescapeCSS(data2);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
tokens.push({ type: SelectorType.Pseudo, name, data: data2 });
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case 44: {
|
|||
|
|
finalizeSubselector();
|
|||
|
|
tokens = [];
|
|||
|
|
stripWhitespace(1);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
default: {
|
|||
|
|
if (selector.startsWith("/*", selectorIndex)) {
|
|||
|
|
const endIndex = selector.indexOf("*/", selectorIndex + 2);
|
|||
|
|
if (endIndex < 0) {
|
|||
|
|
throw new Error("Comment was not terminated");
|
|||
|
|
}
|
|||
|
|
selectorIndex = endIndex + 2;
|
|||
|
|
if (tokens.length === 0) {
|
|||
|
|
stripWhitespace(0);
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
let namespace = null;
|
|||
|
|
let name;
|
|||
|
|
if (firstChar === 42) {
|
|||
|
|
selectorIndex += 1;
|
|||
|
|
name = "*";
|
|||
|
|
} else if (firstChar === 124) {
|
|||
|
|
name = "";
|
|||
|
|
if (selector.charCodeAt(selectorIndex + 1) === 124) {
|
|||
|
|
addTraversal(SelectorType.ColumnCombinator);
|
|||
|
|
stripWhitespace(2);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
} else if (reName.test(selector.slice(selectorIndex))) {
|
|||
|
|
name = getName2(0);
|
|||
|
|
} else {
|
|||
|
|
break loop;
|
|||
|
|
}
|
|||
|
|
if (selector.charCodeAt(selectorIndex) === 124 && selector.charCodeAt(selectorIndex + 1) !== 124) {
|
|||
|
|
namespace = name;
|
|||
|
|
if (selector.charCodeAt(selectorIndex + 1) === 42) {
|
|||
|
|
name = "*";
|
|||
|
|
selectorIndex += 2;
|
|||
|
|
} else {
|
|||
|
|
name = getName2(1);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
tokens.push(name === "*" ? { type: SelectorType.Universal, namespace } : { type: SelectorType.Tag, name, namespace });
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
finalizeSubselector();
|
|||
|
|
return selectorIndex;
|
|||
|
|
}
|
|||
|
|
function getDefaultExportFromCjs(x) {
|
|||
|
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
|
|||
|
|
}
|
|||
|
|
var boolbase$1;
|
|||
|
|
var hasRequiredBoolbase;
|
|||
|
|
function requireBoolbase() {
|
|||
|
|
if (hasRequiredBoolbase) return boolbase$1;
|
|||
|
|
hasRequiredBoolbase = 1;
|
|||
|
|
boolbase$1 = {
|
|||
|
|
trueFunc: function trueFunc() {
|
|||
|
|
return true;
|
|||
|
|
},
|
|||
|
|
falseFunc: function falseFunc() {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
return boolbase$1;
|
|||
|
|
}
|
|||
|
|
var boolbaseExports = requireBoolbase();
|
|||
|
|
const boolbase = /* @__PURE__ */ getDefaultExportFromCjs(boolbaseExports);
|
|||
|
|
const procedure = /* @__PURE__ */ new Map([
|
|||
|
|
[SelectorType.Universal, 50],
|
|||
|
|
[SelectorType.Tag, 30],
|
|||
|
|
[SelectorType.Attribute, 1],
|
|||
|
|
[SelectorType.Pseudo, 0]
|
|||
|
|
]);
|
|||
|
|
function isTraversal(token) {
|
|||
|
|
return !procedure.has(token.type);
|
|||
|
|
}
|
|||
|
|
const attributes = /* @__PURE__ */ new Map([
|
|||
|
|
[AttributeAction.Exists, 10],
|
|||
|
|
[AttributeAction.Equals, 8],
|
|||
|
|
[AttributeAction.Not, 7],
|
|||
|
|
[AttributeAction.Start, 6],
|
|||
|
|
[AttributeAction.End, 6],
|
|||
|
|
[AttributeAction.Any, 5]
|
|||
|
|
]);
|
|||
|
|
function sortByProcedure(arr) {
|
|||
|
|
const procs = arr.map(getProcedure);
|
|||
|
|
for (let i = 1; i < arr.length; i++) {
|
|||
|
|
const procNew = procs[i];
|
|||
|
|
if (procNew < 0)
|
|||
|
|
continue;
|
|||
|
|
for (let j = i - 1; j >= 0 && procNew < procs[j]; j--) {
|
|||
|
|
const token = arr[j + 1];
|
|||
|
|
arr[j + 1] = arr[j];
|
|||
|
|
arr[j] = token;
|
|||
|
|
procs[j + 1] = procs[j];
|
|||
|
|
procs[j] = procNew;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function getProcedure(token) {
|
|||
|
|
var _a2, _b;
|
|||
|
|
let proc = (_a2 = procedure.get(token.type)) !== null && _a2 !== void 0 ? _a2 : -1;
|
|||
|
|
if (token.type === SelectorType.Attribute) {
|
|||
|
|
proc = (_b = attributes.get(token.action)) !== null && _b !== void 0 ? _b : 4;
|
|||
|
|
if (token.action === AttributeAction.Equals && token.name === "id") {
|
|||
|
|
proc = 9;
|
|||
|
|
}
|
|||
|
|
if (token.ignoreCase) {
|
|||
|
|
proc >>= 1;
|
|||
|
|
}
|
|||
|
|
} else if (token.type === SelectorType.Pseudo) {
|
|||
|
|
if (!token.data) {
|
|||
|
|
proc = 3;
|
|||
|
|
} else if (token.name === "has" || token.name === "contains") {
|
|||
|
|
proc = 0;
|
|||
|
|
} else if (Array.isArray(token.data)) {
|
|||
|
|
proc = Math.min(...token.data.map((d) => Math.min(...d.map(getProcedure))));
|
|||
|
|
if (proc < 0) {
|
|||
|
|
proc = 0;
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
proc = 2;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return proc;
|
|||
|
|
}
|
|||
|
|
const reChars = /[-[\]{}()*+?.,\\^$|#\s]/g;
|
|||
|
|
function escapeRegex(value) {
|
|||
|
|
return value.replace(reChars, "\\$&");
|
|||
|
|
}
|
|||
|
|
const caseInsensitiveAttributes = /* @__PURE__ */ new Set([
|
|||
|
|
"accept",
|
|||
|
|
"accept-charset",
|
|||
|
|
"align",
|
|||
|
|
"alink",
|
|||
|
|
"axis",
|
|||
|
|
"bgcolor",
|
|||
|
|
"charset",
|
|||
|
|
"checked",
|
|||
|
|
"clear",
|
|||
|
|
"codetype",
|
|||
|
|
"color",
|
|||
|
|
"compact",
|
|||
|
|
"declare",
|
|||
|
|
"defer",
|
|||
|
|
"dir",
|
|||
|
|
"direction",
|
|||
|
|
"disabled",
|
|||
|
|
"enctype",
|
|||
|
|
"face",
|
|||
|
|
"frame",
|
|||
|
|
"hreflang",
|
|||
|
|
"http-equiv",
|
|||
|
|
"lang",
|
|||
|
|
"language",
|
|||
|
|
"link",
|
|||
|
|
"media",
|
|||
|
|
"method",
|
|||
|
|
"multiple",
|
|||
|
|
"nohref",
|
|||
|
|
"noresize",
|
|||
|
|
"noshade",
|
|||
|
|
"nowrap",
|
|||
|
|
"readonly",
|
|||
|
|
"rel",
|
|||
|
|
"rev",
|
|||
|
|
"rules",
|
|||
|
|
"scope",
|
|||
|
|
"scrolling",
|
|||
|
|
"selected",
|
|||
|
|
"shape",
|
|||
|
|
"target",
|
|||
|
|
"text",
|
|||
|
|
"type",
|
|||
|
|
"valign",
|
|||
|
|
"valuetype",
|
|||
|
|
"vlink"
|
|||
|
|
]);
|
|||
|
|
function shouldIgnoreCase(selector, options) {
|
|||
|
|
return typeof selector.ignoreCase === "boolean" ? selector.ignoreCase : selector.ignoreCase === "quirks" ? !!options.quirksMode : !options.xmlMode && caseInsensitiveAttributes.has(selector.name);
|
|||
|
|
}
|
|||
|
|
const attributeRules = {
|
|||
|
|
equals(next2, data2, options) {
|
|||
|
|
const { adapter } = options;
|
|||
|
|
const { name } = data2;
|
|||
|
|
let { value } = data2;
|
|||
|
|
if (shouldIgnoreCase(data2, options)) {
|
|||
|
|
value = value.toLowerCase();
|
|||
|
|
return (elem) => {
|
|||
|
|
const attr2 = adapter.getAttributeValue(elem, name);
|
|||
|
|
return attr2 != null && attr2.length === value.length && attr2.toLowerCase() === value && next2(elem);
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
return (elem) => adapter.getAttributeValue(elem, name) === value && next2(elem);
|
|||
|
|
},
|
|||
|
|
hyphen(next2, data2, options) {
|
|||
|
|
const { adapter } = options;
|
|||
|
|
const { name } = data2;
|
|||
|
|
let { value } = data2;
|
|||
|
|
const len = value.length;
|
|||
|
|
if (shouldIgnoreCase(data2, options)) {
|
|||
|
|
value = value.toLowerCase();
|
|||
|
|
return function hyphenIC(elem) {
|
|||
|
|
const attr2 = adapter.getAttributeValue(elem, name);
|
|||
|
|
return attr2 != null && (attr2.length === len || attr2.charAt(len) === "-") && attr2.substr(0, len).toLowerCase() === value && next2(elem);
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
return function hyphen(elem) {
|
|||
|
|
const attr2 = adapter.getAttributeValue(elem, name);
|
|||
|
|
return attr2 != null && (attr2.length === len || attr2.charAt(len) === "-") && attr2.substr(0, len) === value && next2(elem);
|
|||
|
|
};
|
|||
|
|
},
|
|||
|
|
element(next2, data2, options) {
|
|||
|
|
const { adapter } = options;
|
|||
|
|
const { name, value } = data2;
|
|||
|
|
if (/\s/.test(value)) {
|
|||
|
|
return boolbase.falseFunc;
|
|||
|
|
}
|
|||
|
|
const regex = new RegExp(`(?:^|\\s)${escapeRegex(value)}(?:$|\\s)`, shouldIgnoreCase(data2, options) ? "i" : "");
|
|||
|
|
return function element(elem) {
|
|||
|
|
const attr2 = adapter.getAttributeValue(elem, name);
|
|||
|
|
return attr2 != null && attr2.length >= value.length && regex.test(attr2) && next2(elem);
|
|||
|
|
};
|
|||
|
|
},
|
|||
|
|
exists(next2, { name }, { adapter }) {
|
|||
|
|
return (elem) => adapter.hasAttrib(elem, name) && next2(elem);
|
|||
|
|
},
|
|||
|
|
start(next2, data2, options) {
|
|||
|
|
const { adapter } = options;
|
|||
|
|
const { name } = data2;
|
|||
|
|
let { value } = data2;
|
|||
|
|
const len = value.length;
|
|||
|
|
if (len === 0) {
|
|||
|
|
return boolbase.falseFunc;
|
|||
|
|
}
|
|||
|
|
if (shouldIgnoreCase(data2, options)) {
|
|||
|
|
value = value.toLowerCase();
|
|||
|
|
return (elem) => {
|
|||
|
|
const attr2 = adapter.getAttributeValue(elem, name);
|
|||
|
|
return attr2 != null && attr2.length >= len && attr2.substr(0, len).toLowerCase() === value && next2(elem);
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
return (elem) => {
|
|||
|
|
var _a2;
|
|||
|
|
return !!((_a2 = adapter.getAttributeValue(elem, name)) === null || _a2 === void 0 ? void 0 : _a2.startsWith(value)) && next2(elem);
|
|||
|
|
};
|
|||
|
|
},
|
|||
|
|
end(next2, data2, options) {
|
|||
|
|
const { adapter } = options;
|
|||
|
|
const { name } = data2;
|
|||
|
|
let { value } = data2;
|
|||
|
|
const len = -value.length;
|
|||
|
|
if (len === 0) {
|
|||
|
|
return boolbase.falseFunc;
|
|||
|
|
}
|
|||
|
|
if (shouldIgnoreCase(data2, options)) {
|
|||
|
|
value = value.toLowerCase();
|
|||
|
|
return (elem) => {
|
|||
|
|
var _a2;
|
|||
|
|
return ((_a2 = adapter.getAttributeValue(elem, name)) === null || _a2 === void 0 ? void 0 : _a2.substr(len).toLowerCase()) === value && next2(elem);
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
return (elem) => {
|
|||
|
|
var _a2;
|
|||
|
|
return !!((_a2 = adapter.getAttributeValue(elem, name)) === null || _a2 === void 0 ? void 0 : _a2.endsWith(value)) && next2(elem);
|
|||
|
|
};
|
|||
|
|
},
|
|||
|
|
any(next2, data2, options) {
|
|||
|
|
const { adapter } = options;
|
|||
|
|
const { name, value } = data2;
|
|||
|
|
if (value === "") {
|
|||
|
|
return boolbase.falseFunc;
|
|||
|
|
}
|
|||
|
|
if (shouldIgnoreCase(data2, options)) {
|
|||
|
|
const regex = new RegExp(escapeRegex(value), "i");
|
|||
|
|
return function anyIC(elem) {
|
|||
|
|
const attr2 = adapter.getAttributeValue(elem, name);
|
|||
|
|
return attr2 != null && attr2.length >= value.length && regex.test(attr2) && next2(elem);
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
return (elem) => {
|
|||
|
|
var _a2;
|
|||
|
|
return !!((_a2 = adapter.getAttributeValue(elem, name)) === null || _a2 === void 0 ? void 0 : _a2.includes(value)) && next2(elem);
|
|||
|
|
};
|
|||
|
|
},
|
|||
|
|
not(next2, data2, options) {
|
|||
|
|
const { adapter } = options;
|
|||
|
|
const { name } = data2;
|
|||
|
|
let { value } = data2;
|
|||
|
|
if (value === "") {
|
|||
|
|
return (elem) => !!adapter.getAttributeValue(elem, name) && next2(elem);
|
|||
|
|
} else if (shouldIgnoreCase(data2, options)) {
|
|||
|
|
value = value.toLowerCase();
|
|||
|
|
return (elem) => {
|
|||
|
|
const attr2 = adapter.getAttributeValue(elem, name);
|
|||
|
|
return (attr2 == null || attr2.length !== value.length || attr2.toLowerCase() !== value) && next2(elem);
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
return (elem) => adapter.getAttributeValue(elem, name) !== value && next2(elem);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
const whitespace = /* @__PURE__ */ new Set([9, 10, 12, 13, 32]);
|
|||
|
|
const ZERO = "0".charCodeAt(0);
|
|||
|
|
const NINE = "9".charCodeAt(0);
|
|||
|
|
function parse$1(formula) {
|
|||
|
|
formula = formula.trim().toLowerCase();
|
|||
|
|
if (formula === "even") {
|
|||
|
|
return [2, 0];
|
|||
|
|
} else if (formula === "odd") {
|
|||
|
|
return [2, 1];
|
|||
|
|
}
|
|||
|
|
let idx = 0;
|
|||
|
|
let a = 0;
|
|||
|
|
let sign = readSign();
|
|||
|
|
let number = readNumber();
|
|||
|
|
if (idx < formula.length && formula.charAt(idx) === "n") {
|
|||
|
|
idx++;
|
|||
|
|
a = sign * (number !== null && number !== void 0 ? number : 1);
|
|||
|
|
skipWhitespace();
|
|||
|
|
if (idx < formula.length) {
|
|||
|
|
sign = readSign();
|
|||
|
|
skipWhitespace();
|
|||
|
|
number = readNumber();
|
|||
|
|
} else {
|
|||
|
|
sign = number = 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (number === null || idx < formula.length) {
|
|||
|
|
throw new Error(`n-th rule couldn't be parsed ('${formula}')`);
|
|||
|
|
}
|
|||
|
|
return [a, sign * number];
|
|||
|
|
function readSign() {
|
|||
|
|
if (formula.charAt(idx) === "-") {
|
|||
|
|
idx++;
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
if (formula.charAt(idx) === "+") {
|
|||
|
|
idx++;
|
|||
|
|
}
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
function readNumber() {
|
|||
|
|
const start = idx;
|
|||
|
|
let value = 0;
|
|||
|
|
while (idx < formula.length && formula.charCodeAt(idx) >= ZERO && formula.charCodeAt(idx) <= NINE) {
|
|||
|
|
value = value * 10 + (formula.charCodeAt(idx) - ZERO);
|
|||
|
|
idx++;
|
|||
|
|
}
|
|||
|
|
return idx === start ? null : value;
|
|||
|
|
}
|
|||
|
|
function skipWhitespace() {
|
|||
|
|
while (idx < formula.length && whitespace.has(formula.charCodeAt(idx))) {
|
|||
|
|
idx++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function compile(parsed) {
|
|||
|
|
const a = parsed[0];
|
|||
|
|
const b = parsed[1] - 1;
|
|||
|
|
if (b < 0 && a <= 0)
|
|||
|
|
return boolbase.falseFunc;
|
|||
|
|
if (a === -1)
|
|||
|
|
return (index2) => index2 <= b;
|
|||
|
|
if (a === 0)
|
|||
|
|
return (index2) => index2 === b;
|
|||
|
|
if (a === 1)
|
|||
|
|
return b < 0 ? boolbase.trueFunc : (index2) => index2 >= b;
|
|||
|
|
const absA = Math.abs(a);
|
|||
|
|
const bMod = (b % absA + absA) % absA;
|
|||
|
|
return a > 1 ? (index2) => index2 >= b && index2 % absA === bMod : (index2) => index2 <= b && index2 % absA === bMod;
|
|||
|
|
}
|
|||
|
|
function nthCheck(formula) {
|
|||
|
|
return compile(parse$1(formula));
|
|||
|
|
}
|
|||
|
|
function getChildFunc(next2, adapter) {
|
|||
|
|
return (elem) => {
|
|||
|
|
const parent2 = adapter.getParent(elem);
|
|||
|
|
return parent2 != null && adapter.isTag(parent2) && next2(elem);
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
const filters = {
|
|||
|
|
contains(next2, text2, { adapter }) {
|
|||
|
|
return function contains2(elem) {
|
|||
|
|
return next2(elem) && adapter.getText(elem).includes(text2);
|
|||
|
|
};
|
|||
|
|
},
|
|||
|
|
icontains(next2, text2, { adapter }) {
|
|||
|
|
const itext = text2.toLowerCase();
|
|||
|
|
return function icontains(elem) {
|
|||
|
|
return next2(elem) && adapter.getText(elem).toLowerCase().includes(itext);
|
|||
|
|
};
|
|||
|
|
},
|
|||
|
|
// Location specific methods
|
|||
|
|
"nth-child"(next2, rule, { adapter, equals }) {
|
|||
|
|
const func = nthCheck(rule);
|
|||
|
|
if (func === boolbase.falseFunc)
|
|||
|
|
return boolbase.falseFunc;
|
|||
|
|
if (func === boolbase.trueFunc)
|
|||
|
|
return getChildFunc(next2, adapter);
|
|||
|
|
return function nthChild(elem) {
|
|||
|
|
const siblings2 = adapter.getSiblings(elem);
|
|||
|
|
let pos = 0;
|
|||
|
|
for (let i = 0; i < siblings2.length; i++) {
|
|||
|
|
if (equals(elem, siblings2[i]))
|
|||
|
|
break;
|
|||
|
|
if (adapter.isTag(siblings2[i])) {
|
|||
|
|
pos++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return func(pos) && next2(elem);
|
|||
|
|
};
|
|||
|
|
},
|
|||
|
|
"nth-last-child"(next2, rule, { adapter, equals }) {
|
|||
|
|
const func = nthCheck(rule);
|
|||
|
|
if (func === boolbase.falseFunc)
|
|||
|
|
return boolbase.falseFunc;
|
|||
|
|
if (func === boolbase.trueFunc)
|
|||
|
|
return getChildFunc(next2, adapter);
|
|||
|
|
return function nthLastChild(elem) {
|
|||
|
|
const siblings2 = adapter.getSiblings(elem);
|
|||
|
|
let pos = 0;
|
|||
|
|
for (let i = siblings2.length - 1; i >= 0; i--) {
|
|||
|
|
if (equals(elem, siblings2[i]))
|
|||
|
|
break;
|
|||
|
|
if (adapter.isTag(siblings2[i])) {
|
|||
|
|
pos++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return func(pos) && next2(elem);
|
|||
|
|
};
|
|||
|
|
},
|
|||
|
|
"nth-of-type"(next2, rule, { adapter, equals }) {
|
|||
|
|
const func = nthCheck(rule);
|
|||
|
|
if (func === boolbase.falseFunc)
|
|||
|
|
return boolbase.falseFunc;
|
|||
|
|
if (func === boolbase.trueFunc)
|
|||
|
|
return getChildFunc(next2, adapter);
|
|||
|
|
return function nthOfType(elem) {
|
|||
|
|
const siblings2 = adapter.getSiblings(elem);
|
|||
|
|
let pos = 0;
|
|||
|
|
for (let i = 0; i < siblings2.length; i++) {
|
|||
|
|
const currentSibling = siblings2[i];
|
|||
|
|
if (equals(elem, currentSibling))
|
|||
|
|
break;
|
|||
|
|
if (adapter.isTag(currentSibling) && adapter.getName(currentSibling) === adapter.getName(elem)) {
|
|||
|
|
pos++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return func(pos) && next2(elem);
|
|||
|
|
};
|
|||
|
|
},
|
|||
|
|
"nth-last-of-type"(next2, rule, { adapter, equals }) {
|
|||
|
|
const func = nthCheck(rule);
|
|||
|
|
if (func === boolbase.falseFunc)
|
|||
|
|
return boolbase.falseFunc;
|
|||
|
|
if (func === boolbase.trueFunc)
|
|||
|
|
return getChildFunc(next2, adapter);
|
|||
|
|
return function nthLastOfType(elem) {
|
|||
|
|
const siblings2 = adapter.getSiblings(elem);
|
|||
|
|
let pos = 0;
|
|||
|
|
for (let i = siblings2.length - 1; i >= 0; i--) {
|
|||
|
|
const currentSibling = siblings2[i];
|
|||
|
|
if (equals(elem, currentSibling))
|
|||
|
|
break;
|
|||
|
|
if (adapter.isTag(currentSibling) && adapter.getName(currentSibling) === adapter.getName(elem)) {
|
|||
|
|
pos++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return func(pos) && next2(elem);
|
|||
|
|
};
|
|||
|
|
},
|
|||
|
|
// TODO determine the actual root element
|
|||
|
|
root(next2, _rule, { adapter }) {
|
|||
|
|
return (elem) => {
|
|||
|
|
const parent2 = adapter.getParent(elem);
|
|||
|
|
return (parent2 == null || !adapter.isTag(parent2)) && next2(elem);
|
|||
|
|
};
|
|||
|
|
},
|
|||
|
|
scope(next2, rule, options, context) {
|
|||
|
|
const { equals } = options;
|
|||
|
|
if (!context || context.length === 0) {
|
|||
|
|
return filters["root"](next2, rule, options);
|
|||
|
|
}
|
|||
|
|
if (context.length === 1) {
|
|||
|
|
return (elem) => equals(context[0], elem) && next2(elem);
|
|||
|
|
}
|
|||
|
|
return (elem) => context.includes(elem) && next2(elem);
|
|||
|
|
},
|
|||
|
|
hover: dynamicStatePseudo("isHovered"),
|
|||
|
|
visited: dynamicStatePseudo("isVisited"),
|
|||
|
|
active: dynamicStatePseudo("isActive")
|
|||
|
|
};
|
|||
|
|
function dynamicStatePseudo(name) {
|
|||
|
|
return function dynamicPseudo(next2, _rule, { adapter }) {
|
|||
|
|
const func = adapter[name];
|
|||
|
|
if (typeof func !== "function") {
|
|||
|
|
return boolbase.falseFunc;
|
|||
|
|
}
|
|||
|
|
return function active(elem) {
|
|||
|
|
return func(elem) && next2(elem);
|
|||
|
|
};
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
const pseudos = {
|
|||
|
|
empty(elem, { adapter }) {
|
|||
|
|
return !adapter.getChildren(elem).some((elem2) => (
|
|||
|
|
// FIXME: `getText` call is potentially expensive.
|
|||
|
|
adapter.isTag(elem2) || adapter.getText(elem2) !== ""
|
|||
|
|
));
|
|||
|
|
},
|
|||
|
|
"first-child"(elem, { adapter, equals }) {
|
|||
|
|
if (adapter.prevElementSibling) {
|
|||
|
|
return adapter.prevElementSibling(elem) == null;
|
|||
|
|
}
|
|||
|
|
const firstChild = adapter.getSiblings(elem).find((elem2) => adapter.isTag(elem2));
|
|||
|
|
return firstChild != null && equals(elem, firstChild);
|
|||
|
|
},
|
|||
|
|
"last-child"(elem, { adapter, equals }) {
|
|||
|
|
const siblings2 = adapter.getSiblings(elem);
|
|||
|
|
for (let i = siblings2.length - 1; i >= 0; i--) {
|
|||
|
|
if (equals(elem, siblings2[i]))
|
|||
|
|
return true;
|
|||
|
|
if (adapter.isTag(siblings2[i]))
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
return false;
|
|||
|
|
},
|
|||
|
|
"first-of-type"(elem, { adapter, equals }) {
|
|||
|
|
const siblings2 = adapter.getSiblings(elem);
|
|||
|
|
const elemName = adapter.getName(elem);
|
|||
|
|
for (let i = 0; i < siblings2.length; i++) {
|
|||
|
|
const currentSibling = siblings2[i];
|
|||
|
|
if (equals(elem, currentSibling))
|
|||
|
|
return true;
|
|||
|
|
if (adapter.isTag(currentSibling) && adapter.getName(currentSibling) === elemName) {
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return false;
|
|||
|
|
},
|
|||
|
|
"last-of-type"(elem, { adapter, equals }) {
|
|||
|
|
const siblings2 = adapter.getSiblings(elem);
|
|||
|
|
const elemName = adapter.getName(elem);
|
|||
|
|
for (let i = siblings2.length - 1; i >= 0; i--) {
|
|||
|
|
const currentSibling = siblings2[i];
|
|||
|
|
if (equals(elem, currentSibling))
|
|||
|
|
return true;
|
|||
|
|
if (adapter.isTag(currentSibling) && adapter.getName(currentSibling) === elemName) {
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return false;
|
|||
|
|
},
|
|||
|
|
"only-of-type"(elem, { adapter, equals }) {
|
|||
|
|
const elemName = adapter.getName(elem);
|
|||
|
|
return adapter.getSiblings(elem).every((sibling) => equals(elem, sibling) || !adapter.isTag(sibling) || adapter.getName(sibling) !== elemName);
|
|||
|
|
},
|
|||
|
|
"only-child"(elem, { adapter, equals }) {
|
|||
|
|
return adapter.getSiblings(elem).every((sibling) => equals(elem, sibling) || !adapter.isTag(sibling));
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
function verifyPseudoArgs(func, name, subselect, argIndex) {
|
|||
|
|
if (subselect === null) {
|
|||
|
|
if (func.length > argIndex) {
|
|||
|
|
throw new Error(`Pseudo-class :${name} requires an argument`);
|
|||
|
|
}
|
|||
|
|
} else if (func.length === argIndex) {
|
|||
|
|
throw new Error(`Pseudo-class :${name} doesn't have any arguments`);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
const aliases = {
|
|||
|
|
// Links
|
|||
|
|
"any-link": ":is(a, area, link)[href]",
|
|||
|
|
link: ":any-link:not(:visited)",
|
|||
|
|
// Forms
|
|||
|
|
// https://html.spec.whatwg.org/multipage/scripting.html#disabled-elements
|
|||
|
|
disabled: `:is(
|
|||
|
|
:is(button, input, select, textarea, optgroup, option)[disabled],
|
|||
|
|
optgroup[disabled] > option,
|
|||
|
|
fieldset[disabled]:not(fieldset[disabled] legend:first-of-type *)
|
|||
|
|
)`,
|
|||
|
|
enabled: ":not(:disabled)",
|
|||
|
|
checked: ":is(:is(input[type=radio], input[type=checkbox])[checked], option:selected)",
|
|||
|
|
required: ":is(input, select, textarea)[required]",
|
|||
|
|
optional: ":is(input, select, textarea):not([required])",
|
|||
|
|
// JQuery extensions
|
|||
|
|
// https://html.spec.whatwg.org/multipage/form-elements.html#concept-option-selectedness
|
|||
|
|
selected: "option:is([selected], select:not([multiple]):not(:has(> option[selected])) > :first-of-type)",
|
|||
|
|
checkbox: "[type=checkbox]",
|
|||
|
|
file: "[type=file]",
|
|||
|
|
password: "[type=password]",
|
|||
|
|
radio: "[type=radio]",
|
|||
|
|
reset: "[type=reset]",
|
|||
|
|
image: "[type=image]",
|
|||
|
|
submit: "[type=submit]",
|
|||
|
|
parent: ":not(:empty)",
|
|||
|
|
header: ":is(h1, h2, h3, h4, h5, h6)",
|
|||
|
|
button: ":is(button, input[type=button])",
|
|||
|
|
input: ":is(input, textarea, select, button)",
|
|||
|
|
text: "input:is(:not([type!='']), [type=text])"
|
|||
|
|
};
|
|||
|
|
const PLACEHOLDER_ELEMENT = {};
|
|||
|
|
function ensureIsTag(next2, adapter) {
|
|||
|
|
if (next2 === boolbase.falseFunc)
|
|||
|
|
return boolbase.falseFunc;
|
|||
|
|
return (elem) => adapter.isTag(elem) && next2(elem);
|
|||
|
|
}
|
|||
|
|
function getNextSiblings(elem, adapter) {
|
|||
|
|
const siblings2 = adapter.getSiblings(elem);
|
|||
|
|
if (siblings2.length <= 1)
|
|||
|
|
return [];
|
|||
|
|
const elemIndex = siblings2.indexOf(elem);
|
|||
|
|
if (elemIndex < 0 || elemIndex === siblings2.length - 1)
|
|||
|
|
return [];
|
|||
|
|
return siblings2.slice(elemIndex + 1).filter(adapter.isTag);
|
|||
|
|
}
|
|||
|
|
function copyOptions(options) {
|
|||
|
|
return {
|
|||
|
|
xmlMode: !!options.xmlMode,
|
|||
|
|
lowerCaseAttributeNames: !!options.lowerCaseAttributeNames,
|
|||
|
|
lowerCaseTags: !!options.lowerCaseTags,
|
|||
|
|
quirksMode: !!options.quirksMode,
|
|||
|
|
cacheResults: !!options.cacheResults,
|
|||
|
|
pseudos: options.pseudos,
|
|||
|
|
adapter: options.adapter,
|
|||
|
|
equals: options.equals
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
const is$2 = (next2, token, options, context, compileToken2) => {
|
|||
|
|
const func = compileToken2(token, copyOptions(options), context);
|
|||
|
|
return func === boolbase.trueFunc ? next2 : func === boolbase.falseFunc ? boolbase.falseFunc : (elem) => func(elem) && next2(elem);
|
|||
|
|
};
|
|||
|
|
const subselects = {
|
|||
|
|
is: is$2,
|
|||
|
|
/**
|
|||
|
|
* `:matches` and `:where` are aliases for `:is`.
|
|||
|
|
*/
|
|||
|
|
matches: is$2,
|
|||
|
|
where: is$2,
|
|||
|
|
not(next2, token, options, context, compileToken2) {
|
|||
|
|
const func = compileToken2(token, copyOptions(options), context);
|
|||
|
|
return func === boolbase.falseFunc ? next2 : func === boolbase.trueFunc ? boolbase.falseFunc : (elem) => !func(elem) && next2(elem);
|
|||
|
|
},
|
|||
|
|
has(next2, subselect, options, _context, compileToken2) {
|
|||
|
|
const { adapter } = options;
|
|||
|
|
const opts = copyOptions(options);
|
|||
|
|
opts.relativeSelector = true;
|
|||
|
|
const context = subselect.some((s) => s.some(isTraversal)) ? (
|
|||
|
|
// Used as a placeholder. Will be replaced with the actual element.
|
|||
|
|
[PLACEHOLDER_ELEMENT]
|
|||
|
|
) : void 0;
|
|||
|
|
const compiled = compileToken2(subselect, opts, context);
|
|||
|
|
if (compiled === boolbase.falseFunc)
|
|||
|
|
return boolbase.falseFunc;
|
|||
|
|
const hasElement = ensureIsTag(compiled, adapter);
|
|||
|
|
if (context && compiled !== boolbase.trueFunc) {
|
|||
|
|
const { shouldTestNextSiblings = false } = compiled;
|
|||
|
|
return (elem) => {
|
|||
|
|
if (!next2(elem))
|
|||
|
|
return false;
|
|||
|
|
context[0] = elem;
|
|||
|
|
const childs = adapter.getChildren(elem);
|
|||
|
|
const nextElements = shouldTestNextSiblings ? [...childs, ...getNextSiblings(elem, adapter)] : childs;
|
|||
|
|
return adapter.existsOne(hasElement, nextElements);
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
return (elem) => next2(elem) && adapter.existsOne(hasElement, adapter.getChildren(elem));
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
function compilePseudoSelector(next2, selector, options, context, compileToken2) {
|
|||
|
|
var _a2;
|
|||
|
|
const { name, data: data2 } = selector;
|
|||
|
|
if (Array.isArray(data2)) {
|
|||
|
|
if (!(name in subselects)) {
|
|||
|
|
throw new Error(`Unknown pseudo-class :${name}(${data2})`);
|
|||
|
|
}
|
|||
|
|
return subselects[name](next2, data2, options, context, compileToken2);
|
|||
|
|
}
|
|||
|
|
const userPseudo = (_a2 = options.pseudos) === null || _a2 === void 0 ? void 0 : _a2[name];
|
|||
|
|
const stringPseudo = typeof userPseudo === "string" ? userPseudo : aliases[name];
|
|||
|
|
if (typeof stringPseudo === "string") {
|
|||
|
|
if (data2 != null) {
|
|||
|
|
throw new Error(`Pseudo ${name} doesn't have any arguments`);
|
|||
|
|
}
|
|||
|
|
const alias = parse$2(stringPseudo);
|
|||
|
|
return subselects["is"](next2, alias, options, context, compileToken2);
|
|||
|
|
}
|
|||
|
|
if (typeof userPseudo === "function") {
|
|||
|
|
verifyPseudoArgs(userPseudo, name, data2, 1);
|
|||
|
|
return (elem) => userPseudo(elem, data2) && next2(elem);
|
|||
|
|
}
|
|||
|
|
if (name in filters) {
|
|||
|
|
return filters[name](next2, data2, options, context);
|
|||
|
|
}
|
|||
|
|
if (name in pseudos) {
|
|||
|
|
const pseudo = pseudos[name];
|
|||
|
|
verifyPseudoArgs(pseudo, name, data2, 2);
|
|||
|
|
return (elem) => pseudo(elem, options, data2) && next2(elem);
|
|||
|
|
}
|
|||
|
|
throw new Error(`Unknown pseudo-class :${name}`);
|
|||
|
|
}
|
|||
|
|
function getElementParent(node, adapter) {
|
|||
|
|
const parent2 = adapter.getParent(node);
|
|||
|
|
if (parent2 && adapter.isTag(parent2)) {
|
|||
|
|
return parent2;
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
function compileGeneralSelector(next2, selector, options, context, compileToken2) {
|
|||
|
|
const { adapter, equals } = options;
|
|||
|
|
switch (selector.type) {
|
|||
|
|
case SelectorType.PseudoElement: {
|
|||
|
|
throw new Error("Pseudo-elements are not supported by css-select");
|
|||
|
|
}
|
|||
|
|
case SelectorType.ColumnCombinator: {
|
|||
|
|
throw new Error("Column combinators are not yet supported by css-select");
|
|||
|
|
}
|
|||
|
|
case SelectorType.Attribute: {
|
|||
|
|
if (selector.namespace != null) {
|
|||
|
|
throw new Error("Namespaced attributes are not yet supported by css-select");
|
|||
|
|
}
|
|||
|
|
if (!options.xmlMode || options.lowerCaseAttributeNames) {
|
|||
|
|
selector.name = selector.name.toLowerCase();
|
|||
|
|
}
|
|||
|
|
return attributeRules[selector.action](next2, selector, options);
|
|||
|
|
}
|
|||
|
|
case SelectorType.Pseudo: {
|
|||
|
|
return compilePseudoSelector(next2, selector, options, context, compileToken2);
|
|||
|
|
}
|
|||
|
|
// Tags
|
|||
|
|
case SelectorType.Tag: {
|
|||
|
|
if (selector.namespace != null) {
|
|||
|
|
throw new Error("Namespaced tag names are not yet supported by css-select");
|
|||
|
|
}
|
|||
|
|
let { name } = selector;
|
|||
|
|
if (!options.xmlMode || options.lowerCaseTags) {
|
|||
|
|
name = name.toLowerCase();
|
|||
|
|
}
|
|||
|
|
return function tag(elem) {
|
|||
|
|
return adapter.getName(elem) === name && next2(elem);
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
// Traversal
|
|||
|
|
case SelectorType.Descendant: {
|
|||
|
|
if (options.cacheResults === false || typeof WeakSet === "undefined") {
|
|||
|
|
return function descendant(elem) {
|
|||
|
|
let current = elem;
|
|||
|
|
while (current = getElementParent(current, adapter)) {
|
|||
|
|
if (next2(current)) {
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return false;
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
const isFalseCache = /* @__PURE__ */ new WeakSet();
|
|||
|
|
return function cachedDescendant(elem) {
|
|||
|
|
let current = elem;
|
|||
|
|
while (current = getElementParent(current, adapter)) {
|
|||
|
|
if (!isFalseCache.has(current)) {
|
|||
|
|
if (adapter.isTag(current) && next2(current)) {
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
isFalseCache.add(current);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return false;
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
case "_flexibleDescendant": {
|
|||
|
|
return function flexibleDescendant(elem) {
|
|||
|
|
let current = elem;
|
|||
|
|
do {
|
|||
|
|
if (next2(current))
|
|||
|
|
return true;
|
|||
|
|
} while (current = getElementParent(current, adapter));
|
|||
|
|
return false;
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
case SelectorType.Parent: {
|
|||
|
|
return function parent2(elem) {
|
|||
|
|
return adapter.getChildren(elem).some((elem2) => adapter.isTag(elem2) && next2(elem2));
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
case SelectorType.Child: {
|
|||
|
|
return function child(elem) {
|
|||
|
|
const parent2 = adapter.getParent(elem);
|
|||
|
|
return parent2 != null && adapter.isTag(parent2) && next2(parent2);
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
case SelectorType.Sibling: {
|
|||
|
|
return function sibling(elem) {
|
|||
|
|
const siblings2 = adapter.getSiblings(elem);
|
|||
|
|
for (let i = 0; i < siblings2.length; i++) {
|
|||
|
|
const currentSibling = siblings2[i];
|
|||
|
|
if (equals(elem, currentSibling))
|
|||
|
|
break;
|
|||
|
|
if (adapter.isTag(currentSibling) && next2(currentSibling)) {
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return false;
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
case SelectorType.Adjacent: {
|
|||
|
|
if (adapter.prevElementSibling) {
|
|||
|
|
return function adjacent(elem) {
|
|||
|
|
const previous = adapter.prevElementSibling(elem);
|
|||
|
|
return previous != null && next2(previous);
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
return function adjacent(elem) {
|
|||
|
|
const siblings2 = adapter.getSiblings(elem);
|
|||
|
|
let lastElement;
|
|||
|
|
for (let i = 0; i < siblings2.length; i++) {
|
|||
|
|
const currentSibling = siblings2[i];
|
|||
|
|
if (equals(elem, currentSibling))
|
|||
|
|
break;
|
|||
|
|
if (adapter.isTag(currentSibling)) {
|
|||
|
|
lastElement = currentSibling;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return !!lastElement && next2(lastElement);
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
case SelectorType.Universal: {
|
|||
|
|
if (selector.namespace != null && selector.namespace !== "*") {
|
|||
|
|
throw new Error("Namespaced universal selectors are not yet supported by css-select");
|
|||
|
|
}
|
|||
|
|
return next2;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function includesScopePseudo(t) {
|
|||
|
|
return t.type === SelectorType.Pseudo && (t.name === "scope" || Array.isArray(t.data) && t.data.some((data2) => data2.some(includesScopePseudo)));
|
|||
|
|
}
|
|||
|
|
const DESCENDANT_TOKEN = { type: SelectorType.Descendant };
|
|||
|
|
const FLEXIBLE_DESCENDANT_TOKEN = {
|
|||
|
|
type: "_flexibleDescendant"
|
|||
|
|
};
|
|||
|
|
const SCOPE_TOKEN = {
|
|||
|
|
type: SelectorType.Pseudo,
|
|||
|
|
name: "scope",
|
|||
|
|
data: null
|
|||
|
|
};
|
|||
|
|
function absolutize(token, { adapter }, context) {
|
|||
|
|
const hasContext = !!(context === null || context === void 0 ? void 0 : context.every((e) => {
|
|||
|
|
const parent2 = adapter.isTag(e) && adapter.getParent(e);
|
|||
|
|
return e === PLACEHOLDER_ELEMENT || parent2 && adapter.isTag(parent2);
|
|||
|
|
}));
|
|||
|
|
for (const t of token) {
|
|||
|
|
if (t.length > 0 && isTraversal(t[0]) && t[0].type !== SelectorType.Descendant) ;
|
|||
|
|
else if (hasContext && !t.some(includesScopePseudo)) {
|
|||
|
|
t.unshift(DESCENDANT_TOKEN);
|
|||
|
|
} else {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
t.unshift(SCOPE_TOKEN);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function compileToken(token, options, context) {
|
|||
|
|
var _a2;
|
|||
|
|
token.forEach(sortByProcedure);
|
|||
|
|
context = (_a2 = options.context) !== null && _a2 !== void 0 ? _a2 : context;
|
|||
|
|
const isArrayContext = Array.isArray(context);
|
|||
|
|
const finalContext = context && (Array.isArray(context) ? context : [context]);
|
|||
|
|
if (options.relativeSelector !== false) {
|
|||
|
|
absolutize(token, options, finalContext);
|
|||
|
|
} else if (token.some((t) => t.length > 0 && isTraversal(t[0]))) {
|
|||
|
|
throw new Error("Relative selectors are not allowed when the `relativeSelector` option is disabled");
|
|||
|
|
}
|
|||
|
|
let shouldTestNextSiblings = false;
|
|||
|
|
const query = token.map((rules) => {
|
|||
|
|
if (rules.length >= 2) {
|
|||
|
|
const [first2, second] = rules;
|
|||
|
|
if (first2.type !== SelectorType.Pseudo || first2.name !== "scope") ;
|
|||
|
|
else if (isArrayContext && second.type === SelectorType.Descendant) {
|
|||
|
|
rules[1] = FLEXIBLE_DESCENDANT_TOKEN;
|
|||
|
|
} else if (second.type === SelectorType.Adjacent || second.type === SelectorType.Sibling) {
|
|||
|
|
shouldTestNextSiblings = true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return compileRules(rules, options, finalContext);
|
|||
|
|
}).reduce(reduceRules, boolbase.falseFunc);
|
|||
|
|
query.shouldTestNextSiblings = shouldTestNextSiblings;
|
|||
|
|
return query;
|
|||
|
|
}
|
|||
|
|
function compileRules(rules, options, context) {
|
|||
|
|
var _a2;
|
|||
|
|
return rules.reduce((previous, rule) => previous === boolbase.falseFunc ? boolbase.falseFunc : compileGeneralSelector(previous, rule, options, context, compileToken), (_a2 = options.rootFunc) !== null && _a2 !== void 0 ? _a2 : boolbase.trueFunc);
|
|||
|
|
}
|
|||
|
|
function reduceRules(a, b) {
|
|||
|
|
if (b === boolbase.falseFunc || a === boolbase.trueFunc) {
|
|||
|
|
return a;
|
|||
|
|
}
|
|||
|
|
if (a === boolbase.falseFunc || b === boolbase.trueFunc) {
|
|||
|
|
return b;
|
|||
|
|
}
|
|||
|
|
return function combine(elem) {
|
|||
|
|
return a(elem) || b(elem);
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
const defaultEquals = (a, b) => a === b;
|
|||
|
|
const defaultOptions$1 = {
|
|||
|
|
adapter: DomUtils,
|
|||
|
|
equals: defaultEquals
|
|||
|
|
};
|
|||
|
|
function convertOptionFormats(options) {
|
|||
|
|
var _a2, _b, _c, _d;
|
|||
|
|
const opts = options !== null && options !== void 0 ? options : defaultOptions$1;
|
|||
|
|
(_a2 = opts.adapter) !== null && _a2 !== void 0 ? _a2 : opts.adapter = DomUtils;
|
|||
|
|
(_b = opts.equals) !== null && _b !== void 0 ? _b : opts.equals = (_d = (_c = opts.adapter) === null || _c === void 0 ? void 0 : _c.equals) !== null && _d !== void 0 ? _d : defaultEquals;
|
|||
|
|
return opts;
|
|||
|
|
}
|
|||
|
|
function wrapCompile(func) {
|
|||
|
|
return function addAdapter(selector, options, context) {
|
|||
|
|
const opts = convertOptionFormats(options);
|
|||
|
|
return func(selector, opts, context);
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
const _compileToken = wrapCompile(compileToken);
|
|||
|
|
function prepareContext(elems, adapter, shouldTestNextSiblings = false) {
|
|||
|
|
if (shouldTestNextSiblings) {
|
|||
|
|
elems = appendNextSiblings(elems, adapter);
|
|||
|
|
}
|
|||
|
|
return Array.isArray(elems) ? adapter.removeSubsets(elems) : adapter.getChildren(elems);
|
|||
|
|
}
|
|||
|
|
function appendNextSiblings(elem, adapter) {
|
|||
|
|
const elems = Array.isArray(elem) ? elem.slice(0) : [elem];
|
|||
|
|
const elemsLength = elems.length;
|
|||
|
|
for (let i = 0; i < elemsLength; i++) {
|
|||
|
|
const nextSiblings = getNextSiblings(elems[i], adapter);
|
|||
|
|
elems.push(...nextSiblings);
|
|||
|
|
}
|
|||
|
|
return elems;
|
|||
|
|
}
|
|||
|
|
const filterNames = /* @__PURE__ */ new Set([
|
|||
|
|
"first",
|
|||
|
|
"last",
|
|||
|
|
"eq",
|
|||
|
|
"gt",
|
|||
|
|
"nth",
|
|||
|
|
"lt",
|
|||
|
|
"even",
|
|||
|
|
"odd"
|
|||
|
|
]);
|
|||
|
|
function isFilter(s) {
|
|||
|
|
if (s.type !== "pseudo")
|
|||
|
|
return false;
|
|||
|
|
if (filterNames.has(s.name))
|
|||
|
|
return true;
|
|||
|
|
if (s.name === "not" && Array.isArray(s.data)) {
|
|||
|
|
return s.data.some((s2) => s2.some(isFilter));
|
|||
|
|
}
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
function getLimit(filter2, data2, partLimit) {
|
|||
|
|
const num = data2 != null ? parseInt(data2, 10) : NaN;
|
|||
|
|
switch (filter2) {
|
|||
|
|
case "first":
|
|||
|
|
return 1;
|
|||
|
|
case "nth":
|
|||
|
|
case "eq":
|
|||
|
|
return isFinite(num) ? num >= 0 ? num + 1 : Infinity : 0;
|
|||
|
|
case "lt":
|
|||
|
|
return isFinite(num) ? num >= 0 ? Math.min(num, partLimit) : Infinity : 0;
|
|||
|
|
case "gt":
|
|||
|
|
return isFinite(num) ? Infinity : 0;
|
|||
|
|
case "odd":
|
|||
|
|
return 2 * partLimit;
|
|||
|
|
case "even":
|
|||
|
|
return 2 * partLimit - 1;
|
|||
|
|
case "last":
|
|||
|
|
case "not":
|
|||
|
|
return Infinity;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function getDocumentRoot(node) {
|
|||
|
|
while (node.parent)
|
|||
|
|
node = node.parent;
|
|||
|
|
return node;
|
|||
|
|
}
|
|||
|
|
function groupSelectors(selectors) {
|
|||
|
|
const filteredSelectors = [];
|
|||
|
|
const plainSelectors = [];
|
|||
|
|
for (const selector of selectors) {
|
|||
|
|
if (selector.some(isFilter)) {
|
|||
|
|
filteredSelectors.push(selector);
|
|||
|
|
} else {
|
|||
|
|
plainSelectors.push(selector);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return [plainSelectors, filteredSelectors];
|
|||
|
|
}
|
|||
|
|
const UNIVERSAL_SELECTOR = {
|
|||
|
|
type: SelectorType.Universal,
|
|||
|
|
namespace: null
|
|||
|
|
};
|
|||
|
|
const SCOPE_PSEUDO = {
|
|||
|
|
type: SelectorType.Pseudo,
|
|||
|
|
name: "scope",
|
|||
|
|
data: null
|
|||
|
|
};
|
|||
|
|
function is$1(element, selector, options = {}) {
|
|||
|
|
return some([element], selector, options);
|
|||
|
|
}
|
|||
|
|
function some(elements, selector, options = {}) {
|
|||
|
|
if (typeof selector === "function")
|
|||
|
|
return elements.some(selector);
|
|||
|
|
const [plain, filtered] = groupSelectors(parse$2(selector));
|
|||
|
|
return plain.length > 0 && elements.some(_compileToken(plain, options)) || filtered.some((sel) => filterBySelector(sel, elements, options).length > 0);
|
|||
|
|
}
|
|||
|
|
function filterByPosition(filter2, elems, data2, options) {
|
|||
|
|
const num = typeof data2 === "string" ? parseInt(data2, 10) : NaN;
|
|||
|
|
switch (filter2) {
|
|||
|
|
case "first":
|
|||
|
|
case "lt":
|
|||
|
|
return elems;
|
|||
|
|
case "last":
|
|||
|
|
return elems.length > 0 ? [elems[elems.length - 1]] : elems;
|
|||
|
|
case "nth":
|
|||
|
|
case "eq":
|
|||
|
|
return isFinite(num) && Math.abs(num) < elems.length ? [num < 0 ? elems[elems.length + num] : elems[num]] : [];
|
|||
|
|
case "gt":
|
|||
|
|
return isFinite(num) ? elems.slice(num + 1) : [];
|
|||
|
|
case "even":
|
|||
|
|
return elems.filter((_, i) => i % 2 === 0);
|
|||
|
|
case "odd":
|
|||
|
|
return elems.filter((_, i) => i % 2 === 1);
|
|||
|
|
case "not": {
|
|||
|
|
const filtered = new Set(filterParsed(data2, elems, options));
|
|||
|
|
return elems.filter((e) => !filtered.has(e));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function filter$1(selector, elements, options = {}) {
|
|||
|
|
return filterParsed(parse$2(selector), elements, options);
|
|||
|
|
}
|
|||
|
|
function filterParsed(selector, elements, options) {
|
|||
|
|
if (elements.length === 0)
|
|||
|
|
return [];
|
|||
|
|
const [plainSelectors, filteredSelectors] = groupSelectors(selector);
|
|||
|
|
let found;
|
|||
|
|
if (plainSelectors.length) {
|
|||
|
|
const filtered = filterElements(elements, plainSelectors, options);
|
|||
|
|
if (filteredSelectors.length === 0) {
|
|||
|
|
return filtered;
|
|||
|
|
}
|
|||
|
|
if (filtered.length) {
|
|||
|
|
found = new Set(filtered);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
for (let i = 0; i < filteredSelectors.length && (found === null || found === void 0 ? void 0 : found.size) !== elements.length; i++) {
|
|||
|
|
const filteredSelector = filteredSelectors[i];
|
|||
|
|
const missing = found ? elements.filter((e) => isTag(e) && !found.has(e)) : elements;
|
|||
|
|
if (missing.length === 0)
|
|||
|
|
break;
|
|||
|
|
const filtered = filterBySelector(filteredSelector, elements, options);
|
|||
|
|
if (filtered.length) {
|
|||
|
|
if (!found) {
|
|||
|
|
if (i === filteredSelectors.length - 1) {
|
|||
|
|
return filtered;
|
|||
|
|
}
|
|||
|
|
found = new Set(filtered);
|
|||
|
|
} else {
|
|||
|
|
filtered.forEach((el) => found.add(el));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return typeof found !== "undefined" ? found.size === elements.length ? elements : (
|
|||
|
|
// Filter elements to preserve order
|
|||
|
|
elements.filter((el) => found.has(el))
|
|||
|
|
) : [];
|
|||
|
|
}
|
|||
|
|
function filterBySelector(selector, elements, options) {
|
|||
|
|
var _a2;
|
|||
|
|
if (selector.some(isTraversal$1)) {
|
|||
|
|
const root2 = (_a2 = options.root) !== null && _a2 !== void 0 ? _a2 : getDocumentRoot(elements[0]);
|
|||
|
|
const opts = { ...options, context: elements, relativeSelector: false };
|
|||
|
|
selector.push(SCOPE_PSEUDO);
|
|||
|
|
return findFilterElements(root2, selector, opts, true, elements.length);
|
|||
|
|
}
|
|||
|
|
return findFilterElements(elements, selector, options, false, elements.length);
|
|||
|
|
}
|
|||
|
|
function select(selector, root2, options = {}, limit = Infinity) {
|
|||
|
|
if (typeof selector === "function") {
|
|||
|
|
return find$1(root2, selector);
|
|||
|
|
}
|
|||
|
|
const [plain, filtered] = groupSelectors(parse$2(selector));
|
|||
|
|
const results = filtered.map((sel) => findFilterElements(root2, sel, options, true, limit));
|
|||
|
|
if (plain.length) {
|
|||
|
|
results.push(findElements(root2, plain, options, limit));
|
|||
|
|
}
|
|||
|
|
if (results.length === 0) {
|
|||
|
|
return [];
|
|||
|
|
}
|
|||
|
|
if (results.length === 1) {
|
|||
|
|
return results[0];
|
|||
|
|
}
|
|||
|
|
return uniqueSort(results.reduce((a, b) => [...a, ...b]));
|
|||
|
|
}
|
|||
|
|
function findFilterElements(root2, selector, options, queryForSelector, totalLimit) {
|
|||
|
|
const filterIndex = selector.findIndex(isFilter);
|
|||
|
|
const sub = selector.slice(0, filterIndex);
|
|||
|
|
const filter2 = selector[filterIndex];
|
|||
|
|
const partLimit = selector.length - 1 === filterIndex ? totalLimit : Infinity;
|
|||
|
|
const limit = getLimit(filter2.name, filter2.data, partLimit);
|
|||
|
|
if (limit === 0)
|
|||
|
|
return [];
|
|||
|
|
const elemsNoLimit = sub.length === 0 && !Array.isArray(root2) ? getChildren(root2).filter(isTag) : sub.length === 0 ? (Array.isArray(root2) ? root2 : [root2]).filter(isTag) : queryForSelector || sub.some(isTraversal$1) ? findElements(root2, [sub], options, limit) : filterElements(root2, [sub], options);
|
|||
|
|
const elems = elemsNoLimit.slice(0, limit);
|
|||
|
|
let result = filterByPosition(filter2.name, elems, filter2.data, options);
|
|||
|
|
if (result.length === 0 || selector.length === filterIndex + 1) {
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
const remainingSelector = selector.slice(filterIndex + 1);
|
|||
|
|
const remainingHasTraversal = remainingSelector.some(isTraversal$1);
|
|||
|
|
if (remainingHasTraversal) {
|
|||
|
|
if (isTraversal$1(remainingSelector[0])) {
|
|||
|
|
const { type } = remainingSelector[0];
|
|||
|
|
if (type === SelectorType.Sibling || type === SelectorType.Adjacent) {
|
|||
|
|
result = prepareContext(result, DomUtils, true);
|
|||
|
|
}
|
|||
|
|
remainingSelector.unshift(UNIVERSAL_SELECTOR);
|
|||
|
|
}
|
|||
|
|
options = {
|
|||
|
|
...options,
|
|||
|
|
// Avoid absolutizing the selector
|
|||
|
|
relativeSelector: false,
|
|||
|
|
/*
|
|||
|
|
* Add a custom root func, to make sure traversals don't match elements
|
|||
|
|
* that aren't a part of the considered tree.
|
|||
|
|
*/
|
|||
|
|
rootFunc: (el) => result.includes(el)
|
|||
|
|
};
|
|||
|
|
} else if (options.rootFunc && options.rootFunc !== boolbaseExports.trueFunc) {
|
|||
|
|
options = { ...options, rootFunc: boolbaseExports.trueFunc };
|
|||
|
|
}
|
|||
|
|
return remainingSelector.some(isFilter) ? findFilterElements(result, remainingSelector, options, false, totalLimit) : remainingHasTraversal ? (
|
|||
|
|
// Query existing elements to resolve traversal.
|
|||
|
|
findElements(result, [remainingSelector], options, totalLimit)
|
|||
|
|
) : (
|
|||
|
|
// If we don't have any more traversals, simply filter elements.
|
|||
|
|
filterElements(result, [remainingSelector], options)
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
function findElements(root2, sel, options, limit) {
|
|||
|
|
const query = _compileToken(sel, options, root2);
|
|||
|
|
return find$1(root2, query, limit);
|
|||
|
|
}
|
|||
|
|
function find$1(root2, query, limit = Infinity) {
|
|||
|
|
const elems = prepareContext(root2, DomUtils, query.shouldTestNextSiblings);
|
|||
|
|
return find$2((node) => isTag(node) && query(node), elems, true, limit);
|
|||
|
|
}
|
|||
|
|
function filterElements(elements, sel, options) {
|
|||
|
|
const els = (Array.isArray(elements) ? elements : [elements]).filter(isTag);
|
|||
|
|
if (els.length === 0)
|
|||
|
|
return els;
|
|||
|
|
const query = _compileToken(sel, options);
|
|||
|
|
return query === boolbaseExports.trueFunc ? els : els.filter(query);
|
|||
|
|
}
|
|||
|
|
const reSiblingSelector = /^\s*[+~]/;
|
|||
|
|
function find(selectorOrHaystack) {
|
|||
|
|
if (!selectorOrHaystack) {
|
|||
|
|
return this._make([]);
|
|||
|
|
}
|
|||
|
|
if (typeof selectorOrHaystack !== "string") {
|
|||
|
|
const haystack = isCheerio(selectorOrHaystack) ? selectorOrHaystack.toArray() : [selectorOrHaystack];
|
|||
|
|
const context = this.toArray();
|
|||
|
|
return this._make(haystack.filter((elem) => context.some((node) => contains(node, elem))));
|
|||
|
|
}
|
|||
|
|
return this._findBySelector(selectorOrHaystack, Number.POSITIVE_INFINITY);
|
|||
|
|
}
|
|||
|
|
function _findBySelector(selector, limit) {
|
|||
|
|
var _a2;
|
|||
|
|
const context = this.toArray();
|
|||
|
|
const elems = reSiblingSelector.test(selector) ? context : this.children().toArray();
|
|||
|
|
const options = {
|
|||
|
|
context,
|
|||
|
|
root: (_a2 = this._root) === null || _a2 === void 0 ? void 0 : _a2[0],
|
|||
|
|
// Pass options that are recognized by `cheerio-select`
|
|||
|
|
xmlMode: this.options.xmlMode,
|
|||
|
|
lowerCaseTags: this.options.lowerCaseTags,
|
|||
|
|
lowerCaseAttributeNames: this.options.lowerCaseAttributeNames,
|
|||
|
|
pseudos: this.options.pseudos,
|
|||
|
|
quirksMode: this.options.quirksMode
|
|||
|
|
};
|
|||
|
|
return this._make(select(selector, elems, options, limit));
|
|||
|
|
}
|
|||
|
|
function _getMatcher(matchMap) {
|
|||
|
|
return function(fn, ...postFns) {
|
|||
|
|
return function(selector) {
|
|||
|
|
var _a2;
|
|||
|
|
let matched = matchMap(fn, this);
|
|||
|
|
if (selector) {
|
|||
|
|
matched = filterArray(matched, selector, this.options.xmlMode, (_a2 = this._root) === null || _a2 === void 0 ? void 0 : _a2[0]);
|
|||
|
|
}
|
|||
|
|
return this._make(
|
|||
|
|
// Post processing is only necessary if there is more than one element.
|
|||
|
|
this.length > 1 && matched.length > 1 ? postFns.reduce((elems, fn2) => fn2(elems), matched) : matched
|
|||
|
|
);
|
|||
|
|
};
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
const _matcher = _getMatcher((fn, elems) => {
|
|||
|
|
let ret = [];
|
|||
|
|
for (let i = 0; i < elems.length; i++) {
|
|||
|
|
const value = fn(elems[i]);
|
|||
|
|
if (value.length > 0)
|
|||
|
|
ret = ret.concat(value);
|
|||
|
|
}
|
|||
|
|
return ret;
|
|||
|
|
});
|
|||
|
|
const _singleMatcher = _getMatcher((fn, elems) => {
|
|||
|
|
const ret = [];
|
|||
|
|
for (let i = 0; i < elems.length; i++) {
|
|||
|
|
const value = fn(elems[i]);
|
|||
|
|
if (value !== null) {
|
|||
|
|
ret.push(value);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return ret;
|
|||
|
|
});
|
|||
|
|
function _matchUntil(nextElem, ...postFns) {
|
|||
|
|
let matches = null;
|
|||
|
|
const innerMatcher = _getMatcher((nextElem2, elems) => {
|
|||
|
|
const matched = [];
|
|||
|
|
domEach(elems, (elem) => {
|
|||
|
|
for (let next2; next2 = nextElem2(elem); elem = next2) {
|
|||
|
|
if (matches === null || matches === void 0 ? void 0 : matches(next2, matched.length))
|
|||
|
|
break;
|
|||
|
|
matched.push(next2);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
return matched;
|
|||
|
|
})(nextElem, ...postFns);
|
|||
|
|
return function(selector, filterSelector) {
|
|||
|
|
matches = typeof selector === "string" ? (elem) => is$1(elem, selector, this.options) : selector ? getFilterFn(selector) : null;
|
|||
|
|
const ret = innerMatcher.call(this, filterSelector);
|
|||
|
|
matches = null;
|
|||
|
|
return ret;
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
function _removeDuplicates(elems) {
|
|||
|
|
return elems.length > 1 ? Array.from(new Set(elems)) : elems;
|
|||
|
|
}
|
|||
|
|
const parent = _singleMatcher(({ parent: parent2 }) => parent2 && !isDocument(parent2) ? parent2 : null, _removeDuplicates);
|
|||
|
|
const parents = _matcher((elem) => {
|
|||
|
|
const matched = [];
|
|||
|
|
while (elem.parent && !isDocument(elem.parent)) {
|
|||
|
|
matched.push(elem.parent);
|
|||
|
|
elem = elem.parent;
|
|||
|
|
}
|
|||
|
|
return matched;
|
|||
|
|
}, uniqueSort, (elems) => elems.reverse());
|
|||
|
|
const parentsUntil = _matchUntil(({ parent: parent2 }) => parent2 && !isDocument(parent2) ? parent2 : null, uniqueSort, (elems) => elems.reverse());
|
|||
|
|
function closest(selector) {
|
|||
|
|
var _a2;
|
|||
|
|
const set = [];
|
|||
|
|
if (!selector) {
|
|||
|
|
return this._make(set);
|
|||
|
|
}
|
|||
|
|
const selectOpts = {
|
|||
|
|
xmlMode: this.options.xmlMode,
|
|||
|
|
root: (_a2 = this._root) === null || _a2 === void 0 ? void 0 : _a2[0]
|
|||
|
|
};
|
|||
|
|
const selectFn = typeof selector === "string" ? (elem) => is$1(elem, selector, selectOpts) : getFilterFn(selector);
|
|||
|
|
domEach(this, (elem) => {
|
|||
|
|
if (elem && !isDocument(elem) && !isTag(elem)) {
|
|||
|
|
elem = elem.parent;
|
|||
|
|
}
|
|||
|
|
while (elem && isTag(elem)) {
|
|||
|
|
if (selectFn(elem, 0)) {
|
|||
|
|
if (!set.includes(elem)) {
|
|||
|
|
set.push(elem);
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
elem = elem.parent;
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
return this._make(set);
|
|||
|
|
}
|
|||
|
|
const next = _singleMatcher((elem) => nextElementSibling(elem));
|
|||
|
|
const nextAll = _matcher((elem) => {
|
|||
|
|
const matched = [];
|
|||
|
|
while (elem.next) {
|
|||
|
|
elem = elem.next;
|
|||
|
|
if (isTag(elem))
|
|||
|
|
matched.push(elem);
|
|||
|
|
}
|
|||
|
|
return matched;
|
|||
|
|
}, _removeDuplicates);
|
|||
|
|
const nextUntil = _matchUntil((el) => nextElementSibling(el), _removeDuplicates);
|
|||
|
|
const prev = _singleMatcher((elem) => prevElementSibling(elem));
|
|||
|
|
const prevAll = _matcher((elem) => {
|
|||
|
|
const matched = [];
|
|||
|
|
while (elem.prev) {
|
|||
|
|
elem = elem.prev;
|
|||
|
|
if (isTag(elem))
|
|||
|
|
matched.push(elem);
|
|||
|
|
}
|
|||
|
|
return matched;
|
|||
|
|
}, _removeDuplicates);
|
|||
|
|
const prevUntil = _matchUntil((el) => prevElementSibling(el), _removeDuplicates);
|
|||
|
|
const siblings = _matcher((elem) => getSiblings(elem).filter((el) => isTag(el) && el !== elem), uniqueSort);
|
|||
|
|
const children = _matcher((elem) => getChildren(elem).filter(isTag), _removeDuplicates);
|
|||
|
|
function contents() {
|
|||
|
|
const elems = this.toArray().reduce((newElems, elem) => hasChildren(elem) ? newElems.concat(elem.children) : newElems, []);
|
|||
|
|
return this._make(elems);
|
|||
|
|
}
|
|||
|
|
function each(fn) {
|
|||
|
|
let i = 0;
|
|||
|
|
const len = this.length;
|
|||
|
|
while (i < len && fn.call(this[i], i, this[i]) !== false)
|
|||
|
|
++i;
|
|||
|
|
return this;
|
|||
|
|
}
|
|||
|
|
function map(fn) {
|
|||
|
|
let elems = [];
|
|||
|
|
for (let i = 0; i < this.length; i++) {
|
|||
|
|
const el = this[i];
|
|||
|
|
const val2 = fn.call(el, i, el);
|
|||
|
|
if (val2 != null) {
|
|||
|
|
elems = elems.concat(val2);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return this._make(elems);
|
|||
|
|
}
|
|||
|
|
function getFilterFn(match) {
|
|||
|
|
if (typeof match === "function") {
|
|||
|
|
return (el, i) => match.call(el, i, el);
|
|||
|
|
}
|
|||
|
|
if (isCheerio(match)) {
|
|||
|
|
return (el) => Array.prototype.includes.call(match, el);
|
|||
|
|
}
|
|||
|
|
return function(el) {
|
|||
|
|
return match === el;
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
function filter(match) {
|
|||
|
|
var _a2;
|
|||
|
|
return this._make(filterArray(this.toArray(), match, this.options.xmlMode, (_a2 = this._root) === null || _a2 === void 0 ? void 0 : _a2[0]));
|
|||
|
|
}
|
|||
|
|
function filterArray(nodes, match, xmlMode, root2) {
|
|||
|
|
return typeof match === "string" ? filter$1(match, nodes, { xmlMode, root: root2 }) : nodes.filter(getFilterFn(match));
|
|||
|
|
}
|
|||
|
|
function is(selector) {
|
|||
|
|
const nodes = this.toArray();
|
|||
|
|
return typeof selector === "string" ? some(nodes.filter(isTag), selector, this.options) : selector ? nodes.some(getFilterFn(selector)) : false;
|
|||
|
|
}
|
|||
|
|
function not(match) {
|
|||
|
|
let nodes = this.toArray();
|
|||
|
|
if (typeof match === "string") {
|
|||
|
|
const matches = new Set(filter$1(match, nodes, this.options));
|
|||
|
|
nodes = nodes.filter((el) => !matches.has(el));
|
|||
|
|
} else {
|
|||
|
|
const filterFn = getFilterFn(match);
|
|||
|
|
nodes = nodes.filter((el, i) => !filterFn(el, i));
|
|||
|
|
}
|
|||
|
|
return this._make(nodes);
|
|||
|
|
}
|
|||
|
|
function has(selectorOrHaystack) {
|
|||
|
|
return this.filter(typeof selectorOrHaystack === "string" ? (
|
|||
|
|
// Using the `:has` selector here short-circuits searches.
|
|||
|
|
`:has(${selectorOrHaystack})`
|
|||
|
|
) : (_, el) => this._make(el).find(selectorOrHaystack).length > 0);
|
|||
|
|
}
|
|||
|
|
function first() {
|
|||
|
|
return this.length > 1 ? this._make(this[0]) : this;
|
|||
|
|
}
|
|||
|
|
function last() {
|
|||
|
|
return this.length > 0 ? this._make(this[this.length - 1]) : this;
|
|||
|
|
}
|
|||
|
|
function eq(i) {
|
|||
|
|
var _a2;
|
|||
|
|
i = +i;
|
|||
|
|
if (i === 0 && this.length <= 1)
|
|||
|
|
return this;
|
|||
|
|
if (i < 0)
|
|||
|
|
i = this.length + i;
|
|||
|
|
return this._make((_a2 = this[i]) !== null && _a2 !== void 0 ? _a2 : []);
|
|||
|
|
}
|
|||
|
|
function get(i) {
|
|||
|
|
if (i == null) {
|
|||
|
|
return this.toArray();
|
|||
|
|
}
|
|||
|
|
return this[i < 0 ? this.length + i : i];
|
|||
|
|
}
|
|||
|
|
function toArray() {
|
|||
|
|
return Array.prototype.slice.call(this);
|
|||
|
|
}
|
|||
|
|
function index(selectorOrNeedle) {
|
|||
|
|
let $haystack;
|
|||
|
|
let needle;
|
|||
|
|
if (selectorOrNeedle == null) {
|
|||
|
|
$haystack = this.parent().children();
|
|||
|
|
needle = this[0];
|
|||
|
|
} else if (typeof selectorOrNeedle === "string") {
|
|||
|
|
$haystack = this._make(selectorOrNeedle);
|
|||
|
|
needle = this[0];
|
|||
|
|
} else {
|
|||
|
|
$haystack = this;
|
|||
|
|
needle = isCheerio(selectorOrNeedle) ? selectorOrNeedle[0] : selectorOrNeedle;
|
|||
|
|
}
|
|||
|
|
return Array.prototype.indexOf.call($haystack, needle);
|
|||
|
|
}
|
|||
|
|
function slice(start, end2) {
|
|||
|
|
return this._make(Array.prototype.slice.call(this, start, end2));
|
|||
|
|
}
|
|||
|
|
function end() {
|
|||
|
|
var _a2;
|
|||
|
|
return (_a2 = this.prevObject) !== null && _a2 !== void 0 ? _a2 : this._make([]);
|
|||
|
|
}
|
|||
|
|
function add(other, context) {
|
|||
|
|
const selection = this._make(other, context);
|
|||
|
|
const contents2 = uniqueSort([...this.get(), ...selection.get()]);
|
|||
|
|
return this._make(contents2);
|
|||
|
|
}
|
|||
|
|
function addBack(selector) {
|
|||
|
|
return this.prevObject ? this.add(selector ? this.prevObject.filter(selector) : this.prevObject) : this;
|
|||
|
|
}
|
|||
|
|
const Traversing = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|||
|
|
__proto__: null,
|
|||
|
|
_findBySelector,
|
|||
|
|
add,
|
|||
|
|
addBack,
|
|||
|
|
children,
|
|||
|
|
closest,
|
|||
|
|
contents,
|
|||
|
|
each,
|
|||
|
|
end,
|
|||
|
|
eq,
|
|||
|
|
filter,
|
|||
|
|
filterArray,
|
|||
|
|
find,
|
|||
|
|
first,
|
|||
|
|
get,
|
|||
|
|
has,
|
|||
|
|
index,
|
|||
|
|
is,
|
|||
|
|
last,
|
|||
|
|
map,
|
|||
|
|
next,
|
|||
|
|
nextAll,
|
|||
|
|
nextUntil,
|
|||
|
|
not,
|
|||
|
|
parent,
|
|||
|
|
parents,
|
|||
|
|
parentsUntil,
|
|||
|
|
prev,
|
|||
|
|
prevAll,
|
|||
|
|
prevUntil,
|
|||
|
|
siblings,
|
|||
|
|
slice,
|
|||
|
|
toArray
|
|||
|
|
}, Symbol.toStringTag, { value: "Module" }));
|
|||
|
|
function getParse(parser) {
|
|||
|
|
return function parse2(content, options, isDocument$1, context) {
|
|||
|
|
if (typeof Buffer !== "undefined" && Buffer.isBuffer(content)) {
|
|||
|
|
content = content.toString();
|
|||
|
|
}
|
|||
|
|
if (typeof content === "string") {
|
|||
|
|
return parser(content, options, isDocument$1, context);
|
|||
|
|
}
|
|||
|
|
const doc = content;
|
|||
|
|
if (!Array.isArray(doc) && isDocument(doc)) {
|
|||
|
|
return doc;
|
|||
|
|
}
|
|||
|
|
const root2 = new Document([]);
|
|||
|
|
update(doc, root2);
|
|||
|
|
return root2;
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
function update(newChilds, parent2) {
|
|||
|
|
const arr = Array.isArray(newChilds) ? newChilds : [newChilds];
|
|||
|
|
if (parent2) {
|
|||
|
|
parent2.children = arr;
|
|||
|
|
} else {
|
|||
|
|
parent2 = null;
|
|||
|
|
}
|
|||
|
|
for (let i = 0; i < arr.length; i++) {
|
|||
|
|
const node = arr[i];
|
|||
|
|
if (node.parent && node.parent.children !== arr) {
|
|||
|
|
removeElement(node);
|
|||
|
|
}
|
|||
|
|
if (parent2) {
|
|||
|
|
node.prev = arr[i - 1] || null;
|
|||
|
|
node.next = arr[i + 1] || null;
|
|||
|
|
} else {
|
|||
|
|
node.prev = node.next = null;
|
|||
|
|
}
|
|||
|
|
node.parent = parent2;
|
|||
|
|
}
|
|||
|
|
return parent2;
|
|||
|
|
}
|
|||
|
|
function _makeDomArray(elem, clone2) {
|
|||
|
|
if (elem == null) {
|
|||
|
|
return [];
|
|||
|
|
}
|
|||
|
|
if (typeof elem === "string") {
|
|||
|
|
return this._parse(elem, this.options, false, null).children.slice(0);
|
|||
|
|
}
|
|||
|
|
if ("length" in elem) {
|
|||
|
|
if (elem.length === 1) {
|
|||
|
|
return this._makeDomArray(elem[0], clone2);
|
|||
|
|
}
|
|||
|
|
const result = [];
|
|||
|
|
for (let i = 0; i < elem.length; i++) {
|
|||
|
|
const el = elem[i];
|
|||
|
|
if (typeof el === "object") {
|
|||
|
|
if (el == null) {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
if (!("length" in el)) {
|
|||
|
|
result.push(clone2 ? cloneNode(el, true) : el);
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
result.push(...this._makeDomArray(el, clone2));
|
|||
|
|
}
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
return [clone2 ? cloneNode(elem, true) : elem];
|
|||
|
|
}
|
|||
|
|
function _insert(concatenator) {
|
|||
|
|
return function(...elems) {
|
|||
|
|
const lastIdx = this.length - 1;
|
|||
|
|
return domEach(this, (el, i) => {
|
|||
|
|
if (!hasChildren(el))
|
|||
|
|
return;
|
|||
|
|
const domSrc = typeof elems[0] === "function" ? elems[0].call(el, i, this._render(el.children)) : elems;
|
|||
|
|
const dom = this._makeDomArray(domSrc, i < lastIdx);
|
|||
|
|
concatenator(dom, el.children, el);
|
|||
|
|
});
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
function uniqueSplice(array, spliceIdx, spliceCount, newElems, parent2) {
|
|||
|
|
var _a2, _b;
|
|||
|
|
const spliceArgs = [
|
|||
|
|
spliceIdx,
|
|||
|
|
spliceCount,
|
|||
|
|
...newElems
|
|||
|
|
];
|
|||
|
|
const prev2 = spliceIdx === 0 ? null : array[spliceIdx - 1];
|
|||
|
|
const next2 = spliceIdx + spliceCount >= array.length ? null : array[spliceIdx + spliceCount];
|
|||
|
|
for (let idx = 0; idx < newElems.length; ++idx) {
|
|||
|
|
const node = newElems[idx];
|
|||
|
|
const oldParent = node.parent;
|
|||
|
|
if (oldParent) {
|
|||
|
|
const oldSiblings = oldParent.children;
|
|||
|
|
const prevIdx = oldSiblings.indexOf(node);
|
|||
|
|
if (prevIdx > -1) {
|
|||
|
|
oldParent.children.splice(prevIdx, 1);
|
|||
|
|
if (parent2 === oldParent && spliceIdx > prevIdx) {
|
|||
|
|
spliceArgs[0]--;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
node.parent = parent2;
|
|||
|
|
if (node.prev) {
|
|||
|
|
node.prev.next = (_a2 = node.next) !== null && _a2 !== void 0 ? _a2 : null;
|
|||
|
|
}
|
|||
|
|
if (node.next) {
|
|||
|
|
node.next.prev = (_b = node.prev) !== null && _b !== void 0 ? _b : null;
|
|||
|
|
}
|
|||
|
|
node.prev = idx === 0 ? prev2 : newElems[idx - 1];
|
|||
|
|
node.next = idx === newElems.length - 1 ? next2 : newElems[idx + 1];
|
|||
|
|
}
|
|||
|
|
if (prev2) {
|
|||
|
|
prev2.next = newElems[0];
|
|||
|
|
}
|
|||
|
|
if (next2) {
|
|||
|
|
next2.prev = newElems[newElems.length - 1];
|
|||
|
|
}
|
|||
|
|
return array.splice(...spliceArgs);
|
|||
|
|
}
|
|||
|
|
function appendTo(target) {
|
|||
|
|
const appendTarget = isCheerio(target) ? target : this._make(target);
|
|||
|
|
appendTarget.append(this);
|
|||
|
|
return this;
|
|||
|
|
}
|
|||
|
|
function prependTo(target) {
|
|||
|
|
const prependTarget = isCheerio(target) ? target : this._make(target);
|
|||
|
|
prependTarget.prepend(this);
|
|||
|
|
return this;
|
|||
|
|
}
|
|||
|
|
const append = _insert((dom, children2, parent2) => {
|
|||
|
|
uniqueSplice(children2, children2.length, 0, dom, parent2);
|
|||
|
|
});
|
|||
|
|
const prepend = _insert((dom, children2, parent2) => {
|
|||
|
|
uniqueSplice(children2, 0, 0, dom, parent2);
|
|||
|
|
});
|
|||
|
|
function _wrap(insert) {
|
|||
|
|
return function(wrapper) {
|
|||
|
|
const lastIdx = this.length - 1;
|
|||
|
|
const lastParent = this.parents().last();
|
|||
|
|
for (let i = 0; i < this.length; i++) {
|
|||
|
|
const el = this[i];
|
|||
|
|
const wrap2 = typeof wrapper === "function" ? wrapper.call(el, i, el) : typeof wrapper === "string" && !isHtml(wrapper) ? lastParent.find(wrapper).clone() : wrapper;
|
|||
|
|
const [wrapperDom] = this._makeDomArray(wrap2, i < lastIdx);
|
|||
|
|
if (!wrapperDom || !hasChildren(wrapperDom))
|
|||
|
|
continue;
|
|||
|
|
let elInsertLocation = wrapperDom;
|
|||
|
|
let j = 0;
|
|||
|
|
while (j < elInsertLocation.children.length) {
|
|||
|
|
const child = elInsertLocation.children[j];
|
|||
|
|
if (isTag(child)) {
|
|||
|
|
elInsertLocation = child;
|
|||
|
|
j = 0;
|
|||
|
|
} else {
|
|||
|
|
j++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
insert(el, elInsertLocation, [wrapperDom]);
|
|||
|
|
}
|
|||
|
|
return this;
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
const wrap = _wrap((el, elInsertLocation, wrapperDom) => {
|
|||
|
|
const { parent: parent2 } = el;
|
|||
|
|
if (!parent2)
|
|||
|
|
return;
|
|||
|
|
const siblings2 = parent2.children;
|
|||
|
|
const index2 = siblings2.indexOf(el);
|
|||
|
|
update([el], elInsertLocation);
|
|||
|
|
uniqueSplice(siblings2, index2, 0, wrapperDom, parent2);
|
|||
|
|
});
|
|||
|
|
const wrapInner = _wrap((el, elInsertLocation, wrapperDom) => {
|
|||
|
|
if (!hasChildren(el))
|
|||
|
|
return;
|
|||
|
|
update(el.children, elInsertLocation);
|
|||
|
|
update(wrapperDom, el);
|
|||
|
|
});
|
|||
|
|
function unwrap(selector) {
|
|||
|
|
this.parent(selector).not("body").each((_, el) => {
|
|||
|
|
this._make(el).replaceWith(el.children);
|
|||
|
|
});
|
|||
|
|
return this;
|
|||
|
|
}
|
|||
|
|
function wrapAll(wrapper) {
|
|||
|
|
const el = this[0];
|
|||
|
|
if (el) {
|
|||
|
|
const wrap2 = this._make(typeof wrapper === "function" ? wrapper.call(el, 0, el) : wrapper).insertBefore(el);
|
|||
|
|
let elInsertLocation;
|
|||
|
|
for (let i = 0; i < wrap2.length; i++) {
|
|||
|
|
if (wrap2[i].type === "tag")
|
|||
|
|
elInsertLocation = wrap2[i];
|
|||
|
|
}
|
|||
|
|
let j = 0;
|
|||
|
|
while (elInsertLocation && j < elInsertLocation.children.length) {
|
|||
|
|
const child = elInsertLocation.children[j];
|
|||
|
|
if (child.type === "tag") {
|
|||
|
|
elInsertLocation = child;
|
|||
|
|
j = 0;
|
|||
|
|
} else {
|
|||
|
|
j++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (elInsertLocation)
|
|||
|
|
this._make(elInsertLocation).append(this);
|
|||
|
|
}
|
|||
|
|
return this;
|
|||
|
|
}
|
|||
|
|
function after(...elems) {
|
|||
|
|
const lastIdx = this.length - 1;
|
|||
|
|
return domEach(this, (el, i) => {
|
|||
|
|
if (!hasChildren(el) || !el.parent) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
const siblings2 = el.parent.children;
|
|||
|
|
const index2 = siblings2.indexOf(el);
|
|||
|
|
if (index2 < 0)
|
|||
|
|
return;
|
|||
|
|
const domSrc = typeof elems[0] === "function" ? elems[0].call(el, i, this._render(el.children)) : elems;
|
|||
|
|
const dom = this._makeDomArray(domSrc, i < lastIdx);
|
|||
|
|
uniqueSplice(siblings2, index2 + 1, 0, dom, el.parent);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
function insertAfter(target) {
|
|||
|
|
if (typeof target === "string") {
|
|||
|
|
target = this._make(target);
|
|||
|
|
}
|
|||
|
|
this.remove();
|
|||
|
|
const clones = [];
|
|||
|
|
for (const el of this._makeDomArray(target)) {
|
|||
|
|
const clonedSelf = this.clone().toArray();
|
|||
|
|
const { parent: parent2 } = el;
|
|||
|
|
if (!parent2) {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
const siblings2 = parent2.children;
|
|||
|
|
const index2 = siblings2.indexOf(el);
|
|||
|
|
if (index2 < 0)
|
|||
|
|
continue;
|
|||
|
|
uniqueSplice(siblings2, index2 + 1, 0, clonedSelf, parent2);
|
|||
|
|
clones.push(...clonedSelf);
|
|||
|
|
}
|
|||
|
|
return this._make(clones);
|
|||
|
|
}
|
|||
|
|
function before(...elems) {
|
|||
|
|
const lastIdx = this.length - 1;
|
|||
|
|
return domEach(this, (el, i) => {
|
|||
|
|
if (!hasChildren(el) || !el.parent) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
const siblings2 = el.parent.children;
|
|||
|
|
const index2 = siblings2.indexOf(el);
|
|||
|
|
if (index2 < 0)
|
|||
|
|
return;
|
|||
|
|
const domSrc = typeof elems[0] === "function" ? elems[0].call(el, i, this._render(el.children)) : elems;
|
|||
|
|
const dom = this._makeDomArray(domSrc, i < lastIdx);
|
|||
|
|
uniqueSplice(siblings2, index2, 0, dom, el.parent);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
function insertBefore(target) {
|
|||
|
|
const targetArr = this._make(target);
|
|||
|
|
this.remove();
|
|||
|
|
const clones = [];
|
|||
|
|
domEach(targetArr, (el) => {
|
|||
|
|
const clonedSelf = this.clone().toArray();
|
|||
|
|
const { parent: parent2 } = el;
|
|||
|
|
if (!parent2) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
const siblings2 = parent2.children;
|
|||
|
|
const index2 = siblings2.indexOf(el);
|
|||
|
|
if (index2 < 0)
|
|||
|
|
return;
|
|||
|
|
uniqueSplice(siblings2, index2, 0, clonedSelf, parent2);
|
|||
|
|
clones.push(...clonedSelf);
|
|||
|
|
});
|
|||
|
|
return this._make(clones);
|
|||
|
|
}
|
|||
|
|
function remove(selector) {
|
|||
|
|
const elems = selector ? this.filter(selector) : this;
|
|||
|
|
domEach(elems, (el) => {
|
|||
|
|
removeElement(el);
|
|||
|
|
el.prev = el.next = el.parent = null;
|
|||
|
|
});
|
|||
|
|
return this;
|
|||
|
|
}
|
|||
|
|
function replaceWith(content) {
|
|||
|
|
return domEach(this, (el, i) => {
|
|||
|
|
const { parent: parent2 } = el;
|
|||
|
|
if (!parent2) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
const siblings2 = parent2.children;
|
|||
|
|
const cont = typeof content === "function" ? content.call(el, i, el) : content;
|
|||
|
|
const dom = this._makeDomArray(cont);
|
|||
|
|
update(dom, null);
|
|||
|
|
const index2 = siblings2.indexOf(el);
|
|||
|
|
uniqueSplice(siblings2, index2, 1, dom, parent2);
|
|||
|
|
if (!dom.includes(el)) {
|
|||
|
|
el.parent = el.prev = el.next = null;
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
function empty() {
|
|||
|
|
return domEach(this, (el) => {
|
|||
|
|
if (!hasChildren(el))
|
|||
|
|
return;
|
|||
|
|
for (const child of el.children) {
|
|||
|
|
child.next = child.prev = child.parent = null;
|
|||
|
|
}
|
|||
|
|
el.children.length = 0;
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
function html(str) {
|
|||
|
|
if (str === void 0) {
|
|||
|
|
const el = this[0];
|
|||
|
|
if (!el || !hasChildren(el))
|
|||
|
|
return null;
|
|||
|
|
return this._render(el.children);
|
|||
|
|
}
|
|||
|
|
return domEach(this, (el) => {
|
|||
|
|
if (!hasChildren(el))
|
|||
|
|
return;
|
|||
|
|
for (const child of el.children) {
|
|||
|
|
child.next = child.prev = child.parent = null;
|
|||
|
|
}
|
|||
|
|
const content = isCheerio(str) ? str.toArray() : this._parse(`${str}`, this.options, false, el).children;
|
|||
|
|
update(content, el);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
function toString() {
|
|||
|
|
return this._render(this);
|
|||
|
|
}
|
|||
|
|
function text(str) {
|
|||
|
|
if (str === void 0) {
|
|||
|
|
return text$1(this);
|
|||
|
|
}
|
|||
|
|
if (typeof str === "function") {
|
|||
|
|
return domEach(this, (el, i) => this._make(el).text(str.call(el, i, text$1([el]))));
|
|||
|
|
}
|
|||
|
|
return domEach(this, (el) => {
|
|||
|
|
if (!hasChildren(el))
|
|||
|
|
return;
|
|||
|
|
for (const child of el.children) {
|
|||
|
|
child.next = child.prev = child.parent = null;
|
|||
|
|
}
|
|||
|
|
const textNode = new Text(`${str}`);
|
|||
|
|
update(textNode, el);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
function clone() {
|
|||
|
|
const clone2 = Array.prototype.map.call(this.get(), (el) => cloneNode(el, true));
|
|||
|
|
const root2 = new Document(clone2);
|
|||
|
|
for (const node of clone2) {
|
|||
|
|
node.parent = root2;
|
|||
|
|
}
|
|||
|
|
return this._make(clone2);
|
|||
|
|
}
|
|||
|
|
const Manipulation = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|||
|
|
__proto__: null,
|
|||
|
|
_makeDomArray,
|
|||
|
|
after,
|
|||
|
|
append,
|
|||
|
|
appendTo,
|
|||
|
|
before,
|
|||
|
|
clone,
|
|||
|
|
empty,
|
|||
|
|
html,
|
|||
|
|
insertAfter,
|
|||
|
|
insertBefore,
|
|||
|
|
prepend,
|
|||
|
|
prependTo,
|
|||
|
|
remove,
|
|||
|
|
replaceWith,
|
|||
|
|
text,
|
|||
|
|
toString,
|
|||
|
|
unwrap,
|
|||
|
|
wrap,
|
|||
|
|
wrapAll,
|
|||
|
|
wrapInner
|
|||
|
|
}, Symbol.toStringTag, { value: "Module" }));
|
|||
|
|
function css(prop2, val2) {
|
|||
|
|
if (prop2 != null && val2 != null || // When `prop` is a "plain" object
|
|||
|
|
typeof prop2 === "object" && !Array.isArray(prop2)) {
|
|||
|
|
return domEach(this, (el, i) => {
|
|||
|
|
if (isTag(el)) {
|
|||
|
|
setCss(el, prop2, val2, i);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
if (this.length === 0) {
|
|||
|
|
return void 0;
|
|||
|
|
}
|
|||
|
|
return getCss(this[0], prop2);
|
|||
|
|
}
|
|||
|
|
function setCss(el, prop2, value, idx) {
|
|||
|
|
if (typeof prop2 === "string") {
|
|||
|
|
const styles = getCss(el);
|
|||
|
|
const val2 = typeof value === "function" ? value.call(el, idx, styles[prop2]) : value;
|
|||
|
|
if (val2 === "") {
|
|||
|
|
delete styles[prop2];
|
|||
|
|
} else if (val2 != null) {
|
|||
|
|
styles[prop2] = val2;
|
|||
|
|
}
|
|||
|
|
el.attribs["style"] = stringify(styles);
|
|||
|
|
} else if (typeof prop2 === "object") {
|
|||
|
|
const keys = Object.keys(prop2);
|
|||
|
|
for (let i = 0; i < keys.length; i++) {
|
|||
|
|
const k = keys[i];
|
|||
|
|
setCss(el, k, prop2[k], i);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function getCss(el, prop2) {
|
|||
|
|
if (!el || !isTag(el))
|
|||
|
|
return;
|
|||
|
|
const styles = parse(el.attribs["style"]);
|
|||
|
|
if (typeof prop2 === "string") {
|
|||
|
|
return styles[prop2];
|
|||
|
|
}
|
|||
|
|
if (Array.isArray(prop2)) {
|
|||
|
|
const newStyles = {};
|
|||
|
|
for (const item of prop2) {
|
|||
|
|
if (styles[item] != null) {
|
|||
|
|
newStyles[item] = styles[item];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return newStyles;
|
|||
|
|
}
|
|||
|
|
return styles;
|
|||
|
|
}
|
|||
|
|
function stringify(obj) {
|
|||
|
|
return Object.keys(obj).reduce((str, prop2) => `${str}${str ? " " : ""}${prop2}: ${obj[prop2]};`, "");
|
|||
|
|
}
|
|||
|
|
function parse(styles) {
|
|||
|
|
styles = (styles || "").trim();
|
|||
|
|
if (!styles)
|
|||
|
|
return {};
|
|||
|
|
const obj = {};
|
|||
|
|
let key;
|
|||
|
|
for (const str of styles.split(";")) {
|
|||
|
|
const n = str.indexOf(":");
|
|||
|
|
if (n < 1 || n === str.length - 1) {
|
|||
|
|
const trimmed = str.trimEnd();
|
|||
|
|
if (trimmed.length > 0 && key !== void 0) {
|
|||
|
|
obj[key] += `;${trimmed}`;
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
key = str.slice(0, n).trim();
|
|||
|
|
obj[key] = str.slice(n + 1).trim();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return obj;
|
|||
|
|
}
|
|||
|
|
const Css = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|||
|
|
__proto__: null,
|
|||
|
|
css
|
|||
|
|
}, Symbol.toStringTag, { value: "Module" }));
|
|||
|
|
const submittableSelector = "input,select,textarea,keygen";
|
|||
|
|
const r20 = /%20/g;
|
|||
|
|
const rCRLF = /\r?\n/g;
|
|||
|
|
function serialize() {
|
|||
|
|
const arr = this.serializeArray();
|
|||
|
|
const retArr = arr.map((data2) => `${encodeURIComponent(data2.name)}=${encodeURIComponent(data2.value)}`);
|
|||
|
|
return retArr.join("&").replace(r20, "+");
|
|||
|
|
}
|
|||
|
|
function serializeArray() {
|
|||
|
|
return this.map((_, elem) => {
|
|||
|
|
const $elem = this._make(elem);
|
|||
|
|
if (isTag(elem) && elem.name === "form") {
|
|||
|
|
return $elem.find(submittableSelector).toArray();
|
|||
|
|
}
|
|||
|
|
return $elem.filter(submittableSelector).toArray();
|
|||
|
|
}).filter(
|
|||
|
|
// Verify elements have a name (`attr.name`) and are not disabled (`:enabled`)
|
|||
|
|
'[name!=""]:enabled:not(:submit, :button, :image, :reset, :file):matches([checked], :not(:checkbox, :radio))'
|
|||
|
|
).map((_, elem) => {
|
|||
|
|
var _a2;
|
|||
|
|
const $elem = this._make(elem);
|
|||
|
|
const name = $elem.attr("name");
|
|||
|
|
const value = (_a2 = $elem.val()) !== null && _a2 !== void 0 ? _a2 : "";
|
|||
|
|
if (Array.isArray(value)) {
|
|||
|
|
return value.map((val2) => (
|
|||
|
|
/*
|
|||
|
|
* We trim replace any line endings (e.g. `\r` or `\r\n` with `\r\n`) to guarantee consistency across platforms
|
|||
|
|
* These can occur inside of `<textarea>'s`
|
|||
|
|
*/
|
|||
|
|
{ name, value: val2.replace(rCRLF, "\r\n") }
|
|||
|
|
));
|
|||
|
|
}
|
|||
|
|
return { name, value: value.replace(rCRLF, "\r\n") };
|
|||
|
|
}).toArray();
|
|||
|
|
}
|
|||
|
|
const Forms = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|||
|
|
__proto__: null,
|
|||
|
|
serialize,
|
|||
|
|
serializeArray
|
|||
|
|
}, Symbol.toStringTag, { value: "Module" }));
|
|||
|
|
function getExtractDescr(descr) {
|
|||
|
|
var _a2;
|
|||
|
|
if (typeof descr === "string") {
|
|||
|
|
return { selector: descr, value: "textContent" };
|
|||
|
|
}
|
|||
|
|
return {
|
|||
|
|
selector: descr.selector,
|
|||
|
|
value: (_a2 = descr.value) !== null && _a2 !== void 0 ? _a2 : "textContent"
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
function extract(map2) {
|
|||
|
|
const ret = {};
|
|||
|
|
for (const key in map2) {
|
|||
|
|
const descr = map2[key];
|
|||
|
|
const isArray = Array.isArray(descr);
|
|||
|
|
const { selector, value } = getExtractDescr(isArray ? descr[0] : descr);
|
|||
|
|
const fn = typeof value === "function" ? value : typeof value === "string" ? (el) => this._make(el).prop(value) : (el) => this._make(el).extract(value);
|
|||
|
|
if (isArray) {
|
|||
|
|
ret[key] = this._findBySelector(selector, Number.POSITIVE_INFINITY).map((_, el) => fn(el, key, ret)).get();
|
|||
|
|
} else {
|
|||
|
|
const $ = this._findBySelector(selector, 1);
|
|||
|
|
ret[key] = $.length > 0 ? fn($[0], key, ret) : void 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return ret;
|
|||
|
|
}
|
|||
|
|
const Extract = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|||
|
|
__proto__: null,
|
|||
|
|
extract
|
|||
|
|
}, Symbol.toStringTag, { value: "Module" }));
|
|||
|
|
class Cheerio {
|
|||
|
|
/**
|
|||
|
|
* Instance of cheerio. Methods are specified in the modules. Usage of this
|
|||
|
|
* constructor is not recommended. Please use `$.load` instead.
|
|||
|
|
*
|
|||
|
|
* @private
|
|||
|
|
* @param elements - The new selection.
|
|||
|
|
* @param root - Sets the root node.
|
|||
|
|
* @param options - Options for the instance.
|
|||
|
|
*/
|
|||
|
|
constructor(elements, root2, options) {
|
|||
|
|
this.length = 0;
|
|||
|
|
this.options = options;
|
|||
|
|
this._root = root2;
|
|||
|
|
if (elements) {
|
|||
|
|
for (let idx = 0; idx < elements.length; idx++) {
|
|||
|
|
this[idx] = elements[idx];
|
|||
|
|
}
|
|||
|
|
this.length = elements.length;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
Cheerio.prototype.cheerio = "[cheerio object]";
|
|||
|
|
Cheerio.prototype.splice = Array.prototype.splice;
|
|||
|
|
Cheerio.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
|
|||
|
|
Object.assign(Cheerio.prototype, Attributes, Traversing, Manipulation, Css, Forms, Extract);
|
|||
|
|
function getLoad(parse2, render2) {
|
|||
|
|
return function load2(content, options, isDocument2 = true) {
|
|||
|
|
if (content == null) {
|
|||
|
|
throw new Error("cheerio.load() expects a string");
|
|||
|
|
}
|
|||
|
|
const internalOpts = flattenOptions(options);
|
|||
|
|
const initialRoot = parse2(content, internalOpts, isDocument2, null);
|
|||
|
|
class LoadedCheerio extends Cheerio {
|
|||
|
|
_make(selector, context) {
|
|||
|
|
const cheerio = initialize(selector, context);
|
|||
|
|
cheerio.prevObject = this;
|
|||
|
|
return cheerio;
|
|||
|
|
}
|
|||
|
|
_parse(content2, options2, isDocument3, context) {
|
|||
|
|
return parse2(content2, options2, isDocument3, context);
|
|||
|
|
}
|
|||
|
|
_render(dom) {
|
|||
|
|
return render2(dom, this.options);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function initialize(selector, context, root2 = initialRoot, opts) {
|
|||
|
|
if (selector && isCheerio(selector))
|
|||
|
|
return selector;
|
|||
|
|
const options2 = flattenOptions(opts, internalOpts);
|
|||
|
|
const r = typeof root2 === "string" ? [parse2(root2, options2, false, null)] : "length" in root2 ? root2 : [root2];
|
|||
|
|
const rootInstance = isCheerio(r) ? r : new LoadedCheerio(r, null, options2);
|
|||
|
|
rootInstance._root = rootInstance;
|
|||
|
|
if (!selector) {
|
|||
|
|
return new LoadedCheerio(void 0, rootInstance, options2);
|
|||
|
|
}
|
|||
|
|
const elements = typeof selector === "string" && isHtml(selector) ? (
|
|||
|
|
// $(<html>)
|
|||
|
|
parse2(selector, options2, false, null).children
|
|||
|
|
) : isNode(selector) ? (
|
|||
|
|
// $(dom)
|
|||
|
|
[selector]
|
|||
|
|
) : Array.isArray(selector) ? (
|
|||
|
|
// $([dom])
|
|||
|
|
selector
|
|||
|
|
) : void 0;
|
|||
|
|
const instance = new LoadedCheerio(elements, rootInstance, options2);
|
|||
|
|
if (elements) {
|
|||
|
|
return instance;
|
|||
|
|
}
|
|||
|
|
if (typeof selector !== "string") {
|
|||
|
|
throw new TypeError("Unexpected type of selector");
|
|||
|
|
}
|
|||
|
|
let search = selector;
|
|||
|
|
const searchContext = context ? (
|
|||
|
|
// If we don't have a context, maybe we have a root, from loading
|
|||
|
|
typeof context === "string" ? isHtml(context) ? (
|
|||
|
|
// $('li', '<ul>...</ul>')
|
|||
|
|
new LoadedCheerio([parse2(context, options2, false, null)], rootInstance, options2)
|
|||
|
|
) : (
|
|||
|
|
// $('li', 'ul')
|
|||
|
|
(search = `${context} ${search}`, rootInstance)
|
|||
|
|
) : isCheerio(context) ? (
|
|||
|
|
// $('li', $)
|
|||
|
|
context
|
|||
|
|
) : (
|
|||
|
|
// $('li', node), $('li', [nodes])
|
|||
|
|
new LoadedCheerio(Array.isArray(context) ? context : [context], rootInstance, options2)
|
|||
|
|
)
|
|||
|
|
) : rootInstance;
|
|||
|
|
if (!searchContext)
|
|||
|
|
return instance;
|
|||
|
|
return searchContext.find(search);
|
|||
|
|
}
|
|||
|
|
Object.assign(initialize, staticMethods, {
|
|||
|
|
load: load2,
|
|||
|
|
// `_root` and `_options` are used in static methods.
|
|||
|
|
_root: initialRoot,
|
|||
|
|
_options: internalOpts,
|
|||
|
|
// Add `fn` for plugins
|
|||
|
|
fn: LoadedCheerio.prototype,
|
|||
|
|
// Add the prototype here to maintain `instanceof` behavior.
|
|||
|
|
prototype: LoadedCheerio.prototype
|
|||
|
|
});
|
|||
|
|
return initialize;
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
function isNode(obj) {
|
|||
|
|
return !!obj.name || obj.type === "root" || obj.type === "text" || obj.type === "comment";
|
|||
|
|
}
|
|||
|
|
var CharCodes;
|
|||
|
|
(function(CharCodes2) {
|
|||
|
|
CharCodes2[CharCodes2["Tab"] = 9] = "Tab";
|
|||
|
|
CharCodes2[CharCodes2["NewLine"] = 10] = "NewLine";
|
|||
|
|
CharCodes2[CharCodes2["FormFeed"] = 12] = "FormFeed";
|
|||
|
|
CharCodes2[CharCodes2["CarriageReturn"] = 13] = "CarriageReturn";
|
|||
|
|
CharCodes2[CharCodes2["Space"] = 32] = "Space";
|
|||
|
|
CharCodes2[CharCodes2["ExclamationMark"] = 33] = "ExclamationMark";
|
|||
|
|
CharCodes2[CharCodes2["Number"] = 35] = "Number";
|
|||
|
|
CharCodes2[CharCodes2["Amp"] = 38] = "Amp";
|
|||
|
|
CharCodes2[CharCodes2["SingleQuote"] = 39] = "SingleQuote";
|
|||
|
|
CharCodes2[CharCodes2["DoubleQuote"] = 34] = "DoubleQuote";
|
|||
|
|
CharCodes2[CharCodes2["Dash"] = 45] = "Dash";
|
|||
|
|
CharCodes2[CharCodes2["Slash"] = 47] = "Slash";
|
|||
|
|
CharCodes2[CharCodes2["Zero"] = 48] = "Zero";
|
|||
|
|
CharCodes2[CharCodes2["Nine"] = 57] = "Nine";
|
|||
|
|
CharCodes2[CharCodes2["Semi"] = 59] = "Semi";
|
|||
|
|
CharCodes2[CharCodes2["Lt"] = 60] = "Lt";
|
|||
|
|
CharCodes2[CharCodes2["Eq"] = 61] = "Eq";
|
|||
|
|
CharCodes2[CharCodes2["Gt"] = 62] = "Gt";
|
|||
|
|
CharCodes2[CharCodes2["Questionmark"] = 63] = "Questionmark";
|
|||
|
|
CharCodes2[CharCodes2["UpperA"] = 65] = "UpperA";
|
|||
|
|
CharCodes2[CharCodes2["LowerA"] = 97] = "LowerA";
|
|||
|
|
CharCodes2[CharCodes2["UpperF"] = 70] = "UpperF";
|
|||
|
|
CharCodes2[CharCodes2["LowerF"] = 102] = "LowerF";
|
|||
|
|
CharCodes2[CharCodes2["UpperZ"] = 90] = "UpperZ";
|
|||
|
|
CharCodes2[CharCodes2["LowerZ"] = 122] = "LowerZ";
|
|||
|
|
CharCodes2[CharCodes2["LowerX"] = 120] = "LowerX";
|
|||
|
|
CharCodes2[CharCodes2["OpeningSquareBracket"] = 91] = "OpeningSquareBracket";
|
|||
|
|
})(CharCodes || (CharCodes = {}));
|
|||
|
|
var State;
|
|||
|
|
(function(State2) {
|
|||
|
|
State2[State2["Text"] = 1] = "Text";
|
|||
|
|
State2[State2["BeforeTagName"] = 2] = "BeforeTagName";
|
|||
|
|
State2[State2["InTagName"] = 3] = "InTagName";
|
|||
|
|
State2[State2["InSelfClosingTag"] = 4] = "InSelfClosingTag";
|
|||
|
|
State2[State2["BeforeClosingTagName"] = 5] = "BeforeClosingTagName";
|
|||
|
|
State2[State2["InClosingTagName"] = 6] = "InClosingTagName";
|
|||
|
|
State2[State2["AfterClosingTagName"] = 7] = "AfterClosingTagName";
|
|||
|
|
State2[State2["BeforeAttributeName"] = 8] = "BeforeAttributeName";
|
|||
|
|
State2[State2["InAttributeName"] = 9] = "InAttributeName";
|
|||
|
|
State2[State2["AfterAttributeName"] = 10] = "AfterAttributeName";
|
|||
|
|
State2[State2["BeforeAttributeValue"] = 11] = "BeforeAttributeValue";
|
|||
|
|
State2[State2["InAttributeValueDq"] = 12] = "InAttributeValueDq";
|
|||
|
|
State2[State2["InAttributeValueSq"] = 13] = "InAttributeValueSq";
|
|||
|
|
State2[State2["InAttributeValueNq"] = 14] = "InAttributeValueNq";
|
|||
|
|
State2[State2["BeforeDeclaration"] = 15] = "BeforeDeclaration";
|
|||
|
|
State2[State2["InDeclaration"] = 16] = "InDeclaration";
|
|||
|
|
State2[State2["InProcessingInstruction"] = 17] = "InProcessingInstruction";
|
|||
|
|
State2[State2["BeforeComment"] = 18] = "BeforeComment";
|
|||
|
|
State2[State2["CDATASequence"] = 19] = "CDATASequence";
|
|||
|
|
State2[State2["InSpecialComment"] = 20] = "InSpecialComment";
|
|||
|
|
State2[State2["InCommentLike"] = 21] = "InCommentLike";
|
|||
|
|
State2[State2["BeforeSpecialS"] = 22] = "BeforeSpecialS";
|
|||
|
|
State2[State2["BeforeSpecialT"] = 23] = "BeforeSpecialT";
|
|||
|
|
State2[State2["SpecialStartSequence"] = 24] = "SpecialStartSequence";
|
|||
|
|
State2[State2["InSpecialTag"] = 25] = "InSpecialTag";
|
|||
|
|
State2[State2["InEntity"] = 26] = "InEntity";
|
|||
|
|
})(State || (State = {}));
|
|||
|
|
function isWhitespace(c) {
|
|||
|
|
return c === CharCodes.Space || c === CharCodes.NewLine || c === CharCodes.Tab || c === CharCodes.FormFeed || c === CharCodes.CarriageReturn;
|
|||
|
|
}
|
|||
|
|
function isEndOfTagSection(c) {
|
|||
|
|
return c === CharCodes.Slash || c === CharCodes.Gt || isWhitespace(c);
|
|||
|
|
}
|
|||
|
|
function isASCIIAlpha(c) {
|
|||
|
|
return c >= CharCodes.LowerA && c <= CharCodes.LowerZ || c >= CharCodes.UpperA && c <= CharCodes.UpperZ;
|
|||
|
|
}
|
|||
|
|
var QuoteType;
|
|||
|
|
(function(QuoteType2) {
|
|||
|
|
QuoteType2[QuoteType2["NoValue"] = 0] = "NoValue";
|
|||
|
|
QuoteType2[QuoteType2["Unquoted"] = 1] = "Unquoted";
|
|||
|
|
QuoteType2[QuoteType2["Single"] = 2] = "Single";
|
|||
|
|
QuoteType2[QuoteType2["Double"] = 3] = "Double";
|
|||
|
|
})(QuoteType || (QuoteType = {}));
|
|||
|
|
const Sequences = {
|
|||
|
|
Cdata: new Uint8Array([67, 68, 65, 84, 65, 91]),
|
|||
|
|
// CDATA[
|
|||
|
|
CdataEnd: new Uint8Array([93, 93, 62]),
|
|||
|
|
// ]]>
|
|||
|
|
CommentEnd: new Uint8Array([45, 45, 62]),
|
|||
|
|
// `-->`
|
|||
|
|
ScriptEnd: new Uint8Array([60, 47, 115, 99, 114, 105, 112, 116]),
|
|||
|
|
// `<\/script`
|
|||
|
|
StyleEnd: new Uint8Array([60, 47, 115, 116, 121, 108, 101]),
|
|||
|
|
// `</style`
|
|||
|
|
TitleEnd: new Uint8Array([60, 47, 116, 105, 116, 108, 101]),
|
|||
|
|
// `</title`
|
|||
|
|
TextareaEnd: new Uint8Array([
|
|||
|
|
60,
|
|||
|
|
47,
|
|||
|
|
116,
|
|||
|
|
101,
|
|||
|
|
120,
|
|||
|
|
116,
|
|||
|
|
97,
|
|||
|
|
114,
|
|||
|
|
101,
|
|||
|
|
97
|
|||
|
|
])
|
|||
|
|
// `</textarea`
|
|||
|
|
};
|
|||
|
|
class Tokenizer {
|
|||
|
|
constructor({ xmlMode = false, decodeEntities = true }, cbs) {
|
|||
|
|
this.cbs = cbs;
|
|||
|
|
this.state = State.Text;
|
|||
|
|
this.buffer = "";
|
|||
|
|
this.sectionStart = 0;
|
|||
|
|
this.index = 0;
|
|||
|
|
this.entityStart = 0;
|
|||
|
|
this.baseState = State.Text;
|
|||
|
|
this.isSpecial = false;
|
|||
|
|
this.running = true;
|
|||
|
|
this.offset = 0;
|
|||
|
|
this.currentSequence = void 0;
|
|||
|
|
this.sequenceIndex = 0;
|
|||
|
|
this.xmlMode = xmlMode;
|
|||
|
|
this.decodeEntities = decodeEntities;
|
|||
|
|
this.entityDecoder = new EntityDecoder(xmlMode ? xmlDecodeTree : htmlDecodeTree, (cp, consumed) => this.emitCodePoint(cp, consumed));
|
|||
|
|
}
|
|||
|
|
reset() {
|
|||
|
|
this.state = State.Text;
|
|||
|
|
this.buffer = "";
|
|||
|
|
this.sectionStart = 0;
|
|||
|
|
this.index = 0;
|
|||
|
|
this.baseState = State.Text;
|
|||
|
|
this.currentSequence = void 0;
|
|||
|
|
this.running = true;
|
|||
|
|
this.offset = 0;
|
|||
|
|
}
|
|||
|
|
write(chunk) {
|
|||
|
|
this.offset += this.buffer.length;
|
|||
|
|
this.buffer = chunk;
|
|||
|
|
this.parse();
|
|||
|
|
}
|
|||
|
|
end() {
|
|||
|
|
if (this.running)
|
|||
|
|
this.finish();
|
|||
|
|
}
|
|||
|
|
pause() {
|
|||
|
|
this.running = false;
|
|||
|
|
}
|
|||
|
|
resume() {
|
|||
|
|
this.running = true;
|
|||
|
|
if (this.index < this.buffer.length + this.offset) {
|
|||
|
|
this.parse();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
stateText(c) {
|
|||
|
|
if (c === CharCodes.Lt || !this.decodeEntities && this.fastForwardTo(CharCodes.Lt)) {
|
|||
|
|
if (this.index > this.sectionStart) {
|
|||
|
|
this.cbs.ontext(this.sectionStart, this.index);
|
|||
|
|
}
|
|||
|
|
this.state = State.BeforeTagName;
|
|||
|
|
this.sectionStart = this.index;
|
|||
|
|
} else if (this.decodeEntities && c === CharCodes.Amp) {
|
|||
|
|
this.startEntity();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
stateSpecialStartSequence(c) {
|
|||
|
|
const isEnd = this.sequenceIndex === this.currentSequence.length;
|
|||
|
|
const isMatch = isEnd ? (
|
|||
|
|
// If we are at the end of the sequence, make sure the tag name has ended
|
|||
|
|
isEndOfTagSection(c)
|
|||
|
|
) : (
|
|||
|
|
// Otherwise, do a case-insensitive comparison
|
|||
|
|
(c | 32) === this.currentSequence[this.sequenceIndex]
|
|||
|
|
);
|
|||
|
|
if (!isMatch) {
|
|||
|
|
this.isSpecial = false;
|
|||
|
|
} else if (!isEnd) {
|
|||
|
|
this.sequenceIndex++;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
this.sequenceIndex = 0;
|
|||
|
|
this.state = State.InTagName;
|
|||
|
|
this.stateInTagName(c);
|
|||
|
|
}
|
|||
|
|
/** Look for an end tag. For <title> tags, also decode entities. */
|
|||
|
|
stateInSpecialTag(c) {
|
|||
|
|
if (this.sequenceIndex === this.currentSequence.length) {
|
|||
|
|
if (c === CharCodes.Gt || isWhitespace(c)) {
|
|||
|
|
const endOfText = this.index - this.currentSequence.length;
|
|||
|
|
if (this.sectionStart < endOfText) {
|
|||
|
|
const actualIndex = this.index;
|
|||
|
|
this.index = endOfText;
|
|||
|
|
this.cbs.ontext(this.sectionStart, endOfText);
|
|||
|
|
this.index = actualIndex;
|
|||
|
|
}
|
|||
|
|
this.isSpecial = false;
|
|||
|
|
this.sectionStart = endOfText + 2;
|
|||
|
|
this.stateInClosingTagName(c);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
this.sequenceIndex = 0;
|
|||
|
|
}
|
|||
|
|
if ((c | 32) === this.currentSequence[this.sequenceIndex]) {
|
|||
|
|
this.sequenceIndex += 1;
|
|||
|
|
} else if (this.sequenceIndex === 0) {
|
|||
|
|
if (this.currentSequence === Sequences.TitleEnd) {
|
|||
|
|
if (this.decodeEntities && c === CharCodes.Amp) {
|
|||
|
|
this.startEntity();
|
|||
|
|
}
|
|||
|
|
} else if (this.fastForwardTo(CharCodes.Lt)) {
|
|||
|
|
this.sequenceIndex = 1;
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
this.sequenceIndex = Number(c === CharCodes.Lt);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
stateCDATASequence(c) {
|
|||
|
|
if (c === Sequences.Cdata[this.sequenceIndex]) {
|
|||
|
|
if (++this.sequenceIndex === Sequences.Cdata.length) {
|
|||
|
|
this.state = State.InCommentLike;
|
|||
|
|
this.currentSequence = Sequences.CdataEnd;
|
|||
|
|
this.sequenceIndex = 0;
|
|||
|
|
this.sectionStart = this.index + 1;
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
this.sequenceIndex = 0;
|
|||
|
|
this.state = State.InDeclaration;
|
|||
|
|
this.stateInDeclaration(c);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* When we wait for one specific character, we can speed things up
|
|||
|
|
* by skipping through the buffer until we find it.
|
|||
|
|
*
|
|||
|
|
* @returns Whether the character was found.
|
|||
|
|
*/
|
|||
|
|
fastForwardTo(c) {
|
|||
|
|
while (++this.index < this.buffer.length + this.offset) {
|
|||
|
|
if (this.buffer.charCodeAt(this.index - this.offset) === c) {
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
this.index = this.buffer.length + this.offset - 1;
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Comments and CDATA end with `-->` and `]]>`.
|
|||
|
|
*
|
|||
|
|
* Their common qualities are:
|
|||
|
|
* - Their end sequences have a distinct character they start with.
|
|||
|
|
* - That character is then repeated, so we have to check multiple repeats.
|
|||
|
|
* - All characters but the start character of the sequence can be skipped.
|
|||
|
|
*/
|
|||
|
|
stateInCommentLike(c) {
|
|||
|
|
if (c === this.currentSequence[this.sequenceIndex]) {
|
|||
|
|
if (++this.sequenceIndex === this.currentSequence.length) {
|
|||
|
|
if (this.currentSequence === Sequences.CdataEnd) {
|
|||
|
|
this.cbs.oncdata(this.sectionStart, this.index, 2);
|
|||
|
|
} else {
|
|||
|
|
this.cbs.oncomment(this.sectionStart, this.index, 2);
|
|||
|
|
}
|
|||
|
|
this.sequenceIndex = 0;
|
|||
|
|
this.sectionStart = this.index + 1;
|
|||
|
|
this.state = State.Text;
|
|||
|
|
}
|
|||
|
|
} else if (this.sequenceIndex === 0) {
|
|||
|
|
if (this.fastForwardTo(this.currentSequence[0])) {
|
|||
|
|
this.sequenceIndex = 1;
|
|||
|
|
}
|
|||
|
|
} else if (c !== this.currentSequence[this.sequenceIndex - 1]) {
|
|||
|
|
this.sequenceIndex = 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* HTML only allows ASCII alpha characters (a-z and A-Z) at the beginning of a tag name.
|
|||
|
|
*
|
|||
|
|
* XML allows a lot more characters here (@see https://www.w3.org/TR/REC-xml/#NT-NameStartChar).
|
|||
|
|
* We allow anything that wouldn't end the tag.
|
|||
|
|
*/
|
|||
|
|
isTagStartChar(c) {
|
|||
|
|
return this.xmlMode ? !isEndOfTagSection(c) : isASCIIAlpha(c);
|
|||
|
|
}
|
|||
|
|
startSpecial(sequence, offset) {
|
|||
|
|
this.isSpecial = true;
|
|||
|
|
this.currentSequence = sequence;
|
|||
|
|
this.sequenceIndex = offset;
|
|||
|
|
this.state = State.SpecialStartSequence;
|
|||
|
|
}
|
|||
|
|
stateBeforeTagName(c) {
|
|||
|
|
if (c === CharCodes.ExclamationMark) {
|
|||
|
|
this.state = State.BeforeDeclaration;
|
|||
|
|
this.sectionStart = this.index + 1;
|
|||
|
|
} else if (c === CharCodes.Questionmark) {
|
|||
|
|
this.state = State.InProcessingInstruction;
|
|||
|
|
this.sectionStart = this.index + 1;
|
|||
|
|
} else if (this.isTagStartChar(c)) {
|
|||
|
|
const lower = c | 32;
|
|||
|
|
this.sectionStart = this.index;
|
|||
|
|
if (this.xmlMode) {
|
|||
|
|
this.state = State.InTagName;
|
|||
|
|
} else if (lower === Sequences.ScriptEnd[2]) {
|
|||
|
|
this.state = State.BeforeSpecialS;
|
|||
|
|
} else if (lower === Sequences.TitleEnd[2]) {
|
|||
|
|
this.state = State.BeforeSpecialT;
|
|||
|
|
} else {
|
|||
|
|
this.state = State.InTagName;
|
|||
|
|
}
|
|||
|
|
} else if (c === CharCodes.Slash) {
|
|||
|
|
this.state = State.BeforeClosingTagName;
|
|||
|
|
} else {
|
|||
|
|
this.state = State.Text;
|
|||
|
|
this.stateText(c);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
stateInTagName(c) {
|
|||
|
|
if (isEndOfTagSection(c)) {
|
|||
|
|
this.cbs.onopentagname(this.sectionStart, this.index);
|
|||
|
|
this.sectionStart = -1;
|
|||
|
|
this.state = State.BeforeAttributeName;
|
|||
|
|
this.stateBeforeAttributeName(c);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
stateBeforeClosingTagName(c) {
|
|||
|
|
if (isWhitespace(c)) ;
|
|||
|
|
else if (c === CharCodes.Gt) {
|
|||
|
|
this.state = State.Text;
|
|||
|
|
} else {
|
|||
|
|
this.state = this.isTagStartChar(c) ? State.InClosingTagName : State.InSpecialComment;
|
|||
|
|
this.sectionStart = this.index;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
stateInClosingTagName(c) {
|
|||
|
|
if (c === CharCodes.Gt || isWhitespace(c)) {
|
|||
|
|
this.cbs.onclosetag(this.sectionStart, this.index);
|
|||
|
|
this.sectionStart = -1;
|
|||
|
|
this.state = State.AfterClosingTagName;
|
|||
|
|
this.stateAfterClosingTagName(c);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
stateAfterClosingTagName(c) {
|
|||
|
|
if (c === CharCodes.Gt || this.fastForwardTo(CharCodes.Gt)) {
|
|||
|
|
this.state = State.Text;
|
|||
|
|
this.sectionStart = this.index + 1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
stateBeforeAttributeName(c) {
|
|||
|
|
if (c === CharCodes.Gt) {
|
|||
|
|
this.cbs.onopentagend(this.index);
|
|||
|
|
if (this.isSpecial) {
|
|||
|
|
this.state = State.InSpecialTag;
|
|||
|
|
this.sequenceIndex = 0;
|
|||
|
|
} else {
|
|||
|
|
this.state = State.Text;
|
|||
|
|
}
|
|||
|
|
this.sectionStart = this.index + 1;
|
|||
|
|
} else if (c === CharCodes.Slash) {
|
|||
|
|
this.state = State.InSelfClosingTag;
|
|||
|
|
} else if (!isWhitespace(c)) {
|
|||
|
|
this.state = State.InAttributeName;
|
|||
|
|
this.sectionStart = this.index;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
stateInSelfClosingTag(c) {
|
|||
|
|
if (c === CharCodes.Gt) {
|
|||
|
|
this.cbs.onselfclosingtag(this.index);
|
|||
|
|
this.state = State.Text;
|
|||
|
|
this.sectionStart = this.index + 1;
|
|||
|
|
this.isSpecial = false;
|
|||
|
|
} else if (!isWhitespace(c)) {
|
|||
|
|
this.state = State.BeforeAttributeName;
|
|||
|
|
this.stateBeforeAttributeName(c);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
stateInAttributeName(c) {
|
|||
|
|
if (c === CharCodes.Eq || isEndOfTagSection(c)) {
|
|||
|
|
this.cbs.onattribname(this.sectionStart, this.index);
|
|||
|
|
this.sectionStart = this.index;
|
|||
|
|
this.state = State.AfterAttributeName;
|
|||
|
|
this.stateAfterAttributeName(c);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
stateAfterAttributeName(c) {
|
|||
|
|
if (c === CharCodes.Eq) {
|
|||
|
|
this.state = State.BeforeAttributeValue;
|
|||
|
|
} else if (c === CharCodes.Slash || c === CharCodes.Gt) {
|
|||
|
|
this.cbs.onattribend(QuoteType.NoValue, this.sectionStart);
|
|||
|
|
this.sectionStart = -1;
|
|||
|
|
this.state = State.BeforeAttributeName;
|
|||
|
|
this.stateBeforeAttributeName(c);
|
|||
|
|
} else if (!isWhitespace(c)) {
|
|||
|
|
this.cbs.onattribend(QuoteType.NoValue, this.sectionStart);
|
|||
|
|
this.state = State.InAttributeName;
|
|||
|
|
this.sectionStart = this.index;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
stateBeforeAttributeValue(c) {
|
|||
|
|
if (c === CharCodes.DoubleQuote) {
|
|||
|
|
this.state = State.InAttributeValueDq;
|
|||
|
|
this.sectionStart = this.index + 1;
|
|||
|
|
} else if (c === CharCodes.SingleQuote) {
|
|||
|
|
this.state = State.InAttributeValueSq;
|
|||
|
|
this.sectionStart = this.index + 1;
|
|||
|
|
} else if (!isWhitespace(c)) {
|
|||
|
|
this.sectionStart = this.index;
|
|||
|
|
this.state = State.InAttributeValueNq;
|
|||
|
|
this.stateInAttributeValueNoQuotes(c);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
handleInAttributeValue(c, quote) {
|
|||
|
|
if (c === quote || !this.decodeEntities && this.fastForwardTo(quote)) {
|
|||
|
|
this.cbs.onattribdata(this.sectionStart, this.index);
|
|||
|
|
this.sectionStart = -1;
|
|||
|
|
this.cbs.onattribend(quote === CharCodes.DoubleQuote ? QuoteType.Double : QuoteType.Single, this.index + 1);
|
|||
|
|
this.state = State.BeforeAttributeName;
|
|||
|
|
} else if (this.decodeEntities && c === CharCodes.Amp) {
|
|||
|
|
this.startEntity();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
stateInAttributeValueDoubleQuotes(c) {
|
|||
|
|
this.handleInAttributeValue(c, CharCodes.DoubleQuote);
|
|||
|
|
}
|
|||
|
|
stateInAttributeValueSingleQuotes(c) {
|
|||
|
|
this.handleInAttributeValue(c, CharCodes.SingleQuote);
|
|||
|
|
}
|
|||
|
|
stateInAttributeValueNoQuotes(c) {
|
|||
|
|
if (isWhitespace(c) || c === CharCodes.Gt) {
|
|||
|
|
this.cbs.onattribdata(this.sectionStart, this.index);
|
|||
|
|
this.sectionStart = -1;
|
|||
|
|
this.cbs.onattribend(QuoteType.Unquoted, this.index);
|
|||
|
|
this.state = State.BeforeAttributeName;
|
|||
|
|
this.stateBeforeAttributeName(c);
|
|||
|
|
} else if (this.decodeEntities && c === CharCodes.Amp) {
|
|||
|
|
this.startEntity();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
stateBeforeDeclaration(c) {
|
|||
|
|
if (c === CharCodes.OpeningSquareBracket) {
|
|||
|
|
this.state = State.CDATASequence;
|
|||
|
|
this.sequenceIndex = 0;
|
|||
|
|
} else {
|
|||
|
|
this.state = c === CharCodes.Dash ? State.BeforeComment : State.InDeclaration;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
stateInDeclaration(c) {
|
|||
|
|
if (c === CharCodes.Gt || this.fastForwardTo(CharCodes.Gt)) {
|
|||
|
|
this.cbs.ondeclaration(this.sectionStart, this.index);
|
|||
|
|
this.state = State.Text;
|
|||
|
|
this.sectionStart = this.index + 1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
stateInProcessingInstruction(c) {
|
|||
|
|
if (c === CharCodes.Gt || this.fastForwardTo(CharCodes.Gt)) {
|
|||
|
|
this.cbs.onprocessinginstruction(this.sectionStart, this.index);
|
|||
|
|
this.state = State.Text;
|
|||
|
|
this.sectionStart = this.index + 1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
stateBeforeComment(c) {
|
|||
|
|
if (c === CharCodes.Dash) {
|
|||
|
|
this.state = State.InCommentLike;
|
|||
|
|
this.currentSequence = Sequences.CommentEnd;
|
|||
|
|
this.sequenceIndex = 2;
|
|||
|
|
this.sectionStart = this.index + 1;
|
|||
|
|
} else {
|
|||
|
|
this.state = State.InDeclaration;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
stateInSpecialComment(c) {
|
|||
|
|
if (c === CharCodes.Gt || this.fastForwardTo(CharCodes.Gt)) {
|
|||
|
|
this.cbs.oncomment(this.sectionStart, this.index, 0);
|
|||
|
|
this.state = State.Text;
|
|||
|
|
this.sectionStart = this.index + 1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
stateBeforeSpecialS(c) {
|
|||
|
|
const lower = c | 32;
|
|||
|
|
if (lower === Sequences.ScriptEnd[3]) {
|
|||
|
|
this.startSpecial(Sequences.ScriptEnd, 4);
|
|||
|
|
} else if (lower === Sequences.StyleEnd[3]) {
|
|||
|
|
this.startSpecial(Sequences.StyleEnd, 4);
|
|||
|
|
} else {
|
|||
|
|
this.state = State.InTagName;
|
|||
|
|
this.stateInTagName(c);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
stateBeforeSpecialT(c) {
|
|||
|
|
const lower = c | 32;
|
|||
|
|
if (lower === Sequences.TitleEnd[3]) {
|
|||
|
|
this.startSpecial(Sequences.TitleEnd, 4);
|
|||
|
|
} else if (lower === Sequences.TextareaEnd[3]) {
|
|||
|
|
this.startSpecial(Sequences.TextareaEnd, 4);
|
|||
|
|
} else {
|
|||
|
|
this.state = State.InTagName;
|
|||
|
|
this.stateInTagName(c);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
startEntity() {
|
|||
|
|
this.baseState = this.state;
|
|||
|
|
this.state = State.InEntity;
|
|||
|
|
this.entityStart = this.index;
|
|||
|
|
this.entityDecoder.startEntity(this.xmlMode ? DecodingMode.Strict : this.baseState === State.Text || this.baseState === State.InSpecialTag ? DecodingMode.Legacy : DecodingMode.Attribute);
|
|||
|
|
}
|
|||
|
|
stateInEntity() {
|
|||
|
|
const length = this.entityDecoder.write(this.buffer, this.index - this.offset);
|
|||
|
|
if (length >= 0) {
|
|||
|
|
this.state = this.baseState;
|
|||
|
|
if (length === 0) {
|
|||
|
|
this.index = this.entityStart;
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
this.index = this.offset + this.buffer.length - 1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Remove data that has already been consumed from the buffer.
|
|||
|
|
*/
|
|||
|
|
cleanup() {
|
|||
|
|
if (this.running && this.sectionStart !== this.index) {
|
|||
|
|
if (this.state === State.Text || this.state === State.InSpecialTag && this.sequenceIndex === 0) {
|
|||
|
|
this.cbs.ontext(this.sectionStart, this.index);
|
|||
|
|
this.sectionStart = this.index;
|
|||
|
|
} else if (this.state === State.InAttributeValueDq || this.state === State.InAttributeValueSq || this.state === State.InAttributeValueNq) {
|
|||
|
|
this.cbs.onattribdata(this.sectionStart, this.index);
|
|||
|
|
this.sectionStart = this.index;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
shouldContinue() {
|
|||
|
|
return this.index < this.buffer.length + this.offset && this.running;
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Iterates through the buffer, calling the function corresponding to the current state.
|
|||
|
|
*
|
|||
|
|
* States that are more likely to be hit are higher up, as a performance improvement.
|
|||
|
|
*/
|
|||
|
|
parse() {
|
|||
|
|
while (this.shouldContinue()) {
|
|||
|
|
const c = this.buffer.charCodeAt(this.index - this.offset);
|
|||
|
|
switch (this.state) {
|
|||
|
|
case State.Text: {
|
|||
|
|
this.stateText(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.SpecialStartSequence: {
|
|||
|
|
this.stateSpecialStartSequence(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.InSpecialTag: {
|
|||
|
|
this.stateInSpecialTag(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.CDATASequence: {
|
|||
|
|
this.stateCDATASequence(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.InAttributeValueDq: {
|
|||
|
|
this.stateInAttributeValueDoubleQuotes(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.InAttributeName: {
|
|||
|
|
this.stateInAttributeName(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.InCommentLike: {
|
|||
|
|
this.stateInCommentLike(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.InSpecialComment: {
|
|||
|
|
this.stateInSpecialComment(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.BeforeAttributeName: {
|
|||
|
|
this.stateBeforeAttributeName(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.InTagName: {
|
|||
|
|
this.stateInTagName(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.InClosingTagName: {
|
|||
|
|
this.stateInClosingTagName(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.BeforeTagName: {
|
|||
|
|
this.stateBeforeTagName(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.AfterAttributeName: {
|
|||
|
|
this.stateAfterAttributeName(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.InAttributeValueSq: {
|
|||
|
|
this.stateInAttributeValueSingleQuotes(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.BeforeAttributeValue: {
|
|||
|
|
this.stateBeforeAttributeValue(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.BeforeClosingTagName: {
|
|||
|
|
this.stateBeforeClosingTagName(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.AfterClosingTagName: {
|
|||
|
|
this.stateAfterClosingTagName(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.BeforeSpecialS: {
|
|||
|
|
this.stateBeforeSpecialS(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.BeforeSpecialT: {
|
|||
|
|
this.stateBeforeSpecialT(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.InAttributeValueNq: {
|
|||
|
|
this.stateInAttributeValueNoQuotes(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.InSelfClosingTag: {
|
|||
|
|
this.stateInSelfClosingTag(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.InDeclaration: {
|
|||
|
|
this.stateInDeclaration(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.BeforeDeclaration: {
|
|||
|
|
this.stateBeforeDeclaration(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.BeforeComment: {
|
|||
|
|
this.stateBeforeComment(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.InProcessingInstruction: {
|
|||
|
|
this.stateInProcessingInstruction(c);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case State.InEntity: {
|
|||
|
|
this.stateInEntity();
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
this.index++;
|
|||
|
|
}
|
|||
|
|
this.cleanup();
|
|||
|
|
}
|
|||
|
|
finish() {
|
|||
|
|
if (this.state === State.InEntity) {
|
|||
|
|
this.entityDecoder.end();
|
|||
|
|
this.state = this.baseState;
|
|||
|
|
}
|
|||
|
|
this.handleTrailingData();
|
|||
|
|
this.cbs.onend();
|
|||
|
|
}
|
|||
|
|
/** Handle any trailing data. */
|
|||
|
|
handleTrailingData() {
|
|||
|
|
const endIndex = this.buffer.length + this.offset;
|
|||
|
|
if (this.sectionStart >= endIndex) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if (this.state === State.InCommentLike) {
|
|||
|
|
if (this.currentSequence === Sequences.CdataEnd) {
|
|||
|
|
this.cbs.oncdata(this.sectionStart, endIndex, 0);
|
|||
|
|
} else {
|
|||
|
|
this.cbs.oncomment(this.sectionStart, endIndex, 0);
|
|||
|
|
}
|
|||
|
|
} else if (this.state === State.InTagName || this.state === State.BeforeAttributeName || this.state === State.BeforeAttributeValue || this.state === State.AfterAttributeName || this.state === State.InAttributeName || this.state === State.InAttributeValueSq || this.state === State.InAttributeValueDq || this.state === State.InAttributeValueNq || this.state === State.InClosingTagName) ;
|
|||
|
|
else {
|
|||
|
|
this.cbs.ontext(this.sectionStart, endIndex);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
emitCodePoint(cp, consumed) {
|
|||
|
|
if (this.baseState !== State.Text && this.baseState !== State.InSpecialTag) {
|
|||
|
|
if (this.sectionStart < this.entityStart) {
|
|||
|
|
this.cbs.onattribdata(this.sectionStart, this.entityStart);
|
|||
|
|
}
|
|||
|
|
this.sectionStart = this.entityStart + consumed;
|
|||
|
|
this.index = this.sectionStart - 1;
|
|||
|
|
this.cbs.onattribentity(cp);
|
|||
|
|
} else {
|
|||
|
|
if (this.sectionStart < this.entityStart) {
|
|||
|
|
this.cbs.ontext(this.sectionStart, this.entityStart);
|
|||
|
|
}
|
|||
|
|
this.sectionStart = this.entityStart + consumed;
|
|||
|
|
this.index = this.sectionStart - 1;
|
|||
|
|
this.cbs.ontextentity(cp, this.sectionStart);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
const formTags = /* @__PURE__ */ new Set([
|
|||
|
|
"input",
|
|||
|
|
"option",
|
|||
|
|
"optgroup",
|
|||
|
|
"select",
|
|||
|
|
"button",
|
|||
|
|
"datalist",
|
|||
|
|
"textarea"
|
|||
|
|
]);
|
|||
|
|
const pTag = /* @__PURE__ */ new Set(["p"]);
|
|||
|
|
const tableSectionTags = /* @__PURE__ */ new Set(["thead", "tbody"]);
|
|||
|
|
const ddtTags = /* @__PURE__ */ new Set(["dd", "dt"]);
|
|||
|
|
const rtpTags = /* @__PURE__ */ new Set(["rt", "rp"]);
|
|||
|
|
const openImpliesClose = /* @__PURE__ */ new Map([
|
|||
|
|
["tr", /* @__PURE__ */ new Set(["tr", "th", "td"])],
|
|||
|
|
["th", /* @__PURE__ */ new Set(["th"])],
|
|||
|
|
["td", /* @__PURE__ */ new Set(["thead", "th", "td"])],
|
|||
|
|
["body", /* @__PURE__ */ new Set(["head", "link", "script"])],
|
|||
|
|
["li", /* @__PURE__ */ new Set(["li"])],
|
|||
|
|
["p", pTag],
|
|||
|
|
["h1", pTag],
|
|||
|
|
["h2", pTag],
|
|||
|
|
["h3", pTag],
|
|||
|
|
["h4", pTag],
|
|||
|
|
["h5", pTag],
|
|||
|
|
["h6", pTag],
|
|||
|
|
["select", formTags],
|
|||
|
|
["input", formTags],
|
|||
|
|
["output", formTags],
|
|||
|
|
["button", formTags],
|
|||
|
|
["datalist", formTags],
|
|||
|
|
["textarea", formTags],
|
|||
|
|
["option", /* @__PURE__ */ new Set(["option"])],
|
|||
|
|
["optgroup", /* @__PURE__ */ new Set(["optgroup", "option"])],
|
|||
|
|
["dd", ddtTags],
|
|||
|
|
["dt", ddtTags],
|
|||
|
|
["address", pTag],
|
|||
|
|
["article", pTag],
|
|||
|
|
["aside", pTag],
|
|||
|
|
["blockquote", pTag],
|
|||
|
|
["details", pTag],
|
|||
|
|
["div", pTag],
|
|||
|
|
["dl", pTag],
|
|||
|
|
["fieldset", pTag],
|
|||
|
|
["figcaption", pTag],
|
|||
|
|
["figure", pTag],
|
|||
|
|
["footer", pTag],
|
|||
|
|
["form", pTag],
|
|||
|
|
["header", pTag],
|
|||
|
|
["hr", pTag],
|
|||
|
|
["main", pTag],
|
|||
|
|
["nav", pTag],
|
|||
|
|
["ol", pTag],
|
|||
|
|
["pre", pTag],
|
|||
|
|
["section", pTag],
|
|||
|
|
["table", pTag],
|
|||
|
|
["ul", pTag],
|
|||
|
|
["rt", rtpTags],
|
|||
|
|
["rp", rtpTags],
|
|||
|
|
["tbody", tableSectionTags],
|
|||
|
|
["tfoot", tableSectionTags]
|
|||
|
|
]);
|
|||
|
|
const voidElements = /* @__PURE__ */ new Set([
|
|||
|
|
"area",
|
|||
|
|
"base",
|
|||
|
|
"basefont",
|
|||
|
|
"br",
|
|||
|
|
"col",
|
|||
|
|
"command",
|
|||
|
|
"embed",
|
|||
|
|
"frame",
|
|||
|
|
"hr",
|
|||
|
|
"img",
|
|||
|
|
"input",
|
|||
|
|
"isindex",
|
|||
|
|
"keygen",
|
|||
|
|
"link",
|
|||
|
|
"meta",
|
|||
|
|
"param",
|
|||
|
|
"source",
|
|||
|
|
"track",
|
|||
|
|
"wbr"
|
|||
|
|
]);
|
|||
|
|
const foreignContextElements = /* @__PURE__ */ new Set(["math", "svg"]);
|
|||
|
|
const htmlIntegrationElements = /* @__PURE__ */ new Set([
|
|||
|
|
"mi",
|
|||
|
|
"mo",
|
|||
|
|
"mn",
|
|||
|
|
"ms",
|
|||
|
|
"mtext",
|
|||
|
|
"annotation-xml",
|
|||
|
|
"foreignobject",
|
|||
|
|
"desc",
|
|||
|
|
"title"
|
|||
|
|
]);
|
|||
|
|
const reNameEnd = /\s|\//;
|
|||
|
|
class Parser {
|
|||
|
|
constructor(cbs, options = {}) {
|
|||
|
|
var _a2, _b, _c, _d, _e, _f;
|
|||
|
|
this.options = options;
|
|||
|
|
this.startIndex = 0;
|
|||
|
|
this.endIndex = 0;
|
|||
|
|
this.openTagStart = 0;
|
|||
|
|
this.tagname = "";
|
|||
|
|
this.attribname = "";
|
|||
|
|
this.attribvalue = "";
|
|||
|
|
this.attribs = null;
|
|||
|
|
this.stack = [];
|
|||
|
|
this.buffers = [];
|
|||
|
|
this.bufferOffset = 0;
|
|||
|
|
this.writeIndex = 0;
|
|||
|
|
this.ended = false;
|
|||
|
|
this.cbs = cbs !== null && cbs !== void 0 ? cbs : {};
|
|||
|
|
this.htmlMode = !this.options.xmlMode;
|
|||
|
|
this.lowerCaseTagNames = (_a2 = options.lowerCaseTags) !== null && _a2 !== void 0 ? _a2 : this.htmlMode;
|
|||
|
|
this.lowerCaseAttributeNames = (_b = options.lowerCaseAttributeNames) !== null && _b !== void 0 ? _b : this.htmlMode;
|
|||
|
|
this.recognizeSelfClosing = (_c = options.recognizeSelfClosing) !== null && _c !== void 0 ? _c : !this.htmlMode;
|
|||
|
|
this.tokenizer = new ((_d = options.Tokenizer) !== null && _d !== void 0 ? _d : Tokenizer)(this.options, this);
|
|||
|
|
this.foreignContext = [!this.htmlMode];
|
|||
|
|
(_f = (_e = this.cbs).onparserinit) === null || _f === void 0 ? void 0 : _f.call(_e, this);
|
|||
|
|
}
|
|||
|
|
// Tokenizer event handlers
|
|||
|
|
/** @internal */
|
|||
|
|
ontext(start, endIndex) {
|
|||
|
|
var _a2, _b;
|
|||
|
|
const data2 = this.getSlice(start, endIndex);
|
|||
|
|
this.endIndex = endIndex - 1;
|
|||
|
|
(_b = (_a2 = this.cbs).ontext) === null || _b === void 0 ? void 0 : _b.call(_a2, data2);
|
|||
|
|
this.startIndex = endIndex;
|
|||
|
|
}
|
|||
|
|
/** @internal */
|
|||
|
|
ontextentity(cp, endIndex) {
|
|||
|
|
var _a2, _b;
|
|||
|
|
this.endIndex = endIndex - 1;
|
|||
|
|
(_b = (_a2 = this.cbs).ontext) === null || _b === void 0 ? void 0 : _b.call(_a2, fromCodePoint(cp));
|
|||
|
|
this.startIndex = endIndex;
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Checks if the current tag is a void element. Override this if you want
|
|||
|
|
* to specify your own additional void elements.
|
|||
|
|
*/
|
|||
|
|
isVoidElement(name) {
|
|||
|
|
return this.htmlMode && voidElements.has(name);
|
|||
|
|
}
|
|||
|
|
/** @internal */
|
|||
|
|
onopentagname(start, endIndex) {
|
|||
|
|
this.endIndex = endIndex;
|
|||
|
|
let name = this.getSlice(start, endIndex);
|
|||
|
|
if (this.lowerCaseTagNames) {
|
|||
|
|
name = name.toLowerCase();
|
|||
|
|
}
|
|||
|
|
this.emitOpenTag(name);
|
|||
|
|
}
|
|||
|
|
emitOpenTag(name) {
|
|||
|
|
var _a2, _b, _c, _d;
|
|||
|
|
this.openTagStart = this.startIndex;
|
|||
|
|
this.tagname = name;
|
|||
|
|
const impliesClose = this.htmlMode && openImpliesClose.get(name);
|
|||
|
|
if (impliesClose) {
|
|||
|
|
while (this.stack.length > 0 && impliesClose.has(this.stack[0])) {
|
|||
|
|
const element = this.stack.shift();
|
|||
|
|
(_b = (_a2 = this.cbs).onclosetag) === null || _b === void 0 ? void 0 : _b.call(_a2, element, true);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (!this.isVoidElement(name)) {
|
|||
|
|
this.stack.unshift(name);
|
|||
|
|
if (this.htmlMode) {
|
|||
|
|
if (foreignContextElements.has(name)) {
|
|||
|
|
this.foreignContext.unshift(true);
|
|||
|
|
} else if (htmlIntegrationElements.has(name)) {
|
|||
|
|
this.foreignContext.unshift(false);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
(_d = (_c = this.cbs).onopentagname) === null || _d === void 0 ? void 0 : _d.call(_c, name);
|
|||
|
|
if (this.cbs.onopentag)
|
|||
|
|
this.attribs = {};
|
|||
|
|
}
|
|||
|
|
endOpenTag(isImplied) {
|
|||
|
|
var _a2, _b;
|
|||
|
|
this.startIndex = this.openTagStart;
|
|||
|
|
if (this.attribs) {
|
|||
|
|
(_b = (_a2 = this.cbs).onopentag) === null || _b === void 0 ? void 0 : _b.call(_a2, this.tagname, this.attribs, isImplied);
|
|||
|
|
this.attribs = null;
|
|||
|
|
}
|
|||
|
|
if (this.cbs.onclosetag && this.isVoidElement(this.tagname)) {
|
|||
|
|
this.cbs.onclosetag(this.tagname, true);
|
|||
|
|
}
|
|||
|
|
this.tagname = "";
|
|||
|
|
}
|
|||
|
|
/** @internal */
|
|||
|
|
onopentagend(endIndex) {
|
|||
|
|
this.endIndex = endIndex;
|
|||
|
|
this.endOpenTag(false);
|
|||
|
|
this.startIndex = endIndex + 1;
|
|||
|
|
}
|
|||
|
|
/** @internal */
|
|||
|
|
onclosetag(start, endIndex) {
|
|||
|
|
var _a2, _b, _c, _d, _e, _f, _g, _h;
|
|||
|
|
this.endIndex = endIndex;
|
|||
|
|
let name = this.getSlice(start, endIndex);
|
|||
|
|
if (this.lowerCaseTagNames) {
|
|||
|
|
name = name.toLowerCase();
|
|||
|
|
}
|
|||
|
|
if (this.htmlMode && (foreignContextElements.has(name) || htmlIntegrationElements.has(name))) {
|
|||
|
|
this.foreignContext.shift();
|
|||
|
|
}
|
|||
|
|
if (!this.isVoidElement(name)) {
|
|||
|
|
const pos = this.stack.indexOf(name);
|
|||
|
|
if (pos !== -1) {
|
|||
|
|
for (let index2 = 0; index2 <= pos; index2++) {
|
|||
|
|
const element = this.stack.shift();
|
|||
|
|
(_b = (_a2 = this.cbs).onclosetag) === null || _b === void 0 ? void 0 : _b.call(_a2, element, index2 !== pos);
|
|||
|
|
}
|
|||
|
|
} else if (this.htmlMode && name === "p") {
|
|||
|
|
this.emitOpenTag("p");
|
|||
|
|
this.closeCurrentTag(true);
|
|||
|
|
}
|
|||
|
|
} else if (this.htmlMode && name === "br") {
|
|||
|
|
(_d = (_c = this.cbs).onopentagname) === null || _d === void 0 ? void 0 : _d.call(_c, "br");
|
|||
|
|
(_f = (_e = this.cbs).onopentag) === null || _f === void 0 ? void 0 : _f.call(_e, "br", {}, true);
|
|||
|
|
(_h = (_g = this.cbs).onclosetag) === null || _h === void 0 ? void 0 : _h.call(_g, "br", false);
|
|||
|
|
}
|
|||
|
|
this.startIndex = endIndex + 1;
|
|||
|
|
}
|
|||
|
|
/** @internal */
|
|||
|
|
onselfclosingtag(endIndex) {
|
|||
|
|
this.endIndex = endIndex;
|
|||
|
|
if (this.recognizeSelfClosing || this.foreignContext[0]) {
|
|||
|
|
this.closeCurrentTag(false);
|
|||
|
|
this.startIndex = endIndex + 1;
|
|||
|
|
} else {
|
|||
|
|
this.onopentagend(endIndex);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
closeCurrentTag(isOpenImplied) {
|
|||
|
|
var _a2, _b;
|
|||
|
|
const name = this.tagname;
|
|||
|
|
this.endOpenTag(isOpenImplied);
|
|||
|
|
if (this.stack[0] === name) {
|
|||
|
|
(_b = (_a2 = this.cbs).onclosetag) === null || _b === void 0 ? void 0 : _b.call(_a2, name, !isOpenImplied);
|
|||
|
|
this.stack.shift();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
/** @internal */
|
|||
|
|
onattribname(start, endIndex) {
|
|||
|
|
this.startIndex = start;
|
|||
|
|
const name = this.getSlice(start, endIndex);
|
|||
|
|
this.attribname = this.lowerCaseAttributeNames ? name.toLowerCase() : name;
|
|||
|
|
}
|
|||
|
|
/** @internal */
|
|||
|
|
onattribdata(start, endIndex) {
|
|||
|
|
this.attribvalue += this.getSlice(start, endIndex);
|
|||
|
|
}
|
|||
|
|
/** @internal */
|
|||
|
|
onattribentity(cp) {
|
|||
|
|
this.attribvalue += fromCodePoint(cp);
|
|||
|
|
}
|
|||
|
|
/** @internal */
|
|||
|
|
onattribend(quote, endIndex) {
|
|||
|
|
var _a2, _b;
|
|||
|
|
this.endIndex = endIndex;
|
|||
|
|
(_b = (_a2 = this.cbs).onattribute) === null || _b === void 0 ? void 0 : _b.call(_a2, this.attribname, this.attribvalue, quote === QuoteType.Double ? '"' : quote === QuoteType.Single ? "'" : quote === QuoteType.NoValue ? void 0 : null);
|
|||
|
|
if (this.attribs && !Object.prototype.hasOwnProperty.call(this.attribs, this.attribname)) {
|
|||
|
|
this.attribs[this.attribname] = this.attribvalue;
|
|||
|
|
}
|
|||
|
|
this.attribvalue = "";
|
|||
|
|
}
|
|||
|
|
getInstructionName(value) {
|
|||
|
|
const index2 = value.search(reNameEnd);
|
|||
|
|
let name = index2 < 0 ? value : value.substr(0, index2);
|
|||
|
|
if (this.lowerCaseTagNames) {
|
|||
|
|
name = name.toLowerCase();
|
|||
|
|
}
|
|||
|
|
return name;
|
|||
|
|
}
|
|||
|
|
/** @internal */
|
|||
|
|
ondeclaration(start, endIndex) {
|
|||
|
|
this.endIndex = endIndex;
|
|||
|
|
const value = this.getSlice(start, endIndex);
|
|||
|
|
if (this.cbs.onprocessinginstruction) {
|
|||
|
|
const name = this.getInstructionName(value);
|
|||
|
|
this.cbs.onprocessinginstruction(`!${name}`, `!${value}`);
|
|||
|
|
}
|
|||
|
|
this.startIndex = endIndex + 1;
|
|||
|
|
}
|
|||
|
|
/** @internal */
|
|||
|
|
onprocessinginstruction(start, endIndex) {
|
|||
|
|
this.endIndex = endIndex;
|
|||
|
|
const value = this.getSlice(start, endIndex);
|
|||
|
|
if (this.cbs.onprocessinginstruction) {
|
|||
|
|
const name = this.getInstructionName(value);
|
|||
|
|
this.cbs.onprocessinginstruction(`?${name}`, `?${value}`);
|
|||
|
|
}
|
|||
|
|
this.startIndex = endIndex + 1;
|
|||
|
|
}
|
|||
|
|
/** @internal */
|
|||
|
|
oncomment(start, endIndex, offset) {
|
|||
|
|
var _a2, _b, _c, _d;
|
|||
|
|
this.endIndex = endIndex;
|
|||
|
|
(_b = (_a2 = this.cbs).oncomment) === null || _b === void 0 ? void 0 : _b.call(_a2, this.getSlice(start, endIndex - offset));
|
|||
|
|
(_d = (_c = this.cbs).oncommentend) === null || _d === void 0 ? void 0 : _d.call(_c);
|
|||
|
|
this.startIndex = endIndex + 1;
|
|||
|
|
}
|
|||
|
|
/** @internal */
|
|||
|
|
oncdata(start, endIndex, offset) {
|
|||
|
|
var _a2, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|||
|
|
this.endIndex = endIndex;
|
|||
|
|
const value = this.getSlice(start, endIndex - offset);
|
|||
|
|
if (!this.htmlMode || this.options.recognizeCDATA) {
|
|||
|
|
(_b = (_a2 = this.cbs).oncdatastart) === null || _b === void 0 ? void 0 : _b.call(_a2);
|
|||
|
|
(_d = (_c = this.cbs).ontext) === null || _d === void 0 ? void 0 : _d.call(_c, value);
|
|||
|
|
(_f = (_e = this.cbs).oncdataend) === null || _f === void 0 ? void 0 : _f.call(_e);
|
|||
|
|
} else {
|
|||
|
|
(_h = (_g = this.cbs).oncomment) === null || _h === void 0 ? void 0 : _h.call(_g, `[CDATA[${value}]]`);
|
|||
|
|
(_k = (_j = this.cbs).oncommentend) === null || _k === void 0 ? void 0 : _k.call(_j);
|
|||
|
|
}
|
|||
|
|
this.startIndex = endIndex + 1;
|
|||
|
|
}
|
|||
|
|
/** @internal */
|
|||
|
|
onend() {
|
|||
|
|
var _a2, _b;
|
|||
|
|
if (this.cbs.onclosetag) {
|
|||
|
|
this.endIndex = this.startIndex;
|
|||
|
|
for (let index2 = 0; index2 < this.stack.length; index2++) {
|
|||
|
|
this.cbs.onclosetag(this.stack[index2], true);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
(_b = (_a2 = this.cbs).onend) === null || _b === void 0 ? void 0 : _b.call(_a2);
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Resets the parser to a blank state, ready to parse a new HTML document
|
|||
|
|
*/
|
|||
|
|
reset() {
|
|||
|
|
var _a2, _b, _c, _d;
|
|||
|
|
(_b = (_a2 = this.cbs).onreset) === null || _b === void 0 ? void 0 : _b.call(_a2);
|
|||
|
|
this.tokenizer.reset();
|
|||
|
|
this.tagname = "";
|
|||
|
|
this.attribname = "";
|
|||
|
|
this.attribs = null;
|
|||
|
|
this.stack.length = 0;
|
|||
|
|
this.startIndex = 0;
|
|||
|
|
this.endIndex = 0;
|
|||
|
|
(_d = (_c = this.cbs).onparserinit) === null || _d === void 0 ? void 0 : _d.call(_c, this);
|
|||
|
|
this.buffers.length = 0;
|
|||
|
|
this.foreignContext.length = 0;
|
|||
|
|
this.foreignContext.unshift(!this.htmlMode);
|
|||
|
|
this.bufferOffset = 0;
|
|||
|
|
this.writeIndex = 0;
|
|||
|
|
this.ended = false;
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Resets the parser, then parses a complete document and
|
|||
|
|
* pushes it to the handler.
|
|||
|
|
*
|
|||
|
|
* @param data Document to parse.
|
|||
|
|
*/
|
|||
|
|
parseComplete(data2) {
|
|||
|
|
this.reset();
|
|||
|
|
this.end(data2);
|
|||
|
|
}
|
|||
|
|
getSlice(start, end2) {
|
|||
|
|
while (start - this.bufferOffset >= this.buffers[0].length) {
|
|||
|
|
this.shiftBuffer();
|
|||
|
|
}
|
|||
|
|
let slice2 = this.buffers[0].slice(start - this.bufferOffset, end2 - this.bufferOffset);
|
|||
|
|
while (end2 - this.bufferOffset > this.buffers[0].length) {
|
|||
|
|
this.shiftBuffer();
|
|||
|
|
slice2 += this.buffers[0].slice(0, end2 - this.bufferOffset);
|
|||
|
|
}
|
|||
|
|
return slice2;
|
|||
|
|
}
|
|||
|
|
shiftBuffer() {
|
|||
|
|
this.bufferOffset += this.buffers[0].length;
|
|||
|
|
this.writeIndex--;
|
|||
|
|
this.buffers.shift();
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Parses a chunk of data and calls the corresponding callbacks.
|
|||
|
|
*
|
|||
|
|
* @param chunk Chunk to parse.
|
|||
|
|
*/
|
|||
|
|
write(chunk) {
|
|||
|
|
var _a2, _b;
|
|||
|
|
if (this.ended) {
|
|||
|
|
(_b = (_a2 = this.cbs).onerror) === null || _b === void 0 ? void 0 : _b.call(_a2, new Error(".write() after done!"));
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
this.buffers.push(chunk);
|
|||
|
|
if (this.tokenizer.running) {
|
|||
|
|
this.tokenizer.write(chunk);
|
|||
|
|
this.writeIndex++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Parses the end of the buffer and clears the stack, calls onend.
|
|||
|
|
*
|
|||
|
|
* @param chunk Optional final chunk to parse.
|
|||
|
|
*/
|
|||
|
|
end(chunk) {
|
|||
|
|
var _a2, _b;
|
|||
|
|
if (this.ended) {
|
|||
|
|
(_b = (_a2 = this.cbs).onerror) === null || _b === void 0 ? void 0 : _b.call(_a2, new Error(".end() after done!"));
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if (chunk)
|
|||
|
|
this.write(chunk);
|
|||
|
|
this.ended = true;
|
|||
|
|
this.tokenizer.end();
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Pauses parsing. The parser won't emit events until `resume` is called.
|
|||
|
|
*/
|
|||
|
|
pause() {
|
|||
|
|
this.tokenizer.pause();
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Resumes parsing after `pause` was called.
|
|||
|
|
*/
|
|||
|
|
resume() {
|
|||
|
|
this.tokenizer.resume();
|
|||
|
|
while (this.tokenizer.running && this.writeIndex < this.buffers.length) {
|
|||
|
|
this.tokenizer.write(this.buffers[this.writeIndex++]);
|
|||
|
|
}
|
|||
|
|
if (this.ended)
|
|||
|
|
this.tokenizer.end();
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Alias of `write`, for backwards compatibility.
|
|||
|
|
*
|
|||
|
|
* @param chunk Chunk to parse.
|
|||
|
|
* @deprecated
|
|||
|
|
*/
|
|||
|
|
parseChunk(chunk) {
|
|||
|
|
this.write(chunk);
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* Alias of `end`, for backwards compatibility.
|
|||
|
|
*
|
|||
|
|
* @param chunk Optional final chunk to parse.
|
|||
|
|
* @deprecated
|
|||
|
|
*/
|
|||
|
|
done(chunk) {
|
|||
|
|
this.end(chunk);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function parseDocument(data2, options) {
|
|||
|
|
const handler = new DomHandler(void 0, options);
|
|||
|
|
new Parser(handler, options).end(data2);
|
|||
|
|
return handler.root;
|
|||
|
|
}
|
|||
|
|
const load = getLoad(getParse(parseDocument), render$1);
|
|||
|
|
var Levels = /* @__PURE__ */ ((Levels2) => {
|
|||
|
|
Levels2[Levels2["None"] = 0] = "None";
|
|||
|
|
Levels2[Levels2["H1"] = 1] = "H1";
|
|||
|
|
Levels2[Levels2["H2"] = 2] = "H2";
|
|||
|
|
Levels2[Levels2["H3"] = 3] = "H3";
|
|||
|
|
Levels2[Levels2["H4"] = 4] = "H4";
|
|||
|
|
Levels2[Levels2["H5"] = 5] = "H5";
|
|||
|
|
Levels2[Levels2["H6"] = 6] = "H6";
|
|||
|
|
Levels2[Levels2["Block"] = 7] = "Block";
|
|||
|
|
Levels2[Levels2["List"] = 8] = "List";
|
|||
|
|
Levels2[Levels2["ListItem"] = 9] = "ListItem";
|
|||
|
|
return Levels2;
|
|||
|
|
})(Levels || {});
|
|||
|
|
const defaultSelectorRules = {
|
|||
|
|
"div,p": ({ $node }) => ({
|
|||
|
|
queue: $node.children()
|
|||
|
|
}),
|
|||
|
|
"h1,h2,h3,h4,h5,h6": ({ $node, getContent }) => ({
|
|||
|
|
...getContent($node.contents())
|
|||
|
|
}),
|
|||
|
|
"ul,ol": ({ $node }) => ({
|
|||
|
|
queue: $node.children(),
|
|||
|
|
nesting: true
|
|||
|
|
}),
|
|||
|
|
li: ({ $node, getContent }) => {
|
|||
|
|
const queue = $node.children().filter("ul,ol");
|
|||
|
|
let content;
|
|||
|
|
if ($node.contents().first().is("div,p")) {
|
|||
|
|
content = getContent($node.children().first());
|
|||
|
|
} else {
|
|||
|
|
let $contents = $node.contents();
|
|||
|
|
const i = $contents.index(queue);
|
|||
|
|
if (i >= 0) $contents = $contents.slice(0, i);
|
|||
|
|
content = getContent($contents);
|
|||
|
|
}
|
|||
|
|
return {
|
|||
|
|
queue,
|
|||
|
|
nesting: true,
|
|||
|
|
...content
|
|||
|
|
};
|
|||
|
|
},
|
|||
|
|
"table,pre,p>img:only-child": ({ $node, getContent }) => ({
|
|||
|
|
...getContent($node)
|
|||
|
|
})
|
|||
|
|
};
|
|||
|
|
const defaultOptions = {
|
|||
|
|
selector: "h1,h2,h3,h4,h5,h6,ul,ol,li,table,pre,p>img:only-child",
|
|||
|
|
selectorRules: defaultSelectorRules
|
|||
|
|
};
|
|||
|
|
const MARKMAP_COMMENT_PREFIX = "markmap: ";
|
|||
|
|
const SELECTOR_HEADING = /^h[1-6]$/;
|
|||
|
|
const SELECTOR_LIST = /^[uo]l$/;
|
|||
|
|
const SELECTOR_LIST_ITEM = /^li$/;
|
|||
|
|
function getLevel(tagName) {
|
|||
|
|
if (SELECTOR_HEADING.test(tagName)) return +tagName[1];
|
|||
|
|
if (SELECTOR_LIST.test(tagName)) return 8;
|
|||
|
|
if (SELECTOR_LIST_ITEM.test(tagName)) return 9;
|
|||
|
|
return 7;
|
|||
|
|
}
|
|||
|
|
function parseHtml(html2, opts) {
|
|||
|
|
const options = {
|
|||
|
|
...defaultOptions,
|
|||
|
|
...opts
|
|||
|
|
};
|
|||
|
|
const $ = load(html2);
|
|||
|
|
let $root = $("body");
|
|||
|
|
if (!$root.length) $root = $.root();
|
|||
|
|
let id = 0;
|
|||
|
|
const rootNode = {
|
|||
|
|
id,
|
|||
|
|
tag: "",
|
|||
|
|
html: "",
|
|||
|
|
level: 0,
|
|||
|
|
parent: 0,
|
|||
|
|
childrenLevel: 0,
|
|||
|
|
children: []
|
|||
|
|
};
|
|||
|
|
const headingStack = [];
|
|||
|
|
let skippingHeading = 0;
|
|||
|
|
checkNodes($root.children());
|
|||
|
|
return rootNode;
|
|||
|
|
function addChild(props) {
|
|||
|
|
var _a2;
|
|||
|
|
const { parent: parent2 } = props;
|
|||
|
|
const node = {
|
|||
|
|
id: ++id,
|
|||
|
|
tag: props.tagName,
|
|||
|
|
level: props.level,
|
|||
|
|
html: props.html,
|
|||
|
|
childrenLevel: 0,
|
|||
|
|
children: props.nesting ? [] : void 0,
|
|||
|
|
parent: parent2.id
|
|||
|
|
};
|
|||
|
|
if ((_a2 = props.comments) == null ? void 0 : _a2.length) {
|
|||
|
|
node.comments = props.comments;
|
|||
|
|
}
|
|||
|
|
if (Object.keys(props.data || {}).length) {
|
|||
|
|
node.data = props.data;
|
|||
|
|
}
|
|||
|
|
if (parent2.children) {
|
|||
|
|
if (parent2.childrenLevel === 0 || parent2.childrenLevel > node.level) {
|
|||
|
|
parent2.children = [];
|
|||
|
|
parent2.childrenLevel = node.level;
|
|||
|
|
}
|
|||
|
|
if (parent2.childrenLevel === node.level) {
|
|||
|
|
parent2.children.push(node);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return node;
|
|||
|
|
}
|
|||
|
|
function getCurrentHeading(level) {
|
|||
|
|
let heading;
|
|||
|
|
while ((heading = headingStack[headingStack.length - 1]) && heading.level >= level) {
|
|||
|
|
headingStack.pop();
|
|||
|
|
}
|
|||
|
|
return heading || rootNode;
|
|||
|
|
}
|
|||
|
|
function getContent($node) {
|
|||
|
|
var _a2;
|
|||
|
|
const result = extractMagicComments($node);
|
|||
|
|
const html22 = (_a2 = $.html(result.$node)) == null ? void 0 : _a2.trimEnd();
|
|||
|
|
return { comments: result.comments, html: html22 };
|
|||
|
|
}
|
|||
|
|
function extractMagicComments($node) {
|
|||
|
|
const comments = [];
|
|||
|
|
$node = $node.filter((_, child) => {
|
|||
|
|
if (child.type === "comment") {
|
|||
|
|
const data2 = child.data.trim();
|
|||
|
|
if (data2.startsWith(MARKMAP_COMMENT_PREFIX)) {
|
|||
|
|
comments.push(data2.slice(MARKMAP_COMMENT_PREFIX.length).trim());
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return true;
|
|||
|
|
});
|
|||
|
|
return { $node, comments };
|
|||
|
|
}
|
|||
|
|
function checkNodes($els, node) {
|
|||
|
|
$els.each((_, child) => {
|
|||
|
|
var _a2;
|
|||
|
|
const $child = $(child);
|
|||
|
|
const rule = (_a2 = Object.entries(options.selectorRules).find(
|
|||
|
|
([selector]) => $child.is(selector)
|
|||
|
|
)) == null ? void 0 : _a2[1];
|
|||
|
|
const result = rule == null ? void 0 : rule({ $node: $child, $, getContent });
|
|||
|
|
if ((result == null ? void 0 : result.queue) && !result.nesting) {
|
|||
|
|
checkNodes(result.queue, node);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
const level = getLevel(child.tagName);
|
|||
|
|
if (!result) {
|
|||
|
|
if (level <= 6) {
|
|||
|
|
skippingHeading = level;
|
|||
|
|
}
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if (skippingHeading > 0 && level > skippingHeading) return;
|
|||
|
|
if (!$child.is(options.selector)) return;
|
|||
|
|
skippingHeading = 0;
|
|||
|
|
const isHeading = level <= 6;
|
|||
|
|
let data2 = {
|
|||
|
|
// If the child is an inline element and expected to be a separate node,
|
|||
|
|
// data from the closest `<p>` should be included, e.g. `<p data-lines><img /></p>`
|
|||
|
|
...$child.closest("p").data(),
|
|||
|
|
...$child.data()
|
|||
|
|
};
|
|||
|
|
let html22 = result.html || "";
|
|||
|
|
if ($child.is("ol>li") && (node == null ? void 0 : node.children)) {
|
|||
|
|
const start = +($child.parent().attr("start") || 1);
|
|||
|
|
const listIndex = start + node.children.length;
|
|||
|
|
html22 = `${listIndex}. ${html22}`;
|
|||
|
|
data2 = {
|
|||
|
|
...data2,
|
|||
|
|
listIndex
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
const childNode = addChild({
|
|||
|
|
parent: node || getCurrentHeading(level),
|
|||
|
|
nesting: !!result.queue || isHeading,
|
|||
|
|
tagName: child.tagName,
|
|||
|
|
level,
|
|||
|
|
html: html22,
|
|||
|
|
comments: result.comments,
|
|||
|
|
data: data2
|
|||
|
|
});
|
|||
|
|
if (isHeading) headingStack.push(childNode);
|
|||
|
|
if (result.queue) checkNodes(result.queue, childNode);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function convertNode(htmlRoot) {
|
|||
|
|
return walkTree(htmlRoot, (htmlNode, next2) => {
|
|||
|
|
const node = {
|
|||
|
|
content: htmlNode.html,
|
|||
|
|
children: next2() || []
|
|||
|
|
};
|
|||
|
|
if (htmlNode.data) {
|
|||
|
|
node.payload = {
|
|||
|
|
tag: htmlNode.tag,
|
|||
|
|
...htmlNode.data
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
if (htmlNode.comments) {
|
|||
|
|
if (htmlNode.comments.includes("foldAll")) {
|
|||
|
|
node.payload = { ...node.payload, fold: 2 };
|
|||
|
|
} else if (htmlNode.comments.includes("fold")) {
|
|||
|
|
node.payload = { ...node.payload, fold: 1 };
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return node;
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
function buildTree(html2, opts) {
|
|||
|
|
const htmlRoot = parseHtml(html2, opts);
|
|||
|
|
return convertNode(htmlRoot);
|
|||
|
|
}
|
|||
|
|
export {
|
|||
|
|
Levels,
|
|||
|
|
buildTree,
|
|||
|
|
convertNode,
|
|||
|
|
defaultOptions,
|
|||
|
|
parseHtml
|
|||
|
|
};
|