obsidian/.obsidian/plugins/simple-embeds/main.js

29229 lines
2.5 MiB
JavaScript
Raw Normal View History

2024-06-28 02:13:12 -05:00
/*
THIS IS A GENERATED/BUNDLED FILE BY ROLLUP
if you want to view the source visit the plugins github repository
*/
'use strict';
var obsidian = require('obsidian');
var require$$2$1 = require('url');
var state = require('@codemirror/state');
var view = require('@codemirror/view');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var require$$2__default = /*#__PURE__*/_interopDefaultLegacy(require$$2$1);
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
const APPLE_MUSIC_LINK = new RegExp(/https:\/\/(?:embed\.)?music\.apple\.com\/.+\/(?:playlist|album)\/.+\/.+/);
const APPLE_MUSIC_SONG_LINK = new RegExp(/https:\/\/(?:embed\.)?music\.apple\.com\/.+\/(?:playlist|album)\/.+\/.+\?i=\d+/);
class AppleMusicEmbed {
constructor() {
this.name = "Apple Music";
this.enabledKey = "replaceAppleMusicLinks";
this.regex = APPLE_MUSIC_LINK;
}
createEmbed(link, container) {
const isSong = APPLE_MUSIC_SONG_LINK.test(link);
const iframe = document.createElement("iframe");
iframe.src = link.replace("https://music.apple", "https://embed.music.apple");
iframe.setAttr("frameborder", "0");
iframe.allow = "autoplay *; encrypted-media *; fullscreen *";
iframe.setAttr("sandbox", "allow-forms allow-popups allow-same-origin allow-scripts allow-top-navigation-by-user-activation");
iframe.height = isSong ? "150" : "450";
iframe.style.width = "100%";
iframe.style.overflow = "hidden";
iframe.style.background = "transparent";
container.classList.add("apple-music");
container.appendChild(iframe);
return container;
}
}
const APPLE_PODCAST_LINK = new RegExp(/https:\/\/podcasts.apple.com\/(?<locale>[a-z-]+)\/podcast\/(?<content>.*\/id[0-9]+(?:\?i=[0-9]+)?)/);
class ApplePodcastsEmbed {
constructor() {
this.name = "Apple Podcasts";
this.enabledKey = "replaceApplePodcastsLinks";
this.regex = APPLE_PODCAST_LINK;
}
createEmbed(link, container, settings, currentTheme) {
const iframe = document.createElement("iframe");
const matches = link.match(APPLE_PODCAST_LINK);
const locale = matches.groups.locale;
const content = matches.groups.content;
const isEpisode = content.contains("?i=");
const src = `https://embed.podcasts.apple.com/${locale}/podcast/${content}${isEpisode ? "&" : "?"}theme=${currentTheme}`;
iframe.src = src;
iframe.setAttribute("frameborder", "0");
iframe.setAttribute("sandbox", "allow-forms allow-popups allow-same-origin allow-scripts allow-top-navigation-by-user-activation");
iframe.allow = "autoplay *; encrypted-media *;";
iframe.height = isEpisode ? "175px" : "450px";
container.appendChild(iframe);
container.classList.add("apple-podcasts");
return container;
}
updateTheme(theme, settings) {
const podcastEmbeds = document.querySelectorAll(".embed-container.apple-podcasts iframe");
podcastEmbeds.forEach((embed) => {
let src = embed.src;
if (theme === "dark") {
src = src.replace("theme=light", "theme=dark");
}
else {
src = src.replace("theme=dark", "theme=light");
}
embed.src = src;
});
}
}
const APPLE_TV_LINK = new RegExp(/https:\/\/tv.apple.com\/(?<locale>[a-z-]+)\/(?<type>episode|show|movie)\/(?<content>\S*)/);
class AppleTVEmbed {
constructor() {
this.name = "Apple TV+";
this.enabledKey = "replaceAppleTVLinks";
this.regex = APPLE_TV_LINK;
}
createEmbed(link, container, settings, currentTheme) {
const wrapper = document.createElement("div");
wrapper.classList.add("video-wrapper");
const iframe = document.createElement("iframe");
const fakeLink = document.createElement("a");
fakeLink.href = link;
fakeLink.classList.add("fake-link");
const matches = link.match(APPLE_TV_LINK);
const locale = matches.groups.locale;
const type = matches.groups.type;
const content = matches.groups.content;
const src = `https://embed.tv.apple.com/${locale}/${type}/${content}`;
iframe.src = src;
iframe.setAttribute("frameborder", "0");
iframe.setAttribute("sandbox", "allow-forms allow-popups allow-same-origin allow-scripts allow-top-navigation-by-user-activation");
iframe.allow = "autoplay *; encrypted-media *;";
wrapper.appendChild(iframe);
wrapper.appendChild(fakeLink);
container.appendChild(wrapper);
container.classList.add("apple-tv");
return container;
}
}
const BANDCAMP_LINK = new RegExp(/http(s)?:\/\/([a-z0-9-]+\.)?bandcamp\.com\/(?<type>album|track)\/[\w&$+,\/:;=?@#\._~%-]+/);
const ID = new RegExp(/<!-- (track|album) id (?<id>\d+)/);
class BandcampEmbed {
constructor() {
this.name = "Bandcamp";
this.enabledKey = "replaceBandcampLinks";
this.regex = BANDCAMP_LINK;
}
createEmbed(link, container) {
const iframe = document.createElement("iframe");
const type = link.match(BANDCAMP_LINK).groups.type;
const isAlbum = type === "album";
obsidian.requestUrl({ url: link }).then(({ text }) => {
var _a;
const id = (_a = text.match(ID).groups) === null || _a === void 0 ? void 0 : _a.id;
if (id) {
iframe.src = `https://bandcamp.com/EmbeddedPlayer/${type}=${id}/tracklist=${isAlbum}/artwork=small/${isAlbum ? "size=large/" : ""}`;
}
});
iframe.setAttribute("frameborder", "0");
iframe.setAttribute("seamless", "");
iframe.height = isAlbum ? "472" : "120";
iframe.width = "400";
container.appendChild(iframe);
container.classList.add("bandcamp");
return container;
}
}
const CODEPEN_LINK = new RegExp(/https:\/\/codepen\.io\/(\w+)\/(?:pen)\/(\w+)/);
class CodepenEmbed {
constructor() {
this.name = "CodePen";
this.enabledKey = "replaceCodepenLinks";
this.regex = CODEPEN_LINK;
}
createEmbed(link, container, settings) {
this._ensureCodepenLoaded();
const user = link.match(CODEPEN_LINK)[1];
const slug = link.match(CODEPEN_LINK)[2];
const defaultTabs = [
settings.codepenDefaultTab,
settings.codepenShowResult ? "result" : false,
].filter(Boolean);
container.classList.add("codepen");
container.dataset["themeId"] = settings.codepenTheme;
container.dataset["height"] = "300";
container.dataset["defaultTab"] = defaultTabs.join(",");
container.dataset["user"] = user;
container.dataset["slugHash"] = slug;
if (settings.codepenClickToLoad) {
container.dataset["preview"] = "true";
}
if (settings.codepenEditable) {
container.dataset["editable"] = "true";
}
container.classList.add("codepen");
return container;
}
afterAllEmbeds() {
setTimeout(() => {
var _a;
(_a = window.__CPEmbed) === null || _a === void 0 ? void 0 : _a.call(window, ".codepen");
});
}
updateTheme(theme, settings) {
if (settings.codepenTheme !== "auto")
return;
const codepenEmbeds = document.querySelectorAll(".cp_embed_wrapper iframe");
codepenEmbeds.forEach((embed) => {
let src = embed.src;
if (theme === "dark") {
src = src.replace("theme-id=light", "theme=dark");
}
else {
src = src.replace("theme-id=dark", "theme=light");
}
embed.src = src;
});
}
_ensureCodepenLoaded() {
(function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id))
return;
js = d.createElement(s);
js.id = id;
js.src = "https://cpwebassets.codepen.io/assets/embed/ei.js";
js.async = true;
fjs.parentNode.insertBefore(js, fjs);
})(document, "script", "ei-codepen");
}
createAdditionalSettings(containerEl, settings, saveSettings) {
const themeSetting = new obsidian.Setting(containerEl)
.setName("Theme")
.addDropdown((dropdown) => {
dropdown.addOptions({
auto: "Automatic",
dark: "Dark",
light: "Light",
})
.setValue(settings.codepenTheme)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
yield saveSettings({ codepenTheme: value });
}));
});
const defaultTabSetting = new obsidian.Setting(containerEl)
.setName("Default tab")
.addDropdown((dropdown) => {
dropdown.addOptions({ html: "HTML", css: "CSS", js: "JS" })
.setValue(settings.codepenDefaultTab)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
yield saveSettings({ codepenDefaultTab: value });
}));
});
const showResultSetting = new obsidian.Setting(containerEl)
.setName("Show result")
.addToggle((toggle) => {
toggle
.setValue(settings.codepenShowResult)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
yield saveSettings({ codepenShowResult: value });
}));
});
const clickToLoadSetting = new obsidian.Setting(containerEl)
.setName("Click to load")
.addToggle((toggle) => {
toggle
.setValue(settings.codepenClickToLoad)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
yield saveSettings({ codepenClickToLoad: value });
}));
});
const editableSetting = new obsidian.Setting(containerEl)
.setName("Codepen editable")
.addToggle((toggle) => {
toggle
.setValue(settings.codepenEditable)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
yield saveSettings({ codepenEditable: value });
}));
});
return [
themeSetting,
defaultTabSetting,
showResultSetting,
clickToLoadSetting,
editableSetting,
];
}
}
const FLAT_IO_LINK = new RegExp(/https:\/\/flat\.io\/(?:score|embed)\/.*/);
class FlatIOEmbed {
constructor() {
this.name = "Flat.io";
this.enabledKey = "replaceFlatIOLinks";
this.regex = FLAT_IO_LINK;
}
createEmbed(link, container) {
const iframe = document.createElement("iframe");
iframe.src = link.replace("/score/", "/embed/");
iframe.setAttribute("frameborder", "0");
iframe.allow = "fullscreen";
container.appendChild(iframe);
container.classList.add("flat_io");
return container;
}
}
const GITHUB_GIST = new RegExp(/https:\/\/gist.github\.com\/[a-zA-Z\d](?:[a-zA-z\d]|-(?=[a-zA-Z\d])){0,38}\/[a-z0-9]{32}/);
class GitHubGistEmbed {
constructor() {
this.name = "GitHub Gists";
this.enabledKey = "replaceGitHubGistLinks";
this.regex = GITHUB_GIST;
}
createEmbed(link, container) {
const iframe = document.createElement("iframe");
iframe.srcdoc = `<script src="${link}.js"></script>`;
iframe.setAttribute("frameborder", "0");
iframe.onload = () => {
iframe.style.height =
`${iframe.contentWindow.document.documentElement.scrollHeight}px`;
};
container.appendChild(iframe);
container.classList.add("github_gist");
return container;
}
}
const INSTAGRAM_LINK = new RegExp(/https:\/\/www\.instagram\.com\/(?:p|tv|reel)\/(\w+)/);
class InstagramEmbed {
constructor() {
this.name = "Instagram";
this.enabledKey = "replaceInstagramLinks";
this.regex = INSTAGRAM_LINK;
}
createEmbed(link, container) {
this._ensureInstagramLoaded();
const blockquote = document.createElement("blockquote");
blockquote.classList.add("instagram-media");
blockquote.dataset["instgrmCaptioned"] = "";
blockquote.dataset["instgrmPermalink"] = link;
blockquote.dataset["instgrmVersion"] = "13";
container.appendChild(blockquote);
container.classList.add("instagram");
return container;
}
afterAllEmbeds() {
setTimeout(() => {
var _a;
(_a = window.instgrm) === null || _a === void 0 ? void 0 : _a.Embeds.process();
});
}
_ensureInstagramLoaded() {
(function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id))
return;
js = d.createElement(s);
js.id = id;
js.src = "http://www.instagram.com/embed.js";
fjs.parentNode.insertBefore(js, fjs);
})(document, "script", "instagram-wjs");
}
}
const NOTEFLIGHT_LINK = new RegExp(/https:\/\/(?:www\.)?noteflight\.com\/(?:(?:scores\/view)|embed)\/.*/g);
class NoteflightEmbed {
constructor() {
this.name = "Noteflight";
this.enabledKey = "replaceNoteflightLinks";
this.regex = NOTEFLIGHT_LINK;
}
createEmbed(link, container) {
const iframe = document.createElement("iframe");
iframe.src = link.replace("/scores/view/", "/embed/");
iframe.setAttribute("frameborder", "0");
iframe.allow = "fullscreen";
container.appendChild(iframe);
container.classList.add("noteflight");
return container;
}
}
const REDDIT_LINK = new RegExp(/https:\/\/(?:www\.)?reddit\.com\/r\/(?<comment>.+)/);
class RedditEmbed {
constructor() {
this.name = "Reddit";
this.enabledKey = "replaceRedditLinks";
this.regex = REDDIT_LINK;
}
createEmbed(link, container, settings, currentTheme) {
const iframe = document.createElement("iframe");
const comment = link.match(REDDIT_LINK).groups.comment;
const theme = settings.redditTheme === "auto" ? currentTheme : settings.redditTheme;
iframe.src = `https://www.redditmedia.com/r/${comment}/?ref_source=embed&amp;ref=share&amp;embed=true;theme=${theme}`;
iframe.setAttribute("frameborder", "0");
iframe.setAttribute("sandbox", "allow-scripts allow-same-origin allow-popups");
iframe.height = "198";
iframe.width = "640";
container.appendChild(iframe);
container.classList.add("reddit");
return container;
}
updateTheme(theme, settings) {
if (settings.redditTheme !== "auto") {
return;
}
const redditEmbed = document.querySelectorAll(".embed-container.reddit iframe");
redditEmbed.forEach((embed) => {
let src = embed.src;
if (theme === "dark") {
src = src.replace("theme=light", "theme=dark");
}
else {
src = src.replace("theme=dark", "theme=light");
}
embed.src = src;
});
}
createAdditionalSettings(containerEl, settings, saveSettings) {
const themeSetting = new obsidian.Setting(containerEl)
.setName("Theme")
.addDropdown((dropdown) => {
dropdown
.addOptions({
auto: "Automatic",
dark: "Dark",
light: "Light",
})
.setValue(settings.redditTheme)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
yield saveSettings({ redditTheme: value });
}));
});
return [themeSetting];
}
}
const TWEET_LINK = new RegExp(/https:\/\/(?:mobile\.)?twitter\.com\/.+\/(\d+)/);
class TwitterEmbed {
constructor() {
this.name = "Twitter";
this.enabledKey = "replaceTwitterLinks";
this.regex = TWEET_LINK;
}
createEmbed(link, container, settings, currentTheme) {
this._ensureTwitterLoaded();
const tweetId = link.match(TWEET_LINK)[1];
container.id = `TweetContainer${tweetId}`;
const theme = settings.twitterTheme == "auto" ? currentTheme : settings.twitterTheme;
window.twttr.ready(() => {
window.twttr.widgets.createTweet(tweetId, container, {
theme,
dnt: true,
});
});
container.classList.add("twitter");
return container;
}
updateTheme(theme, settings) {
if (settings.twitterTheme !== "auto") {
return;
}
const twitterEmbeds = document.querySelectorAll(".embed-container .twitter-tweet.twitter-tweet-rendered iframe");
twitterEmbeds.forEach((embed) => {
let src = embed.src;
if (theme === "dark") {
src = src.replace("theme=light", "theme=dark");
}
else {
src = src.replace("theme=dark", "theme=light");
}
embed.src = src;
});
}
_ensureTwitterLoaded() {
window.twttr = (function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0], t = window.twttr || {};
if (d.getElementById(id))
return t;
js = d.createElement(s);
js.id = id;
js.src = "https://platform.twitter.com/widgets.js";
fjs.parentNode.insertBefore(js, fjs);
t._e = [];
t.ready = function (f) {
t._e.push(f);
};
return t;
})(document, "script", "twitter-wjs");
}
createAdditionalSettings(containerEl, settings, saveSettings) {
const themeSetting = new obsidian.Setting(containerEl)
.setName("Theme")
.addDropdown((dropdown) => {
dropdown
.addOptions({
auto: "Automatic",
dark: "Dark",
light: "Light",
})
.setValue(settings.twitterTheme)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
yield saveSettings({ twitterTheme: value });
}));
});
return [themeSetting];
}
}
const VIMEO_LINK = new RegExp(/https:\/\/(www\.)?vimeo\.com\/(?<id>\d+)/);
class VimeoEmbed {
constructor() {
this.name = "Vimeo";
this.enabledKey = "replaceVimeoLinks";
this.regex = VIMEO_LINK;
}
createEmbed(link, container) {
const wrapper = document.createElement("div");
wrapper.classList.add("video-wrapper");
const iframe = document.createElement("iframe");
const id = link.match(VIMEO_LINK).groups.id;
iframe.src = `https://player.vimeo.com/video/${id}`;
iframe.setAttribute("frameborder", "0");
iframe.allow =
"autoplay; fullscreen; picture-in-picture; picture-in-picture;";
wrapper.appendChild(iframe);
container.appendChild(wrapper);
container.classList.add("vimeo");
return container;
}
}
const WHIMSICAL_LINK = new RegExp(/https:\/\/whimsical.com\/(?:[a-zA-Z0-9\-]+\-)?(?<id>[a-km-zA-HJ-NP-Z1-9]{16,22})(@[a-km-zA-HJ-NP-Z1-9]+)?/);
class WhimsicalEmbed {
constructor() {
this.name = 'Whimsical';
this.enabledKey = 'replaceWhimsicalLinks';
this.regex = WHIMSICAL_LINK;
}
createEmbed(link, container) {
const iframe = document.createElement('iframe');
const matches = link.match(WHIMSICAL_LINK);
const id = matches.groups.id;
iframe.src = `https://whimsical.com/embed/${id}`;
iframe.style.aspectRatio = '800/450';
iframe.style.width = '100%';
iframe.setAttribute('frameborder', '0');
iframe.allow = 'fullscreen';
container.appendChild(iframe);
container.classList.add('whimsical');
return container;
}
}
// TODO: Figure out if there is a better way to include the lib.
// Need to include it myself because the lib self defines. This causes issues when a user disables and reenables the plugin.
// Since there is no way to remove a Custom Element, it throws an error if it is registered twice.
// https://github.com/paulirish/lite-youtube-embed
/**
* A lightweight youtube embed. Still should feel the same to the user, just MUCH faster to initialize and paint.
*
* Thx to these as the inspiration
* https://storage.googleapis.com/amp-vs-non-amp/youtube-lazy.html
* https://autoplay-youtube-player.glitch.me/
*
* Once built it, I also found these:
* https://github.com/ampproject/amphtml/blob/master/extensions/amp-youtube (👍👍)
* https://github.com/Daugilas/lazyYT
* https://github.com/vb/lazyframe
*/
class LiteYTEmbed extends HTMLElement {
connectedCallback() {
this.videoId = this.getAttribute("videoid");
let playBtnEl = this.querySelector(".lty-playbtn");
// A label for the button takes priority over a [playlabel] attribute on the custom-element
this.playLabel =
(playBtnEl && playBtnEl.textContent.trim()) ||
this.getAttribute("playlabel") ||
"Play";
/**
* Lo, the youtube placeholder image! (aka the thumbnail, poster image, etc)
*
* See https://github.com/paulirish/lite-youtube-embed/blob/master/youtube-thumbnail-urls.md
*
* TODO: Do the sddefault->hqdefault fallback
* - When doing this, apply referrerpolicy (https://github.com/ampproject/amphtml/pull/3940)
* TODO: Consider using webp if supported, falling back to jpg
*/
if (!this.style.backgroundImage) {
this.style.backgroundImage = `url("https://i.ytimg.com/vi/${this.videoId}/hqdefault.jpg")`;
}
// Set up play button, and its visually hidden label
if (!playBtnEl) {
playBtnEl = document.createElement("button");
playBtnEl.type = "button";
playBtnEl.classList.add("lty-playbtn");
this.append(playBtnEl);
}
if (!playBtnEl.textContent) {
const playBtnLabelEl = document.createElement("span");
playBtnLabelEl.className = "lyt-visually-hidden";
playBtnLabelEl.textContent = this.playLabel;
playBtnEl.append(playBtnLabelEl);
}
// On hover (or tap), warm up the TCP connections we're (likely) about to use.
this.addEventListener("pointerover", LiteYTEmbed.warmConnections, {
once: true,
});
// Once the user clicks, add the real iframe and drop our play button
// TODO: In the future we could be like amp-youtube and silently swap in the iframe during idle time
// We'd want to only do this for in-viewport or near-viewport ones: https://github.com/ampproject/amphtml/pull/5003
this.addEventListener("click", this.addIframe);
}
// // TODO: Support the the user changing the [videoid] attribute
// attributeChangedCallback() {
// }
/**
* Add a <link rel={preload | preconnect} ...> to the head
*/
static addPrefetch(kind, url, as) {
const linkEl = document.createElement("link");
linkEl.rel = kind;
linkEl.href = url;
if (as) {
linkEl.as = as;
}
document.head.append(linkEl);
}
/**
* Begin pre-connecting to warm up the iframe load
* Since the embed's network requests load within its iframe,
* preload/prefetch'ing them outside the iframe will only cause double-downloads.
* So, the best we can do is warm up a few connections to origins that are in the critical path.
*
* Maybe `<link rel=preload as=document>` would work, but it's unsupported: http://crbug.com/593267
* But TBH, I don't think it'll happen soon with Site Isolation and split caches adding serious complexity.
*/
static warmConnections() {
if (LiteYTEmbed.preconnected) return;
// The iframe document and most of its subresources come right off youtube.com
LiteYTEmbed.addPrefetch("preconnect", "https://www.youtube-nocookie.com");
// The botguard script is fetched off from google.com
LiteYTEmbed.addPrefetch("preconnect", "https://www.google.com");
// Not certain if these ad related domains are in the critical path. Could verify with domain-specific throttling.
LiteYTEmbed.addPrefetch(
"preconnect",
"https://googleads.g.doubleclick.net",
);
LiteYTEmbed.addPrefetch("preconnect", "https://static.doubleclick.net");
LiteYTEmbed.preconnected = true;
}
addIframe(e) {
if (this.classList.contains("lyt-activated")) return;
e.preventDefault();
this.classList.add("lyt-activated");
const params = new URLSearchParams(this.getAttribute("params") || []);
params.append("autoplay", "1");
const iframeEl = document.createElement("iframe");
iframeEl.width = 560;
iframeEl.height = 315;
// No encoding necessary as [title] is safe. https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html#:~:text=Safe%20HTML%20Attributes%20include
iframeEl.title = this.playLabel;
iframeEl.allow =
"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture";
iframeEl.allowFullscreen = true;
// AFAIK, the encoding here isn't necessary for XSS, but we'll do it only because this is a URL
// https://stackoverflow.com/q/64959723/89484
iframeEl.src = `https://www.youtube-nocookie.com/embed/${encodeURIComponent(
this.videoId,
)}?${params.toString()}`;
this.append(iframeEl);
// Set focus for a11y
iframeEl.focus();
}
}
const YOUTUBE_LINK = new RegExp(/http(?:s?):\/\/(?:www\.)?youtu(?:be\.com\/watch\?v=|\.be\/|be\.com\/embed\/|be\.com\/shorts\/)(?<id>[\w\-\_]*)((?:\?|&)(?:t|start)=(?<startTime>(?:\d+h)?(?:\d+m)?\d+s|\d+))?/);
class YouTubeEmbed {
constructor() {
this.name = "YouTube";
this.enabledKey = "replaceYouTubeLinks";
this.regex = YOUTUBE_LINK;
}
createEmbed(link, container) {
this._ensureLiteYouTubeLoaded();
const wrapper = document.createElement("div");
wrapper.classList.add("video-wrapper");
const matches = link.match(YOUTUBE_LINK);
const videoId = matches.groups.id;
const startTime = this._normalizeStartTime(matches.groups.startTime);
const youtube = document.createElement("lite-youtube");
youtube.setAttribute("videoid", videoId);
if (startTime) {
youtube.setAttribute("params", `start=${startTime}`);
}
wrapper.appendChild(youtube);
container.appendChild(wrapper);
container.classList.add("youtube");
return container;
}
_ensureLiteYouTubeLoaded() {
if (!customElements.get("lite-youtube")) {
customElements.define("lite-youtube", LiteYTEmbed);
}
}
_normalizeStartTime(startTime) {
var _a, _b, _c;
if (!startTime) {
return;
}
if (!isNaN(Number(startTime))) {
return startTime;
}
const matches = startTime.match(/(?<hours>\d+h)?(?<minutes>\d+m)?(?<seconds>\d+s)/);
const hoursInSeconds = parseInt((_a = matches.groups.hours) !== null && _a !== void 0 ? _a : "0") * 60 * 60;
const minutesInSeconds = parseInt((_b = matches.groups.minutes) !== null && _b !== void 0 ? _b : "0") * 60;
const seconds = parseInt((_c = matches.groups.seconds) !== null && _c !== void 0 ? _c : "0");
return `${hoursInSeconds + minutesInSeconds + seconds}`;
}
}
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function getAugmentedNamespace(n) {
if (n.__esModule) return n;
var a = Object.defineProperty({}, '__esModule', {value: true});
Object.keys(n).forEach(function (k) {
var d = Object.getOwnPropertyDescriptor(n, k);
Object.defineProperty(a, k, d.get ? d : {
enumerable: true,
get: function () {
return n[k];
}
});
});
return a;
}
function createCommonjsModule(fn) {
var module = { exports: {} };
return fn(module, module.exports), module.exports;
}
var types = /*#__PURE__*/Object.defineProperty({
}, '__esModule', {value: true});
var options = createCommonjsModule(function (module, exports) {
var __assign = (commonjsGlobal && commonjsGlobal.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.flatten = void 0;
var defaultOpts = {
xml: false,
decodeEntities: true,
};
/** Cheerio default options. */
exports.default = defaultOpts;
var xmlModeDefault = {
_useHtmlParser2: true,
xmlMode: true,
};
/**
* Flatten the options for Cheerio.
*
* This will set `_useHtmlParser2` to true if `xml` is set to true.
*
* @param options - The options to flatten.
* @returns The flattened options.
*/
function flatten(options) {
return (options === null || options === void 0 ? void 0 : options.xml)
? typeof options.xml === 'boolean'
? xmlModeDefault
: __assign(__assign({}, xmlModeDefault), options.xml)
: options !== null && options !== void 0 ? options : undefined;
}
exports.flatten = flatten;
});
var lib$9 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.Doctype = exports.CDATA = exports.Tag = exports.Style = exports.Script = exports.Comment = exports.Directive = exports.Text = exports.Root = exports.isTag = exports.ElementType = void 0;
/** Types of elements found in htmlparser2's DOM */
var ElementType;
(function (ElementType) {
/** Type for the root element of a document */
ElementType["Root"] = "root";
/** Type for Text */
ElementType["Text"] = "text";
/** Type for <? ... ?> */
ElementType["Directive"] = "directive";
/** Type for <!-- ... --> */
ElementType["Comment"] = "comment";
/** Type for <script> tags */
ElementType["Script"] = "script";
/** Type for <style> tags */
ElementType["Style"] = "style";
/** Type for Any tag */
ElementType["Tag"] = "tag";
/** Type for <![CDATA[ ... ]]> */
ElementType["CDATA"] = "cdata";
/** Type for <!doctype ...> */
ElementType["Doctype"] = "doctype";
})(ElementType = exports.ElementType || (exports.ElementType = {}));
/**
* Tests whether an element is a tag or not.
*
* @param elem Element to test
*/
function isTag(elem) {
return (elem.type === ElementType.Tag ||
elem.type === ElementType.Script ||
elem.type === ElementType.Style);
}
exports.isTag = isTag;
// Exports for backwards compatibility
/** Type for the root element of a document */
exports.Root = ElementType.Root;
/** Type for Text */
exports.Text = ElementType.Text;
/** Type for <? ... ?> */
exports.Directive = ElementType.Directive;
/** Type for <!-- ... --> */
exports.Comment = ElementType.Comment;
/** Type for <script> tags */
exports.Script = ElementType.Script;
/** Type for <style> tags */
exports.Style = ElementType.Style;
/** Type for Any tag */
exports.Tag = ElementType.Tag;
/** Type for <![CDATA[ ... ]]> */
exports.CDATA = ElementType.CDATA;
/** Type for <!doctype ...> */
exports.Doctype = ElementType.Doctype;
});
var require$$0$5 = lib$9;
var node = createCommonjsModule(function (module, exports) {
var __extends = (commonjsGlobal && commonjsGlobal.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __assign = (commonjsGlobal && commonjsGlobal.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.cloneNode = exports.hasChildren = exports.isDocument = exports.isDirective = exports.isComment = exports.isText = exports.isCDATA = exports.isTag = exports.Element = exports.Document = exports.CDATA = exports.NodeWithChildren = exports.ProcessingInstruction = exports.Comment = exports.Text = exports.DataNode = exports.Node = void 0;
/**
* This object will be used as the prototype for Nodes when creating a
* DOM-Level-1-compliant structure.
*/
var Node = /** @class */ (function () {
function Node() {
/** Parent of the node */
this.parent = null;
/** Previous sibling */
this.prev = null;
/** Next sibling */
this.next = null;
/** The start index of the node. Requires `withStartIndices` on the handler to be `true. */
this.startIndex = null;
/** The end index of the node. Requires `withEndIndices` on the handler to be `true. */
this.endIndex = null;
}
Object.defineProperty(Node.prototype, "parentNode", {
// Read-write aliases for properties
/**
* Same as {@link parent}.
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
*/
get: function () {
return this.parent;
},
set: function (parent) {
this.parent = parent;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Node.prototype, "previousSibling", {
/**
* Same as {@link prev}.
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
*/
get: function () {
return this.prev;
},
set: function (prev) {
this.prev = prev;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Node.prototype, "nextSibling", {
/**
* Same as {@link next}.
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
*/
get: function () {
return this.next;
},
set: function (next) {
this.next = next;
},
enumerable: false,
configurable: true
});
/**
* Clone this node, and optionally its children.
*
* @param recursive Clone child nodes as well.
* @returns A clone of the node.
*/
Node.prototype.cloneNode = function (recursive) {
if (recursive === void 0) { recursive = false; }
return cloneNode(this, recursive);
};
return Node;
}());
exports.Node = Node;
/**
* A node that contains some data.
*/
var DataNode = /** @class */ (function (_super) {
__extends(DataNode, _super);
/**
* @param data The content of the data node
*/
function DataNode(data) {
var _this = _super.call(this) || this;
_this.data = data;
return _this;
}
Object.defineProperty(DataNode.prototype, "nodeValue", {
/**
* Same as {@link data}.
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
*/
get: function () {
return this.data;
},
set: function (data) {
this.data = data;
},
enumerable: false,
configurable: true
});
return DataNode;
}(Node));
exports.DataNode = DataNode;
/**
* Text within the document.
*/
var Text = /** @class */ (function (_super) {
__extends(Text, _super);
function Text() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.type = require$$0$5.ElementType.Text;
return _this;
}
Object.defineProperty(Text.prototype, "nodeType", {
get: function () {
return 3;
},
enumerable: false,
configurable: true
});
return Text;
}(DataNode));
exports.Text = Text;
/**
* Comments within the document.
*/
var Comment = /** @class */ (function (_super) {
__extends(Comment, _super);
function Comment() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.type = require$$0$5.ElementType.Comment;
return _this;
}
Object.defineProperty(Comment.prototype, "nodeType", {
get: function () {
return 8;
},
enumerable: false,
configurable: true
});
return Comment;
}(DataNode));
exports.Comment = Comment;
/**
* Processing instructions, including doc types.
*/
var ProcessingInstruction = /** @class */ (function (_super) {
__extends(ProcessingInstruction, _super);
function ProcessingInstruction(name, data) {
var _this = _super.call(this, data) || this;
_this.name = name;
_this.type = require$$0$5.ElementType.Directive;
return _this;
}
Object.defineProperty(ProcessingInstruction.prototype, "nodeType", {
get: function () {
return 1;
},
enumerable: false,
configurable: true
});
return ProcessingInstruction;
}(DataNode));
exports.ProcessingInstruction = ProcessingInstruction;
/**
* A `Node` that can have children.
*/
var NodeWithChildren = /** @class */ (function (_super) {
__extends(NodeWithChildren, _super);
/**
* @param children Children of the node. Only certain node types can have children.
*/
function NodeWithChildren(children) {
var _this = _super.call(this) || this;
_this.children = children;
return _this;
}
Object.defineProperty(NodeWithChildren.prototype, "firstChild", {
// Aliases
/** First child of the node. */
get: function () {
var _a;
return (_a = this.children[0]) !== null && _a !== void 0 ? _a : null;
},
enumerable: false,
configurable: true
});
Object.defineProperty(NodeWithChildren.prototype, "lastChild", {
/** Last child of the node. */
get: function () {
return this.children.length > 0
? this.children[this.children.length - 1]
: null;
},
enumerable: false,
configurable: true
});
Object.defineProperty(NodeWithChildren.prototype, "childNodes", {
/**
* Same as {@link children}.
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
*/
get: function () {
return this.children;
},
set: function (children) {
this.children = children;
},
enumerable: false,
configurable: true
});
return NodeWithChildren;
}(Node));
exports.NodeWithChildren = NodeWithChildren;
var CDATA = /** @class */ (function (_super) {
__extends(CDATA, _super);
function CDATA() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.type = require$$0$5.ElementType.CDATA;
return _this;
}
Object.defineProperty(CDATA.prototype, "nodeType", {
get: function () {
return 4;
},
enumerable: false,
configurable: true
});
return CDATA;
}(NodeWithChildren));
exports.CDATA = CDATA;
/**
* The root node of the document.
*/
var Document = /** @class */ (function (_super) {
__extends(Document, _super);
function Document() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.type = require$$0$5.ElementType.Root;
return _this;
}
Object.defineProperty(Document.prototype, "nodeType", {
get: function () {
return 9;
},
enumerable: false,
configurable: true
});
return Document;
}(NodeWithChildren));
exports.Document = Document;
/**
* An element within the DOM.
*/
var Element = /** @class */ (function (_super) {
__extends(Element, _super);
/**
* @param name Name of the tag, eg. `div`, `span`.
* @param attribs Object mapping attribute names to attribute values.
* @param children Children of the node.
*/
function Element(name, attribs, children, type) {
if (children === void 0) { children = []; }
if (type === void 0) { type = name === "script"
? require$$0$5.ElementType.Script
: name === "style"
? require$$0$5.ElementType.Style
: require$$0$5.ElementType.Tag; }
var _this = _super.call(this, children) || this;
_this.name = name;
_this.attribs = attribs;
_this.type = type;
return _this;
}
Object.defineProperty(Element.prototype, "nodeType", {
get: function () {
return 1;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Element.prototype, "tagName", {
// DOM Level 1 aliases
/**
* Same as {@link name}.
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
*/
get: function () {
return this.name;
},
set: function (name) {
this.name = name;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Element.prototype, "attributes", {
get: function () {
var _this = this;
return Object.keys(this.attribs).map(function (name) {
var _a, _b;
return ({
name: name,
value: _this.attribs[name],
namespace: (_a = _this["x-attribsNamespace"]) === null || _a === void 0 ? void 0 : _a[name],
prefix: (_b = _this["x-attribsPrefix"]) === null || _b === void 0 ? void 0 : _b[name],
});
});
},
enumerable: false,
configurable: true
});
return Element;
}(NodeWithChildren));
exports.Element = Element;
/**
* @param node Node to check.
* @returns `true` if the node is a `Element`, `false` otherwise.
*/
function isTag(node) {
return (0, require$$0$5.isTag)(node);
}
exports.isTag = isTag;
/**
* @param node Node to check.
* @returns `true` if the node has the type `CDATA`, `false` otherwise.
*/
function isCDATA(node) {
return node.type === require$$0$5.ElementType.CDATA;
}
exports.isCDATA = isCDATA;
/**
* @param node Node to check.
* @returns `true` if the node has the type `Text`, `false` otherwise.
*/
function isText(node) {
return node.type === require$$0$5.ElementType.Text;
}
exports.isText = isText;
/**
* @param node Node to check.
* @returns `true` if the node has the type `Comment`, `false` otherwise.
*/
function isComment(node) {
return node.type === require$$0$5.ElementType.Comment;
}
exports.isComment = isComment;
/**
* @param node Node to check.
* @returns `true` if the node has the type `ProcessingInstruction`, `false` otherwise.
*/
function isDirective(node) {
return node.type === require$$0$5.ElementType.Directive;
}
exports.isDirective = isDirective;
/**
* @param node Node to check.
* @returns `true` if the node has the type `ProcessingInstruction`, `false` otherwise.
*/
function isDocument(node) {
return node.type === require$$0$5.ElementType.Root;
}
exports.isDocument = isDocument;
/**
* @param node Node to check.
* @returns `true` if the node has children, `false` otherwise.
*/
function hasChildren(node) {
return Object.prototype.hasOwnProperty.call(node, "children");
}
exports.hasChildren = hasChildren;
/**
* Clone a node, and optionally its children.
*
* @param recursive Clone child nodes as well.
* @returns A clone of the node.
*/
function cloneNode(node, recursive) {
if (recursive === void 0) { recursive = false; }
var result;
if (isText(node)) {
result = new Text(node.data);
}
else if (isComment(node)) {
result = new Comment(node.data);
}
else if (isTag(node)) {
var children = recursive ? cloneChildren(node.children) : [];
var clone_1 = new Element(node.name, __assign({}, node.attribs), children);
children.forEach(function (child) { return (child.parent = clone_1); });
if (node.namespace != null) {
clone_1.namespace = node.namespace;
}
if (node["x-attribsNamespace"]) {
clone_1["x-attribsNamespace"] = __assign({}, node["x-attribsNamespace"]);
}
if (node["x-attribsPrefix"]) {
clone_1["x-attribsPrefix"] = __assign({}, node["x-attribsPrefix"]);
}
result = clone_1;
}
else if (isCDATA(node)) {
var children = recursive ? cloneChildren(node.children) : [];
var clone_2 = new CDATA(children);
children.forEach(function (child) { return (child.parent = clone_2); });
result = clone_2;
}
else if (isDocument(node)) {
var children = recursive ? cloneChildren(node.children) : [];
var clone_3 = new Document(children);
children.forEach(function (child) { return (child.parent = clone_3); });
if (node["x-mode"]) {
clone_3["x-mode"] = node["x-mode"];
}
result = clone_3;
}
else if (isDirective(node)) {
var 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: ".concat(node.type));
}
result.startIndex = node.startIndex;
result.endIndex = node.endIndex;
if (node.sourceCodeLocation != null) {
result.sourceCodeLocation = node.sourceCodeLocation;
}
return result;
}
exports.cloneNode = cloneNode;
function cloneChildren(childs) {
var children = childs.map(function (child) { return cloneNode(child, true); });
for (var i = 1; i < children.length; i++) {
children[i].prev = children[i - 1];
children[i - 1].next = children[i];
}
return children;
}
});
var node_js_1 = node;
var lib$8 = createCommonjsModule(function (module, exports) {
var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (commonjsGlobal && commonjsGlobal.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DomHandler = void 0;
__exportStar(node_js_1, exports);
// Default options
var defaultOpts = {
withStartIndices: false,
withEndIndices: false,
xmlMode: false,
};
var DomHandler = /** @class */ (function () {
/**
* @param callback Called once parsing has completed.
* @param options Settings for the handler.
* @param elementCB Callback whenever a tag is closed.
*/
function DomHandler(callback, options, elementCB) {
/** The elements of the DOM */
this.dom = [];
/** The root element for the DOM */
this.root = new node_js_1.Document(this.dom);
/** Indicated whether parsing has been completed. */
this.done = false;
/** Stack of open tags. */
this.tagStack = [this.root];
/** A data node that is still being written to. */
this.lastNode = null;
/** Reference to the parser instance. Used for location information. */
this.parser = null;
// Make it possible to skip arguments, for backwards-compatibility
if (typeof options === "function") {
elementCB = options;
options = defaultOpts;
}
if (typeof callback === "object") {
options = callback;
callback = undefined;
}
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;
}
DomHandler.prototype.onparserinit = function (parser) {
this.parser = parser;
};
// Resets the handler back to starting state
DomHandler.prototype.onreset = function () {
this.dom = [];
this.root = new node_js_1.Document(this.dom);
this.done = false;
this.tagStack = [this.root];
this.lastNode = null;
this.parser = null;
};
// Signals the handler that parsing is done
DomHandler.prototype.onend = function () {
if (this.done)
return;
this.done = true;
this.parser = null;
this.handleCallback(null);
};
DomHandler.prototype.onerror = function (error) {
this.handleCallback(error);
};
DomHandler.prototype.onclosetag = function () {
this.lastNode = null;
var elem = this.tagStack.pop();
if (this.options.withEndIndices) {
elem.endIndex = this.parser.endIndex;
}
if (this.elementCB)
this.elementCB(elem);
};
DomHandler.prototype.onopentag = function (name, attribs) {
var type = this.options.xmlMode ? require$$0$5.ElementType.Tag : undefined;
var element = new node_js_1.Element(name, attribs, undefined, type);
this.addNode(element);
this.tagStack.push(element);
};
DomHandler.prototype.ontext = function (data) {
var lastNode = this.lastNode;
if (lastNode && lastNode.type === require$$0$5.ElementType.Text) {
lastNode.data += data;
if (this.options.withEndIndices) {
lastNode.endIndex = this.parser.endIndex;
}
}
else {
var node = new node_js_1.Text(data);
this.addNode(node);
this.lastNode = node;
}
};
DomHandler.prototype.oncomment = function (data) {
if (this.lastNode && this.lastNode.type === require$$0$5.ElementType.Comment) {
this.lastNode.data += data;
return;
}
var node = new node_js_1.Comment(data);
this.addNode(node);
this.lastNode = node;
};
DomHandler.prototype.oncommentend = function () {
this.lastNode = null;
};
DomHandler.prototype.oncdatastart = function () {
var text = new node_js_1.Text("");
var node = new node_js_1.CDATA([text]);
this.addNode(node);
text.parent = node;
this.lastNode = text;
};
DomHandler.prototype.oncdataend = function () {
this.lastNode = null;
};
DomHandler.prototype.onprocessinginstruction = function (name, data) {
var node = new node_js_1.ProcessingInstruction(name, data);
this.addNode(node);
};
DomHandler.prototype.handleCallback = function (error) {
if (typeof this.callback === "function") {
this.callback(error, this.dom);
}
else if (error) {
throw error;
}
};
DomHandler.prototype.addNode = function (node) {
var parent = this.tagStack[this.tagStack.length - 1];
var previousSibling = parent.children[parent.children.length - 1];
if (this.options.withStartIndices) {
node.startIndex = this.parser.startIndex;
}
if (this.options.withEndIndices) {
node.endIndex = this.parser.endIndex;
}
parent.children.push(node);
if (previousSibling) {
node.prev = previousSibling;
previousSibling.next = node;
}
node.parent = parent;
this.lastNode = null;
};
return DomHandler;
}());
exports.DomHandler = DomHandler;
exports.default = DomHandler;
});
// Generated using scripts/write-decode-map.ts
var _default$5 = new Uint16Array(
// prettier-ignore
"\u1d41<\xd5\u0131\u028a\u049d\u057b\u05d0\u0675\u06de\u07a2\u07d6\u080f\u0a4a\u0a91\u0da1\u0e6d\u0f09\u0f26\u10ca\u1228\u12e1\u1415\u149d\u14c3\u14df\u1525\0\0\0\0\0\0\u156b\u16cd\u198d\u1c12\u1ddd\u1f7e\u2060\u21b0\u228d\u23c0\u23fb\u2442\u2824\u2912\u2d08\u2e48\u2fce\u3016\u32ba\u3639\u37ac\u38fe\u3a28\u3a71\u3ae0\u3b2e\u0800EMabcfglmnoprstu\\bfms\x7f\x84\x8b\x90\x95\x98\xa6\xb3\xb9\xc8\xcflig\u803b\xc6\u40c6P\u803b&\u4026cute\u803b\xc1\u40c1reve;\u4102\u0100iyx}rc\u803b\xc2\u40c2;\u4410r;\uc000\ud835\udd04rave\u803b\xc0\u40c0pha;\u4391acr;\u4100d;\u6a53\u0100gp\x9d\xa1on;\u4104f;\uc000\ud835\udd38plyFunction;\u6061ing\u803b\xc5\u40c5\u0100cs\xbe\xc3r;\uc000\ud835\udc9cign;\u6254ilde\u803b\xc3\u40c3ml\u803b\xc4\u40c4\u0400aceforsu\xe5\xfb\xfe\u0117\u011c\u0122\u0127\u012a\u0100cr\xea\xf2kslash;\u6216\u0176\xf6\xf8;\u6ae7ed;\u6306y;\u4411\u0180crt\u0105\u010b\u0114ause;\u6235noullis;\u612ca;\u4392r;\uc000\ud835\udd05pf;\uc000\ud835\udd39eve;\u42d8c\xf2\u0113mpeq;\u624e\u0700HOacdefhilorsu\u014d\u0151\u0156\u0180\u019e\u01a2\u01b5\u01b7\u01ba\u01dc\u0215\u0273\u0278\u027ecy;\u4427PY\u803b\xa9\u40a9\u0180cpy\u015d\u0162\u017aute;\u4106\u0100;i\u0167\u0168\u62d2talDifferentialD;\u6145leys;\u612d\u0200aeio\u0189\u018e\u0194\u0198ron;\u410cdil\u803b\xc7\u40c7rc;\u4108nint;\u6230ot;\u410a\u0100dn\u01a7\u01adilla;\u40b8terDot;\u40b7\xf2\u017fi;\u43a7rcle\u0200DMPT\u01c7\u01cb\u01d1\u01d6ot;\u6299inus;\u6296lus;\u6295imes;\u6297o\u0100cs\u01e2\u01f8kwiseContourIntegral;\u6232eCurly\u0100DQ\u0203\u020foubleQuote;\u601duote;\u6019\u0200lnpu\u021e\u0228\u0247\u0255on\u0100;e\u0225\u0226\u6237;\u6a74\u0180git\u022f\u0236\u023aruent;\u6261nt;\u622fourIntegral;\u622e\u0100fr\u024c\u024e;\u6102oduct;\u6210nterClockwiseContourIntegral;\u6233oss;\u6a2fcr;\uc000\ud835\udc9ep\u0100;C\u0284\u0285\u62d3ap;\u624d\u0580DJSZacefios\u02a0\u02ac\u02b0\u02b4\u02b8\u02cb\u02d7\u02e1\u02e6\u0333\u048d\u0100;o\u0179\u02a5trahd;\u6911cy;\u4402cy;\u4405cy;\u440f\u0180grs\u02bf\u02c4\u02c7ger;\u6021r;\u61a1hv;\u6ae4\u0100ay\u02d0\u02d5ron;\u410e;\u4414l\u0100;t\u02dd\u02de\u6207a;\u4394r;\uc000\ud835\udd07\u0100af\u02eb\u0327\u0100cm\u02f0\u0322ritical\u0200ADGT\u0300\u0306\u0316\u031ccute;\u40b4o\u0174\u030b\u030d;\u42d9bleAcute;\u42ddrave;\u4060ilde;\u42dcond;\u62c4ferentialD;\u6146\u0470\u033d\0\0\0\u0342\u0354\0\u0405f;\uc000\ud835\udd3b\u0180;DE\u0348\u0349\u034d\u40a8ot;\u60dcqual;\u6250ble\u0300CDLRUV\u0363\u0372\u0382\u03cf\u03e2\u03f8ontourIntegra\xec\u0239o\u0274\u0379\0\0\u037b\xbb\u0349nArrow;\u61d3\u0100eo\u0387\u03a4ft\u0180ART\u0390\u0396\u03a1rrow;\u61d0ightArrow;\u61d4e\xe5\u02cang\u0100LR\u03ab\u03c4eft\u0100AR\u03b3\u03b9rrow;\u67f8ightArrow;\u67faightArrow;\u67f9ight\u0100AT\u03d8\u03derrow;\u61d2ee;\u62a8p\u0241\u03e9\0\0\u03efrrow;\u61d1ownArrow;\u61d5erticalBar;\u6225n\u0300ABLRTa\u0412\u042a\u0430\u045e\u047f\u037crrow\u0180;BU\u041d\u041e\u0422\u6193ar;\u6913pArrow;\u61f5reve;\u4311eft\u02d2\u043a\0\u0446\0\u0450ightVector;\u6950eeVector;\u695eector\u0100;B\u0459\u045a\u61bdar;\u6956ight\u01d4\u0467\0\u0471eeVector;\u695fector\u0100;B\u047a\u047b\u61c1ar;\u6957ee\u0100;A\u0486\u0487\u62a4rrow;\u61a7\u0100ct\u0492\u0497r;\uc000\ud835\udc9frok;\u4110\u0800NTacdfglmopqstux\u04bd\u04c0\u04c4\u04cb\u04de\u04e2\u04e7\u04ee\u04f5\u0521\u052f\u0536\u0552\u055d\u0560\u0565G;\u414aH\u803b\xd0\u40d0cute\u803b\xc9\u40c9\u0180aiy\u04d2\u04d7\u04dcron;\u411arc\u803b\xca\u40ca;\u442dot;\u4116r;\uc000\ud835\udd08rave\u803b\xc8\u40c8ement;\u6208\u0100ap\u04fa\u04fecr;\u4112ty\u0253\u0506\0\0\u0512mallSquare;\u65fberySmallSquare;\u65ab\u0100gp\u0526\u052aon;\u4118f;\uc000\ud835\udd3csilon;\u4395u\u0100ai\u053c\u0549l\u0100;T\u0542\u0543\u6a75ilde;\u6242librium;\u61cc\u0100ci\u0557\u055ar;\u6130m;\u6a73a;\u4397ml\u803b\xcb\u40cb\u0100ip\u056a\u056fsts;\u6203onentialE;\u6147\u0280cfios\u0585\u0588\u058d\u05b2\u05ccy;\u4424r;\uc000\ud835\udd09lled\u0253\u0597\0\0\u05a3mallSquare;\u65fcerySmallSquare;\u65aa\u0370\u05ba\0\u05bf\0\0\u05c4f;\uc000\ud835\udd3dAll;\u6200riertrf;\u6131c\xf2\u05cb\u0600JTabcdfgorst\u05e8\u05ec\u05ef\u05fa\u0600\u0612\u06
.split("")
.map(function (c) { return c.charCodeAt(0); }));
var decodeDataHtml = /*#__PURE__*/Object.defineProperty({
default: _default$5
}, '__esModule', {value: true});
// Generated using scripts/write-decode-map.ts
var _default$4 = new Uint16Array(
// prettier-ignore
"\u0200aglq\t\x15\x18\x1b\u026d\x0f\0\0\x12p;\u4026os;\u4027t;\u403et;\u403cuot;\u4022"
.split("")
.map(function (c) { return c.charCodeAt(0); }));
var decodeDataXml = /*#__PURE__*/Object.defineProperty({
default: _default$4
}, '__esModule', {value: true});
var decode_codepoint = createCommonjsModule(function (module, exports) {
// Adapted from https://github.com/mathiasbynens/he/blob/36afe179392226cf1b6ccdb16ebbb7a5a844d93a/src/he.js#L106-L134
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.replaceCodePoint = exports.fromCodePoint = void 0;
var decodeMap = new Map([
[0, 65533],
[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],
]);
exports.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) {
var output = "";
if (codePoint > 0xffff) {
codePoint -= 0x10000;
output += String.fromCharCode(((codePoint >>> 10) & 0x3ff) | 0xd800);
codePoint = 0xdc00 | (codePoint & 0x3ff);
}
output += String.fromCharCode(codePoint);
return output;
};
function replaceCodePoint(codePoint) {
var _a;
if ((codePoint >= 0xd800 && codePoint <= 0xdfff) || codePoint > 0x10ffff) {
return 0xfffd;
}
return (_a = decodeMap.get(codePoint)) !== null && _a !== void 0 ? _a : codePoint;
}
exports.replaceCodePoint = replaceCodePoint;
function decodeCodePoint(codePoint) {
return (0, exports.fromCodePoint)(replaceCodePoint(codePoint));
}
exports.default = decodeCodePoint;
});
var require$$0$4 = decodeDataHtml;
var require$$1$2 = decodeDataXml;
var decode_codepoint_js_2 = decode_codepoint;
var decode = createCommonjsModule(function (module, exports) {
var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.decodeXML = exports.decodeHTMLStrict = exports.decodeHTML = exports.determineBranch = exports.BinTrieFlags = exports.fromCodePoint = exports.replaceCodePoint = exports.decodeCodePoint = exports.xmlDecodeTree = exports.htmlDecodeTree = void 0;
var decode_data_html_js_1 = __importDefault(require$$0$4);
exports.htmlDecodeTree = decode_data_html_js_1.default;
var decode_data_xml_js_1 = __importDefault(require$$1$2);
exports.xmlDecodeTree = decode_data_xml_js_1.default;
var decode_codepoint_js_1 = __importDefault(decode_codepoint_js_2);
exports.decodeCodePoint = decode_codepoint_js_1.default;
Object.defineProperty(exports, "replaceCodePoint", { enumerable: true, get: function () { return decode_codepoint_js_2.replaceCodePoint; } });
Object.defineProperty(exports, "fromCodePoint", { enumerable: true, get: function () { return decode_codepoint_js_2.fromCodePoint; } });
var CharCodes;
(function (CharCodes) {
CharCodes[CharCodes["NUM"] = 35] = "NUM";
CharCodes[CharCodes["SEMI"] = 59] = "SEMI";
CharCodes[CharCodes["ZERO"] = 48] = "ZERO";
CharCodes[CharCodes["NINE"] = 57] = "NINE";
CharCodes[CharCodes["LOWER_A"] = 97] = "LOWER_A";
CharCodes[CharCodes["LOWER_F"] = 102] = "LOWER_F";
CharCodes[CharCodes["LOWER_X"] = 120] = "LOWER_X";
/** Bit that needs to be set to convert an upper case ASCII character to lower case */
CharCodes[CharCodes["To_LOWER_BIT"] = 32] = "To_LOWER_BIT";
})(CharCodes || (CharCodes = {}));
var BinTrieFlags;
(function (BinTrieFlags) {
BinTrieFlags[BinTrieFlags["VALUE_LENGTH"] = 49152] = "VALUE_LENGTH";
BinTrieFlags[BinTrieFlags["BRANCH_LENGTH"] = 16256] = "BRANCH_LENGTH";
BinTrieFlags[BinTrieFlags["JUMP_TABLE"] = 127] = "JUMP_TABLE";
})(BinTrieFlags = exports.BinTrieFlags || (exports.BinTrieFlags = {}));
function getDecoder(decodeTree) {
return function decodeHTMLBinary(str, strict) {
var ret = "";
var lastIdx = 0;
var strIdx = 0;
while ((strIdx = str.indexOf("&", strIdx)) >= 0) {
ret += str.slice(lastIdx, strIdx);
lastIdx = strIdx;
// Skip the "&"
strIdx += 1;
// If we have a numeric entity, handle this separately.
if (str.charCodeAt(strIdx) === CharCodes.NUM) {
// Skip the leading "&#". For hex entities, also skip the leading "x".
var start = strIdx + 1;
var base = 10;
var cp = str.charCodeAt(start);
if ((cp | CharCodes.To_LOWER_BIT) === CharCodes.LOWER_X) {
base = 16;
strIdx += 1;
start += 1;
}
do
cp = str.charCodeAt(++strIdx);
while ((cp >= CharCodes.ZERO && cp <= CharCodes.NINE) ||
(base === 16 &&
(cp | CharCodes.To_LOWER_BIT) >= CharCodes.LOWER_A &&
(cp | CharCodes.To_LOWER_BIT) <= CharCodes.LOWER_F));
if (start !== strIdx) {
var entity = str.substring(start, strIdx);
var parsed = parseInt(entity, base);
if (str.charCodeAt(strIdx) === CharCodes.SEMI) {
strIdx += 1;
}
else if (strict) {
continue;
}
ret += (0, decode_codepoint_js_1.default)(parsed);
lastIdx = strIdx;
}
continue;
}
var resultIdx = 0;
var excess = 1;
var treeIdx = 0;
var current = decodeTree[treeIdx];
for (; strIdx < str.length; strIdx++, excess++) {
treeIdx = determineBranch(decodeTree, current, treeIdx + 1, str.charCodeAt(strIdx));
if (treeIdx < 0)
break;
current = decodeTree[treeIdx];
var masked = current & BinTrieFlags.VALUE_LENGTH;
// If the branch is a value, store it and continue
if (masked) {
// If we have a legacy entity while parsing strictly, just skip the number of bytes
if (!strict || str.charCodeAt(strIdx) === CharCodes.SEMI) {
resultIdx = treeIdx;
excess = 0;
}
// The mask is the number of bytes of the value, including the current byte.
var valueLength = (masked >> 14) - 1;
if (valueLength === 0)
break;
treeIdx += valueLength;
}
}
if (resultIdx !== 0) {
var valueLength = (decodeTree[resultIdx] & BinTrieFlags.VALUE_LENGTH) >> 14;
ret +=
valueLength === 1
? String.fromCharCode(decodeTree[resultIdx] & ~BinTrieFlags.VALUE_LENGTH)
: valueLength === 2
? String.fromCharCode(decodeTree[resultIdx + 1])
: String.fromCharCode(decodeTree[resultIdx + 1], decodeTree[resultIdx + 2]);
lastIdx = strIdx - excess + 1;
}
}
return ret + str.slice(lastIdx);
};
}
function determineBranch(decodeTree, current, nodeIdx, char) {
var branchCount = (current & BinTrieFlags.BRANCH_LENGTH) >> 7;
var jumpOffset = current & BinTrieFlags.JUMP_TABLE;
// Case 1: Single branch encoded in jump offset
if (branchCount === 0) {
return jumpOffset !== 0 && char === jumpOffset ? nodeIdx : -1;
}
// Case 2: Multiple branches encoded in jump table
if (jumpOffset) {
var value = char - jumpOffset;
return value < 0 || value >= branchCount
? -1
: decodeTree[nodeIdx + value] - 1;
}
// Case 3: Multiple branches encoded in dictionary
// Binary search for the character.
var lo = nodeIdx;
var hi = lo + branchCount - 1;
while (lo <= hi) {
var mid = (lo + hi) >>> 1;
var midVal = decodeTree[mid];
if (midVal < char) {
lo = mid + 1;
}
else if (midVal > char) {
hi = mid - 1;
}
else {
return decodeTree[mid + branchCount];
}
}
return -1;
}
exports.determineBranch = determineBranch;
var htmlDecoder = getDecoder(decode_data_html_js_1.default);
var xmlDecoder = getDecoder(decode_data_xml_js_1.default);
/**
* Decodes an HTML string, allowing for entities not terminated by a semi-colon.
*
* @param str The string to decode.
* @returns The decoded string.
*/
function decodeHTML(str) {
return htmlDecoder(str, false);
}
exports.decodeHTML = decodeHTML;
/**
* Decodes an HTML string, requiring all entities to be terminated by a semi-colon.
*
* @param str The string to decode.
* @returns The decoded string.
*/
function decodeHTMLStrict(str) {
return htmlDecoder(str, true);
}
exports.decodeHTMLStrict = decodeHTMLStrict;
/**
* Decodes an XML string, requiring all entities to be terminated by a semi-colon.
*
* @param str The string to decode.
* @returns The decoded string.
*/
function decodeXML(str) {
return xmlDecoder(str, true);
}
exports.decodeXML = decodeXML;
});
// Generated using scripts/write-encode-map.ts
function restoreDiff(arr) {
for (var i = 1; i < arr.length; i++) {
arr[i][0] += arr[i - 1][0] + 1;
}
return arr;
}
// prettier-ignore
var _default$3 = new Map(/* #__PURE__ */ restoreDiff([[9, "&Tab;"], [0, "&NewLine;"], [22, "&excl;"], [0, "&quot;"], [0, "&num;"], [0, "&dollar;"], [0, "&percnt;"], [0, "&amp;"], [0, "&apos;"], [0, "&lpar;"], [0, "&rpar;"], [0, "&ast;"], [0, "&plus;"], [0, "&comma;"], [1, "&period;"], [0, "&sol;"], [10, "&colon;"], [0, "&semi;"], [0, { v: "&lt;", n: 8402, o: "&nvlt;" }], [0, { v: "&equals;", n: 8421, o: "&bne;" }], [0, { v: "&gt;", n: 8402, o: "&nvgt;" }], [0, "&quest;"], [0, "&commat;"], [26, "&lbrack;"], [0, "&bsol;"], [0, "&rbrack;"], [0, "&Hat;"], [0, "&lowbar;"], [0, "&DiacriticalGrave;"], [5, { n: 106, o: "&fjlig;" }], [20, "&lbrace;"], [0, "&verbar;"], [0, "&rbrace;"], [34, "&nbsp;"], [0, "&iexcl;"], [0, "&cent;"], [0, "&pound;"], [0, "&curren;"], [0, "&yen;"], [0, "&brvbar;"], [0, "&sect;"], [0, "&die;"], [0, "&copy;"], [0, "&ordf;"], [0, "&laquo;"], [0, "&not;"], [0, "&shy;"], [0, "&circledR;"], [0, "&macr;"], [0, "&deg;"], [0, "&PlusMinus;"], [0, "&sup2;"], [0, "&sup3;"], [0, "&acute;"], [0, "&micro;"], [0, "&para;"], [0, "&centerdot;"], [0, "&cedil;"], [0, "&sup1;"], [0, "&ordm;"], [0, "&raquo;"], [0, "&frac14;"], [0, "&frac12;"], [0, "&frac34;"], [0, "&iquest;"], [0, "&Agrave;"], [0, "&Aacute;"], [0, "&Acirc;"], [0, "&Atilde;"], [0, "&Auml;"], [0, "&angst;"], [0, "&AElig;"], [0, "&Ccedil;"], [0, "&Egrave;"], [0, "&Eacute;"], [0, "&Ecirc;"], [0, "&Euml;"], [0, "&Igrave;"], [0, "&Iacute;"], [0, "&Icirc;"], [0, "&Iuml;"], [0, "&ETH;"], [0, "&Ntilde;"], [0, "&Ograve;"], [0, "&Oacute;"], [0, "&Ocirc;"], [0, "&Otilde;"], [0, "&Ouml;"], [0, "&times;"], [0, "&Oslash;"], [0, "&Ugrave;"], [0, "&Uacute;"], [0, "&Ucirc;"], [0, "&Uuml;"], [0, "&Yacute;"], [0, "&THORN;"], [0, "&szlig;"], [0, "&agrave;"], [0, "&aacute;"], [0, "&acirc;"], [0, "&atilde;"], [0, "&auml;"], [0, "&aring;"], [0, "&aelig;"], [0, "&ccedil;"], [0, "&egrave;"], [0, "&eacute;"], [0, "&ecirc;"], [0, "&euml;"], [0, "&igrave;"], [0, "&iacute;"], [0, "&icirc;"], [0, "&iuml;"], [0, "&eth;"], [0, "&ntilde;"], [0, "&ograve;"], [0, "&oacute;"], [0, "&ocirc;"], [0, "&otilde;"], [0, "&ouml;"], [0, "&div;"], [0, "&oslash;"], [0, "&ugrave;"], [0, "&uacute;"], [0, "&ucirc;"], [0, "&uuml;"], [0, "&yacute;"], [0, "&thorn;"], [0, "&yuml;"], [0, "&Amacr;"], [0, "&amacr;"], [0, "&Abreve;"], [0, "&abreve;"], [0, "&Aogon;"], [0, "&aogon;"], [0, "&Cacute;"], [0, "&cacute;"], [0, "&Ccirc;"], [0, "&ccirc;"], [0, "&Cdot;"], [0, "&cdot;"], [0, "&Ccaron;"], [0, "&ccaron;"], [0, "&Dcaron;"], [0, "&dcaron;"], [0, "&Dstrok;"], [0, "&dstrok;"], [0, "&Emacr;"], [0, "&emacr;"], [2, "&Edot;"], [0, "&edot;"], [0, "&Eogon;"], [0, "&eogon;"], [0, "&Ecaron;"], [0, "&ecaron;"], [0, "&Gcirc;"], [0, "&gcirc;"], [0, "&Gbreve;"], [0, "&gbreve;"], [0, "&Gdot;"], [0, "&gdot;"], [0, "&Gcedil;"], [1, "&Hcirc;"], [0, "&hcirc;"], [0, "&Hstrok;"], [0, "&hstrok;"], [0, "&Itilde;"], [0, "&itilde;"], [0, "&Imacr;"], [0, "&imacr;"], [2, "&Iogon;"], [0, "&iogon;"], [0, "&Idot;"], [0, "&imath;"], [0, "&IJlig;"], [0, "&ijlig;"], [0, "&Jcirc;"], [0, "&jcirc;"], [0, "&Kcedil;"], [0, "&kcedil;"], [0, "&kgreen;"], [0, "&Lacute;"], [0, "&lacute;"], [0, "&Lcedil;"], [0, "&lcedil;"], [0, "&Lcaron;"], [0, "&lcaron;"], [0, "&Lmidot;"], [0, "&lmidot;"], [0, "&Lstrok;"], [0, "&lstrok;"], [0, "&Nacute;"], [0, "&nacute;"], [0, "&Ncedil;"], [0, "&ncedil;"], [0, "&Ncaron;"], [0, "&ncaron;"], [0, "&napos;"], [0, "&ENG;"], [0, "&eng;"], [0, "&Omacr;"], [0, "&omacr;"], [2, "&Odblac;"], [0, "&odblac;"], [0, "&OElig;"], [0, "&oelig;"], [0, "&Racute;"], [0, "&racute;"], [0, "&Rcedil;"], [0, "&rcedil;"], [0, "&Rcaron;"], [0, "&rcaron;"], [0, "&Sacute;"], [0, "&sacute;"], [0, "&Scirc;"], [0, "&scirc;"], [0, "&Scedil;"], [0, "&scedil;"], [0, "&Scaron;"], [0, "&scaron;"], [0, "&Tcedil;"], [0, "&tcedil;"], [0, "&Tcaron;"], [0, "&tcaron;"], [0, "&Tstrok;"], [0, "&tstrok;"], [0, "&Utilde;"], [0, "&utilde;"], [0, "&Umacr;"], [0, "&umacr;"], [0, "&Ubreve;"], [0, "&ubreve;"], [0, "&Uring;"], [0, "&uring;"], [0, "&Udblac;"], [0, "&udblac;"], [0, "&Uogon;"], [0, "&uogon;"], [0, "&Wcirc;"], [0, "&wcirc;"], [0, "&Ycirc;"], [0, "&ycirc;"], [
var encodeHtml = /*#__PURE__*/Object.defineProperty({
default: _default$3
}, '__esModule', {value: true});
var _escape = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.escapeText = exports.escapeAttribute = exports.escapeUTF8 = exports.escape = exports.encodeXML = exports.getCodePoint = exports.xmlReplacer = void 0;
exports.xmlReplacer = /["&'<>$\x80-\uFFFF]/g;
var xmlCodeMap = new Map([
[34, "&quot;"],
[38, "&amp;"],
[39, "&apos;"],
[60, "&lt;"],
[62, "&gt;"],
]);
// For compatibility with node < 4, we wrap `codePointAt`
exports.getCodePoint =
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
String.prototype.codePointAt != null
? function (str, index) { return str.codePointAt(index); }
: // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
function (c, index) {
return (c.charCodeAt(index) & 0xfc00) === 0xd800
? (c.charCodeAt(index) - 0xd800) * 0x400 +
c.charCodeAt(index + 1) -
0xdc00 +
0x10000
: c.charCodeAt(index);
};
/**
* Encodes all non-ASCII characters, as well as characters not valid in XML
* documents using XML entities.
*
* If a character has no equivalent entity, a
* numeric hexadecimal reference (eg. `&#xfc;`) will be used.
*/
function encodeXML(str) {
var ret = "";
var lastIdx = 0;
var match;
while ((match = exports.xmlReplacer.exec(str)) !== null) {
var i = match.index;
var char = str.charCodeAt(i);
var next = xmlCodeMap.get(char);
if (next !== undefined) {
ret += str.substring(lastIdx, i) + next;
lastIdx = i + 1;
}
else {
ret += "".concat(str.substring(lastIdx, i), "&#x").concat((0, exports.getCodePoint)(str, i).toString(16), ";");
// Increase by 1 if we have a surrogate pair
lastIdx = exports.xmlReplacer.lastIndex += Number((char & 0xfc00) === 0xd800);
}
}
return ret + str.substr(lastIdx);
}
exports.encodeXML = encodeXML;
/**
* Encodes all non-ASCII characters, as well as characters not valid in XML
* documents using numeric hexadecimal reference (eg. `&#xfc;`).
*
* Have a look at `escapeUTF8` if you want a more concise output at the expense
* of reduced transportability.
*
* @param data String to escape.
*/
exports.escape = encodeXML;
function getEscaper(regex, map) {
return function escape(data) {
var match;
var lastIdx = 0;
var result = "";
while ((match = regex.exec(data))) {
if (lastIdx !== match.index) {
result += data.substring(lastIdx, match.index);
}
// We know that this chararcter will be in the map.
result += map.get(match[0].charCodeAt(0));
// Every match will be of length 1
lastIdx = match.index + 1;
}
return result + data.substring(lastIdx);
};
}
/**
* Encodes all characters not valid in XML documents using XML entities.
*
* Note that the output will be character-set dependent.
*
* @param data String to escape.
*/
exports.escapeUTF8 = getEscaper(/[&<>'"]/g, xmlCodeMap);
/**
* Encodes all characters that have to be escaped in HTML attributes,
* following {@link https://html.spec.whatwg.org/multipage/parsing.html#escapingString}.
*
* @param data String to escape.
*/
exports.escapeAttribute = getEscaper(/["&\u00A0]/g, new Map([
[34, "&quot;"],
[38, "&amp;"],
[160, "&nbsp;"],
]));
/**
* Encodes all characters that have to be escaped in HTML text,
* following {@link https://html.spec.whatwg.org/multipage/parsing.html#escapingString}.
*
* @param data String to escape.
*/
exports.escapeText = getEscaper(/[&<>\u00A0]/g, new Map([
[38, "&amp;"],
[60, "&lt;"],
[62, "&gt;"],
[160, "&nbsp;"],
]));
});
var require$$0$3 = encodeHtml;
var escape_js_1 = _escape;
var encode = createCommonjsModule(function (module, exports) {
var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.encodeNonAsciiHTML = exports.encodeHTML = void 0;
var encode_html_js_1 = __importDefault(require$$0$3);
var htmlReplacer = /[\t\n!-,./:-@[-`\f{-}$\x80-\uFFFF]/g;
/**
* Encodes all characters in the input using HTML entities. This includes
* characters that are valid ASCII characters in HTML documents, such as `#`.
*
* To get a more compact output, consider using the `encodeNonAsciiHTML`
* function, which will only encode characters that are not valid in HTML
* documents, as well as non-ASCII characters.
*
* If a character has no equivalent entity, a numeric hexadecimal reference
* (eg. `&#xfc;`) will be used.
*/
function encodeHTML(data) {
return encodeHTMLTrieRe(htmlReplacer, data);
}
exports.encodeHTML = encodeHTML;
/**
* Encodes all non-ASCII characters, as well as characters not valid in HTML
* documents using HTML entities. This function will not encode characters that
* are valid in HTML documents, such as `#`.
*
* If a character has no equivalent entity, a numeric hexadecimal reference
* (eg. `&#xfc;`) will be used.
*/
function encodeNonAsciiHTML(data) {
return encodeHTMLTrieRe(escape_js_1.xmlReplacer, data);
}
exports.encodeNonAsciiHTML = encodeNonAsciiHTML;
function encodeHTMLTrieRe(regExp, str) {
var ret = "";
var lastIdx = 0;
var match;
while ((match = regExp.exec(str)) !== null) {
var i = match.index;
ret += str.substring(lastIdx, i);
var char = str.charCodeAt(i);
var next = encode_html_js_1.default.get(char);
if (typeof next === "object") {
// We are in a branch. Try to match the next char.
if (i + 1 < str.length) {
var nextChar = str.charCodeAt(i + 1);
var value = typeof next.n === "number"
? next.n === nextChar
? next.o
: undefined
: next.n.get(nextChar);
if (value !== undefined) {
ret += value;
lastIdx = regExp.lastIndex += 1;
continue;
}
}
next = next.v;
}
// We might have a tree node without a value; skip and use a numeric entitiy.
if (next !== undefined) {
ret += next;
lastIdx = i + 1;
}
else {
var cp = (0, escape_js_1.getCodePoint)(str, i);
ret += "&#x".concat(cp.toString(16), ";");
// Increase by 1 if we have a surrogate pair
lastIdx = regExp.lastIndex += Number(cp !== char);
}
}
return ret + str.substr(lastIdx);
}
});
var decode_js_1 = decode;
var encode_js_1 = encode;
var lib$7 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.decodeXMLStrict = exports.decodeHTML5Strict = exports.decodeHTML4Strict = exports.decodeHTML5 = exports.decodeHTML4 = exports.decodeHTMLStrict = exports.decodeHTML = exports.decodeXML = exports.encodeHTML5 = exports.encodeHTML4 = exports.encodeNonAsciiHTML = exports.encodeHTML = exports.escapeText = exports.escapeAttribute = exports.escapeUTF8 = exports.escape = exports.encodeXML = exports.encode = exports.decodeStrict = exports.decode = exports.EncodingMode = exports.DecodingMode = exports.EntityLevel = void 0;
/** The level of entities to support. */
var EntityLevel;
(function (EntityLevel) {
/** Support only XML entities. */
EntityLevel[EntityLevel["XML"] = 0] = "XML";
/** Support HTML entities, which are a superset of XML entities. */
EntityLevel[EntityLevel["HTML"] = 1] = "HTML";
})(EntityLevel = exports.EntityLevel || (exports.EntityLevel = {}));
/** Determines whether some entities are allowed to be written without a trailing `;`. */
var DecodingMode;
(function (DecodingMode) {
/** Support legacy HTML entities. */
DecodingMode[DecodingMode["Legacy"] = 0] = "Legacy";
/** Do not support legacy HTML entities. */
DecodingMode[DecodingMode["Strict"] = 1] = "Strict";
})(DecodingMode = exports.DecodingMode || (exports.DecodingMode = {}));
var EncodingMode;
(function (EncodingMode) {
/**
* The output is UTF-8 encoded. Only characters that need escaping within
* XML will be escaped.
*/
EncodingMode[EncodingMode["UTF8"] = 0] = "UTF8";
/**
* The output consists only of ASCII characters. Characters that need
* escaping within HTML, and characters that aren't ASCII characters will
* be escaped.
*/
EncodingMode[EncodingMode["ASCII"] = 1] = "ASCII";
/**
* Encode all characters that have an equivalent entity, as well as all
* characters that are not ASCII characters.
*/
EncodingMode[EncodingMode["Extensive"] = 2] = "Extensive";
/**
* Encode all characters that have to be escaped in HTML attributes,
* following {@link https://html.spec.whatwg.org/multipage/parsing.html#escapingString}.
*/
EncodingMode[EncodingMode["Attribute"] = 3] = "Attribute";
/**
* Encode all characters that have to be escaped in HTML text,
* following {@link https://html.spec.whatwg.org/multipage/parsing.html#escapingString}.
*/
EncodingMode[EncodingMode["Text"] = 4] = "Text";
})(EncodingMode = exports.EncodingMode || (exports.EncodingMode = {}));
/**
* Decodes a string with entities.
*
* @param data String to decode.
* @param options Decoding options.
*/
function decode(data, options) {
if (options === void 0) { options = EntityLevel.XML; }
var opts = typeof options === "number" ? { level: options } : options;
if (opts.level === EntityLevel.HTML) {
if (opts.mode === DecodingMode.Strict) {
return (0, decode_js_1.decodeHTMLStrict)(data);
}
return (0, decode_js_1.decodeHTML)(data);
}
return (0, decode_js_1.decodeXML)(data);
}
exports.decode = decode;
/**
* Decodes a string with entities. Does not allow missing trailing semicolons for entities.
*
* @param data String to decode.
* @param options Decoding options.
* @deprecated Use `decode` with the `mode` set to `Strict`.
*/
function decodeStrict(data, options) {
if (options === void 0) { options = EntityLevel.XML; }
var opts = typeof options === "number" ? { level: options } : options;
if (opts.level === EntityLevel.HTML) {
if (opts.mode === DecodingMode.Legacy) {
return (0, decode_js_1.decodeHTML)(data);
}
return (0, decode_js_1.decodeHTMLStrict)(data);
}
return (0, decode_js_1.decodeXML)(data);
}
exports.decodeStrict = decodeStrict;
/**
* Encodes a string with entities.
*
* @param data String to encode.
* @param options Encoding options.
*/
function encode(data, options) {
if (options === void 0) { options = EntityLevel.XML; }
var opts = typeof options === "number" ? { level: options } : options;
// Mode `UTF8` just escapes XML entities
if (opts.mode === EncodingMode.UTF8)
return (0, escape_js_1.escapeUTF8)(data);
if (opts.mode === EncodingMode.Attribute)
return (0, escape_js_1.escapeAttribute)(data);
if (opts.mode === EncodingMode.Text)
return (0, escape_js_1.escapeText)(data);
if (opts.level === EntityLevel.HTML) {
if (opts.mode === EncodingMode.ASCII) {
return (0, encode_js_1.encodeNonAsciiHTML)(data);
}
return (0, encode_js_1.encodeHTML)(data);
}
// ASCII and Extensive are equivalent
return (0, escape_js_1.encodeXML)(data);
}
exports.encode = encode;
var escape_js_2 = escape_js_1;
Object.defineProperty(exports, "encodeXML", { enumerable: true, get: function () { return escape_js_2.encodeXML; } });
Object.defineProperty(exports, "escape", { enumerable: true, get: function () { return escape_js_2.escape; } });
Object.defineProperty(exports, "escapeUTF8", { enumerable: true, get: function () { return escape_js_2.escapeUTF8; } });
Object.defineProperty(exports, "escapeAttribute", { enumerable: true, get: function () { return escape_js_2.escapeAttribute; } });
Object.defineProperty(exports, "escapeText", { enumerable: true, get: function () { return escape_js_2.escapeText; } });
var encode_js_2 = encode_js_1;
Object.defineProperty(exports, "encodeHTML", { enumerable: true, get: function () { return encode_js_2.encodeHTML; } });
Object.defineProperty(exports, "encodeNonAsciiHTML", { enumerable: true, get: function () { return encode_js_2.encodeNonAsciiHTML; } });
// Legacy aliases (deprecated)
Object.defineProperty(exports, "encodeHTML4", { enumerable: true, get: function () { return encode_js_2.encodeHTML; } });
Object.defineProperty(exports, "encodeHTML5", { enumerable: true, get: function () { return encode_js_2.encodeHTML; } });
var decode_js_2 = decode_js_1;
Object.defineProperty(exports, "decodeXML", { enumerable: true, get: function () { return decode_js_2.decodeXML; } });
Object.defineProperty(exports, "decodeHTML", { enumerable: true, get: function () { return decode_js_2.decodeHTML; } });
Object.defineProperty(exports, "decodeHTMLStrict", { enumerable: true, get: function () { return decode_js_2.decodeHTMLStrict; } });
// Legacy aliases (deprecated)
Object.defineProperty(exports, "decodeHTML4", { enumerable: true, get: function () { return decode_js_2.decodeHTML; } });
Object.defineProperty(exports, "decodeHTML5", { enumerable: true, get: function () { return decode_js_2.decodeHTML; } });
Object.defineProperty(exports, "decodeHTML4Strict", { enumerable: true, get: function () { return decode_js_2.decodeHTMLStrict; } });
Object.defineProperty(exports, "decodeHTML5Strict", { enumerable: true, get: function () { return decode_js_2.decodeHTMLStrict; } });
Object.defineProperty(exports, "decodeXMLStrict", { enumerable: true, get: function () { return decode_js_2.decodeXML; } });
});
var foreignNames = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.attributeNames = exports.elementNames = void 0;
exports.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(function (val) { return [val.toLowerCase(), val]; }));
exports.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(function (val) { return [val.toLowerCase(), val]; }));
});
var entities_1 = lib$7;
var foreignNames_js_1 = foreignNames;
var lib$6 = createCommonjsModule(function (module, exports) {
var __assign = (commonjsGlobal && commonjsGlobal.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (commonjsGlobal && commonjsGlobal.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (commonjsGlobal && commonjsGlobal.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.render = void 0;
/*
* Module dependencies
*/
var ElementType = __importStar(require$$0$5);
/**
* Mixed-case SVG and MathML tags & attributes
* recognized by the HTML parser.
*
* @see https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inforeign
*/
var unencodedElements = new Set([
"style",
"script",
"xmp",
"iframe",
"noembed",
"noframes",
"plaintext",
"noscript",
]);
function replaceQuotes(value) {
return value.replace(/"/g, "&quot;");
}
/**
* Format attributes
*/
function formatAttributes(attributes, opts) {
var _a;
if (!attributes)
return;
var encode = ((_a = opts.encodeEntities) !== null && _a !== void 0 ? _a : opts.decodeEntities) === false
? replaceQuotes
: opts.xmlMode || opts.encodeEntities !== "utf8"
? entities_1.encodeXML
: entities_1.escapeAttribute;
return Object.keys(attributes)
.map(function (key) {
var _a, _b;
var value = (_a = attributes[key]) !== null && _a !== void 0 ? _a : "";
if (opts.xmlMode === "foreign") {
/* Fix up mixed-case attribute names */
key = (_b = foreignNames_js_1.attributeNames.get(key)) !== null && _b !== void 0 ? _b : key;
}
if (!opts.emptyAttrs && !opts.xmlMode && value === "") {
return key;
}
return "".concat(key, "=\"").concat(encode(value), "\"");
})
.join(" ");
}
/**
* Self-enclosing tags
*/
var singleTag = new Set([
"area",
"base",
"basefont",
"br",
"col",
"command",
"embed",
"frame",
"hr",
"img",
"input",
"isindex",
"keygen",
"link",
"meta",
"param",
"source",
"track",
"wbr",
]);
/**
* Renders a DOM node or an array of DOM nodes to a string.
*
* Can be thought of as the equivalent of the `outerHTML` of the passed node(s).
*
* @param node Node to be rendered.
* @param options Changes serialization behavior
*/
function render(node, options) {
if (options === void 0) { options = {}; }
var nodes = "length" in node ? node : [node];
var output = "";
for (var i = 0; i < nodes.length; i++) {
output += renderNode(nodes[i], options);
}
return output;
}
exports.render = render;
exports.default = render;
function renderNode(node, options) {
switch (node.type) {
case ElementType.Root:
return render(node.children, options);
// @ts-expect-error We don't use `Doctype` yet
case ElementType.Doctype:
case ElementType.Directive:
return renderDirective(node);
case ElementType.Comment:
return renderComment(node);
case ElementType.CDATA:
return renderCdata(node);
case ElementType.Script:
case ElementType.Style:
case ElementType.Tag:
return renderTag(node, options);
case ElementType.Text:
return renderText(node, options);
}
}
var foreignModeIntegrationPoints = new Set([
"mi",
"mo",
"mn",
"ms",
"mtext",
"annotation-xml",
"foreignObject",
"desc",
"title",
]);
var foreignElements = new Set(["svg", "math"]);
function renderTag(elem, opts) {
var _a;
// Handle SVG / MathML in HTML
if (opts.xmlMode === "foreign") {
/* Fix up mixed-case element names */
elem.name = (_a = foreignNames_js_1.elementNames.get(elem.name)) !== null && _a !== void 0 ? _a : elem.name;
/* Exit foreign mode at integration points */
if (elem.parent &&
foreignModeIntegrationPoints.has(elem.parent.name)) {
opts = __assign(__assign({}, opts), { xmlMode: false });
}
}
if (!opts.xmlMode && foreignElements.has(elem.name)) {
opts = __assign(__assign({}, opts), { xmlMode: "foreign" });
}
var tag = "<".concat(elem.name);
var attribs = formatAttributes(elem.attribs, opts);
if (attribs) {
tag += " ".concat(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(elem.children, opts);
}
if (opts.xmlMode || !singleTag.has(elem.name)) {
tag += "</".concat(elem.name, ">");
}
}
return tag;
}
function renderDirective(elem) {
return "<".concat(elem.data, ">");
}
function renderText(elem, opts) {
var _a;
var data = elem.data || "";
// If entities weren't decoded, no need to encode them back
if (((_a = opts.encodeEntities) !== null && _a !== void 0 ? _a : opts.decodeEntities) !== false &&
!(!opts.xmlMode &&
elem.parent &&
unencodedElements.has(elem.parent.name))) {
data =
opts.xmlMode || opts.encodeEntities !== "utf8"
? (0, entities_1.encodeXML)(data)
: (0, entities_1.escapeText)(data);
}
return data;
}
function renderCdata(elem) {
return "<![CDATA[".concat(elem.children[0].data, "]]>");
}
function renderComment(elem) {
return "<!--".concat(elem.data, "-->");
}
});
var domhandler_1 = lib$8;
var require$$1$1 = lib$6;
var stringify$1 = createCommonjsModule(function (module, exports) {
var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.innerText = exports.textContent = exports.getText = exports.getInnerHTML = exports.getOuterHTML = void 0;
var dom_serializer_1 = __importDefault(require$$1$1);
/**
* @category Stringify
* @deprecated Use the `dom-serializer` module directly.
* @param node Node to get the outer HTML of.
* @param options Options for serialization.
* @returns `node`'s outer HTML.
*/
function getOuterHTML(node, options) {
return (0, dom_serializer_1.default)(node, options);
}
exports.getOuterHTML = getOuterHTML;
/**
* @category Stringify
* @deprecated Use the `dom-serializer` module directly.
* @param node Node to get the inner HTML of.
* @param options Options for serialization.
* @returns `node`'s inner HTML.
*/
function getInnerHTML(node, options) {
return (0, domhandler_1.hasChildren)(node)
? node.children.map(function (node) { return getOuterHTML(node, options); }).join("")
: "";
}
exports.getInnerHTML = getInnerHTML;
/**
* Get a node's inner text. Same as `textContent`, but inserts newlines for `<br>` tags.
*
* @category Stringify
* @deprecated Use `textContent` instead.
* @param node Node to get the inner text of.
* @returns `node`'s inner text.
*/
function getText(node) {
if (Array.isArray(node))
return node.map(getText).join("");
if ((0, domhandler_1.isTag)(node))
return node.name === "br" ? "\n" : getText(node.children);
if ((0, domhandler_1.isCDATA)(node))
return getText(node.children);
if ((0, domhandler_1.isText)(node))
return node.data;
return "";
}
exports.getText = getText;
/**
* Get a node's text content.
*
* @category Stringify
* @param node Node to get the text content of.
* @returns `node`'s text content.
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent}
*/
function textContent(node) {
if (Array.isArray(node))
return node.map(textContent).join("");
if ((0, domhandler_1.hasChildren)(node) && !(0, domhandler_1.isComment)(node)) {
return textContent(node.children);
}
if ((0, domhandler_1.isText)(node))
return node.data;
return "";
}
exports.textContent = textContent;
/**
* Get a node's inner text.
*
* @category Stringify
* @param node Node to get the inner text of.
* @returns `node`'s inner text.
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Node/innerText}
*/
function innerText(node) {
if (Array.isArray(node))
return node.map(innerText).join("");
if ((0, domhandler_1.hasChildren)(node) && (node.type === require$$0$5.ElementType.Tag || (0, domhandler_1.isCDATA)(node))) {
return innerText(node.children);
}
if ((0, domhandler_1.isText)(node))
return node.data;
return "";
}
exports.innerText = innerText;
});
var traversal = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.prevElementSibling = exports.nextElementSibling = exports.getName = exports.hasAttrib = exports.getAttributeValue = exports.getSiblings = exports.getParent = exports.getChildren = void 0;
/**
* Get a node's children.
*
* @category Traversal
* @param elem Node to get the children of.
* @returns `elem`'s children, or an empty array.
*/
function getChildren(elem) {
return (0, domhandler_1.hasChildren)(elem) ? elem.children : [];
}
exports.getChildren = getChildren;
/**
* Get a node's parent.
*
* @category Traversal
* @param elem Node to get the parent of.
* @returns `elem`'s parent node.
*/
function getParent(elem) {
return elem.parent || null;
}
exports.getParent = getParent;
/**
* Gets an elements siblings, including the element itself.
*
* Attempts to get the children through the element's parent first. If we don't
* have a parent (the element is a root node), we walk the element's `prev` &
* `next` to get all remaining nodes.
*
* @category Traversal
* @param elem Element to get the siblings of.
* @returns `elem`'s siblings.
*/
function getSiblings(elem) {
var _a, _b;
var parent = getParent(elem);
if (parent != null)
return getChildren(parent);
var siblings = [elem];
var prev = elem.prev, next = elem.next;
while (prev != null) {
siblings.unshift(prev);
(_a = prev, prev = _a.prev);
}
while (next != null) {
siblings.push(next);
(_b = next, next = _b.next);
}
return siblings;
}
exports.getSiblings = getSiblings;
/**
* Gets an attribute from an element.
*
* @category Traversal
* @param elem Element to check.
* @param name Attribute name to retrieve.
* @returns The element's attribute value, or `undefined`.
*/
function getAttributeValue(elem, name) {
var _a;
return (_a = elem.attribs) === null || _a === void 0 ? void 0 : _a[name];
}
exports.getAttributeValue = getAttributeValue;
/**
* Checks whether an element has an attribute.
*
* @category Traversal
* @param elem Element to check.
* @param name Attribute name to look for.
* @returns Returns whether `elem` has the attribute `name`.
*/
function hasAttrib(elem, name) {
return (elem.attribs != null &&
Object.prototype.hasOwnProperty.call(elem.attribs, name) &&
elem.attribs[name] != null);
}
exports.hasAttrib = hasAttrib;
/**
* Get the tag name of an element.
*
* @category Traversal
* @param elem The element to get the name for.
* @returns The tag name of `elem`.
*/
function getName(elem) {
return elem.name;
}
exports.getName = getName;
/**
* Returns the next element sibling of a node.
*
* @category Traversal
* @param elem The element to get the next sibling of.
* @returns `elem`'s next sibling that is a tag.
*/
function nextElementSibling(elem) {
var _a;
var next = elem.next;
while (next !== null && !(0, domhandler_1.isTag)(next))
(_a = next, next = _a.next);
return next;
}
exports.nextElementSibling = nextElementSibling;
/**
* Returns the previous element sibling of a node.
*
* @category Traversal
* @param elem The element to get the previous sibling of.
* @returns `elem`'s previous sibling that is a tag.
*/
function prevElementSibling(elem) {
var _a;
var prev = elem.prev;
while (prev !== null && !(0, domhandler_1.isTag)(prev))
(_a = prev, prev = _a.prev);
return prev;
}
exports.prevElementSibling = prevElementSibling;
});
var manipulation$1 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.prepend = exports.prependChild = exports.append = exports.appendChild = exports.replaceElement = exports.removeElement = void 0;
/**
* Remove an element from the dom
*
* @category Manipulation
* @param elem The element to be removed
*/
function removeElement(elem) {
if (elem.prev)
elem.prev.next = elem.next;
if (elem.next)
elem.next.prev = elem.prev;
if (elem.parent) {
var childs = elem.parent.children;
childs.splice(childs.lastIndexOf(elem), 1);
}
}
exports.removeElement = removeElement;
/**
* Replace an element in the dom
*
* @category Manipulation
* @param elem The element to be replaced
* @param replacement The element to be added
*/
function replaceElement(elem, replacement) {
var prev = (replacement.prev = elem.prev);
if (prev) {
prev.next = replacement;
}
var next = (replacement.next = elem.next);
if (next) {
next.prev = replacement;
}
var parent = (replacement.parent = elem.parent);
if (parent) {
var childs = parent.children;
childs[childs.lastIndexOf(elem)] = replacement;
elem.parent = null;
}
}
exports.replaceElement = replaceElement;
/**
* Append a child to an element.
*
* @category Manipulation
* @param elem The element to append to.
* @param child The element to be added as a child.
*/
function appendChild(elem, child) {
removeElement(child);
child.next = null;
child.parent = elem;
if (elem.children.push(child) > 1) {
var sibling = elem.children[elem.children.length - 2];
sibling.next = child;
child.prev = sibling;
}
else {
child.prev = null;
}
}
exports.appendChild = appendChild;
/**
* Append an element after another.
*
* @category Manipulation
* @param elem The element to append after.
* @param next The element be added.
*/
function append(elem, next) {
removeElement(next);
var parent = elem.parent;
var currNext = elem.next;
next.next = currNext;
next.prev = elem;
elem.next = next;
next.parent = parent;
if (currNext) {
currNext.prev = next;
if (parent) {
var childs = parent.children;
childs.splice(childs.lastIndexOf(currNext), 0, next);
}
}
else if (parent) {
parent.children.push(next);
}
}
exports.append = append;
/**
* Prepend a child to an element.
*
* @category Manipulation
* @param elem The element to prepend before.
* @param child The element to be added as a child.
*/
function prependChild(elem, child) {
removeElement(child);
child.parent = elem;
child.prev = null;
if (elem.children.unshift(child) !== 1) {
var sibling = elem.children[1];
sibling.prev = child;
child.next = sibling;
}
else {
child.next = null;
}
}
exports.prependChild = prependChild;
/**
* Prepend an element before another.
*
* @category Manipulation
* @param elem The element to prepend before.
* @param prev The element be added.
*/
function prepend(elem, prev) {
removeElement(prev);
var parent = elem.parent;
if (parent) {
var childs = parent.children;
childs.splice(childs.indexOf(elem), 0, prev);
}
if (elem.prev) {
elem.prev.next = prev;
}
prev.parent = parent;
prev.prev = elem.prev;
prev.next = elem;
elem.prev = prev;
}
exports.prepend = prepend;
});
var querying = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.findAll = exports.existsOne = exports.findOne = exports.findOneChild = exports.find = exports.filter = void 0;
/**
* Search a node and its children for nodes passing a test function.
*
* @category Querying
* @param test Function to test nodes on.
* @param node Node to search. Will be included in the result set if it matches.
* @param recurse Also consider child nodes.
* @param limit Maximum number of nodes to return.
* @returns All nodes passing `test`.
*/
function filter(test, node, recurse, limit) {
if (recurse === void 0) { recurse = true; }
if (limit === void 0) { limit = Infinity; }
if (!Array.isArray(node))
node = [node];
return find(test, node, recurse, limit);
}
exports.filter = filter;
/**
* Search an array of node and its children for nodes passing a test function.
*
* @category Querying
* @param test Function to test nodes on.
* @param nodes Array of nodes to search.
* @param recurse Also consider child nodes.
* @param limit Maximum number of nodes to return.
* @returns All nodes passing `test`.
*/
function find(test, nodes, recurse, limit) {
var result = [];
for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) {
var elem = nodes_1[_i];
if (test(elem)) {
result.push(elem);
if (--limit <= 0)
break;
}
if (recurse && (0, domhandler_1.hasChildren)(elem) && elem.children.length > 0) {
var children = find(test, elem.children, recurse, limit);
result.push.apply(result, children);
limit -= children.length;
if (limit <= 0)
break;
}
}
return result;
}
exports.find = find;
/**
* Finds the first element inside of an array that matches a test function.
*
* @category Querying
* @param test Function to test nodes on.
* @param nodes Array of nodes to search.
* @returns The first node in the array that passes `test`.
* @deprecated Use `Array.prototype.find` directly.
*/
function findOneChild(test, nodes) {
return nodes.find(test);
}
exports.findOneChild = findOneChild;
/**
* Finds one element in a tree that passes a test.
*
* @category Querying
* @param test Function to test nodes on.
* @param nodes Array of nodes to search.
* @param recurse Also consider child nodes.
* @returns The first child node that passes `test`.
*/
function findOne(test, nodes, recurse) {
if (recurse === void 0) { recurse = true; }
var elem = null;
for (var i = 0; i < nodes.length && !elem; i++) {
var checked = nodes[i];
if (!(0, domhandler_1.isTag)(checked)) {
continue;
}
else if (test(checked)) {
elem = checked;
}
else if (recurse && checked.children.length > 0) {
elem = findOne(test, checked.children, true);
}
}
return elem;
}
exports.findOne = findOne;
/**
* @category Querying
* @param test Function to test nodes on.
* @param nodes Array of nodes to search.
* @returns Whether a tree of nodes contains at least one node passing the test.
*/
function existsOne(test, nodes) {
return nodes.some(function (checked) {
return (0, domhandler_1.isTag)(checked) &&
(test(checked) ||
(checked.children.length > 0 &&
existsOne(test, checked.children)));
});
}
exports.existsOne = existsOne;
/**
* Search and array of nodes and its children for elements passing a test function.
*
* Same as `find`, but limited to elements and with less options, leading to reduced complexity.
*
* @category Querying
* @param test Function to test nodes on.
* @param nodes Array of nodes to search.
* @returns All nodes passing `test`.
*/
function findAll(test, nodes) {
var _a;
var result = [];
var stack = nodes.filter(domhandler_1.isTag);
var elem;
while ((elem = stack.shift())) {
var children = (_a = elem.children) === null || _a === void 0 ? void 0 : _a.filter(domhandler_1.isTag);
if (children && children.length > 0) {
stack.unshift.apply(stack, children);
}
if (test(elem))
result.push(elem);
}
return result;
}
exports.findAll = findAll;
});
var require$$3 = querying;
var legacy = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.getElementsByTagType = exports.getElementsByTagName = exports.getElementById = exports.getElements = exports.testElement = void 0;
var Checks = {
tag_name: function (name) {
if (typeof name === "function") {
return function (elem) { return (0, domhandler_1.isTag)(elem) && name(elem.name); };
}
else if (name === "*") {
return domhandler_1.isTag;
}
return function (elem) { return (0, domhandler_1.isTag)(elem) && elem.name === name; };
},
tag_type: function (type) {
if (typeof type === "function") {
return function (elem) { return type(elem.type); };
}
return function (elem) { return elem.type === type; };
},
tag_contains: function (data) {
if (typeof data === "function") {
return function (elem) { return (0, domhandler_1.isText)(elem) && data(elem.data); };
}
return function (elem) { return (0, domhandler_1.isText)(elem) && elem.data === data; };
},
};
/**
* @param attrib Attribute to check.
* @param value Attribute value to look for.
* @returns A function to check whether the a node has an attribute with a
* particular value.
*/
function getAttribCheck(attrib, value) {
if (typeof value === "function") {
return function (elem) { return (0, domhandler_1.isTag)(elem) && value(elem.attribs[attrib]); };
}
return function (elem) { return (0, domhandler_1.isTag)(elem) && elem.attribs[attrib] === value; };
}
/**
* @param a First function to combine.
* @param b Second function to combine.
* @returns A function taking a node and returning `true` if either of the input
* functions returns `true` for the node.
*/
function combineFuncs(a, b) {
return function (elem) { return a(elem) || b(elem); };
}
/**
* @param options An object describing nodes to look for.
* @returns A function executing all checks in `options` and returning `true` if
* any of them match a node.
*/
function compileTest(options) {
var funcs = Object.keys(options).map(function (key) {
var value = options[key];
return Object.prototype.hasOwnProperty.call(Checks, key)
? Checks[key](value)
: getAttribCheck(key, value);
});
return funcs.length === 0 ? null : funcs.reduce(combineFuncs);
}
/**
* @category Legacy Query Functions
* @param options An object describing nodes to look for.
* @param node The element to test.
* @returns Whether the element matches the description in `options`.
*/
function testElement(options, node) {
var test = compileTest(options);
return test ? test(node) : true;
}
exports.testElement = testElement;
/**
* @category Legacy Query Functions
* @param options An object describing nodes to look for.
* @param nodes Nodes to search through.
* @param recurse Also consider child nodes.
* @param limit Maximum number of nodes to return.
* @returns All nodes that match `options`.
*/
function getElements(options, nodes, recurse, limit) {
if (limit === void 0) { limit = Infinity; }
var test = compileTest(options);
return test ? (0, require$$3.filter)(test, nodes, recurse, limit) : [];
}
exports.getElements = getElements;
/**
* @category Legacy Query Functions
* @param id The unique ID attribute value to look for.
* @param nodes Nodes to search through.
* @param recurse Also consider child nodes.
* @returns The node with the supplied ID.
*/
function getElementById(id, nodes, recurse) {
if (recurse === void 0) { recurse = true; }
if (!Array.isArray(nodes))
nodes = [nodes];
return (0, require$$3.findOne)(getAttribCheck("id", id), nodes, recurse);
}
exports.getElementById = getElementById;
/**
* @category Legacy Query Functions
* @param tagName Tag name to search for.
* @param nodes Nodes to search through.
* @param recurse Also consider child nodes.
* @param limit Maximum number of nodes to return.
* @returns All nodes with the supplied `tagName`.
*/
function getElementsByTagName(tagName, nodes, recurse, limit) {
if (recurse === void 0) { recurse = true; }
if (limit === void 0) { limit = Infinity; }
return (0, require$$3.filter)(Checks["tag_name"](tagName), nodes, recurse, limit);
}
exports.getElementsByTagName = getElementsByTagName;
/**
* @category Legacy Query Functions
* @param type Element type to look for.
* @param nodes Nodes to search through.
* @param recurse Also consider child nodes.
* @param limit Maximum number of nodes to return.
* @returns All nodes with the supplied `type`.
*/
function getElementsByTagType(type, nodes, recurse, limit) {
if (recurse === void 0) { recurse = true; }
if (limit === void 0) { limit = Infinity; }
return (0, require$$3.filter)(Checks["tag_type"](type), nodes, recurse, limit);
}
exports.getElementsByTagType = getElementsByTagType;
});
var helpers$1 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.uniqueSort = exports.compareDocumentPosition = exports.DocumentPosition = exports.removeSubsets = void 0;
/**
* Given an array of nodes, remove any member that is contained by another.
*
* @category Helpers
* @param nodes Nodes to filter.
* @returns Remaining nodes that aren't subtrees of each other.
*/
function removeSubsets(nodes) {
var idx = nodes.length;
/*
* Check if each node (or one of its ancestors) is already contained in the
* array.
*/
while (--idx >= 0) {
var node = nodes[idx];
/*
* Remove the node if it is not unique.
* We are going through the array from the end, so we only
* have to check nodes that preceed the node under consideration in the array.
*/
if (idx > 0 && nodes.lastIndexOf(node, idx - 1) >= 0) {
nodes.splice(idx, 1);
continue;
}
for (var ancestor = node.parent; ancestor; ancestor = ancestor.parent) {
if (nodes.includes(ancestor)) {
nodes.splice(idx, 1);
break;
}
}
}
return nodes;
}
exports.removeSubsets = removeSubsets;
/**
* @category Helpers
* @see {@link http://dom.spec.whatwg.org/#dom-node-comparedocumentposition}
*/
var DocumentPosition;
(function (DocumentPosition) {
DocumentPosition[DocumentPosition["DISCONNECTED"] = 1] = "DISCONNECTED";
DocumentPosition[DocumentPosition["PRECEDING"] = 2] = "PRECEDING";
DocumentPosition[DocumentPosition["FOLLOWING"] = 4] = "FOLLOWING";
DocumentPosition[DocumentPosition["CONTAINS"] = 8] = "CONTAINS";
DocumentPosition[DocumentPosition["CONTAINED_BY"] = 16] = "CONTAINED_BY";
})(DocumentPosition = exports.DocumentPosition || (exports.DocumentPosition = {}));
/**
* Compare the position of one node against another node in any other document.
* The return value is a bitmask with the values from {@link DocumentPosition}.
*
* Document order:
* > There is an ordering, document order, defined on all the nodes in the
* > document corresponding to the order in which the first character of the
* > XML representation of each node occurs in the XML representation of the
* > document after expansion of general entities. Thus, the document element
* > node will be the first node. Element nodes occur before their children.
* > Thus, document order orders element nodes in order of the occurrence of
* > their start-tag in the XML (after expansion of entities). The attribute
* > nodes of an element occur after the element and before its children. The
* > relative order of attribute nodes is implementation-dependent.
*
* Source:
* http://www.w3.org/TR/DOM-Level-3-Core/glossary.html#dt-document-order
*
* @category Helpers
* @param nodeA The first node to use in the comparison
* @param nodeB The second node to use in the comparison
* @returns A bitmask describing the input nodes' relative position.
*
* See http://dom.spec.whatwg.org/#dom-node-comparedocumentposition for
* a description of these values.
*/
function compareDocumentPosition(nodeA, nodeB) {
var aParents = [];
var bParents = [];
if (nodeA === nodeB) {
return 0;
}
var current = (0, domhandler_1.hasChildren)(nodeA) ? nodeA : nodeA.parent;
while (current) {
aParents.unshift(current);
current = current.parent;
}
current = (0, domhandler_1.hasChildren)(nodeB) ? nodeB : nodeB.parent;
while (current) {
bParents.unshift(current);
current = current.parent;
}
var maxIdx = Math.min(aParents.length, bParents.length);
var idx = 0;
while (idx < maxIdx && aParents[idx] === bParents[idx]) {
idx++;
}
if (idx === 0) {
return DocumentPosition.DISCONNECTED;
}
var sharedParent = aParents[idx - 1];
var siblings = sharedParent.children;
var aSibling = aParents[idx];
var bSibling = bParents[idx];
if (siblings.indexOf(aSibling) > siblings.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;
}
exports.compareDocumentPosition = compareDocumentPosition;
/**
* Sort an array of nodes based on their relative position in the document and
* remove any duplicate nodes. If the array contains nodes that do not belong to
* the same document, sort order is unspecified.
*
* @category Helpers
* @param nodes Array of DOM nodes.
* @returns Collection of unique nodes, sorted in document order.
*/
function uniqueSort(nodes) {
nodes = nodes.filter(function (node, i, arr) { return !arr.includes(node, i + 1); });
nodes.sort(function (a, b) {
var relative = compareDocumentPosition(a, b);
if (relative & DocumentPosition.PRECEDING) {
return -1;
}
else if (relative & DocumentPosition.FOLLOWING) {
return 1;
}
return 0;
});
return nodes;
}
exports.uniqueSort = uniqueSort;
});
var require$$0$2 = stringify$1;
var require$$4 = legacy;
var feeds = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.getFeed = void 0;
/**
* Get the feed object from the root of a DOM tree.
*
* @category Feeds
* @param doc - The DOM to to extract the feed from.
* @returns The feed.
*/
function getFeed(doc) {
var feedRoot = getOneElement(isValidFeed, doc);
return !feedRoot
? null
: feedRoot.name === "feed"
? getAtomFeed(feedRoot)
: getRssFeed(feedRoot);
}
exports.getFeed = getFeed;
/**
* Parse an Atom feed.
*
* @param feedRoot The root of the feed.
* @returns The parsed feed.
*/
function getAtomFeed(feedRoot) {
var _a;
var childs = feedRoot.children;
var feed = {
type: "atom",
items: (0, require$$4.getElementsByTagName)("entry", childs).map(function (item) {
var _a;
var children = item.children;
var entry = { media: getMediaElements(children) };
addConditionally(entry, "id", "id", children);
addConditionally(entry, "title", "title", children);
var href = (_a = getOneElement("link", children)) === null || _a === void 0 ? void 0 : _a.attribs["href"];
if (href) {
entry.link = href;
}
var description = fetch("summary", children) || fetch("content", children);
if (description) {
entry.description = description;
}
var pubDate = fetch("updated", children);
if (pubDate) {
entry.pubDate = new Date(pubDate);
}
return entry;
}),
};
addConditionally(feed, "id", "id", childs);
addConditionally(feed, "title", "title", childs);
var href = (_a = getOneElement("link", childs)) === null || _a === void 0 ? void 0 : _a.attribs["href"];
if (href) {
feed.link = href;
}
addConditionally(feed, "description", "subtitle", childs);
var updated = fetch("updated", childs);
if (updated) {
feed.updated = new Date(updated);
}
addConditionally(feed, "author", "email", childs, true);
return feed;
}
/**
* Parse a RSS feed.
*
* @param feedRoot The root of the feed.
* @returns The parsed feed.
*/
function getRssFeed(feedRoot) {
var _a, _b;
var childs = (_b = (_a = getOneElement("channel", feedRoot.children)) === null || _a === void 0 ? void 0 : _a.children) !== null && _b !== void 0 ? _b : [];
var feed = {
type: feedRoot.name.substr(0, 3),
id: "",
items: (0, require$$4.getElementsByTagName)("item", feedRoot.children).map(function (item) {
var children = item.children;
var entry = { media: getMediaElements(children) };
addConditionally(entry, "id", "guid", children);
addConditionally(entry, "title", "title", children);
addConditionally(entry, "link", "link", children);
addConditionally(entry, "description", "description", children);
var pubDate = fetch("pubDate", children);
if (pubDate)
entry.pubDate = new Date(pubDate);
return entry;
}),
};
addConditionally(feed, "title", "title", childs);
addConditionally(feed, "link", "link", childs);
addConditionally(feed, "description", "description", childs);
var updated = fetch("lastBuildDate", childs);
if (updated) {
feed.updated = new Date(updated);
}
addConditionally(feed, "author", "managingEditor", childs, true);
return feed;
}
var MEDIA_KEYS_STRING = ["url", "type", "lang"];
var MEDIA_KEYS_INT = [
"fileSize",
"bitrate",
"framerate",
"samplingrate",
"channels",
"duration",
"height",
"width",
];
/**
* Get all media elements of a feed item.
*
* @param where Nodes to search in.
* @returns Media elements.
*/
function getMediaElements(where) {
return (0, require$$4.getElementsByTagName)("media:content", where).map(function (elem) {
var attribs = elem.attribs;
var media = {
medium: attribs["medium"],
isDefault: !!attribs["isDefault"],
};
for (var _i = 0, MEDIA_KEYS_STRING_1 = MEDIA_KEYS_STRING; _i < MEDIA_KEYS_STRING_1.length; _i++) {
var attrib = MEDIA_KEYS_STRING_1[_i];
if (attribs[attrib]) {
media[attrib] = attribs[attrib];
}
}
for (var _a = 0, MEDIA_KEYS_INT_1 = MEDIA_KEYS_INT; _a < MEDIA_KEYS_INT_1.length; _a++) {
var attrib = MEDIA_KEYS_INT_1[_a];
if (attribs[attrib]) {
media[attrib] = parseInt(attribs[attrib], 10);
}
}
if (attribs["expression"]) {
media.expression = attribs["expression"];
}
return media;
});
}
/**
* Get one element by tag name.
*
* @param tagName Tag name to look for
* @param node Node to search in
* @returns The element or null
*/
function getOneElement(tagName, node) {
return (0, require$$4.getElementsByTagName)(tagName, node, true, 1)[0];
}
/**
* Get the text content of an element with a certain tag name.
*
* @param tagName Tag name to look for.
* @param where Node to search in.
* @param recurse Whether to recurse into child nodes.
* @returns The text content of the element.
*/
function fetch(tagName, where, recurse) {
if (recurse === void 0) { recurse = false; }
return (0, require$$0$2.textContent)((0, require$$4.getElementsByTagName)(tagName, where, recurse, 1)).trim();
}
/**
* Adds a property to an object if it has a value.
*
* @param obj Object to be extended
* @param prop Property name
* @param tagName Tag name that contains the conditionally added property
* @param where Element to search for the property
* @param recurse Whether to recurse into child nodes.
*/
function addConditionally(obj, prop, tagName, where, recurse) {
if (recurse === void 0) { recurse = false; }
var val = fetch(tagName, where, recurse);
if (val)
obj[prop] = val;
}
/**
* Checks if an element is a feed root node.
*
* @param value The name of the element to check.
* @returns Whether an element is a feed root node.
*/
function isValidFeed(value) {
return value === "rss" || value === "feed" || value === "rdf:RDF";
}
});
var require$$1 = traversal;
var require$$2 = manipulation$1;
var require$$5 = helpers$1;
var require$$6 = feeds;
var lib$5 = createCommonjsModule(function (module, exports) {
var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (commonjsGlobal && commonjsGlobal.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.hasChildren = exports.isDocument = exports.isComment = exports.isText = exports.isCDATA = exports.isTag = void 0;
__exportStar(require$$0$2, exports);
__exportStar(require$$1, exports);
__exportStar(require$$2, exports);
__exportStar(require$$3, exports);
__exportStar(require$$4, exports);
__exportStar(require$$5, exports);
__exportStar(require$$6, exports);
/** @deprecated Use these methods from `domhandler` directly. */
Object.defineProperty(exports, "isTag", { enumerable: true, get: function () { return domhandler_1.isTag; } });
Object.defineProperty(exports, "isCDATA", { enumerable: true, get: function () { return domhandler_1.isCDATA; } });
Object.defineProperty(exports, "isText", { enumerable: true, get: function () { return domhandler_1.isText; } });
Object.defineProperty(exports, "isComment", { enumerable: true, get: function () { return domhandler_1.isComment; } });
Object.defineProperty(exports, "isDocument", { enumerable: true, get: function () { return domhandler_1.isDocument; } });
Object.defineProperty(exports, "hasChildren", { enumerable: true, get: function () { return domhandler_1.hasChildren; } });
});
var domutils_1 = lib$5;
var _static = createCommonjsModule(function (module, exports) {
var __assign = (commonjsGlobal && commonjsGlobal.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (commonjsGlobal && commonjsGlobal.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (commonjsGlobal && commonjsGlobal.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.merge = exports.contains = exports.root = exports.parseHTML = exports.text = exports.xml = exports.html = void 0;
var options_js_1 = __importStar(options);
/**
* Helper function to render a DOM.
*
* @param that - Cheerio instance to render.
* @param dom - The DOM to render. Defaults to `that`'s root.
* @param options - Options for rendering.
* @returns The rendered document.
*/
function render(that, dom, options) {
if (!that)
return '';
return that(dom !== null && dom !== void 0 ? dom : that._root.children, null, undefined, options).toString();
}
/**
* Checks if a passed object is an options object.
*
* @param dom - Object to check if it is an options object.
* @returns Whether the object is an options object.
*/
function isOptions(dom, options) {
return (!options &&
typeof dom === 'object' &&
dom != null &&
!('length' in dom) &&
!('type' in dom));
}
function html(dom, options) {
/*
* Be flexible about parameters, sometimes we call html(),
* with options as only parameter
* check dom argument for dom element specific properties
* assume there is no 'length' or 'type' properties in the options object
*/
var toRender = isOptions(dom) ? ((options = dom), undefined) : dom;
/*
* Sometimes `$.html()` is used without preloading html,
* so fallback non-existing options to the default ones.
*/
var opts = __assign(__assign(__assign({}, options_js_1.default), this === null || this === void 0 ? void 0 : this._options), (0, options_js_1.flatten)(options !== null && options !== void 0 ? options : {}));
return render(this, toRender, opts);
}
exports.html = html;
/**
* Render the document as XML.
*
* @param dom - Element to render.
* @returns THe rendered document.
*/
function xml(dom) {
var options = __assign(__assign({}, this._options), { xmlMode: true });
return render(this, dom, options);
}
exports.xml = xml;
/**
* Render the document as text.
*
* This returns the `textContent` of the passed elements. The result will
* include the contents of `script` and `stype` elements. To avoid this, use
* `.prop('innerText')` instead.
*
* @param elements - Elements to render.
* @returns The rendered document.
*/
function text(elements) {
var elems = elements ? elements : this ? this.root() : [];
var ret = '';
for (var i = 0; i < elems.length; i++) {
ret += (0, domutils_1.textContent)(elems[i]);
}
return ret;
}
exports.text = text;
function parseHTML(data, context, keepScripts) {
if (keepScripts === void 0) { keepScripts = typeof context === 'boolean' ? context : false; }
if (!data || typeof data !== 'string') {
return null;
}
if (typeof context === 'boolean') {
keepScripts = context;
}
var parsed = this.load(data, options_js_1.default, false);
if (!keepScripts) {
parsed('script').remove();
}
/*
* The `children` array is used by Cheerio internally to group elements that
* share the same parents. When nodes created through `parseHTML` are
* inserted into previously-existing DOM structures, they will be removed
* from the `children` array. The results of `parseHTML` should remain
* constant across these operations, so a shallow copy should be returned.
*/
return parsed.root()[0].children.slice();
}
exports.parseHTML = parseHTML;
/**
* Sometimes you need to work with the top-level root element. To query it, you
* can use `$.root()`.
*
* @example
*
* ```js
* $.root().append('<ul id="vegetables"></ul>').html();
* //=> <ul id="fruits">...</ul><ul id="vegetables"></ul>
* ```
*
* @returns Cheerio instance wrapping the root node.
* @alias Cheerio.root
*/
function root() {
return this(this._root);
}
exports.root = root;
/**
* Checks to see if the `contained` DOM element is a descendant of the
* `container` DOM element.
*
* @param container - Potential parent node.
* @param contained - Potential child node.
* @returns Indicates if the nodes contain one another.
* @alias Cheerio.contains
* @see {@link https://api.jquery.com/jQuery.contains/}
*/
function contains(container, contained) {
// According to the jQuery API, an element does not "contain" itself
if (contained === container) {
return false;
}
/*
* Step up the descendants, stopping when the root element is reached
* (signaled by `.parent` returning a reference to the same object)
*/
var next = contained;
while (next && next !== next.parent) {
next = next.parent;
if (next === container) {
return true;
}
}
return false;
}
exports.contains = contains;
/**
* $.merge().
*
* @param arr1 - First array.
* @param arr2 - Second array.
* @returns `arr1`, with elements of `arr2` inserted.
* @alias Cheerio.merge
* @see {@link https://api.jquery.com/jQuery.merge/}
*/
function merge(arr1, arr2) {
if (!isArrayLike(arr1) || !isArrayLike(arr2)) {
return;
}
var newLength = arr1.length;
var len = +arr2.length;
for (var i = 0; i < len; i++) {
arr1[newLength++] = arr2[i];
}
arr1.length = newLength;
return arr1;
}
exports.merge = merge;
/**
* Checks if an object is array-like.
*
* @param item - Item to check.
* @returns Indicates if the item is array-like.
*/
function isArrayLike(item) {
if (Array.isArray(item)) {
return true;
}
if (typeof item !== 'object' ||
!Object.prototype.hasOwnProperty.call(item, 'length') ||
typeof item.length !== 'number' ||
item.length < 0) {
return false;
}
for (var i = 0; i < item.length; i++) {
if (!(i in item)) {
return false;
}
}
return true;
}
});
var utils = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.isHtml = exports.cloneDom = exports.domEach = exports.cssCase = exports.camelCase = exports.isCheerio = exports.isTag = void 0;
/**
* Check if the DOM element is a tag.
*
* `isTag(type)` includes `<script>` and `<style>` tags.
*
* @private
* @category Utils
* @param type - The DOM node to check.
* @returns Whether the node is a tag.
*/
var domhandler_2 = domhandler_1;
Object.defineProperty(exports, "isTag", { enumerable: true, get: function () { return domhandler_2.isTag; } });
/**
* Checks if an object is a Cheerio instance.
*
* @category Utils
* @param maybeCheerio - The object to check.
* @returns Whether the object is a Cheerio instance.
*/
function isCheerio(maybeCheerio) {
return maybeCheerio.cheerio != null;
}
exports.isCheerio = isCheerio;
/**
* Convert a string to camel case notation.
*
* @private
* @category Utils
* @param str - The string to be converted.
* @returns String in camel case notation.
*/
function camelCase(str) {
return str.replace(/[_.-](\w|$)/g, function (_, x) { return x.toUpperCase(); });
}
exports.camelCase = camelCase;
/**
* Convert a string from camel case to "CSS case", where word boundaries are
* described by hyphens ("-") and all characters are lower-case.
*
* @private
* @category Utils
* @param str - The string to be converted.
* @returns String in "CSS case".
*/
function cssCase(str) {
return str.replace(/[A-Z]/g, '-$&').toLowerCase();
}
exports.cssCase = cssCase;
/**
* Iterate over each DOM element without creating intermediary Cheerio instances.
*
* This is indented for use internally to avoid otherwise unnecessary memory
* pressure introduced by _make.
*
* @category Utils
* @param array - The array to iterate over.
* @param fn - Function to call.
* @returns The original instance.
*/
function domEach(array, fn) {
var len = array.length;
for (var i = 0; i < len; i++)
fn(array[i], i);
return array;
}
exports.domEach = domEach;
/**
* Create a deep copy of the given DOM structure. Sets the parents of the copies
* of the passed nodes to `null`.
*
* @private
* @category Utils
* @param dom - The domhandler-compliant DOM structure.
* @returns - The cloned DOM.
*/
function cloneDom(dom) {
var clone = 'length' in dom
? Array.prototype.map.call(dom, function (el) { return (0, domhandler_1.cloneNode)(el, true); })
: [(0, domhandler_1.cloneNode)(dom, true)];
// Add a root node around the cloned nodes
var root = new domhandler_1.Document(clone);
clone.forEach(function (node) {
node.parent = root;
});
return clone;
}
exports.cloneDom = cloneDom;
var CharacterCodes;
(function (CharacterCodes) {
CharacterCodes[CharacterCodes["LowerA"] = 97] = "LowerA";
CharacterCodes[CharacterCodes["LowerZ"] = 122] = "LowerZ";
CharacterCodes[CharacterCodes["UpperA"] = 65] = "UpperA";
CharacterCodes[CharacterCodes["UpperZ"] = 90] = "UpperZ";
CharacterCodes[CharacterCodes["Exclamation"] = 33] = "Exclamation";
})(CharacterCodes || (CharacterCodes = {}));
/**
* Check if string is HTML.
*
* Tests for a `<` within a string, immediate followed by a letter and
* eventually followed by a `>`.
*
* @private
* @category Utils
* @param str - The string to check.
* @returns Indicates if `str` is HTML.
*/
function isHtml(str) {
var tagStart = str.indexOf('<');
if (tagStart < 0 || tagStart > str.length - 3)
return false;
var 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));
}
exports.isHtml = isHtml;
});
var attributes$1 = createCommonjsModule(function (module, exports) {
/**
* Methods for getting and modifying attributes.
*
* @module cheerio/attributes
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.toggleClass = exports.removeClass = exports.addClass = exports.hasClass = exports.removeAttr = exports.val = exports.data = exports.prop = exports.attr = void 0;
var hasOwn = Object.prototype.hasOwnProperty;
var rspace = /\s+/;
var dataAttrPrefix = 'data-';
/*
* Lookup table for coercing string data-* attributes to their corresponding
* JavaScript primitives
*/
var primitives = {
null: null,
true: true,
false: false,
};
// Attributes that are booleans
var rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i;
// Matches strings that look like JSON objects or arrays
var rbrace = /^{[^]*}$|^\[[^]*]$/;
function getAttr(elem, name, xmlMode) {
var _a;
if (!elem || !(0, utils.isTag)(elem))
return undefined;
(_a = elem.attribs) !== null && _a !== void 0 ? _a : (elem.attribs = {});
// Return the entire attribs object if no attribute specified
if (!name) {
return elem.attribs;
}
if (hasOwn.call(elem.attribs, name)) {
// Get the (decoded) attribute
return !xmlMode && rboolean.test(name) ? name : elem.attribs[name];
}
// Mimic the DOM and return text content as value for `option's`
if (elem.name === 'option' && name === 'value') {
return (0, _static.text)(elem.children);
}
// Mimic DOM with default value for radios/checkboxes
if (elem.name === 'input' &&
(elem.attribs['type'] === 'radio' || elem.attribs['type'] === 'checkbox') &&
name === 'value') {
return 'on';
}
return undefined;
}
/**
* Sets the value of an attribute. The attribute will be deleted if the value is `null`.
*
* @private
* @param el - The element to set the attribute on.
* @param name - The attribute's name.
* @param value - The attribute's value.
*/
function setAttr(el, name, value) {
if (value === null) {
removeAttribute(el, name);
}
else {
el.attribs[name] = "".concat(value);
}
}
function attr(name, value) {
// Set the value (with attr map support)
if (typeof name === 'object' || value !== undefined) {
if (typeof value === 'function') {
if (typeof name !== 'string') {
{
throw new Error('Bad combination of arguments.');
}
}
return (0, utils.domEach)(this, function (el, i) {
if ((0, utils.isTag)(el))
setAttr(el, name, value.call(el, i, el.attribs[name]));
});
}
return (0, utils.domEach)(this, function (el) {
if (!(0, utils.isTag)(el))
return;
if (typeof name === 'object') {
Object.keys(name).forEach(function (objName) {
var objValue = name[objName];
setAttr(el, objName, objValue);
});
}
else {
setAttr(el, name, value);
}
});
}
return arguments.length > 1
? this
: getAttr(this[0], name, this.options.xmlMode);
}
exports.attr = attr;
/**
* Gets a node's prop.
*
* @private
* @category Attributes
* @param el - Element to get the prop of.
* @param name - Name of the prop.
* @returns The prop's value.
*/
function getProp(el, name, xmlMode) {
if (!el || !(0, utils.isTag)(el))
return;
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) !== undefined
: getAttr(el, name, xmlMode);
}
/**
* Sets the value of a prop.
*
* @private
* @param el - The element to set the prop on.
* @param name - The prop's name.
* @param value - The prop's value.
*/
function setProp(el, name, value, xmlMode) {
if (name in el) {
// @ts-expect-error Overriding value
el[name] = value;
}
else {
setAttr(el, name, !xmlMode && rboolean.test(name) ? (value ? '' : null) : "".concat(value));
}
}
function prop(name, value) {
var _this = this;
var _a;
if (typeof name === 'string' && value === undefined) {
switch (name) {
case 'style': {
var property_1 = this.css();
var keys = Object.keys(property_1);
keys.forEach(function (p, i) {
property_1[i] = p;
});
property_1.length = keys.length;
return property_1;
}
case 'tagName':
case 'nodeName': {
var el = this[0];
return (0, utils.isTag)(el) ? el.name.toUpperCase() : undefined;
}
case 'href':
case 'src': {
var el = this[0];
if (!(0, utils.isTag)(el)) {
return undefined;
}
var prop_1 = (_a = el.attribs) === null || _a === void 0 ? void 0 : _a[name];
/* eslint-disable node/no-unsupported-features/node-builtins */
if (typeof URL !== 'undefined' &&
((name === 'href' && (el.tagName === 'a' || el.name === 'link')) ||
(name === 'src' &&
(el.tagName === 'img' ||
el.tagName === 'iframe' ||
el.tagName === 'audio' ||
el.tagName === 'video' ||
el.tagName === 'source'))) &&
prop_1 !== undefined &&
this.options.baseURI) {
return new URL(prop_1, this.options.baseURI).href;
}
/* eslint-enable node/no-unsupported-features/node-builtins */
return prop_1;
}
case 'innerText':
return (0, domutils_1.innerText)(this[0]);
case 'textContent':
return (0, domutils_1.textContent)(this[0]);
case 'outerHTML':
return this.clone().wrap('<container />').parent().html();
case 'innerHTML':
return this.html();
default:
return getProp(this[0], name, this.options.xmlMode);
}
}
if (typeof name === 'object' || value !== undefined) {
if (typeof value === 'function') {
if (typeof name === 'object') {
throw new Error('Bad combination of arguments.');
}
return (0, utils.domEach)(this, function (el, i) {
if ((0, utils.isTag)(el)) {
setProp(el, name, value.call(el, i, getProp(el, name, _this.options.xmlMode)), _this.options.xmlMode);
}
});
}
return (0, utils.domEach)(this, function (el) {
if (!(0, utils.isTag)(el))
return;
if (typeof name === 'object') {
Object.keys(name).forEach(function (key) {
var val = name[key];
setProp(el, key, val, _this.options.xmlMode);
});
}
else {
setProp(el, name, value, _this.options.xmlMode);
}
});
}
return undefined;
}
exports.prop = prop;
/**
* Sets the value of a data attribute.
*
* @private
* @param el - The element to set the data attribute on.
* @param name - The data attribute's name.
* @param value - The data attribute's value.
*/
function setData(el, name, value) {
var _a;
var elem = el;
(_a = elem.data) !== null && _a !== void 0 ? _a : (elem.data = {});
if (typeof name === 'object')
Object.assign(elem.data, name);
else if (typeof name === 'string' && value !== undefined) {
elem.data[name] = value;
}
}
/**
* Read the specified attribute from the equivalent HTML5 `data-*` attribute,
* and (if present) cache the value in the node's internal data store. If no
* attribute name is specified, read _all_ HTML5 `data-*` attributes in this manner.
*
* @private
* @category Attributes
* @param el - Element to get the data attribute of.
* @param name - Name of the data attribute.
* @returns The data attribute's value, or a map with all of the data attributes.
*/
function readData(el, name) {
var domNames;
var jsNames;
var value;
if (name == null) {
domNames = Object.keys(el.attribs).filter(function (attrName) {
return attrName.startsWith(dataAttrPrefix);
});
jsNames = domNames.map(function (domName) {
return (0, utils.camelCase)(domName.slice(dataAttrPrefix.length));
});
}
else {
domNames = [dataAttrPrefix + (0, utils.cssCase)(name)];
jsNames = [name];
}
for (var idx = 0; idx < domNames.length; ++idx) {
var domName = domNames[idx];
var jsName = jsNames[idx];
if (hasOwn.call(el.attribs, domName) &&
!hasOwn.call(el.data, jsName)) {
value = el.attribs[domName];
if (hasOwn.call(primitives, value)) {
value = primitives[value];
}
else if (value === String(Number(value))) {
value = Number(value);
}
else if (rbrace.test(value)) {
try {
value = JSON.parse(value);
}
catch (e) {
/* Ignore */
}
}
el.data[jsName] = value;
}
}
return name == null ? el.data : value;
}
function data(name, value) {
var _a;
var elem = this[0];
if (!elem || !(0, utils.isTag)(elem))
return;
var dataEl = elem;
(_a = dataEl.data) !== null && _a !== void 0 ? _a : (dataEl.data = {});
// Return the entire data object if no data specified
if (!name) {
return readData(dataEl);
}
// Set the value (with attr map support)
if (typeof name === 'object' || value !== undefined) {
(0, utils.domEach)(this, function (el) {
if ((0, utils.isTag)(el)) {
if (typeof name === 'object')
setData(el, name);
else
setData(el, name, value);
}
});
return this;
}
if (hasOwn.call(dataEl.data, name)) {
return dataEl.data[name];
}
return readData(dataEl, name);
}
exports.data = data;
function val(value) {
var querying = arguments.length === 0;
var element = this[0];
if (!element || !(0, utils.isTag)(element))
return querying ? undefined : this;
switch (element.name) {
case 'textarea':
return this.text(value);
case 'select': {
var option = this.find('option:selected');
if (!querying) {
if (this.attr('multiple') == null && typeof value === 'object') {
return this;
}
this.find('option').removeAttr('selected');
var values = typeof value !== 'object' ? [value] : value;
for (var i = 0; i < values.length; i++) {
this.find("option[value=\"".concat(values[i], "\"]")).attr('selected', '');
}
return this;
}
return this.attr('multiple')
? option.toArray().map(function (el) { return (0, _static.text)(el.children); })
: option.attr('value');
}
case 'input':
case 'option':
return querying
? this.attr('value')
: this.attr('value', value);
}
return undefined;
}
exports.val = val;
/**
* Remove an attribute.
*
* @private
* @param elem - Node to remove attribute from.
* @param name - Name of the attribute to remove.
*/
function removeAttribute(elem, name) {
if (!elem.attribs || !hasOwn.call(elem.attribs, name))
return;
delete elem.attribs[name];
}
/**
* Splits a space-separated list of names to individual names.
*
* @category Attributes
* @param names - Names to split.
* @returns - Split names.
*/
function splitNames(names) {
return names ? names.trim().split(rspace) : [];
}
/**
* Method for removing attributes by `name`.
*
* @category Attributes
* @example
*
* ```js
* $('.pear').removeAttr('class').html();
* //=> <li>Pear</li>
*
* $('.apple').attr('id', 'favorite');
* $('.apple').removeAttr('id class').html();
* //=> <li>Apple</li>
* ```
*
* @param name - Name of the attribute.
* @returns The instance itself.
* @see {@link https://api.jquery.com/removeAttr/}
*/
function removeAttr(name) {
var attrNames = splitNames(name);
var _loop_1 = function (i) {
(0, utils.domEach)(this_1, function (elem) {
if ((0, utils.isTag)(elem))
removeAttribute(elem, attrNames[i]);
});
};
var this_1 = this;
for (var i = 0; i < attrNames.length; i++) {
_loop_1(i);
}
return this;
}
exports.removeAttr = removeAttr;
/**
* Check to see if _any_ of the matched elements have the given `className`.
*
* @category Attributes
* @example
*
* ```js
* $('.pear').hasClass('pear');
* //=> true
*
* $('apple').hasClass('fruit');
* //=> false
*
* $('li').hasClass('pear');
* //=> true
* ```
*
* @param className - Name of the class.
* @returns Indicates if an element has the given `className`.
* @see {@link https://api.jquery.com/hasClass/}
*/
function hasClass(className) {
return this.toArray().some(function (elem) {
var clazz = (0, utils.isTag)(elem) && elem.attribs['class'];
var idx = -1;
if (clazz && className.length) {
while ((idx = clazz.indexOf(className, idx + 1)) > -1) {
var end = idx + className.length;
if ((idx === 0 || rspace.test(clazz[idx - 1])) &&
(end === clazz.length || rspace.test(clazz[end]))) {
return true;
}
}
}
return false;
});
}
exports.hasClass = hasClass;
/**
* Adds class(es) to all of the matched elements. Also accepts a `function`.
*
* @category Attributes
* @example
*
* ```js
* $('.pear').addClass('fruit').html();
* //=> <li class="pear fruit">Pear</li>
*
* $('.apple').addClass('fruit red').html();
* //=> <li class="apple fruit red">Apple</li>
* ```
*
* @param value - Name of new class.
* @returns The instance itself.
* @see {@link https://api.jquery.com/addClass/}
*/
function addClass(value) {
// Support functions
if (typeof value === 'function') {
return (0, utils.domEach)(this, function (el, i) {
if ((0, utils.isTag)(el)) {
var className = el.attribs['class'] || '';
addClass.call([el], value.call(el, i, className));
}
});
}
// Return if no value or not a string or function
if (!value || typeof value !== 'string')
return this;
var classNames = value.split(rspace);
var numElements = this.length;
for (var i = 0; i < numElements; i++) {
var el = this[i];
// If selected element isn't a tag, move on
if (!(0, utils.isTag)(el))
continue;
// If we don't already have classes — always set xmlMode to false here, as it doesn't matter for classes
var className = getAttr(el, 'class', false);
if (!className) {
setAttr(el, 'class', classNames.join(' ').trim());
}
else {
var setClass = " ".concat(className, " ");
// Check if class already exists
for (var j = 0; j < classNames.length; j++) {
var appendClass = "".concat(classNames[j], " ");
if (!setClass.includes(" ".concat(appendClass)))
setClass += appendClass;
}
setAttr(el, 'class', setClass.trim());
}
}
return this;
}
exports.addClass = addClass;
/**
* Removes one or more space-separated classes from the selected elements. If no
* `className` is defined, all classes will be removed. Also accepts a `function`.
*
* @category Attributes
* @example
*
* ```js
* $('.pear').removeClass('pear').html();
* //=> <li class="">Pear</li>
*
* $('.apple').addClass('red').removeClass().html();
* //=> <li class="">Apple</li>
* ```
*
* @param name - Name of the class. If not specified, removes all elements.
* @returns The instance itself.
* @see {@link https://api.jquery.com/removeClass/}
*/
function removeClass(name) {
// Handle if value is a function
if (typeof name === 'function') {
return (0, utils.domEach)(this, function (el, i) {
if ((0, utils.isTag)(el)) {
removeClass.call([el], name.call(el, i, el.attribs['class'] || ''));
}
});
}
var classes = splitNames(name);
var numClasses = classes.length;
var removeAll = arguments.length === 0;
return (0, utils.domEach)(this, function (el) {
if (!(0, utils.isTag)(el))
return;
if (removeAll) {
// Short circuit the remove all case as this is the nice one
el.attribs['class'] = '';
}
else {
var elClasses = splitNames(el.attribs['class']);
var changed = false;
for (var j = 0; j < numClasses; j++) {
var index = elClasses.indexOf(classes[j]);
if (index >= 0) {
elClasses.splice(index, 1);
changed = true;
/*
* We have to do another pass to ensure that there are not duplicate
* classes listed
*/
j--;
}
}
if (changed) {
el.attribs['class'] = elClasses.join(' ');
}
}
});
}
exports.removeClass = removeClass;
/**
* Add or remove class(es) from the matched elements, depending on either the
* class's presence or the value of the switch argument. Also accepts a `function`.
*
* @category Attributes
* @example
*
* ```js
* $('.apple.green').toggleClass('fruit green red').html();
* //=> <li class="apple fruit red">Apple</li>
*
* $('.apple.green').toggleClass('fruit green red', true).html();
* //=> <li class="apple green fruit red">Apple</li>
* ```
*
* @param value - Name of the class. Can also be a function.
* @param stateVal - If specified the state of the class.
* @returns The instance itself.
* @see {@link https://api.jquery.com/toggleClass/}
*/
function toggleClass(value, stateVal) {
// Support functions
if (typeof value === 'function') {
return (0, utils.domEach)(this, function (el, i) {
if ((0, utils.isTag)(el)) {
toggleClass.call([el], value.call(el, i, el.attribs['class'] || '', stateVal), stateVal);
}
});
}
// Return if no value or not a string or function
if (!value || typeof value !== 'string')
return this;
var classNames = value.split(rspace);
var numClasses = classNames.length;
var state = typeof stateVal === 'boolean' ? (stateVal ? 1 : -1) : 0;
var numElements = this.length;
for (var i = 0; i < numElements; i++) {
var el = this[i];
// If selected element isn't a tag, move on
if (!(0, utils.isTag)(el))
continue;
var elementClasses = splitNames(el.attribs['class']);
// Check if class already exists
for (var j = 0; j < numClasses; j++) {
// Check if the class name is currently defined
var index = elementClasses.indexOf(classNames[j]);
// Add if stateValue === true or we are toggling and there is no value
if (state >= 0 && index < 0) {
elementClasses.push(classNames[j]);
}
else if (state <= 0 && index >= 0) {
// Otherwise remove but only if the item exists
elementClasses.splice(index, 1);
}
}
el.attribs['class'] = elementClasses.join(' ');
}
return this;
}
exports.toggleClass = toggleClass;
});
var SelectorType;
(function (SelectorType) {
SelectorType["Attribute"] = "attribute";
SelectorType["Pseudo"] = "pseudo";
SelectorType["PseudoElement"] = "pseudo-element";
SelectorType["Tag"] = "tag";
SelectorType["Universal"] = "universal";
// Traversals
SelectorType["Adjacent"] = "adjacent";
SelectorType["Child"] = "child";
SelectorType["Descendant"] = "descendant";
SelectorType["Parent"] = "parent";
SelectorType["Sibling"] = "sibling";
SelectorType["ColumnCombinator"] = "column-combinator";
})(SelectorType || (SelectorType = {}));
/**
* Modes for ignore case.
*
* This could be updated to an enum, and the object is
* the current stand-in that will allow code to be updated
* without big changes.
*/
const IgnoreCaseMode = {
Unknown: null,
QuirksMode: "quirks",
IgnoreCase: true,
CaseSensitive: false,
};
var AttributeAction;
(function (AttributeAction) {
AttributeAction["Any"] = "any";
AttributeAction["Element"] = "element";
AttributeAction["End"] = "end";
AttributeAction["Equals"] = "equals";
AttributeAction["Exists"] = "exists";
AttributeAction["Hyphen"] = "hyphen";
AttributeAction["Not"] = "not";
AttributeAction["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 = new Map([
[126 /* Tilde */, AttributeAction.Element],
[94 /* Circumflex */, AttributeAction.Start],
[36 /* Dollar */, AttributeAction.End],
[42 /* Asterisk */, AttributeAction.Any],
[33 /* ExclamationMark */, AttributeAction.Not],
[124 /* Pipe */, AttributeAction.Hyphen],
]);
// Pseudos, whose data property is parsed as well.
const unpackPseudos = new Set([
"has",
"not",
"matches",
"is",
"where",
"host",
"host-context",
]);
/**
* Checks whether a specific selector is a traversal.
* This is useful eg. in swapping the order of elements that
* are not traversals.
*
* @param selector Selector to check.
*/
function isTraversal(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 = new Set(["contains", "icontains"]);
// Unescape function taken from https://github.com/jquery/sizzle/blob/master/src/sizzle.js#L152
function funescape(_, escaped, escapedWhitespace) {
const high = parseInt(escaped, 16) - 0x10000;
// NaN means non-codepoint
return high !== high || escapedWhitespace
? escaped
: high < 0
? // BMP codepoint
String.fromCharCode(high + 0x10000)
: // Supplemental Plane codepoint (surrogate pair)
String.fromCharCode((high >> 10) | 0xd800, (high & 0x3ff) | 0xdc00);
}
function unescapeCSS(str) {
return str.replace(reEscape, funescape);
}
function isQuote(c) {
return c === 39 /* SingleQuote */ || c === 34 /* DoubleQuote */;
}
function isWhitespace(c) {
return (c === 32 /* Space */ ||
c === 9 /* Tab */ ||
c === 10 /* NewLine */ ||
c === 12 /* FormFeed */ ||
c === 13 /* CarriageReturn */);
}
/**
* Parses `selector`, optionally with the passed `options`.
*
* @param selector Selector to parse.
* @param options Options for parsing.
* @returns Returns a two-dimensional array.
* The first dimension represents selectors separated by commas (eg. `sub1, sub2`),
* the second contains the relevant tokens for that selector.
*/
function parse$1(selector) {
const subselects = [];
const endIndex = parseSelector(subselects, `${selector}`, 0);
if (endIndex < selector.length) {
throw new Error(`Unmatched selector: ${selector.slice(endIndex)}`);
}
return subselects;
}
function parseSelector(subselects, selector, selectorIndex) {
let tokens = [];
function getName(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(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 /* LeftParenthesis */ &&
!isEscaped(selectorIndex)) {
counter++;
}
else if (selector.charCodeAt(selectorIndex) ===
41 /* RightParenthesis */ &&
!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 /* BackSlash */)
slashCount++;
return (slashCount & 1) === 1;
}
function ensureNotTraversal() {
if (tokens.length > 0 && isTraversal(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: getName(1),
namespace: null,
ignoreCase: "quirks",
});
}
/**
* We have finished parsing the current part of the selector.
*
* Remove descendant tokens at the end if they exist,
* and return the last index, so that parsing can be
* picked up from here.
*/
function finalizeSubselector() {
if (tokens.length &&
tokens[tokens.length - 1].type === SelectorType.Descendant) {
tokens.pop();
}
if (tokens.length === 0) {
throw new Error("Empty sub-selector");
}
subselects.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 /* Space */:
case 9 /* Tab */:
case 10 /* NewLine */:
case 12 /* FormFeed */:
case 13 /* CarriageReturn */: {
if (tokens.length === 0 ||
tokens[0].type !== SelectorType.Descendant) {
ensureNotTraversal();
tokens.push({ type: SelectorType.Descendant });
}
stripWhitespace(1);
break;
}
// Traversals
case 62 /* GreaterThan */: {
addTraversal(SelectorType.Child);
stripWhitespace(1);
break;
}
case 60 /* LessThan */: {
addTraversal(SelectorType.Parent);
stripWhitespace(1);
break;
}
case 126 /* Tilde */: {
addTraversal(SelectorType.Sibling);
stripWhitespace(1);
break;
}
case 43 /* Plus */: {
addTraversal(SelectorType.Adjacent);
stripWhitespace(1);
break;
}
// Special attribute selectors: .class, #id
case 46 /* Period */: {
addSpecialAttribute("class", AttributeAction.Element);
break;
}
case 35 /* Hash */: {
addSpecialAttribute("id", AttributeAction.Equals);
break;
}
case 91 /* LeftSquareBracket */: {
stripWhitespace(1);
// Determine attribute name and namespace
let name;
let namespace = null;
if (selector.charCodeAt(selectorIndex) === 124 /* Pipe */) {
// Equivalent to no namespace
name = getName(1);
}
else if (selector.startsWith("*|", selectorIndex)) {
namespace = "*";
name = getName(2);
}
else {
name = getName(0);
if (selector.charCodeAt(selectorIndex) === 124 /* Pipe */ &&
selector.charCodeAt(selectorIndex + 1) !==
61 /* Equal */) {
namespace = name;
name = getName(1);
}
}
stripWhitespace(0);
// Determine comparison operation
let action = AttributeAction.Exists;
const possibleAction = actionTypes.get(selector.charCodeAt(selectorIndex));
if (possibleAction) {
action = possibleAction;
if (selector.charCodeAt(selectorIndex + 1) !==
61 /* Equal */) {
throw new Error("Expected `=`");
}
stripWhitespace(2);
}
else if (selector.charCodeAt(selectorIndex) === 61 /* Equal */) {
action = AttributeAction.Equals;
stripWhitespace(1);
}
// Determine value
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(selector.charCodeAt(selectorIndex)) &&
selector.charCodeAt(selectorIndex) !==
93 /* RightSquareBracket */) ||
isEscaped(selectorIndex))) {
selectorIndex += 1;
}
value = unescapeCSS(selector.slice(valueStart, selectorIndex));
}
stripWhitespace(0);
// See if we have a force ignore flag
const forceIgnore = selector.charCodeAt(selectorIndex) | 0x20;
// If the forceIgnore flag is set (either `i` or `s`), use that value
if (forceIgnore === 115 /* LowerS */) {
ignoreCase = false;
stripWhitespace(1);
}
else if (forceIgnore === 105 /* LowerI */) {
ignoreCase = true;
stripWhitespace(1);
}
}
if (selector.charCodeAt(selectorIndex) !==
93 /* RightSquareBracket */) {
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 /* Colon */: {
if (selector.charCodeAt(selectorIndex + 1) === 58 /* Colon */) {
tokens.push({
type: SelectorType.PseudoElement,
name: getName(2).toLowerCase(),
data: selector.charCodeAt(selectorIndex) ===
40 /* LeftParenthesis */
? readValueWithParenthesis()
: null,
});
continue;
}
const name = getName(1).toLowerCase();
let data = null;
if (selector.charCodeAt(selectorIndex) ===
40 /* LeftParenthesis */) {
if (unpackPseudos.has(name)) {
if (isQuote(selector.charCodeAt(selectorIndex + 1))) {
throw new Error(`Pseudo-selector ${name} cannot be quoted`);
}
data = [];
selectorIndex = parseSelector(data, selector, selectorIndex + 1);
if (selector.charCodeAt(selectorIndex) !==
41 /* RightParenthesis */) {
throw new Error(`Missing closing parenthesis in :${name} (${selector})`);
}
selectorIndex += 1;
}
else {
data = readValueWithParenthesis();
if (stripQuotesFromPseudos.has(name)) {
const quot = data.charCodeAt(0);
if (quot === data.charCodeAt(data.length - 1) &&
isQuote(quot)) {
data = data.slice(1, -1);
}
}
data = unescapeCSS(data);
}
}
tokens.push({ type: SelectorType.Pseudo, name, data });
break;
}
case 44 /* Comma */: {
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;
// Remove leading whitespace
if (tokens.length === 0) {
stripWhitespace(0);
}
break;
}
let namespace = null;
let name;
if (firstChar === 42 /* Asterisk */) {
selectorIndex += 1;
name = "*";
}
else if (firstChar === 124 /* Pipe */) {
name = "";
if (selector.charCodeAt(selectorIndex + 1) === 124 /* Pipe */) {
addTraversal(SelectorType.ColumnCombinator);
stripWhitespace(2);
break;
}
}
else if (reName.test(selector.slice(selectorIndex))) {
name = getName(0);
}
else {
break loop;
}
if (selector.charCodeAt(selectorIndex) === 124 /* Pipe */ &&
selector.charCodeAt(selectorIndex + 1) !== 124 /* Pipe */) {
namespace = name;
if (selector.charCodeAt(selectorIndex + 1) ===
42 /* Asterisk */) {
name = "*";
selectorIndex += 2;
}
else {
name = getName(1);
}
}
tokens.push(name === "*"
? { type: SelectorType.Universal, namespace }
: { type: SelectorType.Tag, name, namespace });
}
}
}
finalizeSubselector();
return selectorIndex;
}
const attribValChars = ["\\", '"'];
const pseudoValChars = [...attribValChars, "(", ")"];
const charsToEscapeInAttributeValue = new Set(attribValChars.map((c) => c.charCodeAt(0)));
const charsToEscapeInPseudoValue = new Set(pseudoValChars.map((c) => c.charCodeAt(0)));
const charsToEscapeInName = new Set([
...pseudoValChars,
"~",
"^",
"$",
"*",
"+",
"!",
"|",
":",
"[",
"]",
" ",
".",
].map((c) => c.charCodeAt(0)));
/**
* Turns `selector` back into a string.
*
* @param selector Selector to stringify.
*/
function stringify(selector) {
return selector
.map((token) => token.map(stringifyToken).join(""))
.join(", ");
}
function stringifyToken(token, index, arr) {
switch (token.type) {
// Simple types
case SelectorType.Child:
return index === 0 ? "> " : " > ";
case SelectorType.Parent:
return index === 0 ? "< " : " < ";
case SelectorType.Sibling:
return index === 0 ? "~ " : " ~ ";
case SelectorType.Adjacent:
return index === 0 ? "+ " : " + ";
case SelectorType.Descendant:
return " ";
case SelectorType.ColumnCombinator:
return index === 0 ? "|| " : " || ";
case SelectorType.Universal:
// Return an empty string if the selector isn't needed.
return token.namespace === "*" &&
index + 1 < arr.length &&
"name" in arr[index + 1]
? ""
: `${getNamespace(token.namespace)}*`;
case SelectorType.Tag:
return getNamespacedName(token);
case SelectorType.PseudoElement:
return `::${escapeName(token.name, charsToEscapeInName)}${token.data === null
? ""
: `(${escapeName(token.data, charsToEscapeInPseudoValue)})`}`;
case SelectorType.Pseudo:
return `:${escapeName(token.name, charsToEscapeInName)}${token.data === null
? ""
: `(${typeof token.data === "string"
? escapeName(token.data, charsToEscapeInPseudoValue)
: stringify(token.data)})`}`;
case SelectorType.Attribute: {
if (token.name === "id" &&
token.action === AttributeAction.Equals &&
token.ignoreCase === "quirks" &&
!token.namespace) {
return `#${escapeName(token.value, charsToEscapeInName)}`;
}
if (token.name === "class" &&
token.action === AttributeAction.Element &&
token.ignoreCase === "quirks" &&
!token.namespace) {
return `.${escapeName(token.value, charsToEscapeInName)}`;
}
const name = getNamespacedName(token);
if (token.action === AttributeAction.Exists) {
return `[${name}]`;
}
return `[${name}${getActionValue(token.action)}="${escapeName(token.value, charsToEscapeInAttributeValue)}"${token.ignoreCase === null ? "" : token.ignoreCase ? " i" : " s"}]`;
}
}
}
function getActionValue(action) {
switch (action) {
case AttributeAction.Equals:
return "";
case AttributeAction.Element:
return "~";
case AttributeAction.Start:
return "^";
case AttributeAction.End:
return "$";
case AttributeAction.Any:
return "*";
case AttributeAction.Not:
return "!";
case AttributeAction.Hyphen:
return "|";
case AttributeAction.Exists:
throw new Error("Shouldn't be here");
}
}
function getNamespacedName(token) {
return `${getNamespace(token.namespace)}${escapeName(token.name, charsToEscapeInName)}`;
}
function getNamespace(namespace) {
return namespace !== null
? `${namespace === "*"
? "*"
: escapeName(namespace, charsToEscapeInName)}|`
: "";
}
function escapeName(str, charsToEscape) {
let lastIdx = 0;
let ret = "";
for (let i = 0; i < str.length; i++) {
if (charsToEscape.has(str.charCodeAt(i))) {
ret += `${str.slice(lastIdx, i)}\\${str.charAt(i)}`;
lastIdx = i + 1;
}
}
return ret.length > 0 ? ret + str.slice(lastIdx) : str;
}
var es = /*#__PURE__*/Object.freeze({
__proto__: null,
isTraversal: isTraversal,
parse: parse$1,
stringify: stringify,
get SelectorType () { return SelectorType; },
IgnoreCaseMode: IgnoreCaseMode,
get AttributeAction () { return AttributeAction; }
});
var boolbase = {
trueFunc: function trueFunc(){
return true;
},
falseFunc: function falseFunc(){
return false;
}
};
var css_what_1 = /*@__PURE__*/getAugmentedNamespace(es);
var sort = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.isTraversal = void 0;
var procedure = new Map([
[css_what_1.SelectorType.Universal, 50],
[css_what_1.SelectorType.Tag, 30],
[css_what_1.SelectorType.Attribute, 1],
[css_what_1.SelectorType.Pseudo, 0],
]);
function isTraversal(token) {
return !procedure.has(token.type);
}
exports.isTraversal = isTraversal;
var attributes = new Map([
[css_what_1.AttributeAction.Exists, 10],
[css_what_1.AttributeAction.Equals, 8],
[css_what_1.AttributeAction.Not, 7],
[css_what_1.AttributeAction.Start, 6],
[css_what_1.AttributeAction.End, 6],
[css_what_1.AttributeAction.Any, 5],
]);
/**
* Sort the parts of the passed selector,
* as there is potential for optimization
* (some types of selectors are faster than others)
*
* @param arr Selector to sort
*/
function sortByProcedure(arr) {
var procs = arr.map(getProcedure);
for (var i = 1; i < arr.length; i++) {
var procNew = procs[i];
if (procNew < 0)
continue;
for (var j = i - 1; j >= 0 && procNew < procs[j]; j--) {
var token = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = token;
procs[j + 1] = procs[j];
procs[j] = procNew;
}
}
}
exports.default = sortByProcedure;
function getProcedure(token) {
var _a, _b;
var proc = (_a = procedure.get(token.type)) !== null && _a !== void 0 ? _a : -1;
if (token.type === css_what_1.SelectorType.Attribute) {
proc = (_b = attributes.get(token.action)) !== null && _b !== void 0 ? _b : 4;
if (token.action === css_what_1.AttributeAction.Equals && token.name === "id") {
// Prefer ID selectors (eg. #ID)
proc = 9;
}
if (token.ignoreCase) {
/*
* IgnoreCase adds some overhead, prefer "normal" token
* this is a binary operation, to ensure it's still an int
*/
proc >>= 1;
}
}
else if (token.type === css_what_1.SelectorType.Pseudo) {
if (!token.data) {
proc = 3;
}
else if (token.name === "has" || token.name === "contains") {
proc = 0; // Expensive in any case
}
else if (Array.isArray(token.data)) {
// Eg. :matches, :not
proc = Math.min.apply(Math, token.data.map(function (d) { return Math.min.apply(Math, d.map(getProcedure)); }));
// If we have traversals, try to avoid executing this selector
if (proc < 0) {
proc = 0;
}
}
else {
proc = 2;
}
}
return proc;
}
});
var attributes = createCommonjsModule(function (module, exports) {
var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.attributeRules = void 0;
var boolbase_1 = __importDefault(boolbase);
/**
* All reserved characters in a regex, used for escaping.
*
* Taken from XRegExp, (c) 2007-2020 Steven Levithan under the MIT license
* https://github.com/slevithan/xregexp/blob/95eeebeb8fac8754d54eafe2b4743661ac1cf028/src/xregexp.js#L794
*/
var reChars = /[-[\]{}()*+?.,\\^$|#\s]/g;
function escapeRegex(value) {
return value.replace(reChars, "\\$&");
}
/**
* Attributes that are case-insensitive in HTML.
*
* @private
* @see https://html.spec.whatwg.org/multipage/semantics-other.html#case-sensitivity-of-selectors
*/
var caseInsensitiveAttributes = 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);
}
/**
* Attribute selectors
*/
exports.attributeRules = {
equals: function (next, data, options) {
var adapter = options.adapter;
var name = data.name;
var value = data.value;
if (shouldIgnoreCase(data, options)) {
value = value.toLowerCase();
return function (elem) {
var attr = adapter.getAttributeValue(elem, name);
return (attr != null &&
attr.length === value.length &&
attr.toLowerCase() === value &&
next(elem));
};
}
return function (elem) {
return adapter.getAttributeValue(elem, name) === value && next(elem);
};
},
hyphen: function (next, data, options) {
var adapter = options.adapter;
var name = data.name;
var value = data.value;
var len = value.length;
if (shouldIgnoreCase(data, options)) {
value = value.toLowerCase();
return function hyphenIC(elem) {
var attr = adapter.getAttributeValue(elem, name);
return (attr != null &&
(attr.length === len || attr.charAt(len) === "-") &&
attr.substr(0, len).toLowerCase() === value &&
next(elem));
};
}
return function hyphen(elem) {
var attr = adapter.getAttributeValue(elem, name);
return (attr != null &&
(attr.length === len || attr.charAt(len) === "-") &&
attr.substr(0, len) === value &&
next(elem));
};
},
element: function (next, data, options) {
var adapter = options.adapter;
var name = data.name, value = data.value;
if (/\s/.test(value)) {
return boolbase_1.default.falseFunc;
}
var regex = new RegExp("(?:^|\\s)".concat(escapeRegex(value), "(?:$|\\s)"), shouldIgnoreCase(data, options) ? "i" : "");
return function element(elem) {
var attr = adapter.getAttributeValue(elem, name);
return (attr != null &&
attr.length >= value.length &&
regex.test(attr) &&
next(elem));
};
},
exists: function (next, _a, _b) {
var name = _a.name;
var adapter = _b.adapter;
return function (elem) { return adapter.hasAttrib(elem, name) && next(elem); };
},
start: function (next, data, options) {
var adapter = options.adapter;
var name = data.name;
var value = data.value;
var len = value.length;
if (len === 0) {
return boolbase_1.default.falseFunc;
}
if (shouldIgnoreCase(data, options)) {
value = value.toLowerCase();
return function (elem) {
var attr = adapter.getAttributeValue(elem, name);
return (attr != null &&
attr.length >= len &&
attr.substr(0, len).toLowerCase() === value &&
next(elem));
};
}
return function (elem) {
var _a;
return !!((_a = adapter.getAttributeValue(elem, name)) === null || _a === void 0 ? void 0 : _a.startsWith(value)) &&
next(elem);
};
},
end: function (next, data, options) {
var adapter = options.adapter;
var name = data.name;
var value = data.value;
var len = -value.length;
if (len === 0) {
return boolbase_1.default.falseFunc;
}
if (shouldIgnoreCase(data, options)) {
value = value.toLowerCase();
return function (elem) {
var _a;
return ((_a = adapter
.getAttributeValue(elem, name)) === null || _a === void 0 ? void 0 : _a.substr(len).toLowerCase()) === value && next(elem);
};
}
return function (elem) {
var _a;
return !!((_a = adapter.getAttributeValue(elem, name)) === null || _a === void 0 ? void 0 : _a.endsWith(value)) &&
next(elem);
};
},
any: function (next, data, options) {
var adapter = options.adapter;
var name = data.name, value = data.value;
if (value === "") {
return boolbase_1.default.falseFunc;
}
if (shouldIgnoreCase(data, options)) {
var regex_1 = new RegExp(escapeRegex(value), "i");
return function anyIC(elem) {
var attr = adapter.getAttributeValue(elem, name);
return (attr != null &&
attr.length >= value.length &&
regex_1.test(attr) &&
next(elem));
};
}
return function (elem) {
var _a;
return !!((_a = adapter.getAttributeValue(elem, name)) === null || _a === void 0 ? void 0 : _a.includes(value)) &&
next(elem);
};
},
not: function (next, data, options) {
var adapter = options.adapter;
var name = data.name;
var value = data.value;
if (value === "") {
return function (elem) {
return !!adapter.getAttributeValue(elem, name) && next(elem);
};
}
else if (shouldIgnoreCase(data, options)) {
value = value.toLowerCase();
return function (elem) {
var attr = adapter.getAttributeValue(elem, name);
return ((attr == null ||
attr.length !== value.length ||
attr.toLowerCase() !== value) &&
next(elem));
};
}
return function (elem) {
return adapter.getAttributeValue(elem, name) !== value && next(elem);
};
},
};
});
var parse_1 = createCommonjsModule(function (module, exports) {
// Following http://www.w3.org/TR/css3-selectors/#nth-child-pseudo
Object.defineProperty(exports, "__esModule", { value: true });
exports.parse = void 0;
// Whitespace as per https://www.w3.org/TR/selectors-3/#lex is " \t\r\n\f"
var whitespace = new Set([9, 10, 12, 13, 32]);
var ZERO = "0".charCodeAt(0);
var NINE = "9".charCodeAt(0);
/**
* Parses an expression.
*
* @throws An `Error` if parsing fails.
* @returns An array containing the integer step size and the integer offset of the nth rule.
* @example nthCheck.parse("2n+3"); // returns [2, 3]
*/
function parse(formula) {
formula = formula.trim().toLowerCase();
if (formula === "even") {
return [2, 0];
}
else if (formula === "odd") {
return [2, 1];
}
// Parse [ ['-'|'+']? INTEGER? {N} [ S* ['-'|'+'] S* INTEGER ]?
var idx = 0;
var a = 0;
var sign = readSign();
var 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;
}
}
// Throw if there is anything else
if (number === null || idx < formula.length) {
throw new Error("n-th rule couldn't be parsed ('".concat(formula, "')"));
}
return [a, sign * number];
function readSign() {
if (formula.charAt(idx) === "-") {
idx++;
return -1;
}
if (formula.charAt(idx) === "+") {
idx++;
}
return 1;
}
function readNumber() {
var start = idx;
var value = 0;
while (idx < formula.length &&
formula.charCodeAt(idx) >= ZERO &&
formula.charCodeAt(idx) <= NINE) {
value = value * 10 + (formula.charCodeAt(idx) - ZERO);
idx++;
}
// Return `null` if we didn't read anything.
return idx === start ? null : value;
}
function skipWhitespace() {
while (idx < formula.length &&
whitespace.has(formula.charCodeAt(idx))) {
idx++;
}
}
}
exports.parse = parse;
});
var compile_1$1 = createCommonjsModule(function (module, exports) {
var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.generate = exports.compile = void 0;
var boolbase_1 = __importDefault(boolbase);
/**
* Returns a function that checks if an elements index matches the given rule
* highly optimized to return the fastest solution.
*
* @param parsed A tuple [a, b], as returned by `parse`.
* @returns A highly optimized function that returns whether an index matches the nth-check.
* @example
*
* ```js
* const check = nthCheck.compile([2, 3]);
*
* check(0); // `false`
* check(1); // `false`
* check(2); // `true`
* check(3); // `false`
* check(4); // `true`
* check(5); // `false`
* check(6); // `true`
* ```
*/
function compile(parsed) {
var a = parsed[0];
// Subtract 1 from `b`, to convert from one- to zero-indexed.
var b = parsed[1] - 1;
/*
* When `b <= 0`, `a * n` won't be lead to any matches for `a < 0`.
* Besides, the specification states that no elements are
* matched when `a` and `b` are 0.
*
* `b < 0` here as we subtracted 1 from `b` above.
*/
if (b < 0 && a <= 0)
return boolbase_1.default.falseFunc;
// When `a` is in the range -1..1, it matches any element (so only `b` is checked).
if (a === -1)
return function (index) { return index <= b; };
if (a === 0)
return function (index) { return index === b; };
// When `b <= 0` and `a === 1`, they match any element.
if (a === 1)
return b < 0 ? boolbase_1.default.trueFunc : function (index) { return index >= b; };
/*
* Otherwise, modulo can be used to check if there is a match.
*
* Modulo doesn't care about the sign, so let's use `a`s absolute value.
*/
var absA = Math.abs(a);
// Get `b mod a`, + a if this is negative.
var bMod = ((b % absA) + absA) % absA;
return a > 1
? function (index) { return index >= b && index % absA === bMod; }
: function (index) { return index <= b && index % absA === bMod; };
}
exports.compile = compile;
/**
* Returns a function that produces a monotonously increasing sequence of indices.
*
* If the sequence has an end, the returned function will return `null` after
* the last index in the sequence.
*
* @param parsed A tuple [a, b], as returned by `parse`.
* @returns A function that produces a sequence of indices.
* @example <caption>Always increasing (2n+3)</caption>
*
* ```js
* const gen = nthCheck.generate([2, 3])
*
* gen() // `1`
* gen() // `3`
* gen() // `5`
* gen() // `8`
* gen() // `11`
* ```
*
* @example <caption>With end value (-2n+10)</caption>
*
* ```js
*
* const gen = nthCheck.generate([-2, 5]);
*
* gen() // 0
* gen() // 2
* gen() // 4
* gen() // null
* ```
*/
function generate(parsed) {
var a = parsed[0];
// Subtract 1 from `b`, to convert from one- to zero-indexed.
var b = parsed[1] - 1;
var n = 0;
// Make sure to always return an increasing sequence
if (a < 0) {
var aPos_1 = -a;
// Get `b mod a`
var minValue_1 = ((b % aPos_1) + aPos_1) % aPos_1;
return function () {
var val = minValue_1 + aPos_1 * n++;
return val > b ? null : val;
};
}
if (a === 0)
return b < 0
? // There are no result — always return `null`
function () { return null; }
: // Return `b` exactly once
function () { return (n++ === 0 ? b : null); };
if (b < 0) {
b += a * Math.ceil(-b / a);
}
return function () { return a * n++ + b; };
}
exports.generate = generate;
});
var parse_js_1 = parse_1;
var compile_js_1 = compile_1$1;
var lib$4 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.sequence = exports.generate = exports.compile = exports.parse = void 0;
Object.defineProperty(exports, "parse", { enumerable: true, get: function () { return parse_js_1.parse; } });
Object.defineProperty(exports, "compile", { enumerable: true, get: function () { return compile_js_1.compile; } });
Object.defineProperty(exports, "generate", { enumerable: true, get: function () { return compile_js_1.generate; } });
/**
* Parses and compiles a formula to a highly optimized function.
* Combination of {@link parse} and {@link compile}.
*
* If the formula doesn't match any elements,
* it returns [`boolbase`](https://github.com/fb55/boolbase)'s `falseFunc`.
* Otherwise, a function accepting an _index_ is returned, which returns
* whether or not the passed _index_ matches the formula.
*
* Note: The nth-rule starts counting at `1`, the returned function at `0`.
*
* @param formula The formula to compile.
* @example
* const check = nthCheck("2n+3");
*
* check(0); // `false`
* check(1); // `false`
* check(2); // `true`
* check(3); // `false`
* check(4); // `true`
* check(5); // `false`
* check(6); // `true`
*/
function nthCheck(formula) {
return (0, compile_js_1.compile)((0, parse_js_1.parse)(formula));
}
exports.default = nthCheck;
/**
* Parses and compiles a formula to a generator that produces a sequence of indices.
* Combination of {@link parse} and {@link generate}.
*
* @param formula The formula to compile.
* @returns A function that produces a sequence of indices.
* @example <caption>Always increasing</caption>
*
* ```js
* const gen = nthCheck.sequence('2n+3')
*
* gen() // `1`
* gen() // `3`
* gen() // `5`
* gen() // `8`
* gen() // `11`
* ```
*
* @example <caption>With end value</caption>
*
* ```js
*
* const gen = nthCheck.sequence('-2n+5');
*
* gen() // 0
* gen() // 2
* gen() // 4
* gen() // null
* ```
*/
function sequence(formula) {
return (0, compile_js_1.generate)((0, parse_js_1.parse)(formula));
}
exports.sequence = sequence;
});
var require$$0$1 = lib$4;
var filters = createCommonjsModule(function (module, exports) {
var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.filters = void 0;
var nth_check_1 = __importDefault(require$$0$1);
var boolbase_1 = __importDefault(boolbase);
function getChildFunc(next, adapter) {
return function (elem) {
var parent = adapter.getParent(elem);
return parent != null && adapter.isTag(parent) && next(elem);
};
}
exports.filters = {
contains: function (next, text, _a) {
var adapter = _a.adapter;
return function contains(elem) {
return next(elem) && adapter.getText(elem).includes(text);
};
},
icontains: function (next, text, _a) {
var adapter = _a.adapter;
var itext = text.toLowerCase();
return function icontains(elem) {
return (next(elem) &&
adapter.getText(elem).toLowerCase().includes(itext));
};
},
// Location specific methods
"nth-child": function (next, rule, _a) {
var adapter = _a.adapter, equals = _a.equals;
var func = (0, nth_check_1.default)(rule);
if (func === boolbase_1.default.falseFunc)
return boolbase_1.default.falseFunc;
if (func === boolbase_1.default.trueFunc)
return getChildFunc(next, adapter);
return function nthChild(elem) {
var siblings = adapter.getSiblings(elem);
var pos = 0;
for (var i = 0; i < siblings.length; i++) {
if (equals(elem, siblings[i]))
break;
if (adapter.isTag(siblings[i])) {
pos++;
}
}
return func(pos) && next(elem);
};
},
"nth-last-child": function (next, rule, _a) {
var adapter = _a.adapter, equals = _a.equals;
var func = (0, nth_check_1.default)(rule);
if (func === boolbase_1.default.falseFunc)
return boolbase_1.default.falseFunc;
if (func === boolbase_1.default.trueFunc)
return getChildFunc(next, adapter);
return function nthLastChild(elem) {
var siblings = adapter.getSiblings(elem);
var pos = 0;
for (var i = siblings.length - 1; i >= 0; i--) {
if (equals(elem, siblings[i]))
break;
if (adapter.isTag(siblings[i])) {
pos++;
}
}
return func(pos) && next(elem);
};
},
"nth-of-type": function (next, rule, _a) {
var adapter = _a.adapter, equals = _a.equals;
var func = (0, nth_check_1.default)(rule);
if (func === boolbase_1.default.falseFunc)
return boolbase_1.default.falseFunc;
if (func === boolbase_1.default.trueFunc)
return getChildFunc(next, adapter);
return function nthOfType(elem) {
var siblings = adapter.getSiblings(elem);
var pos = 0;
for (var i = 0; i < siblings.length; i++) {
var currentSibling = siblings[i];
if (equals(elem, currentSibling))
break;
if (adapter.isTag(currentSibling) &&
adapter.getName(currentSibling) === adapter.getName(elem)) {
pos++;
}
}
return func(pos) && next(elem);
};
},
"nth-last-of-type": function (next, rule, _a) {
var adapter = _a.adapter, equals = _a.equals;
var func = (0, nth_check_1.default)(rule);
if (func === boolbase_1.default.falseFunc)
return boolbase_1.default.falseFunc;
if (func === boolbase_1.default.trueFunc)
return getChildFunc(next, adapter);
return function nthLastOfType(elem) {
var siblings = adapter.getSiblings(elem);
var pos = 0;
for (var i = siblings.length - 1; i >= 0; i--) {
var currentSibling = siblings[i];
if (equals(elem, currentSibling))
break;
if (adapter.isTag(currentSibling) &&
adapter.getName(currentSibling) === adapter.getName(elem)) {
pos++;
}
}
return func(pos) && next(elem);
};
},
// TODO determine the actual root element
root: function (next, _rule, _a) {
var adapter = _a.adapter;
return function (elem) {
var parent = adapter.getParent(elem);
return (parent == null || !adapter.isTag(parent)) && next(elem);
};
},
scope: function (next, rule, options, context) {
var equals = options.equals;
if (!context || context.length === 0) {
// Equivalent to :root
return exports.filters["root"](next, rule, options);
}
if (context.length === 1) {
// NOTE: can't be unpacked, as :has uses this for side-effects
return function (elem) { return equals(context[0], elem) && next(elem); };
}
return function (elem) { return context.includes(elem) && next(elem); };
},
hover: dynamicStatePseudo("isHovered"),
visited: dynamicStatePseudo("isVisited"),
active: dynamicStatePseudo("isActive"),
};
/**
* Dynamic state pseudos. These depend on optional Adapter methods.
*
* @param name The name of the adapter method to call.
* @returns Pseudo for the `filters` object.
*/
function dynamicStatePseudo(name) {
return function dynamicPseudo(next, _rule, _a) {
var adapter = _a.adapter;
var func = adapter[name];
if (typeof func !== "function") {
return boolbase_1.default.falseFunc;
}
return function active(elem) {
return func(elem) && next(elem);
};
};
}
});
var pseudos = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyPseudoArgs = exports.pseudos = void 0;
// While filters are precompiled, pseudos get called when they are needed
exports.pseudos = {
empty: function (elem, _a) {
var adapter = _a.adapter;
return !adapter.getChildren(elem).some(function (elem) {
// FIXME: `getText` call is potentially expensive.
return adapter.isTag(elem) || adapter.getText(elem) !== "";
});
},
"first-child": function (elem, _a) {
var adapter = _a.adapter, equals = _a.equals;
if (adapter.prevElementSibling) {
return adapter.prevElementSibling(elem) == null;
}
var firstChild = adapter
.getSiblings(elem)
.find(function (elem) { return adapter.isTag(elem); });
return firstChild != null && equals(elem, firstChild);
},
"last-child": function (elem, _a) {
var adapter = _a.adapter, equals = _a.equals;
var siblings = adapter.getSiblings(elem);
for (var i = siblings.length - 1; i >= 0; i--) {
if (equals(elem, siblings[i]))
return true;
if (adapter.isTag(siblings[i]))
break;
}
return false;
},
"first-of-type": function (elem, _a) {
var adapter = _a.adapter, equals = _a.equals;
var siblings = adapter.getSiblings(elem);
var elemName = adapter.getName(elem);
for (var i = 0; i < siblings.length; i++) {
var currentSibling = siblings[i];
if (equals(elem, currentSibling))
return true;
if (adapter.isTag(currentSibling) &&
adapter.getName(currentSibling) === elemName) {
break;
}
}
return false;
},
"last-of-type": function (elem, _a) {
var adapter = _a.adapter, equals = _a.equals;
var siblings = adapter.getSiblings(elem);
var elemName = adapter.getName(elem);
for (var i = siblings.length - 1; i >= 0; i--) {
var currentSibling = siblings[i];
if (equals(elem, currentSibling))
return true;
if (adapter.isTag(currentSibling) &&
adapter.getName(currentSibling) === elemName) {
break;
}
}
return false;
},
"only-of-type": function (elem, _a) {
var adapter = _a.adapter, equals = _a.equals;
var elemName = adapter.getName(elem);
return adapter
.getSiblings(elem)
.every(function (sibling) {
return equals(elem, sibling) ||
!adapter.isTag(sibling) ||
adapter.getName(sibling) !== elemName;
});
},
"only-child": function (elem, _a) {
var adapter = _a.adapter, equals = _a.equals;
return adapter
.getSiblings(elem)
.every(function (sibling) { return equals(elem, sibling) || !adapter.isTag(sibling); });
},
};
function verifyPseudoArgs(func, name, subselect, argIndex) {
if (subselect === null) {
if (func.length > argIndex) {
throw new Error("Pseudo-class :".concat(name, " requires an argument"));
}
}
else if (func.length === argIndex) {
throw new Error("Pseudo-class :".concat(name, " doesn't have any arguments"));
}
}
exports.verifyPseudoArgs = verifyPseudoArgs;
});
var aliases = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.aliases = void 0;
/**
* Aliases are pseudos that are expressed as selectors.
*/
exports.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(\n :is(button, input, select, textarea, optgroup, option)[disabled],\n optgroup[disabled] > option,\n fieldset[disabled]:not(fieldset[disabled] legend:first-of-type *)\n )",
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])",
};
});
var subselects = createCommonjsModule(function (module, exports) {
var __spreadArray = (commonjsGlobal && commonjsGlobal.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.subselects = exports.getNextSiblings = exports.ensureIsTag = exports.PLACEHOLDER_ELEMENT = void 0;
var boolbase_1 = __importDefault(boolbase);
/** Used as a placeholder for :has. Will be replaced with the actual element. */
exports.PLACEHOLDER_ELEMENT = {};
function ensureIsTag(next, adapter) {
if (next === boolbase_1.default.falseFunc)
return boolbase_1.default.falseFunc;
return function (elem) { return adapter.isTag(elem) && next(elem); };
}
exports.ensureIsTag = ensureIsTag;
function getNextSiblings(elem, adapter) {
var siblings = adapter.getSiblings(elem);
if (siblings.length <= 1)
return [];
var elemIndex = siblings.indexOf(elem);
if (elemIndex < 0 || elemIndex === siblings.length - 1)
return [];
return siblings.slice(elemIndex + 1).filter(adapter.isTag);
}
exports.getNextSiblings = getNextSiblings;
function copyOptions(options) {
// Not copied: context, rootFunc
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,
};
}
var is = function (next, token, options, context, compileToken) {
var func = compileToken(token, copyOptions(options), context);
return func === boolbase_1.default.trueFunc
? next
: func === boolbase_1.default.falseFunc
? boolbase_1.default.falseFunc
: function (elem) { return func(elem) && next(elem); };
};
/*
* :not, :has, :is, :matches and :where have to compile selectors
* doing this in src/pseudos.ts would lead to circular dependencies,
* so we add them here
*/
exports.subselects = {
is: is,
/**
* `:matches` and `:where` are aliases for `:is`.
*/
matches: is,
where: is,
not: function (next, token, options, context, compileToken) {
var func = compileToken(token, copyOptions(options), context);
return func === boolbase_1.default.falseFunc
? next
: func === boolbase_1.default.trueFunc
? boolbase_1.default.falseFunc
: function (elem) { return !func(elem) && next(elem); };
},
has: function (next, subselect, options, _context, compileToken) {
var adapter = options.adapter;
var opts = copyOptions(options);
opts.relativeSelector = true;
var context = subselect.some(function (s) { return s.some(sort.isTraversal); })
? // Used as a placeholder. Will be replaced with the actual element.
[exports.PLACEHOLDER_ELEMENT]
: undefined;
var compiled = compileToken(subselect, opts, context);
if (compiled === boolbase_1.default.falseFunc)
return boolbase_1.default.falseFunc;
var hasElement = ensureIsTag(compiled, adapter);
// If `compiled` is `trueFunc`, we can skip this.
if (context && compiled !== boolbase_1.default.trueFunc) {
/*
* `shouldTestNextSiblings` will only be true if the query starts with
* a traversal (sibling or adjacent). That means we will always have a context.
*/
var _a = compiled.shouldTestNextSiblings, shouldTestNextSiblings_1 = _a === void 0 ? false : _a;
return function (elem) {
if (!next(elem))
return false;
context[0] = elem;
var childs = adapter.getChildren(elem);
var nextElements = shouldTestNextSiblings_1
? __spreadArray(__spreadArray([], childs, true), getNextSiblings(elem, adapter), true) : childs;
return adapter.existsOne(hasElement, nextElements);
};
}
return function (elem) {
return next(elem) &&
adapter.existsOne(hasElement, adapter.getChildren(elem));
};
},
};
});
var pseudoSelectors = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.compilePseudoSelector = exports.aliases = exports.pseudos = exports.filters = void 0;
Object.defineProperty(exports, "filters", { enumerable: true, get: function () { return filters.filters; } });
Object.defineProperty(exports, "pseudos", { enumerable: true, get: function () { return pseudos.pseudos; } });
Object.defineProperty(exports, "aliases", { enumerable: true, get: function () { return aliases.aliases; } });
function compilePseudoSelector(next, selector, options, context, compileToken) {
var _a;
var name = selector.name, data = selector.data;
if (Array.isArray(data)) {
if (!(name in subselects.subselects)) {
throw new Error("Unknown pseudo-class :".concat(name, "(").concat(data, ")"));
}
return subselects.subselects[name](next, data, options, context, compileToken);
}
var userPseudo = (_a = options.pseudos) === null || _a === void 0 ? void 0 : _a[name];
var stringPseudo = typeof userPseudo === "string" ? userPseudo : aliases.aliases[name];
if (typeof stringPseudo === "string") {
if (data != null) {
throw new Error("Pseudo ".concat(name, " doesn't have any arguments"));
}
// The alias has to be parsed here, to make sure options are respected.
var alias = (0, css_what_1.parse)(stringPseudo);
return subselects.subselects["is"](next, alias, options, context, compileToken);
}
if (typeof userPseudo === "function") {
(0, pseudos.verifyPseudoArgs)(userPseudo, name, data, 1);
return function (elem) { return userPseudo(elem, data) && next(elem); };
}
if (name in filters.filters) {
return filters.filters[name](next, data, options, context);
}
if (name in pseudos.pseudos) {
var pseudo_1 = pseudos.pseudos[name];
(0, pseudos.verifyPseudoArgs)(pseudo_1, name, data, 2);
return function (elem) { return pseudo_1(elem, options, data) && next(elem); };
}
throw new Error("Unknown pseudo-class :".concat(name));
}
exports.compilePseudoSelector = compilePseudoSelector;
});
var general = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.compileGeneralSelector = void 0;
function getElementParent(node, adapter) {
var parent = adapter.getParent(node);
if (parent && adapter.isTag(parent)) {
return parent;
}
return null;
}
/*
* All available rules
*/
function compileGeneralSelector(next, selector, options, context, compileToken) {
var adapter = options.adapter, equals = options.equals;
switch (selector.type) {
case css_what_1.SelectorType.PseudoElement: {
throw new Error("Pseudo-elements are not supported by css-select");
}
case css_what_1.SelectorType.ColumnCombinator: {
throw new Error("Column combinators are not yet supported by css-select");
}
case css_what_1.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 attributes.attributeRules[selector.action](next, selector, options);
}
case css_what_1.SelectorType.Pseudo: {
return (0, pseudoSelectors.compilePseudoSelector)(next, selector, options, context, compileToken);
}
// Tags
case css_what_1.SelectorType.Tag: {
if (selector.namespace != null) {
throw new Error("Namespaced tag names are not yet supported by css-select");
}
var name_1 = selector.name;
if (!options.xmlMode || options.lowerCaseTags) {
name_1 = name_1.toLowerCase();
}
return function tag(elem) {
return adapter.getName(elem) === name_1 && next(elem);
};
}
// Traversal
case css_what_1.SelectorType.Descendant: {
if (options.cacheResults === false ||
typeof WeakSet === "undefined") {
return function descendant(elem) {
var current = elem;
while ((current = getElementParent(current, adapter))) {
if (next(current)) {
return true;
}
}
return false;
};
}
// @ts-expect-error `ElementNode` is not extending object
var isFalseCache_1 = new WeakSet();
return function cachedDescendant(elem) {
var current = elem;
while ((current = getElementParent(current, adapter))) {
if (!isFalseCache_1.has(current)) {
if (adapter.isTag(current) && next(current)) {
return true;
}
isFalseCache_1.add(current);
}
}
return false;
};
}
case "_flexibleDescendant": {
// Include element itself, only used while querying an array
return function flexibleDescendant(elem) {
var current = elem;
do {
if (next(current))
return true;
} while ((current = getElementParent(current, adapter)));
return false;
};
}
case css_what_1.SelectorType.Parent: {
return function parent(elem) {
return adapter
.getChildren(elem)
.some(function (elem) { return adapter.isTag(elem) && next(elem); });
};
}
case css_what_1.SelectorType.Child: {
return function child(elem) {
var parent = adapter.getParent(elem);
return parent != null && adapter.isTag(parent) && next(parent);
};
}
case css_what_1.SelectorType.Sibling: {
return function sibling(elem) {
var siblings = adapter.getSiblings(elem);
for (var i = 0; i < siblings.length; i++) {
var currentSibling = siblings[i];
if (equals(elem, currentSibling))
break;
if (adapter.isTag(currentSibling) && next(currentSibling)) {
return true;
}
}
return false;
};
}
case css_what_1.SelectorType.Adjacent: {
if (adapter.prevElementSibling) {
return function adjacent(elem) {
var previous = adapter.prevElementSibling(elem);
return previous != null && next(previous);
};
}
return function adjacent(elem) {
var siblings = adapter.getSiblings(elem);
var lastElement;
for (var i = 0; i < siblings.length; i++) {
var currentSibling = siblings[i];
if (equals(elem, currentSibling))
break;
if (adapter.isTag(currentSibling)) {
lastElement = currentSibling;
}
}
return !!lastElement && next(lastElement);
};
}
case css_what_1.SelectorType.Universal: {
if (selector.namespace != null && selector.namespace !== "*") {
throw new Error("Namespaced universal selectors are not yet supported by css-select");
}
return next;
}
}
}
exports.compileGeneralSelector = compileGeneralSelector;
});
var compile_1 = createCommonjsModule(function (module, exports) {
var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (commonjsGlobal && commonjsGlobal.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (commonjsGlobal && commonjsGlobal.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.compileToken = exports.compileUnsafe = exports.compile = void 0;
var boolbase_1 = __importDefault(boolbase);
var sort_js_1 = __importStar(sort);
/**
* Compiles a selector to an executable function.
*
* @param selector Selector to compile.
* @param options Compilation options.
* @param context Optional context for the selector.
*/
function compile(selector, options, context) {
var next = compileUnsafe(selector, options, context);
return (0, subselects.ensureIsTag)(next, options.adapter);
}
exports.compile = compile;
function compileUnsafe(selector, options, context) {
var token = typeof selector === "string" ? (0, css_what_1.parse)(selector) : selector;
return compileToken(token, options, context);
}
exports.compileUnsafe = compileUnsafe;
function includesScopePseudo(t) {
return (t.type === css_what_1.SelectorType.Pseudo &&
(t.name === "scope" ||
(Array.isArray(t.data) &&
t.data.some(function (data) { return data.some(includesScopePseudo); }))));
}
var DESCENDANT_TOKEN = { type: css_what_1.SelectorType.Descendant };
var FLEXIBLE_DESCENDANT_TOKEN = {
type: "_flexibleDescendant",
};
var SCOPE_TOKEN = {
type: css_what_1.SelectorType.Pseudo,
name: "scope",
data: null,
};
/*
* CSS 4 Spec (Draft): 3.4.1. Absolutizing a Relative Selector
* http://www.w3.org/TR/selectors4/#absolutizing
*/
function absolutize(token, _a, context) {
var adapter = _a.adapter;
// TODO Use better check if the context is a document
var hasContext = !!(context === null || context === void 0 ? void 0 : context.every(function (e) {
var parent = adapter.isTag(e) && adapter.getParent(e);
return e === subselects.PLACEHOLDER_ELEMENT || (parent && adapter.isTag(parent));
}));
for (var _i = 0, token_1 = token; _i < token_1.length; _i++) {
var t = token_1[_i];
if (t.length > 0 &&
(0, sort_js_1.isTraversal)(t[0]) &&
t[0].type !== css_what_1.SelectorType.Descendant) ;
else if (hasContext && !t.some(includesScopePseudo)) {
t.unshift(DESCENDANT_TOKEN);
}
else {
continue;
}
t.unshift(SCOPE_TOKEN);
}
}
function compileToken(token, options, context) {
var _a;
token.forEach(sort_js_1.default);
context = (_a = options.context) !== null && _a !== void 0 ? _a : context;
var isArrayContext = Array.isArray(context);
var finalContext = context && (Array.isArray(context) ? context : [context]);
// Check if the selector is relative
if (options.relativeSelector !== false) {
absolutize(token, options, finalContext);
}
else if (token.some(function (t) { return t.length > 0 && (0, sort_js_1.isTraversal)(t[0]); })) {
throw new Error("Relative selectors are not allowed when the `relativeSelector` option is disabled");
}
var shouldTestNextSiblings = false;
var query = token
.map(function (rules) {
if (rules.length >= 2) {
var first = rules[0], second = rules[1];
if (first.type !== css_what_1.SelectorType.Pseudo ||
first.name !== "scope") ;
else if (isArrayContext &&
second.type === css_what_1.SelectorType.Descendant) {
rules[1] = FLEXIBLE_DESCENDANT_TOKEN;
}
else if (second.type === css_what_1.SelectorType.Adjacent ||
second.type === css_what_1.SelectorType.Sibling) {
shouldTestNextSiblings = true;
}
}
return compileRules(rules, options, finalContext);
})
.reduce(reduceRules, boolbase_1.default.falseFunc);
query.shouldTestNextSiblings = shouldTestNextSiblings;
return query;
}
exports.compileToken = compileToken;
function compileRules(rules, options, context) {
var _a;
return rules.reduce(function (previous, rule) {
return previous === boolbase_1.default.falseFunc
? boolbase_1.default.falseFunc
: (0, general.compileGeneralSelector)(previous, rule, options, context, compileToken);
}, (_a = options.rootFunc) !== null && _a !== void 0 ? _a : boolbase_1.default.trueFunc);
}
function reduceRules(a, b) {
if (b === boolbase_1.default.falseFunc || a === boolbase_1.default.trueFunc) {
return a;
}
if (a === boolbase_1.default.falseFunc || b === boolbase_1.default.trueFunc) {
return b;
}
return function combine(elem) {
return a(elem) || b(elem);
};
}
});
var lib$3 = createCommonjsModule(function (module, exports) {
var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (commonjsGlobal && commonjsGlobal.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (commonjsGlobal && commonjsGlobal.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.aliases = exports.pseudos = exports.filters = exports.is = exports.selectOne = exports.selectAll = exports.prepareContext = exports._compileToken = exports._compileUnsafe = exports.compile = void 0;
var DomUtils = __importStar(domutils_1);
var boolbase_1 = __importDefault(boolbase);
var defaultEquals = function (a, b) { return a === b; };
var defaultOptions = {
adapter: DomUtils,
equals: defaultEquals,
};
function convertOptionFormats(options) {
var _a, _b, _c, _d;
/*
* We force one format of options to the other one.
*/
// @ts-expect-error Default options may have incompatible `Node` / `ElementNode`.
var opts = options !== null && options !== void 0 ? options : defaultOptions;
// @ts-expect-error Same as above.
(_a = opts.adapter) !== null && _a !== void 0 ? _a : (opts.adapter = DomUtils);
// @ts-expect-error `equals` does not exist on `Options`
(_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) {
var opts = convertOptionFormats(options);
return func(selector, opts, context);
};
}
/**
* Compiles the query, returns a function.
*/
exports.compile = wrapCompile(compile_1.compile);
exports._compileUnsafe = wrapCompile(compile_1.compileUnsafe);
exports._compileToken = wrapCompile(compile_1.compileToken);
function getSelectorFunc(searchFunc) {
return function select(query, elements, options) {
var opts = convertOptionFormats(options);
if (typeof query !== "function") {
query = (0, compile_1.compileUnsafe)(query, opts, elements);
}
var filteredElements = prepareContext(elements, opts.adapter, query.shouldTestNextSiblings);
return searchFunc(query, filteredElements, opts);
};
}
function prepareContext(elems, adapter, shouldTestNextSiblings) {
if (shouldTestNextSiblings === void 0) { shouldTestNextSiblings = false; }
/*
* Add siblings if the query requires them.
* See https://github.com/fb55/css-select/pull/43#issuecomment-225414692
*/
if (shouldTestNextSiblings) {
elems = appendNextSiblings(elems, adapter);
}
return Array.isArray(elems)
? adapter.removeSubsets(elems)
: adapter.getChildren(elems);
}
exports.prepareContext = prepareContext;
function appendNextSiblings(elem, adapter) {
// Order matters because jQuery seems to check the children before the siblings
var elems = Array.isArray(elem) ? elem.slice(0) : [elem];
var elemsLength = elems.length;
for (var i = 0; i < elemsLength; i++) {
var nextSiblings = (0, subselects.getNextSiblings)(elems[i], adapter);
elems.push.apply(elems, nextSiblings);
}
return elems;
}
/**
* @template Node The generic Node type for the DOM adapter being used.
* @template ElementNode The Node type for elements for the DOM adapter being used.
* @param elems Elements to query. If it is an element, its children will be queried..
* @param query can be either a CSS selector string or a compiled query function.
* @param [options] options for querying the document.
* @see compile for supported selector queries.
* @returns All matching elements.
*
*/
exports.selectAll = getSelectorFunc(function (query, elems, options) {
return query === boolbase_1.default.falseFunc || !elems || elems.length === 0
? []
: options.adapter.findAll(query, elems);
});
/**
* @template Node The generic Node type for the DOM adapter being used.
* @template ElementNode The Node type for elements for the DOM adapter being used.
* @param elems Elements to query. If it is an element, its children will be queried..
* @param query can be either a CSS selector string or a compiled query function.
* @param [options] options for querying the document.
* @see compile for supported selector queries.
* @returns the first match, or null if there was no match.
*/
exports.selectOne = getSelectorFunc(function (query, elems, options) {
return query === boolbase_1.default.falseFunc || !elems || elems.length === 0
? null
: options.adapter.findOne(query, elems);
});
/**
* Tests whether or not an element is matched by query.
*
* @template Node The generic Node type for the DOM adapter being used.
* @template ElementNode The Node type for elements for the DOM adapter being used.
* @param elem The element to test if it matches the query.
* @param query can be either a CSS selector string or a compiled query function.
* @param [options] options for querying the document.
* @see compile for supported selector queries.
* @returns
*/
function is(elem, query, options) {
var opts = convertOptionFormats(options);
return (typeof query === "function" ? query : (0, compile_1.compile)(query, opts))(elem);
}
exports.is = is;
/**
* Alias for selectAll(query, elems, options).
* @see [compile] for supported selector queries.
*/
exports.default = exports.selectAll;
// Export filters, pseudos and aliases to allow users to supply their own.
/** @deprecated Use the `pseudos` option instead. */
Object.defineProperty(exports, "filters", { enumerable: true, get: function () { return pseudoSelectors.filters; } });
Object.defineProperty(exports, "pseudos", { enumerable: true, get: function () { return pseudoSelectors.pseudos; } });
Object.defineProperty(exports, "aliases", { enumerable: true, get: function () { return pseudoSelectors.aliases; } });
});
var positionals = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.getLimit = exports.isFilter = exports.filterNames = void 0;
exports.filterNames = new Set([
"first",
"last",
"eq",
"gt",
"nth",
"lt",
"even",
"odd",
]);
function isFilter(s) {
if (s.type !== "pseudo")
return false;
if (exports.filterNames.has(s.name))
return true;
if (s.name === "not" && Array.isArray(s.data)) {
// Only consider `:not` with embedded filters
return s.data.some(function (s) { return s.some(isFilter); });
}
return false;
}
exports.isFilter = isFilter;
function getLimit(filter, data, partLimit) {
var num = data != null ? parseInt(data, 10) : NaN;
switch (filter) {
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;
}
}
exports.getLimit = getLimit;
});
var positionals_js_1 = positionals;
var helpers = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.groupSelectors = exports.getDocumentRoot = void 0;
function getDocumentRoot(node) {
while (node.parent)
node = node.parent;
return node;
}
exports.getDocumentRoot = getDocumentRoot;
function groupSelectors(selectors) {
var filteredSelectors = [];
var plainSelectors = [];
for (var _i = 0, selectors_1 = selectors; _i < selectors_1.length; _i++) {
var selector = selectors_1[_i];
if (selector.some(positionals_js_1.isFilter)) {
filteredSelectors.push(selector);
}
else {
plainSelectors.push(selector);
}
}
return [plainSelectors, filteredSelectors];
}
exports.groupSelectors = groupSelectors;
});
var helpers_js_1 = helpers;
var lib$2 = createCommonjsModule(function (module, exports) {
var __assign = (commonjsGlobal && commonjsGlobal.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (commonjsGlobal && commonjsGlobal.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (commonjsGlobal && commonjsGlobal.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __spreadArray = (commonjsGlobal && commonjsGlobal.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.select = exports.filter = exports.some = exports.is = exports.aliases = exports.pseudos = exports.filters = void 0;
var DomUtils = __importStar(domutils_1);
var boolbase$1 = __importStar(boolbase);
// Re-export pseudo extension points
var css_select_2 = lib$3;
Object.defineProperty(exports, "filters", { enumerable: true, get: function () { return css_select_2.filters; } });
Object.defineProperty(exports, "pseudos", { enumerable: true, get: function () { return css_select_2.pseudos; } });
Object.defineProperty(exports, "aliases", { enumerable: true, get: function () { return css_select_2.aliases; } });
var UNIVERSAL_SELECTOR = {
type: css_what_1.SelectorType.Universal,
namespace: null,
};
var SCOPE_PSEUDO = {
type: css_what_1.SelectorType.Pseudo,
name: "scope",
data: null,
};
function is(element, selector, options) {
if (options === void 0) { options = {}; }
return some([element], selector, options);
}
exports.is = is;
function some(elements, selector, options) {
if (options === void 0) { options = {}; }
if (typeof selector === "function")
return elements.some(selector);
var _a = (0, helpers_js_1.groupSelectors)((0, css_what_1.parse)(selector)), plain = _a[0], filtered = _a[1];
return ((plain.length > 0 && elements.some((0, lib$3._compileToken)(plain, options))) ||
filtered.some(function (sel) { return filterBySelector(sel, elements, options).length > 0; }));
}
exports.some = some;
function filterByPosition(filter, elems, data, options) {
var num = typeof data === "string" ? parseInt(data, 10) : NaN;
switch (filter) {
case "first":
case "lt":
// Already done in `getLimit`
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(function (_, i) { return i % 2 === 0; });
case "odd":
return elems.filter(function (_, i) { return i % 2 === 1; });
case "not": {
var filtered_1 = new Set(filterParsed(data, elems, options));
return elems.filter(function (e) { return !filtered_1.has(e); });
}
}
}
function filter(selector, elements, options) {
if (options === void 0) { options = {}; }
return filterParsed((0, css_what_1.parse)(selector), elements, options);
}
exports.filter = filter;
/**
* Filter a set of elements by a selector.
*
* Will return elements in the original order.
*
* @param selector Selector to filter by.
* @param elements Elements to filter.
* @param options Options for selector.
*/
function filterParsed(selector, elements, options) {
if (elements.length === 0)
return [];
var _a = (0, helpers_js_1.groupSelectors)(selector), plainSelectors = _a[0], filteredSelectors = _a[1];
var found;
if (plainSelectors.length) {
var filtered = filterElements(elements, plainSelectors, options);
// If there are no filters, just return
if (filteredSelectors.length === 0) {
return filtered;
}
// Otherwise, we have to do some filtering
if (filtered.length) {
found = new Set(filtered);
}
}
for (var i = 0; i < filteredSelectors.length && (found === null || found === void 0 ? void 0 : found.size) !== elements.length; i++) {
var filteredSelector = filteredSelectors[i];
var missing = found
? elements.filter(function (e) { return DomUtils.isTag(e) && !found.has(e); })
: elements;
if (missing.length === 0)
break;
var filtered = filterBySelector(filteredSelector, elements, options);
if (filtered.length) {
if (!found) {
/*
* If we haven't found anything before the last selector,
* just return what we found now.
*/
if (i === filteredSelectors.length - 1) {
return filtered;
}
found = new Set(filtered);
}
else {
filtered.forEach(function (el) { return found.add(el); });
}
}
}
return typeof found !== "undefined"
? (found.size === elements.length
? elements
: // Filter elements to preserve order
elements.filter(function (el) {
return found.has(el);
}))
: [];
}
function filterBySelector(selector, elements, options) {
var _a;
if (selector.some(css_what_1.isTraversal)) {
/*
* Get root node, run selector with the scope
* set to all of our nodes.
*/
var root = (_a = options.root) !== null && _a !== void 0 ? _a : (0, helpers_js_1.getDocumentRoot)(elements[0]);
var opts = __assign(__assign({}, options), { context: elements, relativeSelector: false });
selector.push(SCOPE_PSEUDO);
return findFilterElements(root, selector, opts, true, elements.length);
}
// Performance optimization: If we don't have to traverse, just filter set.
return findFilterElements(elements, selector, options, false, elements.length);
}
function select(selector, root, options, limit) {
if (options === void 0) { options = {}; }
if (limit === void 0) { limit = Infinity; }
if (typeof selector === "function") {
return find(root, selector);
}
var _a = (0, helpers_js_1.groupSelectors)((0, css_what_1.parse)(selector)), plain = _a[0], filtered = _a[1];
var results = filtered.map(function (sel) {
return findFilterElements(root, sel, options, true, limit);
});
// Plain selectors can be queried in a single go
if (plain.length) {
results.push(findElements(root, plain, options, limit));
}
if (results.length === 0) {
return [];
}
// If there was only a single selector, just return the result
if (results.length === 1) {
return results[0];
}
// Sort results, filtering for duplicates
return DomUtils.uniqueSort(results.reduce(function (a, b) { return __spreadArray(__spreadArray([], a, true), b, true); }));
}
exports.select = select;
/**
*
* @param root Element(s) to search from.
* @param selector Selector to look for.
* @param options Options for querying.
* @param queryForSelector Query multiple levels deep for the initial selector, even if it doesn't contain a traversal.
*/
function findFilterElements(root, selector, options, queryForSelector, totalLimit) {
var filterIndex = selector.findIndex(positionals_js_1.isFilter);
var sub = selector.slice(0, filterIndex);
var filter = selector[filterIndex];
// If we are at the end of the selector, we can limit the number of elements to retrieve.
var partLimit = selector.length - 1 === filterIndex ? totalLimit : Infinity;
/*
* Set the number of elements to retrieve.
* Eg. for :first, we only have to get a single element.
*/
var limit = (0, positionals_js_1.getLimit)(filter.name, filter.data, partLimit);
if (limit === 0)
return [];
/*
* Skip `findElements` call if our selector starts with a positional
* pseudo.
*/
var elemsNoLimit = sub.length === 0 && !Array.isArray(root)
? DomUtils.getChildren(root).filter(DomUtils.isTag)
: sub.length === 0
? (Array.isArray(root) ? root : [root]).filter(DomUtils.isTag)
: queryForSelector || sub.some(css_what_1.isTraversal)
? findElements(root, [sub], options, limit)
: filterElements(root, [sub], options);
var elems = elemsNoLimit.slice(0, limit);
var result = filterByPosition(filter.name, elems, filter.data, options);
if (result.length === 0 || selector.length === filterIndex + 1) {
return result;
}
var remainingSelector = selector.slice(filterIndex + 1);
var remainingHasTraversal = remainingSelector.some(css_what_1.isTraversal);
if (remainingHasTraversal) {
if ((0, css_what_1.isTraversal)(remainingSelector[0])) {
var type = remainingSelector[0].type;
if (type === css_what_1.SelectorType.Sibling ||
type === css_what_1.SelectorType.Adjacent) {
// If we have a sibling traversal, we need to also look at the siblings.
result = (0, lib$3.prepareContext)(result, DomUtils, true);
}
// Avoid a traversal-first selector error.
remainingSelector.unshift(UNIVERSAL_SELECTOR);
}
options = __assign(__assign({}, 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: function (el) { return result.includes(el); } });
}
else if (options.rootFunc && options.rootFunc !== boolbase$1.trueFunc) {
options = __assign(__assign({}, options), { rootFunc: boolbase$1.trueFunc });
}
/*
* If we have another filter, recursively call `findFilterElements`,
* with the `recursive` flag disabled. We only have to look for more
* elements when we see a traversal.
*
* Otherwise,
*/
return remainingSelector.some(positionals_js_1.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(root, sel, options, limit) {
var query = (0, lib$3._compileToken)(sel, options, root);
return find(root, query, limit);
}
function find(root, query, limit) {
if (limit === void 0) { limit = Infinity; }
var elems = (0, lib$3.prepareContext)(root, DomUtils, query.shouldTestNextSiblings);
return DomUtils.find(function (node) { return DomUtils.isTag(node) && query(node); }, elems, true, limit);
}
function filterElements(elements, sel, options) {
var els = (Array.isArray(elements) ? elements : [elements]).filter(DomUtils.isTag);
if (els.length === 0)
return els;
var query = (0, lib$3._compileToken)(sel, options);
return query === boolbase$1.trueFunc ? els : els.filter(query);
}
});
var require$$0 = lib$2;
var traversing = createCommonjsModule(function (module, exports) {
/**
* Methods for traversing the DOM structure.
*
* @module cheerio/traversing
*/
var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (commonjsGlobal && commonjsGlobal.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (commonjsGlobal && commonjsGlobal.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __spreadArray = (commonjsGlobal && commonjsGlobal.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.addBack = exports.add = exports.end = exports.slice = exports.index = exports.toArray = exports.get = exports.eq = exports.last = exports.first = exports.has = exports.not = exports.is = exports.filterArray = exports.filter = exports.map = exports.each = exports.contents = exports.children = exports.siblings = exports.prevUntil = exports.prevAll = exports.prev = exports.nextUntil = exports.nextAll = exports.next = exports.closest = exports.parentsUntil = exports.parents = exports.parent = exports.find = void 0;
var select = __importStar(require$$0);
var reSiblingSelector = /^\s*[~+]/;
/**
* Get the descendants of each element in the current set of matched elements,
* filtered by a selector, jQuery object, or element.
*
* @category Traversing
* @example
*
* ```js
* $('#fruits').find('li').length;
* //=> 3
* $('#fruits').find($('.apple')).length;
* //=> 1
* ```
*
* @param selectorOrHaystack - Element to look for.
* @returns The found elements.
* @see {@link https://api.jquery.com/find/}
*/
function find(selectorOrHaystack) {
var _a;
if (!selectorOrHaystack) {
return this._make([]);
}
var context = this.toArray();
if (typeof selectorOrHaystack !== 'string') {
var haystack = (0, utils.isCheerio)(selectorOrHaystack)
? selectorOrHaystack.toArray()
: [selectorOrHaystack];
return this._make(haystack.filter(function (elem) { return context.some(function (node) { return (0, _static.contains)(node, elem); }); }));
}
var elems = reSiblingSelector.test(selectorOrHaystack)
? context
: this.children().toArray();
var options = {
context: context,
root: (_a = this._root) === null || _a === void 0 ? void 0 : _a[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.select(selectorOrHaystack, elems, options));
}
exports.find = find;
/**
* Creates a matcher, using a particular mapping function. Matchers provide a
* function that finds elements using a generating function, supporting filtering.
*
* @private
* @param matchMap - Mapping function.
* @returns - Function for wrapping generating functions.
*/
function _getMatcher(matchMap) {
return function (fn) {
var postFns = [];
for (var _i = 1; _i < arguments.length; _i++) {
postFns[_i - 1] = arguments[_i];
}
return function (selector) {
var _a;
var matched = matchMap(fn, this);
if (selector) {
matched = filterArray(matched, selector, this.options.xmlMode, (_a = this._root) === null || _a === void 0 ? void 0 : _a[0]);
}
return this._make(
// Post processing is only necessary if there is more than one element.
this.length > 1 && matched.length > 1
? postFns.reduce(function (elems, fn) { return fn(elems); }, matched)
: matched);
};
};
}
/** Matcher that adds multiple elements for each entry in the input. */
var _matcher = _getMatcher(function (fn, elems) {
var _a;
var ret = [];
for (var i = 0; i < elems.length; i++) {
var value = fn(elems[i]);
ret.push(value);
}
return (_a = new Array()).concat.apply(_a, ret);
});
/** Matcher that adds at most one element for each entry in the input. */
var _singleMatcher = _getMatcher(function (fn, elems) {
var ret = [];
for (var i = 0; i < elems.length; i++) {
var value = fn(elems[i]);
if (value !== null) {
ret.push(value);
}
}
return ret;
});
/**
* Matcher that supports traversing until a condition is met.
*
* @returns A function usable for `*Until` methods.
*/
function _matchUntil(nextElem) {
var postFns = [];
for (var _i = 1; _i < arguments.length; _i++) {
postFns[_i - 1] = arguments[_i];
}
// We use a variable here that is used from within the matcher.
var matches = null;
var innerMatcher = _getMatcher(function (nextElem, elems) {
var matched = [];
(0, utils.domEach)(elems, function (elem) {
for (var next_1; (next_1 = nextElem(elem)); elem = next_1) {
// FIXME: `matched` might contain duplicates here and the index is too large.
if (matches === null || matches === void 0 ? void 0 : matches(next_1, matched.length))
break;
matched.push(next_1);
}
});
return matched;
}).apply(void 0, __spreadArray([nextElem], postFns, false));
return function (selector, filterSelector) {
var _this = this;
// Override `matches` variable with the new target.
matches =
typeof selector === 'string'
? function (elem) { return select.is(elem, selector, _this.options); }
: selector
? getFilterFn(selector)
: null;
var ret = innerMatcher.call(this, filterSelector);
// Set `matches` to `null`, so we don't waste memory.
matches = null;
return ret;
};
}
function _removeDuplicates(elems) {
return Array.from(new Set(elems));
}
/**
* Get the parent of each element in the current set of matched elements,
* optionally filtered by a selector.
*
* @category Traversing
* @example
*
* ```js
* $('.pear').parent().attr('id');
* //=> fruits
* ```
*
* @param selector - If specified filter for parent.
* @returns The parents.
* @see {@link https://api.jquery.com/parent/}
*/
exports.parent = _singleMatcher(function (_a) {
var parent = _a.parent;
return (parent && !(0, domhandler_1.isDocument)(parent) ? parent : null);
}, _removeDuplicates);
/**
* Get a set of parents filtered by `selector` of each element in the current
* set of match elements.
*
* @category Traversing
* @example
*
* ```js
* $('.orange').parents().length;
* //=> 2
* $('.orange').parents('#fruits').length;
* //=> 1
* ```
*
* @param selector - If specified filter for parents.
* @returns The parents.
* @see {@link https://api.jquery.com/parents/}
*/
exports.parents = _matcher(function (elem) {
var matched = [];
while (elem.parent && !(0, domhandler_1.isDocument)(elem.parent)) {
matched.push(elem.parent);
elem = elem.parent;
}
return matched;
}, domutils_1.uniqueSort, function (elems) { return elems.reverse(); });
/**
* Get the ancestors of each element in the current set of matched elements, up
* to but not including the element matched by the selector, DOM node, or cheerio object.
*
* @category Traversing
* @example
*
* ```js
* $('.orange').parentsUntil('#food').length;
* //=> 1
* ```
*
* @param selector - Selector for element to stop at.
* @param filterSelector - Optional filter for parents.
* @returns The parents.
* @see {@link https://api.jquery.com/parentsUntil/}
*/
exports.parentsUntil = _matchUntil(function (_a) {
var parent = _a.parent;
return (parent && !(0, domhandler_1.isDocument)(parent) ? parent : null);
}, domutils_1.uniqueSort, function (elems) { return elems.reverse(); });
/**
* For each element in the set, get the first element that matches the selector
* by testing the element itself and traversing up through its ancestors in the DOM tree.
*
* @category Traversing
* @example
*
* ```js
* $('.orange').closest();
* //=> []
*
* $('.orange').closest('.apple');
* // => []
*
* $('.orange').closest('li');
* //=> [<li class="orange">Orange</li>]
*
* $('.orange').closest('#fruits');
* //=> [<ul id="fruits"> ... </ul>]
* ```
*
* @param selector - Selector for the element to find.
* @returns The closest nodes.
* @see {@link https://api.jquery.com/closest/}
*/
function closest(selector) {
var _a;
var set = [];
if (!selector) {
return this._make(set);
}
var selectOpts = {
xmlMode: this.options.xmlMode,
root: (_a = this._root) === null || _a === void 0 ? void 0 : _a[0],
};
var selectFn = typeof selector === 'string'
? function (elem) { return select.is(elem, selector, selectOpts); }
: getFilterFn(selector);
(0, utils.domEach)(this, function (elem) {
while (elem && (0, utils.isTag)(elem)) {
if (selectFn(elem, 0)) {
// Do not add duplicate elements to the set
if (!set.includes(elem)) {
set.push(elem);
}
break;
}
elem = elem.parent;
}
});
return this._make(set);
}
exports.closest = closest;
/**
* Gets the next sibling of the first selected element, optionally filtered by a selector.
*
* @category Traversing
* @example
*
* ```js
* $('.apple').next().hasClass('orange');
* //=> true
* ```
*
* @param selector - If specified filter for sibling.
* @returns The next nodes.
* @see {@link https://api.jquery.com/next/}
*/
exports.next = _singleMatcher(function (elem) { return (0, domutils_1.nextElementSibling)(elem); });
/**
* Gets all the following siblings of the first selected element, optionally
* filtered by a selector.
*
* @category Traversing
* @example
*
* ```js
* $('.apple').nextAll();
* //=> [<li class="orange">Orange</li>, <li class="pear">Pear</li>]
* $('.apple').nextAll('.orange');
* //=> [<li class="orange">Orange</li>]
* ```
*
* @param selector - If specified filter for siblings.
* @returns The next nodes.
* @see {@link https://api.jquery.com/nextAll/}
*/
exports.nextAll = _matcher(function (elem) {
var matched = [];
while (elem.next) {
elem = elem.next;
if ((0, utils.isTag)(elem))
matched.push(elem);
}
return matched;
}, _removeDuplicates);
/**
* Gets all the following siblings up to but not including the element matched
* by the selector, optionally filtered by another selector.
*
* @category Traversing
* @example
*
* ```js
* $('.apple').nextUntil('.pear');
* //=> [<li class="orange">Orange</li>]
* ```
*
* @param selector - Selector for element to stop at.
* @param filterSelector - If specified filter for siblings.
* @returns The next nodes.
* @see {@link https://api.jquery.com/nextUntil/}
*/
exports.nextUntil = _matchUntil(function (el) { return (0, domutils_1.nextElementSibling)(el); }, _removeDuplicates);
/**
* Gets the previous sibling of the first selected element optionally filtered
* by a selector.
*
* @category Traversing
* @example
*
* ```js
* $('.orange').prev().hasClass('apple');
* //=> true
* ```
*
* @param selector - If specified filter for siblings.
* @returns The previous nodes.
* @see {@link https://api.jquery.com/prev/}
*/
exports.prev = _singleMatcher(function (elem) { return (0, domutils_1.prevElementSibling)(elem); });
/**
* Gets all the preceding siblings of the first selected element, optionally
* filtered by a selector.
*
* @category Traversing
* @example
*
* ```js
* $('.pear').prevAll();
* //=> [<li class="orange">Orange</li>, <li class="apple">Apple</li>]
*
* $('.pear').prevAll('.orange');
* //=> [<li class="orange">Orange</li>]
* ```
*
* @param selector - If specified filter for siblings.
* @returns The previous nodes.
* @see {@link https://api.jquery.com/prevAll/}
*/
exports.prevAll = _matcher(function (elem) {
var matched = [];
while (elem.prev) {
elem = elem.prev;
if ((0, utils.isTag)(elem))
matched.push(elem);
}
return matched;
}, _removeDuplicates);
/**
* Gets all the preceding siblings up to but not including the element matched
* by the selector, optionally filtered by another selector.
*
* @category Traversing
* @example
*
* ```js
* $('.pear').prevUntil('.apple');
* //=> [<li class="orange">Orange</li>]
* ```
*
* @param selector - Selector for element to stop at.
* @param filterSelector - If specified filter for siblings.
* @returns The previous nodes.
* @see {@link https://api.jquery.com/prevUntil/}
*/
exports.prevUntil = _matchUntil(function (el) { return (0, domutils_1.prevElementSibling)(el); }, _removeDuplicates);
/**
* Get the siblings of each element (excluding the element) in the set of
* matched elements, optionally filtered by a selector.
*
* @category Traversing
* @example
*
* ```js
* $('.pear').siblings().length;
* //=> 2
*
* $('.pear').siblings('.orange').length;
* //=> 1
* ```
*
* @param selector - If specified filter for siblings.
* @returns The siblings.
* @see {@link https://api.jquery.com/siblings/}
*/
exports.siblings = _matcher(function (elem) {
return (0, domutils_1.getSiblings)(elem).filter(function (el) { return (0, utils.isTag)(el) && el !== elem; });
}, domutils_1.uniqueSort);
/**
* Gets the element children of each element in the set of matched elements.
*
* @category Traversing
* @example
*
* ```js
* $('#fruits').children().length;
* //=> 3
*
* $('#fruits').children('.pear').text();
* //=> Pear
* ```
*
* @param selector - If specified filter for children.
* @returns The children.
* @see {@link https://api.jquery.com/children/}
*/
exports.children = _matcher(function (elem) { return (0, domutils_1.getChildren)(elem).filter(utils.isTag); }, _removeDuplicates);
/**
* Gets the children of each element in the set of matched elements, including
* text and comment nodes.
*
* @category Traversing
* @example
*
* ```js
* $('#fruits').contents().length;
* //=> 3
* ```
*
* @returns The children.
* @see {@link https://api.jquery.com/contents/}
*/
function contents() {
var elems = this.toArray().reduce(function (newElems, elem) {
return (0, domhandler_1.hasChildren)(elem) ? newElems.concat(elem.children) : newElems;
}, []);
return this._make(elems);
}
exports.contents = contents;
/**
* Iterates over a cheerio object, executing a function for each matched
* element. When the callback is fired, the function is fired in the context of
* the DOM element, so `this` refers to the current element, which is equivalent
* to the function parameter `element`. To break out of the `each` loop early,
* return with `false`.
*
* @category Traversing
* @example
*
* ```js
* const fruits = [];
*
* $('li').each(function (i, elem) {
* fruits[i] = $(this).text();
* });
*
* fruits.join(', ');
* //=> Apple, Orange, Pear
* ```
*
* @param fn - Function to execute.
* @returns The instance itself, useful for chaining.
* @see {@link https://api.jquery.com/each/}
*/
function each(fn) {
var i = 0;
var len = this.length;
while (i < len && fn.call(this[i], i, this[i]) !== false)
++i;
return this;
}
exports.each = each;
/**
* Pass each element in the current matched set through a function, producing a
* new Cheerio object containing the return values. The function can return an
* individual data item or an array of data items to be inserted into the
* resulting set. If an array is returned, the elements inside the array are
* inserted into the set. If the function returns null or undefined, no element
* will be inserted.
*
* @category Traversing
* @example
*
* ```js
* $('li')
* .map(function (i, el) {
* // this === el
* return $(this).text();
* })
* .toArray()
* .join(' ');
* //=> "apple orange pear"
* ```
*
* @param fn - Function to execute.
* @returns The mapped elements, wrapped in a Cheerio collection.
* @see {@link https://api.jquery.com/map/}
*/
function map(fn) {
var elems = [];
for (var i = 0; i < this.length; i++) {
var el = this[i];
var val = fn.call(el, i, el);
if (val != null) {
elems = elems.concat(val);
}
}
return this._make(elems);
}
exports.map = map;
/**
* Creates a function to test if a filter is matched.
*
* @param match - A filter.
* @returns A function that determines if a filter has been matched.
*/
function getFilterFn(match) {
if (typeof match === 'function') {
return function (el, i) { return match.call(el, i, el); };
}
if ((0, utils.isCheerio)(match)) {
return function (el) { return Array.prototype.includes.call(match, el); };
}
return function (el) {
return match === el;
};
}
function filter(match) {
var _a;
return this._make(filterArray(this.toArray(), match, this.options.xmlMode, (_a = this._root) === null || _a === void 0 ? void 0 : _a[0]));
}
exports.filter = filter;
function filterArray(nodes, match, xmlMode, root) {
return typeof match === 'string'
? select.filter(match, nodes, { xmlMode: xmlMode, root: root })
: nodes.filter(getFilterFn(match));
}
exports.filterArray = filterArray;
/**
* Checks the current list of elements and returns `true` if _any_ of the
* elements match the selector. If using an element or Cheerio selection,
* returns `true` if _any_ of the elements match. If using a predicate function,
* the function is executed in the context of the selected element, so `this`
* refers to the current element.
*
* @category Attributes
* @param selector - Selector for the selection.
* @returns Whether or not the selector matches an element of the instance.
* @see {@link https://api.jquery.com/is/}
*/
function is(selector) {
var nodes = this.toArray();
return typeof selector === 'string'
? select.some(nodes.filter(utils.isTag), selector, this.options)
: selector
? nodes.some(getFilterFn(selector))
: false;
}
exports.is = is;
/**
* Remove elements from the set of matched elements. Given a Cheerio object that
* represents a set of DOM elements, the `.not()` method constructs a new
* Cheerio object from a subset of the matching elements. The supplied selector
* is tested against each element; the elements that don't match the selector
* will be included in the result.
*
* The `.not()` method can take a function as its argument in the same way that
* `.filter()` does. Elements for which the function returns `true` are excluded
* from the filtered set; all other elements are included.
*
* @category Traversing
* @example <caption>Selector</caption>
*
* ```js
* $('li').not('.apple').length;
* //=> 2
* ```
*
* @example <caption>Function</caption>
*
* ```js
* $('li').not(function (i, el) {
* // this === el
* return $(this).attr('class') === 'orange';
* }).length; //=> 2
* ```
*
* @param match - Value to look for, following the rules above.
* @param container - Optional node to filter instead.
* @returns The filtered collection.
* @see {@link https://api.jquery.com/not/}
*/
function not(match) {
var nodes = this.toArray();
if (typeof match === 'string') {
var matches_1 = new Set(select.filter(match, nodes, this.options));
nodes = nodes.filter(function (el) { return !matches_1.has(el); });
}
else {
var filterFn_1 = getFilterFn(match);
nodes = nodes.filter(function (el, i) { return !filterFn_1(el, i); });
}
return this._make(nodes);
}
exports.not = not;
/**
* Filters the set of matched elements to only those which have the given DOM
* element as a descendant or which have a descendant that matches the given
* selector. Equivalent to `.filter(':has(selector)')`.
*
* @category Traversing
* @example <caption>Selector</caption>
*
* ```js
* $('ul').has('.pear').attr('id');
* //=> fruits
* ```
*
* @example <caption>Element</caption>
*
* ```js
* $('ul').has($('.pear')[0]).attr('id');
* //=> fruits
* ```
*
* @param selectorOrHaystack - Element to look for.
* @returns The filtered collection.
* @see {@link https://api.jquery.com/has/}
*/
function has(selectorOrHaystack) {
var _this = this;
return this.filter(typeof selectorOrHaystack === 'string'
? // Using the `:has` selector here short-circuits searches.
":has(".concat(selectorOrHaystack, ")")
: function (_, el) { return _this._make(el).find(selectorOrHaystack).length > 0; });
}
exports.has = has;
/**
* Will select the first element of a cheerio object.
*
* @category Traversing
* @example
*
* ```js
* $('#fruits').children().first().text();
* //=> Apple
* ```
*
* @returns The first element.
* @see {@link https://api.jquery.com/first/}
*/
function first() {
return this.length > 1 ? this._make(this[0]) : this;
}
exports.first = first;
/**
* Will select the last element of a cheerio object.
*
* @category Traversing
* @example
*
* ```js
* $('#fruits').children().last().text();
* //=> Pear
* ```
*
* @returns The last element.
* @see {@link https://api.jquery.com/last/}
*/
function last() {
return this.length > 0 ? this._make(this[this.length - 1]) : this;
}
exports.last = last;
/**
* Reduce the set of matched elements to the one at the specified index. Use
* `.eq(-i)` to count backwards from the last selected element.
*
* @category Traversing
* @example
*
* ```js
* $('li').eq(0).text();
* //=> Apple
*
* $('li').eq(-1).text();
* //=> Pear
* ```
*
* @param i - Index of the element to select.
* @returns The element at the `i`th position.
* @see {@link https://api.jquery.com/eq/}
*/
function eq(i) {
var _a;
i = +i;
// Use the first identity optimization if possible
if (i === 0 && this.length <= 1)
return this;
if (i < 0)
i = this.length + i;
return this._make((_a = this[i]) !== null && _a !== void 0 ? _a : []);
}
exports.eq = eq;
function get(i) {
if (i == null) {
return this.toArray();
}
return this[i < 0 ? this.length + i : i];
}
exports.get = get;
/**
* Retrieve all the DOM elements contained in the jQuery set as an array.
*
* @example
*
* ```js
* $('li').toArray();
* //=> [ {...}, {...}, {...} ]
* ```
*
* @returns The contained items.
*/
function toArray() {
return Array.prototype.slice.call(this);
}
exports.toArray = toArray;
/**
* Search for a given element from among the matched elements.
*
* @category Traversing
* @example
*
* ```js
* $('.pear').index();
* //=> 2 $('.orange').index('li');
* //=> 1
* $('.apple').index($('#fruit, li'));
* //=> 1
* ```
*
* @param selectorOrNeedle - Element to look for.
* @returns The index of the element.
* @see {@link https://api.jquery.com/index/}
*/
function index(selectorOrNeedle) {
var $haystack;
var needle;
if (selectorOrNeedle == null) {
$haystack = this.parent().children();
needle = this[0];
}
else if (typeof selectorOrNeedle === 'string') {
$haystack = this._make(selectorOrNeedle);
needle = this[0];
}
else {
// eslint-disable-next-line @typescript-eslint/no-this-alias
$haystack = this;
needle = (0, utils.isCheerio)(selectorOrNeedle)
? selectorOrNeedle[0]
: selectorOrNeedle;
}
return Array.prototype.indexOf.call($haystack, needle);
}
exports.index = index;
/**
* Gets the elements matching the specified range (0-based position).
*
* @category Traversing
* @example
*
* ```js
* $('li').slice(1).eq(0).text();
* //=> 'Orange'
*
* $('li').slice(1, 2).length;
* //=> 1
* ```
*
* @param start - An position at which the elements begin to be selected. If
* negative, it indicates an offset from the end of the set.
* @param end - An position at which the elements stop being selected. If
* negative, it indicates an offset from the end of the set. If omitted, the
* range continues until the end of the set.
* @returns The elements matching the specified range.
* @see {@link https://api.jquery.com/slice/}
*/
function slice(start, end) {
return this._make(Array.prototype.slice.call(this, start, end));
}
exports.slice = slice;
/**
* End the most recent filtering operation in the current chain and return the
* set of matched elements to its previous state.
*
* @category Traversing
* @example
*
* ```js
* $('li').eq(0).end().length;
* //=> 3
* ```
*
* @returns The previous state of the set of matched elements.
* @see {@link https://api.jquery.com/end/}
*/
function end() {
var _a;
return (_a = this.prevObject) !== null && _a !== void 0 ? _a : this._make([]);
}
exports.end = end;
/**
* Add elements to the set of matched elements.
*
* @category Traversing
* @example
*
* ```js
* $('.apple').add('.orange').length;
* //=> 2
* ```
*
* @param other - Elements to add.
* @param context - Optionally the context of the new selection.
* @returns The combined set.
* @see {@link https://api.jquery.com/add/}
*/
function add(other, context) {
var selection = this._make(other, context);
var contents = (0, domutils_1.uniqueSort)(__spreadArray(__spreadArray([], this.get(), true), selection.get(), true));
return this._make(contents);
}
exports.add = add;
/**
* Add the previous set of elements on the stack to the current set, optionally
* filtered by a selector.
*
* @category Traversing
* @example
*
* ```js
* $('li').eq(0).addBack('.orange').length;
* //=> 2
* ```
*
* @param selector - Selector for the elements to add.
* @returns The combined set.
* @see {@link https://api.jquery.com/addBack/}
*/
function addBack(selector) {
return this.prevObject
? this.add(selector ? this.prevObject.filter(selector) : this.prevObject)
: this;
}
exports.addBack = addBack;
});
var parse = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.update = exports.getParse = void 0;
/**
* Get the parse function with options.
*
* @param parser - The parser function.
* @returns The parse function with options.
*/
function getParse(parser) {
/**
* Parse a HTML string or a node.
*
* @param content - The HTML string or node.
* @param options - The parser options.
* @param isDocument - If `content` is a document.
* @param context - The context node in the DOM tree.
* @returns The parsed document node.
*/
return function parse(content, options, isDocument, context) {
if (typeof Buffer !== 'undefined' && Buffer.isBuffer(content)) {
content = content.toString();
}
if (typeof content === 'string') {
return parser(content, options, isDocument, context);
}
var doc = content;
if (!Array.isArray(doc) && (0, domhandler_1.isDocument)(doc)) {
// If `doc` is already a root, just return it
return doc;
}
// Add conent to new root element
var root = new domhandler_1.Document([]);
// Update the DOM using the root
update(doc, root);
return root;
};
}
exports.getParse = getParse;
/**
* Update the dom structure, for one changed layer.
*
* @param newChilds - The new children.
* @param parent - The new parent.
* @returns The parent node.
*/
function update(newChilds, parent) {
// Normalize
var arr = Array.isArray(newChilds) ? newChilds : [newChilds];
// Update parent
if (parent) {
parent.children = arr;
}
else {
parent = null;
}
// Update neighbors
for (var i = 0; i < arr.length; i++) {
var node = arr[i];
// Cleanly remove existing nodes from their previous structures.
if (node.parent && node.parent.children !== arr) {
(0, domutils_1.removeElement)(node);
}
if (parent) {
node.prev = arr[i - 1] || null;
node.next = arr[i + 1] || null;
}
else {
node.prev = node.next = null;
}
node.parent = parent;
}
return parent;
}
exports.update = update;
});
var manipulation = createCommonjsModule(function (module, exports) {
/**
* Methods for modifying the DOM structure.
*
* @module cheerio/manipulation
*/
var __spreadArray = (commonjsGlobal && commonjsGlobal.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.clone = exports.text = exports.toString = exports.html = exports.empty = exports.replaceWith = exports.remove = exports.insertBefore = exports.before = exports.insertAfter = exports.after = exports.wrapAll = exports.unwrap = exports.wrapInner = exports.wrap = exports.prepend = exports.append = exports.prependTo = exports.appendTo = exports._makeDomArray = void 0;
/**
* Create an array of nodes, recursing into arrays and parsing strings if necessary.
*
* @private
* @category Manipulation
* @param elem - Elements to make an array of.
* @param clone - Optionally clone nodes.
* @returns The array of nodes.
*/
function _makeDomArray(elem, clone) {
var _this = this;
if (elem == null) {
return [];
}
if ((0, utils.isCheerio)(elem)) {
return clone ? (0, utils.cloneDom)(elem.get()) : elem.get();
}
if (Array.isArray(elem)) {
return elem.reduce(function (newElems, el) { return newElems.concat(_this._makeDomArray(el, clone)); }, []);
}
if (typeof elem === 'string') {
return this._parse(elem, this.options, false, null).children;
}
return clone ? (0, utils.cloneDom)([elem]) : [elem];
}
exports._makeDomArray = _makeDomArray;
function _insert(concatenator) {
return function () {
var _this = this;
var elems = [];
for (var _i = 0; _i < arguments.length; _i++) {
elems[_i] = arguments[_i];
}
var lastIdx = this.length - 1;
return (0, utils.domEach)(this, function (el, i) {
if (!(0, domhandler_1.hasChildren)(el))
return;
var domSrc = typeof elems[0] === 'function'
? elems[0].call(el, i, _this._render(el.children))
: elems;
var dom = _this._makeDomArray(domSrc, i < lastIdx);
concatenator(dom, el.children, el);
});
};
}
/**
* Modify an array in-place, removing some number of elements and adding new
* elements directly following them.
*
* @private
* @category Manipulation
* @param array - Target array to splice.
* @param spliceIdx - Index at which to begin changing the array.
* @param spliceCount - Number of elements to remove from the array.
* @param newElems - Elements to insert into the array.
* @param parent - The parent of the node.
* @returns The spliced array.
*/
function uniqueSplice(array, spliceIdx, spliceCount, newElems, parent) {
var _a, _b;
var spliceArgs = __spreadArray([
spliceIdx,
spliceCount
], newElems, true);
var prev = spliceIdx === 0 ? null : array[spliceIdx - 1];
var next = spliceIdx + spliceCount >= array.length
? null
: array[spliceIdx + spliceCount];
/*
* Before splicing in new elements, ensure they do not already appear in the
* current array.
*/
for (var idx = 0; idx < newElems.length; ++idx) {
var node = newElems[idx];
var oldParent = node.parent;
if (oldParent) {
var oldSiblings = oldParent.children;
var prevIdx = oldSiblings.indexOf(node);
if (prevIdx > -1) {
oldParent.children.splice(prevIdx, 1);
if (parent === oldParent && spliceIdx > prevIdx) {
spliceArgs[0]--;
}
}
}
node.parent = parent;
if (node.prev) {
node.prev.next = (_a = node.next) !== null && _a !== void 0 ? _a : null;
}
if (node.next) {
node.next.prev = (_b = node.prev) !== null && _b !== void 0 ? _b : null;
}
node.prev = idx === 0 ? prev : newElems[idx - 1];
node.next = idx === newElems.length - 1 ? next : newElems[idx + 1];
}
if (prev) {
prev.next = newElems[0];
}
if (next) {
next.prev = newElems[newElems.length - 1];
}
return array.splice.apply(array, spliceArgs);
}
/**
* Insert every element in the set of matched elements to the end of the target.
*
* @category Manipulation
* @example
*
* ```js
* $('<li class="plum">Plum</li>').appendTo('#fruits');
* $.html();
* //=> <ul id="fruits">
* // <li class="apple">Apple</li>
* // <li class="orange">Orange</li>
* // <li class="pear">Pear</li>
* // <li class="plum">Plum</li>
* // </ul>
* ```
*
* @param target - Element to append elements to.
* @returns The instance itself.
* @see {@link https://api.jquery.com/appendTo/}
*/
function appendTo(target) {
var appendTarget = (0, utils.isCheerio)(target) ? target : this._make(target);
appendTarget.append(this);
return this;
}
exports.appendTo = appendTo;
/**
* Insert every element in the set of matched elements to the beginning of the target.
*
* @category Manipulation
* @example
*
* ```js
* $('<li class="plum">Plum</li>').prependTo('#fruits');
* $.html();
* //=> <ul id="fruits">
* // <li class="plum">Plum</li>
* // <li class="apple">Apple</li>
* // <li class="orange">Orange</li>
* // <li class="pear">Pear</li>
* // </ul>
* ```
*
* @param target - Element to prepend elements to.
* @returns The instance itself.
* @see {@link https://api.jquery.com/prependTo/}
*/
function prependTo(target) {
var prependTarget = (0, utils.isCheerio)(target) ? target : this._make(target);
prependTarget.prepend(this);
return this;
}
exports.prependTo = prependTo;
/**
* Inserts content as the _last_ child of each of the selected elements.
*
* @category Manipulation
* @example
*
* ```js
* $('ul').append('<li class="plum">Plum</li>');
* $.html();
* //=> <ul id="fruits">
* // <li class="apple">Apple</li>
* // <li class="orange">Orange</li>
* // <li class="pear">Pear</li>
* // <li class="plum">Plum</li>
* // </ul>
* ```
*
* @see {@link https://api.jquery.com/append/}
*/
exports.append = _insert(function (dom, children, parent) {
uniqueSplice(children, children.length, 0, dom, parent);
});
/**
* Inserts content as the _first_ child of each of the selected elements.
*
* @category Manipulation
* @example
*
* ```js
* $('ul').prepend('<li class="plum">Plum</li>');
* $.html();
* //=> <ul id="fruits">
* // <li class="plum">Plum</li>
* // <li class="apple">Apple</li>
* // <li class="orange">Orange</li>
* // <li class="pear">Pear</li>
* // </ul>
* ```
*
* @see {@link https://api.jquery.com/prepend/}
*/
exports.prepend = _insert(function (dom, children, parent) {
uniqueSplice(children, 0, 0, dom, parent);
});
function _wrap(insert) {
return function (wrapper) {
var lastIdx = this.length - 1;
var lastParent = this.parents().last();
for (var i = 0; i < this.length; i++) {
var el = this[i];
var wrap_1 = typeof wrapper === 'function'
? wrapper.call(el, i, el)
: typeof wrapper === 'string' && !(0, utils.isHtml)(wrapper)
? lastParent.find(wrapper).clone()
: wrapper;
var wrapperDom = this._makeDomArray(wrap_1, i < lastIdx)[0];
if (!wrapperDom || !(0, domhandler_1.hasChildren)(wrapperDom))
continue;
var elInsertLocation = wrapperDom;
/*
* Find the deepest child. Only consider the first tag child of each node
* (ignore text); stop if no children are found.
*/
var j = 0;
while (j < elInsertLocation.children.length) {
var child = elInsertLocation.children[j];
if ((0, utils.isTag)(child)) {
elInsertLocation = child;
j = 0;
}
else {
j++;
}
}
insert(el, elInsertLocation, [wrapperDom]);
}
return this;
};
}
/**
* The .wrap() function can take any string or object that could be passed to
* the $() factory function to specify a DOM structure. This structure may be
* nested several levels deep, but should contain only one inmost element. A
* copy of this structure will be wrapped around each of the elements in the set
* of matched elements. This method returns the original set of elements for
* chaining purposes.
*
* @category Manipulation
* @example
*
* ```js
* const redFruit = $('<div class="red-fruit"></div>');
* $('.apple').wrap(redFruit);
*
* //=> <ul id="fruits">
* // <div class="red-fruit">
* // <li class="apple">Apple</li>
* // </div>
* // <li class="orange">Orange</li>
* // <li class="plum">Plum</li>
* // </ul>
*
* const healthy = $('<div class="healthy"></div>');
* $('li').wrap(healthy);
*
* //=> <ul id="fruits">
* // <div class="healthy">
* // <li class="apple">Apple</li>
* // </div>
* // <div class="healthy">
* // <li class="orange">Orange</li>
* // </div>
* // <div class="healthy">
* // <li class="plum">Plum</li>
* // </div>
* // </ul>
* ```
*
* @param wrapper - The DOM structure to wrap around each element in the selection.
* @see {@link https://api.jquery.com/wrap/}
*/
exports.wrap = _wrap(function (el, elInsertLocation, wrapperDom) {
var parent = el.parent;
if (!parent)
return;
var siblings = parent.children;
var index = siblings.indexOf(el);
(0, parse.update)([el], elInsertLocation);
/*
* The previous operation removed the current element from the `siblings`
* array, so the `dom` array can be inserted without removing any
* additional elements.
*/
uniqueSplice(siblings, index, 0, wrapperDom, parent);
});
/**
* The .wrapInner() function can take any string or object that could be passed
* to the $() factory function to specify a DOM structure. This structure may be
* nested several levels deep, but should contain only one inmost element. The
* structure will be wrapped around the content of each of the elements in the
* set of matched elements.
*
* @category Manipulation
* @example
*
* ```js
* const redFruit = $('<div class="red-fruit"></div>');
* $('.apple').wrapInner(redFruit);
*
* //=> <ul id="fruits">
* // <li class="apple">
* // <div class="red-fruit">Apple</div>
* // </li>
* // <li class="orange">Orange</li>
* // <li class="pear">Pear</li>
* // </ul>
*
* const healthy = $('<div class="healthy"></div>');
* $('li').wrapInner(healthy);
*
* //=> <ul id="fruits">
* // <li class="apple">
* // <div class="healthy">Apple</div>
* // </li>
* // <li class="orange">
* // <div class="healthy">Orange</div>
* // </li>
* // <li class="pear">
* // <div class="healthy">Pear</div>
* // </li>
* // </ul>
* ```
*
* @param wrapper - The DOM structure to wrap around the content of each element
* in the selection.
* @returns The instance itself, for chaining.
* @see {@link https://api.jquery.com/wrapInner/}
*/
exports.wrapInner = _wrap(function (el, elInsertLocation, wrapperDom) {
if (!(0, domhandler_1.hasChildren)(el))
return;
(0, parse.update)(el.children, elInsertLocation);
(0, parse.update)(wrapperDom, el);
});
/**
* The .unwrap() function, removes the parents of the set of matched elements
* from the DOM, leaving the matched elements in their place.
*
* @category Manipulation
* @example <caption>without selector</caption>
*
* ```js
* const $ = cheerio.load(
* '<div id=test>\n <div><p>Hello</p></div>\n <div><p>World</p></div>\n</div>'
* );
* $('#test p').unwrap();
*
* //=> <div id=test>
* // <p>Hello</p>
* // <p>World</p>
* // </div>
* ```
*
* @example <caption>with selector</caption>
*
* ```js
* const $ = cheerio.load(
* '<div id=test>\n <p>Hello</p>\n <b><p>World</p></b>\n</div>'
* );
* $('#test p').unwrap('b');
*
* //=> <div id=test>
* // <p>Hello</p>
* // <p>World</p>
* // </div>
* ```
*
* @param selector - A selector to check the parent element against. If an
* element's parent does not match the selector, the element won't be unwrapped.
* @returns The instance itself, for chaining.
* @see {@link https://api.jquery.com/unwrap/}
*/
function unwrap(selector) {
var _this = this;
this.parent(selector)
.not('body')
.each(function (_, el) {
_this._make(el).replaceWith(el.children);
});
return this;
}
exports.unwrap = unwrap;
/**
* The .wrapAll() function can take any string or object that could be passed to
* the $() function to specify a DOM structure. This structure may be nested
* several levels deep, but should contain only one inmost element. The
* structure will be wrapped around all of the elements in the set of matched
* elements, as a single group.
*
* @category Manipulation
* @example <caption>With markup passed to `wrapAll`</caption>
*
* ```js
* const $ = cheerio.load(
* '<div class="container"><div class="inner">First</div><div class="inner">Second</div></div>'
* );
* $('.inner').wrapAll("<div class='new'></div>");
*
* //=> <div class="container">
* // <div class='new'>
* // <div class="inner">First</div>
* // <div class="inner">Second</div>
* // </div>
* // </div>
* ```
*
* @example <caption>With an existing cheerio instance</caption>
*
* ```js
* const $ = cheerio.load(
* '<span>Span 1</span><strong>Strong</strong><span>Span 2</span>'
* );
* const wrap = $('<div><p><em><b></b></em></p></div>');
* $('span').wrapAll(wrap);
*
* //=> <div>
* // <p>
* // <em>
* // <b>
* // <span>Span 1</span>
* // <span>Span 2</span>
* // </b>
* // </em>
* // </p>
* // </div>
* // <strong>Strong</strong>
* ```
*
* @param wrapper - The DOM structure to wrap around all matched elements in the
* selection.
* @returns The instance itself.
* @see {@link https://api.jquery.com/wrapAll/}
*/
function wrapAll(wrapper) {
var el = this[0];
if (el) {
var wrap_2 = this._make(typeof wrapper === 'function' ? wrapper.call(el, 0, el) : wrapper).insertBefore(el);
// If html is given as wrapper, wrap may contain text elements
var elInsertLocation = void 0;
for (var i = 0; i < wrap_2.length; i++) {
if (wrap_2[i].type === 'tag')
elInsertLocation = wrap_2[i];
}
var j = 0;
/*
* Find the deepest child. Only consider the first tag child of each node
* (ignore text); stop if no children are found.
*/
while (elInsertLocation && j < elInsertLocation.children.length) {
var child = elInsertLocation.children[j];
if (child.type === 'tag') {
elInsertLocation = child;
j = 0;
}
else {
j++;
}
}
if (elInsertLocation)
this._make(elInsertLocation).append(this);
}
return this;
}
exports.wrapAll = wrapAll;
/* eslint-disable jsdoc/check-param-names*/
/**
* Insert content next to each element in the set of matched elements.
*
* @category Manipulation
* @example
*
* ```js
* $('.apple').after('<li class="plum">Plum</li>');
* $.html();
* //=> <ul id="fruits">
* // <li class="apple">Apple</li>
* // <li class="plum">Plum</li>
* // <li class="orange">Orange</li>
* // <li class="pear">Pear</li>
* // </ul>
* ```
*
* @param content - HTML string, DOM element, array of DOM elements or Cheerio
* to insert after each element in the set of matched elements.
* @returns The instance itself.
* @see {@link https://api.jquery.com/after/}
*/
function after() {
var _this = this;
var elems = [];
for (var _i = 0; _i < arguments.length; _i++) {
elems[_i] = arguments[_i];
}
var lastIdx = this.length - 1;
return (0, utils.domEach)(this, function (el, i) {
var parent = el.parent;
if (!(0, domhandler_1.hasChildren)(el) || !parent) {
return;
}
var siblings = parent.children;
var index = siblings.indexOf(el);
// If not found, move on
/* istanbul ignore next */
if (index < 0)
return;
var domSrc = typeof elems[0] === 'function'
? elems[0].call(el, i, _this._render(el.children))
: elems;
var dom = _this._makeDomArray(domSrc, i < lastIdx);
// Add element after `this` element
uniqueSplice(siblings, index + 1, 0, dom, parent);
});
}
exports.after = after;
/* eslint-enable jsdoc/check-param-names*/
/**
* Insert every element in the set of matched elements after the target.
*
* @category Manipulation
* @example
*
* ```js
* $('<li class="plum">Plum</li>').insertAfter('.apple');
* $.html();
* //=> <ul id="fruits">
* // <li class="apple">Apple</li>
* // <li class="plum">Plum</li>
* // <li class="orange">Orange</li>
* // <li class="pear">Pear</li>
* // </ul>
* ```
*
* @param target - Element to insert elements after.
* @returns The set of newly inserted elements.
* @see {@link https://api.jquery.com/insertAfter/}
*/
function insertAfter(target) {
var _this = this;
if (typeof target === 'string') {
target = this._make(target);
}
this.remove();
var clones = [];
this._makeDomArray(target).forEach(function (el) {
var clonedSelf = _this.clone().toArray();
var parent = el.parent;
if (!parent) {
return;
}
var siblings = parent.children;
var index = siblings.indexOf(el);
// If not found, move on
/* istanbul ignore next */
if (index < 0)
return;
// Add cloned `this` element(s) after target element
uniqueSplice(siblings, index + 1, 0, clonedSelf, parent);
clones.push.apply(clones, clonedSelf);
});
return this._make(clones);
}
exports.insertAfter = insertAfter;
/* eslint-disable jsdoc/check-param-names*/
/**
* Insert content previous to each element in the set of matched elements.
*
* @category Manipulation
* @example
*
* ```js
* $('.apple').before('<li class="plum">Plum</li>');
* $.html();
* //=> <ul id="fruits">
* // <li class="plum">Plum</li>
* // <li class="apple">Apple</li>
* // <li class="orange">Orange</li>
* // <li class="pear">Pear</li>
* // </ul>
* ```
*
* @param content - HTML string, DOM element, array of DOM elements or Cheerio
* to insert before each element in the set of matched elements.
* @returns The instance itself.
* @see {@link https://api.jquery.com/before/}
*/
function before() {
var _this = this;
var elems = [];
for (var _i = 0; _i < arguments.length; _i++) {
elems[_i] = arguments[_i];
}
var lastIdx = this.length - 1;
return (0, utils.domEach)(this, function (el, i) {
var parent = el.parent;
if (!(0, domhandler_1.hasChildren)(el) || !parent) {
return;
}
var siblings = parent.children;
var index = siblings.indexOf(el);
// If not found, move on
/* istanbul ignore next */
if (index < 0)
return;
var domSrc = typeof elems[0] === 'function'
? elems[0].call(el, i, _this._render(el.children))
: elems;
var dom = _this._makeDomArray(domSrc, i < lastIdx);
// Add element before `el` element
uniqueSplice(siblings, index, 0, dom, parent);
});
}
exports.before = before;
/* eslint-enable jsdoc/check-param-names*/
/**
* Insert every element in the set of matched elements before the target.
*
* @category Manipulation
* @example
*
* ```js
* $('<li class="plum">Plum</li>').insertBefore('.apple');
* $.html();
* //=> <ul id="fruits">
* // <li class="plum">Plum</li>
* // <li class="apple">Apple</li>
* // <li class="orange">Orange</li>
* // <li class="pear">Pear</li>
* // </ul>
* ```
*
* @param target - Element to insert elements before.
* @returns The set of newly inserted elements.
* @see {@link https://api.jquery.com/insertBefore/}
*/
function insertBefore(target) {
var _this = this;
var targetArr = this._make(target);
this.remove();
var clones = [];
(0, utils.domEach)(targetArr, function (el) {
var clonedSelf = _this.clone().toArray();
var parent = el.parent;
if (!parent) {
return;
}
var siblings = parent.children;
var index = siblings.indexOf(el);
// If not found, move on
/* istanbul ignore next */
if (index < 0)
return;
// Add cloned `this` element(s) after target element
uniqueSplice(siblings, index, 0, clonedSelf, parent);
clones.push.apply(clones, clonedSelf);
});
return this._make(clones);
}
exports.insertBefore = insertBefore;
/**
* Removes the set of matched elements from the DOM and all their children.
* `selector` filters the set of matched elements to be removed.
*
* @category Manipulation
* @example
*
* ```js
* $('.pear').remove();
* $.html();
* //=> <ul id="fruits">
* // <li class="apple">Apple</li>
* // <li class="orange">Orange</li>
* // </ul>
* ```
*
* @param selector - Optional selector for elements to remove.
* @returns The instance itself.
* @see {@link https://api.jquery.com/remove/}
*/
function remove(selector) {
// Filter if we have selector
var elems = selector ? this.filter(selector) : this;
(0, utils.domEach)(elems, function (el) {
(0, domutils_1.removeElement)(el);
el.prev = el.next = el.parent = null;
});
return this;
}
exports.remove = remove;
/**
* Replaces matched elements with `content`.
*
* @category Manipulation
* @example
*
* ```js
* const plum = $('<li class="plum">Plum</li>');
* $('.pear').replaceWith(plum);
* $.html();
* //=> <ul id="fruits">
* // <li class="apple">Apple</li>
* // <li class="orange">Orange</li>
* // <li class="plum">Plum</li>
* // </ul>
* ```
*
* @param content - Replacement for matched elements.
* @returns The instance itself.
* @see {@link https://api.jquery.com/replaceWith/}
*/
function replaceWith(content) {
var _this = this;
return (0, utils.domEach)(this, function (el, i) {
var parent = el.parent;
if (!parent) {
return;
}
var siblings = parent.children;
var cont = typeof content === 'function' ? content.call(el, i, el) : content;
var dom = _this._makeDomArray(cont);
/*
* In the case that `dom` contains nodes that already exist in other
* structures, ensure those nodes are properly removed.
*/
(0, parse.update)(dom, null);
var index = siblings.indexOf(el);
// Completely remove old element
uniqueSplice(siblings, index, 1, dom, parent);
if (!dom.includes(el)) {
el.parent = el.prev = el.next = null;
}
});
}
exports.replaceWith = replaceWith;
/**
* Empties an element, removing all its children.
*
* @category Manipulation
* @example
*
* ```js
* $('ul').empty();
* $.html();
* //=> <ul id="fruits"></ul>
* ```
*
* @returns The instance itself.
* @see {@link https://api.jquery.com/empty/}
*/
function empty() {
return (0, utils.domEach)(this, function (el) {
if (!(0, domhandler_1.hasChildren)(el))
return;
el.children.forEach(function (child) {
child.next = child.prev = child.parent = null;
});
el.children.length = 0;
});
}
exports.empty = empty;
function html(str) {
var _this = this;
if (str === undefined) {
var el = this[0];
if (!el || !(0, domhandler_1.hasChildren)(el))
return null;
return this._render(el.children);
}
return (0, utils.domEach)(this, function (el) {
if (!(0, domhandler_1.hasChildren)(el))
return;
el.children.forEach(function (child) {
child.next = child.prev = child.parent = null;
});
var content = (0, utils.isCheerio)(str)
? str.toArray()
: _this._parse("".concat(str), _this.options, false, el).children;
(0, parse.update)(content, el);
});
}
exports.html = html;
/**
* Turns the collection to a string. Alias for `.html()`.
*
* @category Manipulation
* @returns The rendered document.
*/
function toString() {
return this._render(this);
}
exports.toString = toString;
function text(str) {
var _this = this;
// If `str` is undefined, act as a "getter"
if (str === undefined) {
return (0, _static.text)(this);
}
if (typeof str === 'function') {
// Function support
return (0, utils.domEach)(this, function (el, i) {
return _this._make(el).text(str.call(el, i, (0, _static.text)([el])));
});
}
// Append text node to each selected elements
return (0, utils.domEach)(this, function (el) {
if (!(0, domhandler_1.hasChildren)(el))
return;
el.children.forEach(function (child) {
child.next = child.prev = child.parent = null;
});
var textNode = new domhandler_1.Text("".concat(str));
(0, parse.update)(textNode, el);
});
}
exports.text = text;
/**
* Clone the cheerio object.
*
* @category Manipulation
* @example
*
* ```js
* const moreFruit = $('#fruits').clone();
* ```
*
* @returns The cloned object.
* @see {@link https://api.jquery.com/clone/}
*/
function clone() {
return this._make((0, utils.cloneDom)(this.get()));
}
exports.clone = clone;
});
var css_1 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.css = void 0;
/**
* Set multiple CSS properties for every matched element.
*
* @category CSS
* @param prop - The names of the properties.
* @param val - The new values.
* @returns The instance itself.
* @see {@link https://api.jquery.com/css/}
*/
function css(prop, val) {
if ((prop != null && val != null) ||
// When `prop` is a "plain" object
(typeof prop === 'object' && !Array.isArray(prop))) {
return (0, utils.domEach)(this, function (el, i) {
if ((0, utils.isTag)(el)) {
// `prop` can't be an array here anymore.
setCss(el, prop, val, i);
}
});
}
if (this.length === 0) {
return undefined;
}
return getCss(this[0], prop);
}
exports.css = css;
/**
* Set styles of all elements.
*
* @private
* @param el - Element to set style of.
* @param prop - Name of property.
* @param value - Value to set property to.
* @param idx - Optional index within the selection.
*/
function setCss(el, prop, value, idx) {
if (typeof prop === 'string') {
var styles = getCss(el);
var val = typeof value === 'function' ? value.call(el, idx, styles[prop]) : value;
if (val === '') {
delete styles[prop];
}
else if (val != null) {
styles[prop] = val;
}
el.attribs['style'] = stringify(styles);
}
else if (typeof prop === 'object') {
Object.keys(prop).forEach(function (k, i) {
setCss(el, k, prop[k], i);
});
}
}
function getCss(el, prop) {
if (!el || !(0, utils.isTag)(el))
return;
var styles = parse(el.attribs['style']);
if (typeof prop === 'string') {
return styles[prop];
}
if (Array.isArray(prop)) {
var newStyles_1 = {};
prop.forEach(function (item) {
if (styles[item] != null) {
newStyles_1[item] = styles[item];
}
});
return newStyles_1;
}
return styles;
}
/**
* Stringify `obj` to styles.
*
* @private
* @category CSS
* @param obj - Object to stringify.
* @returns The serialized styles.
*/
function stringify(obj) {
return Object.keys(obj).reduce(function (str, prop) { return "".concat(str).concat(str ? ' ' : '').concat(prop, ": ").concat(obj[prop], ";"); }, '');
}
/**
* Parse `styles`.
*
* @private
* @category CSS
* @param styles - Styles to be parsed.
* @returns The parsed styles.
*/
function parse(styles) {
styles = (styles || '').trim();
if (!styles)
return {};
var obj = {};
var key;
for (var _i = 0, _a = styles.split(';'); _i < _a.length; _i++) {
var str = _a[_i];
var n = str.indexOf(':');
// If there is no :, or if it is the first/last character, add to the previous item's value
if (n < 1 || n === str.length - 1) {
var trimmed = str.trimEnd();
if (trimmed.length > 0 && key !== undefined) {
obj[key] += ";".concat(trimmed);
}
}
else {
key = str.slice(0, n).trim();
obj[key] = str.slice(n + 1).trim();
}
}
return obj;
}
});
var forms = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.serializeArray = exports.serialize = void 0;
/*
* https://github.com/jquery/jquery/blob/2.1.3/src/manipulation/var/rcheckableType.js
* https://github.com/jquery/jquery/blob/2.1.3/src/serialize.js
*/
var submittableSelector = 'input,select,textarea,keygen';
var r20 = /%20/g;
var rCRLF = /\r?\n/g;
/**
* Encode a set of form elements as a string for submission.
*
* @category Forms
* @example
*
* ```js
* $('<form><input name="foo" value="bar" /></form>').serialize();
* //=> 'foo=bar'
* ```
*
* @returns The serialized form.
* @see {@link https://api.jquery.com/serialize/}
*/
function serialize() {
// Convert form elements into name/value objects
var arr = this.serializeArray();
// Serialize each element into a key/value string
var retArr = arr.map(function (data) {
return "".concat(encodeURIComponent(data.name), "=").concat(encodeURIComponent(data.value));
});
// Return the resulting serialization
return retArr.join('&').replace(r20, '+');
}
exports.serialize = serialize;
/**
* Encode a set of form elements as an array of names and values.
*
* @category Forms
* @example
*
* ```js
* $('<form><input name="foo" value="bar" /></form>').serializeArray();
* //=> [ { name: 'foo', value: 'bar' } ]
* ```
*
* @returns The serialized form.
* @see {@link https://api.jquery.com/serializeArray/}
*/
function serializeArray() {
var _this = this;
// Resolve all form elements from either forms or collections of form elements
return this.map(function (_, elem) {
var $elem = _this._make(elem);
if ((0, utils.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' +
// And cannot be clicked (`[type=submit]`) or are used in `x-www-form-urlencoded` (`[type=file]`)
':not(:submit, :button, :image, :reset, :file)' +
// And are either checked/don't have a checkable state
':matches([checked], :not(:checkbox, :radio))'
// Convert each of the elements to its value(s)
)
.map(function (_, elem) {
var _a;
var $elem = _this._make(elem);
var name = $elem.attr('name'); // We have filtered for elements with a name before.
// If there is no value set (e.g. `undefined`, `null`), then default value to empty
var value = (_a = $elem.val()) !== null && _a !== void 0 ? _a : '';
// If we have an array of values (e.g. `<select multiple>`), return an array of key/value pairs
if (Array.isArray(value)) {
return value.map(function (val) {
/*
* 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`
*/
return ({ name: name, value: val.replace(rCRLF, '\r\n') });
});
}
// Otherwise (e.g. `<input type="text">`, return only one key/value pair
return { name: name, value: value.replace(rCRLF, '\r\n') };
})
.toArray();
}
exports.serializeArray = serializeArray;
});
var cheerio = createCommonjsModule(function (module, exports) {
var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (commonjsGlobal && commonjsGlobal.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (commonjsGlobal && commonjsGlobal.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Cheerio = void 0;
var Attributes = __importStar(attributes$1);
var Traversing = __importStar(traversing);
var Manipulation = __importStar(manipulation);
var Css = __importStar(css_1);
var Forms = __importStar(forms);
var Cheerio = /** @class */ (function () {
/**
* 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.
*/
function Cheerio(elements, root, options) {
this.length = 0;
this.options = options;
this._root = root;
if (elements) {
for (var idx = 0; idx < elements.length; idx++) {
this[idx] = elements[idx];
}
this.length = elements.length;
}
}
return Cheerio;
}());
exports.Cheerio = Cheerio;
/** Set a signature of the object. */
Cheerio.prototype.cheerio = '[cheerio object]';
/*
* Make cheerio an array-like object
*/
Cheerio.prototype.splice = Array.prototype.splice;
// Support for (const element of $(...)) iteration:
Cheerio.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
// Plug in the API
Object.assign(Cheerio.prototype, Attributes, Traversing, Manipulation, Css, Forms);
});
var load = createCommonjsModule(function (module, exports) {
var __extends = (commonjsGlobal && commonjsGlobal.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __assign = (commonjsGlobal && commonjsGlobal.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (commonjsGlobal && commonjsGlobal.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (commonjsGlobal && commonjsGlobal.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getLoad = void 0;
var options_js_1 = __importStar(options);
var staticMethods = __importStar(_static);
function getLoad(parse, render) {
/**
* Create a querying function, bound to a document created from the provided markup.
*
* Note that similar to web browser contexts, this operation may introduce
* `<html>`, `<head>`, and `<body>` elements; set `isDocument` to `false` to
* switch to fragment mode and disable this.
*
* @param content - Markup to be loaded.
* @param options - Options for the created instance.
* @param isDocument - Allows parser to be switched to fragment mode.
* @returns The loaded document.
* @see {@link https://cheerio.js.org#loading} for additional usage information.
*/
return function load(content, options, isDocument) {
if (isDocument === void 0) { isDocument = true; }
if (content == null) {
throw new Error('cheerio.load() expects a string');
}
var internalOpts = __assign(__assign({}, options_js_1.default), (0, options_js_1.flatten)(options));
var initialRoot = parse(content, internalOpts, isDocument, null);
/** Create an extended class here, so that extensions only live on one instance. */
var LoadedCheerio = /** @class */ (function (_super) {
__extends(LoadedCheerio, _super);
function LoadedCheerio() {
return _super !== null && _super.apply(this, arguments) || this;
}
LoadedCheerio.prototype._make = function (selector, context) {
var cheerio = initialize(selector, context);
cheerio.prevObject = this;
return cheerio;
};
LoadedCheerio.prototype._parse = function (content, options, isDocument, context) {
return parse(content, options, isDocument, context);
};
LoadedCheerio.prototype._render = function (dom) {
return render(dom, this.options);
};
return LoadedCheerio;
}(cheerio.Cheerio));
function initialize(selector, context, root, opts) {
if (root === void 0) { root = initialRoot; }
// $($)
if (selector && (0, utils.isCheerio)(selector))
return selector;
var options = __assign(__assign({}, internalOpts), (0, options_js_1.flatten)(opts));
var r = typeof root === 'string'
? [parse(root, options, false, null)]
: 'length' in root
? root
: [root];
var rootInstance = (0, utils.isCheerio)(r)
? r
: new LoadedCheerio(r, null, options);
// Add a cyclic reference, so that calling methods on `_root` never fails.
rootInstance._root = rootInstance;
// $(), $(null), $(undefined), $(false)
if (!selector) {
return new LoadedCheerio(undefined, rootInstance, options);
}
var elements = typeof selector === 'string' && (0, utils.isHtml)(selector)
? // $(<html>)
parse(selector, options, false, null).children
: isNode(selector)
? // $(dom)
[selector]
: Array.isArray(selector)
? // $([dom])
selector
: undefined;
var instance = new LoadedCheerio(elements, rootInstance, options);
if (elements) {
return instance;
}
if (typeof selector !== 'string') {
throw new Error('Unexpected type of selector');
}
// We know that our selector is a string now.
var search = selector;
var searchContext = !context
? // If we don't have a context, maybe we have a root, from loading
rootInstance
: typeof context === 'string'
? (0, utils.isHtml)(context)
? // $('li', '<ul>...</ul>')
new LoadedCheerio([parse(context, options, false, null)], rootInstance, options)
: // $('li', 'ul')
((search = "".concat(context, " ").concat(search)), rootInstance)
: (0, utils.isCheerio)(context)
? // $('li', $)
context
: // $('li', node), $('li', [nodes])
new LoadedCheerio(Array.isArray(context) ? context : [context], rootInstance, options);
// If we still don't have a context, return
if (!searchContext)
return instance;
/*
* #id, .class, tag
*/
return searchContext.find(search);
}
// Add in static methods & properties
Object.assign(initialize, staticMethods, {
load: load,
// `_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;
};
}
exports.getLoad = getLoad;
function isNode(obj) {
return (!!obj.name ||
obj.type === 'root' ||
obj.type === 'text' ||
obj.type === 'comment');
}
});
var unicode$1 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.isUndefinedCodePoint = exports.isControlCodePoint = exports.getSurrogatePairCodePoint = exports.isSurrogatePair = exports.isSurrogate = exports.SEQUENCES = exports.CODE_POINTS = exports.REPLACEMENT_CHARACTER = void 0;
const UNDEFINED_CODE_POINTS = new Set([
65534, 65535, 131070, 131071, 196606, 196607, 262142, 262143, 327678, 327679, 393214,
393215, 458750, 458751, 524286, 524287, 589822, 589823, 655358, 655359, 720894,
720895, 786430, 786431, 851966, 851967, 917502, 917503, 983038, 983039, 1048574,
1048575, 1114110, 1114111,
]);
exports.REPLACEMENT_CHARACTER = '\uFFFD';
(function (CODE_POINTS) {
CODE_POINTS[CODE_POINTS["EOF"] = -1] = "EOF";
CODE_POINTS[CODE_POINTS["NULL"] = 0] = "NULL";
CODE_POINTS[CODE_POINTS["TABULATION"] = 9] = "TABULATION";
CODE_POINTS[CODE_POINTS["CARRIAGE_RETURN"] = 13] = "CARRIAGE_RETURN";
CODE_POINTS[CODE_POINTS["LINE_FEED"] = 10] = "LINE_FEED";
CODE_POINTS[CODE_POINTS["FORM_FEED"] = 12] = "FORM_FEED";
CODE_POINTS[CODE_POINTS["SPACE"] = 32] = "SPACE";
CODE_POINTS[CODE_POINTS["EXCLAMATION_MARK"] = 33] = "EXCLAMATION_MARK";
CODE_POINTS[CODE_POINTS["QUOTATION_MARK"] = 34] = "QUOTATION_MARK";
CODE_POINTS[CODE_POINTS["NUMBER_SIGN"] = 35] = "NUMBER_SIGN";
CODE_POINTS[CODE_POINTS["AMPERSAND"] = 38] = "AMPERSAND";
CODE_POINTS[CODE_POINTS["APOSTROPHE"] = 39] = "APOSTROPHE";
CODE_POINTS[CODE_POINTS["HYPHEN_MINUS"] = 45] = "HYPHEN_MINUS";
CODE_POINTS[CODE_POINTS["SOLIDUS"] = 47] = "SOLIDUS";
CODE_POINTS[CODE_POINTS["DIGIT_0"] = 48] = "DIGIT_0";
CODE_POINTS[CODE_POINTS["DIGIT_9"] = 57] = "DIGIT_9";
CODE_POINTS[CODE_POINTS["SEMICOLON"] = 59] = "SEMICOLON";
CODE_POINTS[CODE_POINTS["LESS_THAN_SIGN"] = 60] = "LESS_THAN_SIGN";
CODE_POINTS[CODE_POINTS["EQUALS_SIGN"] = 61] = "EQUALS_SIGN";
CODE_POINTS[CODE_POINTS["GREATER_THAN_SIGN"] = 62] = "GREATER_THAN_SIGN";
CODE_POINTS[CODE_POINTS["QUESTION_MARK"] = 63] = "QUESTION_MARK";
CODE_POINTS[CODE_POINTS["LATIN_CAPITAL_A"] = 65] = "LATIN_CAPITAL_A";
CODE_POINTS[CODE_POINTS["LATIN_CAPITAL_F"] = 70] = "LATIN_CAPITAL_F";
CODE_POINTS[CODE_POINTS["LATIN_CAPITAL_X"] = 88] = "LATIN_CAPITAL_X";
CODE_POINTS[CODE_POINTS["LATIN_CAPITAL_Z"] = 90] = "LATIN_CAPITAL_Z";
CODE_POINTS[CODE_POINTS["RIGHT_SQUARE_BRACKET"] = 93] = "RIGHT_SQUARE_BRACKET";
CODE_POINTS[CODE_POINTS["GRAVE_ACCENT"] = 96] = "GRAVE_ACCENT";
CODE_POINTS[CODE_POINTS["LATIN_SMALL_A"] = 97] = "LATIN_SMALL_A";
CODE_POINTS[CODE_POINTS["LATIN_SMALL_F"] = 102] = "LATIN_SMALL_F";
CODE_POINTS[CODE_POINTS["LATIN_SMALL_X"] = 120] = "LATIN_SMALL_X";
CODE_POINTS[CODE_POINTS["LATIN_SMALL_Z"] = 122] = "LATIN_SMALL_Z";
CODE_POINTS[CODE_POINTS["REPLACEMENT_CHARACTER"] = 65533] = "REPLACEMENT_CHARACTER";
})(exports.CODE_POINTS || (exports.CODE_POINTS = {}));
exports.SEQUENCES = {
DASH_DASH: '--',
CDATA_START: '[CDATA[',
DOCTYPE: 'doctype',
SCRIPT: 'script',
PUBLIC: 'public',
SYSTEM: 'system',
};
//Surrogates
function isSurrogate(cp) {
return cp >= 55296 && cp <= 57343;
}
exports.isSurrogate = isSurrogate;
function isSurrogatePair(cp) {
return cp >= 56320 && cp <= 57343;
}
exports.isSurrogatePair = isSurrogatePair;
function getSurrogatePairCodePoint(cp1, cp2) {
return (cp1 - 55296) * 1024 + 9216 + cp2;
}
exports.getSurrogatePairCodePoint = getSurrogatePairCodePoint;
//NOTE: excluding NULL and ASCII whitespace
function isControlCodePoint(cp) {
return ((cp !== 0x20 && cp !== 0x0a && cp !== 0x0d && cp !== 0x09 && cp !== 0x0c && cp >= 0x01 && cp <= 0x1f) ||
(cp >= 0x7f && cp <= 0x9f));
}
exports.isControlCodePoint = isControlCodePoint;
function isUndefinedCodePoint(cp) {
return (cp >= 64976 && cp <= 65007) || UNDEFINED_CODE_POINTS.has(cp);
}
exports.isUndefinedCodePoint = isUndefinedCodePoint;
});
var errorCodes$1 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.ERR = void 0;
(function (ERR) {
ERR["controlCharacterInInputStream"] = "control-character-in-input-stream";
ERR["noncharacterInInputStream"] = "noncharacter-in-input-stream";
ERR["surrogateInInputStream"] = "surrogate-in-input-stream";
ERR["nonVoidHtmlElementStartTagWithTrailingSolidus"] = "non-void-html-element-start-tag-with-trailing-solidus";
ERR["endTagWithAttributes"] = "end-tag-with-attributes";
ERR["endTagWithTrailingSolidus"] = "end-tag-with-trailing-solidus";
ERR["unexpectedSolidusInTag"] = "unexpected-solidus-in-tag";
ERR["unexpectedNullCharacter"] = "unexpected-null-character";
ERR["unexpectedQuestionMarkInsteadOfTagName"] = "unexpected-question-mark-instead-of-tag-name";
ERR["invalidFirstCharacterOfTagName"] = "invalid-first-character-of-tag-name";
ERR["unexpectedEqualsSignBeforeAttributeName"] = "unexpected-equals-sign-before-attribute-name";
ERR["missingEndTagName"] = "missing-end-tag-name";
ERR["unexpectedCharacterInAttributeName"] = "unexpected-character-in-attribute-name";
ERR["unknownNamedCharacterReference"] = "unknown-named-character-reference";
ERR["missingSemicolonAfterCharacterReference"] = "missing-semicolon-after-character-reference";
ERR["unexpectedCharacterAfterDoctypeSystemIdentifier"] = "unexpected-character-after-doctype-system-identifier";
ERR["unexpectedCharacterInUnquotedAttributeValue"] = "unexpected-character-in-unquoted-attribute-value";
ERR["eofBeforeTagName"] = "eof-before-tag-name";
ERR["eofInTag"] = "eof-in-tag";
ERR["missingAttributeValue"] = "missing-attribute-value";
ERR["missingWhitespaceBetweenAttributes"] = "missing-whitespace-between-attributes";
ERR["missingWhitespaceAfterDoctypePublicKeyword"] = "missing-whitespace-after-doctype-public-keyword";
ERR["missingWhitespaceBetweenDoctypePublicAndSystemIdentifiers"] = "missing-whitespace-between-doctype-public-and-system-identifiers";
ERR["missingWhitespaceAfterDoctypeSystemKeyword"] = "missing-whitespace-after-doctype-system-keyword";
ERR["missingQuoteBeforeDoctypePublicIdentifier"] = "missing-quote-before-doctype-public-identifier";
ERR["missingQuoteBeforeDoctypeSystemIdentifier"] = "missing-quote-before-doctype-system-identifier";
ERR["missingDoctypePublicIdentifier"] = "missing-doctype-public-identifier";
ERR["missingDoctypeSystemIdentifier"] = "missing-doctype-system-identifier";
ERR["abruptDoctypePublicIdentifier"] = "abrupt-doctype-public-identifier";
ERR["abruptDoctypeSystemIdentifier"] = "abrupt-doctype-system-identifier";
ERR["cdataInHtmlContent"] = "cdata-in-html-content";
ERR["incorrectlyOpenedComment"] = "incorrectly-opened-comment";
ERR["eofInScriptHtmlCommentLikeText"] = "eof-in-script-html-comment-like-text";
ERR["eofInDoctype"] = "eof-in-doctype";
ERR["nestedComment"] = "nested-comment";
ERR["abruptClosingOfEmptyComment"] = "abrupt-closing-of-empty-comment";
ERR["eofInComment"] = "eof-in-comment";
ERR["incorrectlyClosedComment"] = "incorrectly-closed-comment";
ERR["eofInCdata"] = "eof-in-cdata";
ERR["absenceOfDigitsInNumericCharacterReference"] = "absence-of-digits-in-numeric-character-reference";
ERR["nullCharacterReference"] = "null-character-reference";
ERR["surrogateCharacterReference"] = "surrogate-character-reference";
ERR["characterReferenceOutsideUnicodeRange"] = "character-reference-outside-unicode-range";
ERR["controlCharacterReference"] = "control-character-reference";
ERR["noncharacterCharacterReference"] = "noncharacter-character-reference";
ERR["missingWhitespaceBeforeDoctypeName"] = "missing-whitespace-before-doctype-name";
ERR["missingDoctypeName"] = "missing-doctype-name";
ERR["invalidCharacterSequenceAfterDoctypeName"] = "invalid-character-sequence-after-doctype-name";
ERR["duplicateAttribute"] = "duplicate-attribute";
ERR["nonConformingDoctype"] = "non-conforming-doctype";
ERR["missingDoctype"] = "missing-doctype";
ERR["misplacedDoctype"] = "misplaced-doctype";
ERR["endTagWithoutMatchingOpenElement"] = "end-tag-without-matching-open-element";
ERR["closingOfElementWithOpenChildElements"] = "closing-of-element-with-open-child-elements";
ERR["disallowedContentInNoscriptInHead"] = "disallowed-content-in-noscript-in-head";
ERR["openElementsLeftAfterEof"] = "open-elements-left-after-eof";
ERR["abandonedHeadElementChild"] = "abandoned-head-element-child";
ERR["misplacedStartTagForHeadElement"] = "misplaced-start-tag-for-head-element";
ERR["nestedNoscriptInHead"] = "nested-noscript-in-head";
ERR["eofInElementThatCanContainOnlyText"] = "eof-in-element-that-can-contain-only-text";
})(exports.ERR || (exports.ERR = {}));
});
var preprocessor$1 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.Preprocessor = void 0;
//Const
const DEFAULT_BUFFER_WATERLINE = 1 << 16;
//Preprocessor
//NOTE: HTML input preprocessing
//(see: http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#preprocessing-the-input-stream)
class Preprocessor {
constructor(handler) {
this.handler = handler;
this.html = '';
this.pos = -1;
// NOTE: Initial `lastGapPos` is -2, to ensure `col` on initialisation is 0
this.lastGapPos = -2;
this.gapStack = [];
this.skipNextNewLine = false;
this.lastChunkWritten = false;
this.endOfChunkHit = false;
this.bufferWaterline = DEFAULT_BUFFER_WATERLINE;
this.isEol = false;
this.lineStartPos = 0;
this.droppedBufferSize = 0;
this.line = 1;
//NOTE: avoid reporting errors twice on advance/retreat
this.lastErrOffset = -1;
}
/** The column on the current line. If we just saw a gap (eg. a surrogate pair), return the index before. */
get col() {
return this.pos - this.lineStartPos + Number(this.lastGapPos !== this.pos);
}
get offset() {
return this.droppedBufferSize + this.pos;
}
getError(code) {
const { line, col, offset } = this;
return {
code,
startLine: line,
endLine: line,
startCol: col,
endCol: col,
startOffset: offset,
endOffset: offset,
};
}
_err(code) {
if (this.handler.onParseError && this.lastErrOffset !== this.offset) {
this.lastErrOffset = this.offset;
this.handler.onParseError(this.getError(code));
}
}
_addGap() {
this.gapStack.push(this.lastGapPos);
this.lastGapPos = this.pos;
}
_processSurrogate(cp) {
//NOTE: try to peek a surrogate pair
if (this.pos !== this.html.length - 1) {
const nextCp = this.html.charCodeAt(this.pos + 1);
if ((0, unicode$1.isSurrogatePair)(nextCp)) {
//NOTE: we have a surrogate pair. Peek pair character and recalculate code point.
this.pos++;
//NOTE: add a gap that should be avoided during retreat
this._addGap();
return (0, unicode$1.getSurrogatePairCodePoint)(cp, nextCp);
}
}
//NOTE: we are at the end of a chunk, therefore we can't infer the surrogate pair yet.
else if (!this.lastChunkWritten) {
this.endOfChunkHit = true;
return unicode$1.CODE_POINTS.EOF;
}
//NOTE: isolated surrogate
this._err(errorCodes$1.ERR.surrogateInInputStream);
return cp;
}
willDropParsedChunk() {
return this.pos > this.bufferWaterline;
}
dropParsedChunk() {
if (this.willDropParsedChunk()) {
this.html = this.html.substring(this.pos);
this.lineStartPos -= this.pos;
this.droppedBufferSize += this.pos;
this.pos = 0;
this.lastGapPos = -2;
this.gapStack.length = 0;
}
}
write(chunk, isLastChunk) {
if (this.html.length > 0) {
this.html += chunk;
}
else {
this.html = chunk;
}
this.endOfChunkHit = false;
this.lastChunkWritten = isLastChunk;
}
insertHtmlAtCurrentPos(chunk) {
this.html = this.html.substring(0, this.pos + 1) + chunk + this.html.substring(this.pos + 1);
this.endOfChunkHit = false;
}
startsWith(pattern, caseSensitive) {
// Check if our buffer has enough characters
if (this.pos + pattern.length > this.html.length) {
this.endOfChunkHit = !this.lastChunkWritten;
return false;
}
if (caseSensitive) {
return this.html.startsWith(pattern, this.pos);
}
for (let i = 0; i < pattern.length; i++) {
const cp = this.html.charCodeAt(this.pos + i) | 0x20;
if (cp !== pattern.charCodeAt(i)) {
return false;
}
}
return true;
}
peek(offset) {
const pos = this.pos + offset;
if (pos >= this.html.length) {
this.endOfChunkHit = !this.lastChunkWritten;
return unicode$1.CODE_POINTS.EOF;
}
const code = this.html.charCodeAt(pos);
return code === unicode$1.CODE_POINTS.CARRIAGE_RETURN ? unicode$1.CODE_POINTS.LINE_FEED : code;
}
advance() {
this.pos++;
//NOTE: LF should be in the last column of the line
if (this.isEol) {
this.isEol = false;
this.line++;
this.lineStartPos = this.pos;
}
if (this.pos >= this.html.length) {
this.endOfChunkHit = !this.lastChunkWritten;
return unicode$1.CODE_POINTS.EOF;
}
let cp = this.html.charCodeAt(this.pos);
//NOTE: all U+000D CARRIAGE RETURN (CR) characters must be converted to U+000A LINE FEED (LF) characters
if (cp === unicode$1.CODE_POINTS.CARRIAGE_RETURN) {
this.isEol = true;
this.skipNextNewLine = true;
return unicode$1.CODE_POINTS.LINE_FEED;
}
//NOTE: any U+000A LINE FEED (LF) characters that immediately follow a U+000D CARRIAGE RETURN (CR) character
//must be ignored.
if (cp === unicode$1.CODE_POINTS.LINE_FEED) {
this.isEol = true;
if (this.skipNextNewLine) {
// `line` will be bumped again in the recursive call.
this.line--;
this.skipNextNewLine = false;
this._addGap();
return this.advance();
}
}
this.skipNextNewLine = false;
if ((0, unicode$1.isSurrogate)(cp)) {
cp = this._processSurrogate(cp);
}
//OPTIMIZATION: first check if code point is in the common allowed
//range (ASCII alphanumeric, whitespaces, big chunk of BMP)
//before going into detailed performance cost validation.
const isCommonValidRange = this.handler.onParseError === null ||
(cp > 0x1f && cp < 0x7f) ||
cp === unicode$1.CODE_POINTS.LINE_FEED ||
cp === unicode$1.CODE_POINTS.CARRIAGE_RETURN ||
(cp > 0x9f && cp < 64976);
if (!isCommonValidRange) {
this._checkForProblematicCharacters(cp);
}
return cp;
}
_checkForProblematicCharacters(cp) {
if ((0, unicode$1.isControlCodePoint)(cp)) {
this._err(errorCodes$1.ERR.controlCharacterInInputStream);
}
else if ((0, unicode$1.isUndefinedCodePoint)(cp)) {
this._err(errorCodes$1.ERR.noncharacterInInputStream);
}
}
retreat(count) {
this.pos -= count;
while (this.pos < this.lastGapPos) {
this.lastGapPos = this.gapStack.pop();
this.pos--;
}
this.isEol = false;
}
}
exports.Preprocessor = Preprocessor;
});
var token$1 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.getTokenAttr = exports.TokenType = void 0;
(function (TokenType) {
TokenType[TokenType["CHARACTER"] = 0] = "CHARACTER";
TokenType[TokenType["NULL_CHARACTER"] = 1] = "NULL_CHARACTER";
TokenType[TokenType["WHITESPACE_CHARACTER"] = 2] = "WHITESPACE_CHARACTER";
TokenType[TokenType["START_TAG"] = 3] = "START_TAG";
TokenType[TokenType["END_TAG"] = 4] = "END_TAG";
TokenType[TokenType["COMMENT"] = 5] = "COMMENT";
TokenType[TokenType["DOCTYPE"] = 6] = "DOCTYPE";
TokenType[TokenType["EOF"] = 7] = "EOF";
TokenType[TokenType["HIBERNATION"] = 8] = "HIBERNATION";
})(exports.TokenType || (exports.TokenType = {}));
function getTokenAttr(token, attrName) {
for (let i = token.attrs.length - 1; i >= 0; i--) {
if (token.attrs[i].name === attrName) {
return token.attrs[i].value;
}
}
return null;
}
exports.getTokenAttr = getTokenAttr;
});
var html$1 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.hasUnescapedText = exports.isNumberedHeader = exports.SPECIAL_ELEMENTS = exports.getTagID = exports.TAG_ID = exports.TAG_NAMES = exports.DOCUMENT_MODE = exports.ATTRS = exports.NS = void 0;
/** All valid namespaces in HTML. */
var NS;
(function (NS) {
NS["HTML"] = "http://www.w3.org/1999/xhtml";
NS["MATHML"] = "http://www.w3.org/1998/Math/MathML";
NS["SVG"] = "http://www.w3.org/2000/svg";
NS["XLINK"] = "http://www.w3.org/1999/xlink";
NS["XML"] = "http://www.w3.org/XML/1998/namespace";
NS["XMLNS"] = "http://www.w3.org/2000/xmlns/";
})(NS = exports.NS || (exports.NS = {}));
(function (ATTRS) {
ATTRS["TYPE"] = "type";
ATTRS["ACTION"] = "action";
ATTRS["ENCODING"] = "encoding";
ATTRS["PROMPT"] = "prompt";
ATTRS["NAME"] = "name";
ATTRS["COLOR"] = "color";
ATTRS["FACE"] = "face";
ATTRS["SIZE"] = "size";
})(exports.ATTRS || (exports.ATTRS = {}));
(function (DOCUMENT_MODE) {
DOCUMENT_MODE["NO_QUIRKS"] = "no-quirks";
DOCUMENT_MODE["QUIRKS"] = "quirks";
DOCUMENT_MODE["LIMITED_QUIRKS"] = "limited-quirks";
})(exports.DOCUMENT_MODE || (exports.DOCUMENT_MODE = {}));
var TAG_NAMES;
(function (TAG_NAMES) {
TAG_NAMES["A"] = "a";
TAG_NAMES["ADDRESS"] = "address";
TAG_NAMES["ANNOTATION_XML"] = "annotation-xml";
TAG_NAMES["APPLET"] = "applet";
TAG_NAMES["AREA"] = "area";
TAG_NAMES["ARTICLE"] = "article";
TAG_NAMES["ASIDE"] = "aside";
TAG_NAMES["B"] = "b";
TAG_NAMES["BASE"] = "base";
TAG_NAMES["BASEFONT"] = "basefont";
TAG_NAMES["BGSOUND"] = "bgsound";
TAG_NAMES["BIG"] = "big";
TAG_NAMES["BLOCKQUOTE"] = "blockquote";
TAG_NAMES["BODY"] = "body";
TAG_NAMES["BR"] = "br";
TAG_NAMES["BUTTON"] = "button";
TAG_NAMES["CAPTION"] = "caption";
TAG_NAMES["CENTER"] = "center";
TAG_NAMES["CODE"] = "code";
TAG_NAMES["COL"] = "col";
TAG_NAMES["COLGROUP"] = "colgroup";
TAG_NAMES["DD"] = "dd";
TAG_NAMES["DESC"] = "desc";
TAG_NAMES["DETAILS"] = "details";
TAG_NAMES["DIALOG"] = "dialog";
TAG_NAMES["DIR"] = "dir";
TAG_NAMES["DIV"] = "div";
TAG_NAMES["DL"] = "dl";
TAG_NAMES["DT"] = "dt";
TAG_NAMES["EM"] = "em";
TAG_NAMES["EMBED"] = "embed";
TAG_NAMES["FIELDSET"] = "fieldset";
TAG_NAMES["FIGCAPTION"] = "figcaption";
TAG_NAMES["FIGURE"] = "figure";
TAG_NAMES["FONT"] = "font";
TAG_NAMES["FOOTER"] = "footer";
TAG_NAMES["FOREIGN_OBJECT"] = "foreignObject";
TAG_NAMES["FORM"] = "form";
TAG_NAMES["FRAME"] = "frame";
TAG_NAMES["FRAMESET"] = "frameset";
TAG_NAMES["H1"] = "h1";
TAG_NAMES["H2"] = "h2";
TAG_NAMES["H3"] = "h3";
TAG_NAMES["H4"] = "h4";
TAG_NAMES["H5"] = "h5";
TAG_NAMES["H6"] = "h6";
TAG_NAMES["HEAD"] = "head";
TAG_NAMES["HEADER"] = "header";
TAG_NAMES["HGROUP"] = "hgroup";
TAG_NAMES["HR"] = "hr";
TAG_NAMES["HTML"] = "html";
TAG_NAMES["I"] = "i";
TAG_NAMES["IMG"] = "img";
TAG_NAMES["IMAGE"] = "image";
TAG_NAMES["INPUT"] = "input";
TAG_NAMES["IFRAME"] = "iframe";
TAG_NAMES["KEYGEN"] = "keygen";
TAG_NAMES["LABEL"] = "label";
TAG_NAMES["LI"] = "li";
TAG_NAMES["LINK"] = "link";
TAG_NAMES["LISTING"] = "listing";
TAG_NAMES["MAIN"] = "main";
TAG_NAMES["MALIGNMARK"] = "malignmark";
TAG_NAMES["MARQUEE"] = "marquee";
TAG_NAMES["MATH"] = "math";
TAG_NAMES["MENU"] = "menu";
TAG_NAMES["META"] = "meta";
TAG_NAMES["MGLYPH"] = "mglyph";
TAG_NAMES["MI"] = "mi";
TAG_NAMES["MO"] = "mo";
TAG_NAMES["MN"] = "mn";
TAG_NAMES["MS"] = "ms";
TAG_NAMES["MTEXT"] = "mtext";
TAG_NAMES["NAV"] = "nav";
TAG_NAMES["NOBR"] = "nobr";
TAG_NAMES["NOFRAMES"] = "noframes";
TAG_NAMES["NOEMBED"] = "noembed";
TAG_NAMES["NOSCRIPT"] = "noscript";
TAG_NAMES["OBJECT"] = "object";
TAG_NAMES["OL"] = "ol";
TAG_NAMES["OPTGROUP"] = "optgroup";
TAG_NAMES["OPTION"] = "option";
TAG_NAMES["P"] = "p";
TAG_NAMES["PARAM"] = "param";
TAG_NAMES["PLAINTEXT"] = "plaintext";
TAG_NAMES["PRE"] = "pre";
TAG_NAMES["RB"] = "rb";
TAG_NAMES["RP"] = "rp";
TAG_NAMES["RT"] = "rt";
TAG_NAMES["RTC"] = "rtc";
TAG_NAMES["RUBY"] = "ruby";
TAG_NAMES["S"] = "s";
TAG_NAMES["SCRIPT"] = "script";
TAG_NAMES["SECTION"] = "section";
TAG_NAMES["SELECT"] = "select";
TAG_NAMES["SOURCE"] = "source";
TAG_NAMES["SMALL"] = "small";
TAG_NAMES["SPAN"] = "span";
TAG_NAMES["STRIKE"] = "strike";
TAG_NAMES["STRONG"] = "strong";
TAG_NAMES["STYLE"] = "style";
TAG_NAMES["SUB"] = "sub";
TAG_NAMES["SUMMARY"] = "summary";
TAG_NAMES["SUP"] = "sup";
TAG_NAMES["TABLE"] = "table";
TAG_NAMES["TBODY"] = "tbody";
TAG_NAMES["TEMPLATE"] = "template";
TAG_NAMES["TEXTAREA"] = "textarea";
TAG_NAMES["TFOOT"] = "tfoot";
TAG_NAMES["TD"] = "td";
TAG_NAMES["TH"] = "th";
TAG_NAMES["THEAD"] = "thead";
TAG_NAMES["TITLE"] = "title";
TAG_NAMES["TR"] = "tr";
TAG_NAMES["TRACK"] = "track";
TAG_NAMES["TT"] = "tt";
TAG_NAMES["U"] = "u";
TAG_NAMES["UL"] = "ul";
TAG_NAMES["SVG"] = "svg";
TAG_NAMES["VAR"] = "var";
TAG_NAMES["WBR"] = "wbr";
TAG_NAMES["XMP"] = "xmp";
})(TAG_NAMES = exports.TAG_NAMES || (exports.TAG_NAMES = {}));
/**
* Tag IDs are numeric IDs for known tag names.
*
* We use tag IDs to improve the performance of tag name comparisons.
*/
var TAG_ID;
(function (TAG_ID) {
TAG_ID[TAG_ID["UNKNOWN"] = 0] = "UNKNOWN";
TAG_ID[TAG_ID["A"] = 1] = "A";
TAG_ID[TAG_ID["ADDRESS"] = 2] = "ADDRESS";
TAG_ID[TAG_ID["ANNOTATION_XML"] = 3] = "ANNOTATION_XML";
TAG_ID[TAG_ID["APPLET"] = 4] = "APPLET";
TAG_ID[TAG_ID["AREA"] = 5] = "AREA";
TAG_ID[TAG_ID["ARTICLE"] = 6] = "ARTICLE";
TAG_ID[TAG_ID["ASIDE"] = 7] = "ASIDE";
TAG_ID[TAG_ID["B"] = 8] = "B";
TAG_ID[TAG_ID["BASE"] = 9] = "BASE";
TAG_ID[TAG_ID["BASEFONT"] = 10] = "BASEFONT";
TAG_ID[TAG_ID["BGSOUND"] = 11] = "BGSOUND";
TAG_ID[TAG_ID["BIG"] = 12] = "BIG";
TAG_ID[TAG_ID["BLOCKQUOTE"] = 13] = "BLOCKQUOTE";
TAG_ID[TAG_ID["BODY"] = 14] = "BODY";
TAG_ID[TAG_ID["BR"] = 15] = "BR";
TAG_ID[TAG_ID["BUTTON"] = 16] = "BUTTON";
TAG_ID[TAG_ID["CAPTION"] = 17] = "CAPTION";
TAG_ID[TAG_ID["CENTER"] = 18] = "CENTER";
TAG_ID[TAG_ID["CODE"] = 19] = "CODE";
TAG_ID[TAG_ID["COL"] = 20] = "COL";
TAG_ID[TAG_ID["COLGROUP"] = 21] = "COLGROUP";
TAG_ID[TAG_ID["DD"] = 22] = "DD";
TAG_ID[TAG_ID["DESC"] = 23] = "DESC";
TAG_ID[TAG_ID["DETAILS"] = 24] = "DETAILS";
TAG_ID[TAG_ID["DIALOG"] = 25] = "DIALOG";
TAG_ID[TAG_ID["DIR"] = 26] = "DIR";
TAG_ID[TAG_ID["DIV"] = 27] = "DIV";
TAG_ID[TAG_ID["DL"] = 28] = "DL";
TAG_ID[TAG_ID["DT"] = 29] = "DT";
TAG_ID[TAG_ID["EM"] = 30] = "EM";
TAG_ID[TAG_ID["EMBED"] = 31] = "EMBED";
TAG_ID[TAG_ID["FIELDSET"] = 32] = "FIELDSET";
TAG_ID[TAG_ID["FIGCAPTION"] = 33] = "FIGCAPTION";
TAG_ID[TAG_ID["FIGURE"] = 34] = "FIGURE";
TAG_ID[TAG_ID["FONT"] = 35] = "FONT";
TAG_ID[TAG_ID["FOOTER"] = 36] = "FOOTER";
TAG_ID[TAG_ID["FOREIGN_OBJECT"] = 37] = "FOREIGN_OBJECT";
TAG_ID[TAG_ID["FORM"] = 38] = "FORM";
TAG_ID[TAG_ID["FRAME"] = 39] = "FRAME";
TAG_ID[TAG_ID["FRAMESET"] = 40] = "FRAMESET";
TAG_ID[TAG_ID["H1"] = 41] = "H1";
TAG_ID[TAG_ID["H2"] = 42] = "H2";
TAG_ID[TAG_ID["H3"] = 43] = "H3";
TAG_ID[TAG_ID["H4"] = 44] = "H4";
TAG_ID[TAG_ID["H5"] = 45] = "H5";
TAG_ID[TAG_ID["H6"] = 46] = "H6";
TAG_ID[TAG_ID["HEAD"] = 47] = "HEAD";
TAG_ID[TAG_ID["HEADER"] = 48] = "HEADER";
TAG_ID[TAG_ID["HGROUP"] = 49] = "HGROUP";
TAG_ID[TAG_ID["HR"] = 50] = "HR";
TAG_ID[TAG_ID["HTML"] = 51] = "HTML";
TAG_ID[TAG_ID["I"] = 52] = "I";
TAG_ID[TAG_ID["IMG"] = 53] = "IMG";
TAG_ID[TAG_ID["IMAGE"] = 54] = "IMAGE";
TAG_ID[TAG_ID["INPUT"] = 55] = "INPUT";
TAG_ID[TAG_ID["IFRAME"] = 56] = "IFRAME";
TAG_ID[TAG_ID["KEYGEN"] = 57] = "KEYGEN";
TAG_ID[TAG_ID["LABEL"] = 58] = "LABEL";
TAG_ID[TAG_ID["LI"] = 59] = "LI";
TAG_ID[TAG_ID["LINK"] = 60] = "LINK";
TAG_ID[TAG_ID["LISTING"] = 61] = "LISTING";
TAG_ID[TAG_ID["MAIN"] = 62] = "MAIN";
TAG_ID[TAG_ID["MALIGNMARK"] = 63] = "MALIGNMARK";
TAG_ID[TAG_ID["MARQUEE"] = 64] = "MARQUEE";
TAG_ID[TAG_ID["MATH"] = 65] = "MATH";
TAG_ID[TAG_ID["MENU"] = 66] = "MENU";
TAG_ID[TAG_ID["META"] = 67] = "META";
TAG_ID[TAG_ID["MGLYPH"] = 68] = "MGLYPH";
TAG_ID[TAG_ID["MI"] = 69] = "MI";
TAG_ID[TAG_ID["MO"] = 70] = "MO";
TAG_ID[TAG_ID["MN"] = 71] = "MN";
TAG_ID[TAG_ID["MS"] = 72] = "MS";
TAG_ID[TAG_ID["MTEXT"] = 73] = "MTEXT";
TAG_ID[TAG_ID["NAV"] = 74] = "NAV";
TAG_ID[TAG_ID["NOBR"] = 75] = "NOBR";
TAG_ID[TAG_ID["NOFRAMES"] = 76] = "NOFRAMES";
TAG_ID[TAG_ID["NOEMBED"] = 77] = "NOEMBED";
TAG_ID[TAG_ID["NOSCRIPT"] = 78] = "NOSCRIPT";
TAG_ID[TAG_ID["OBJECT"] = 79] = "OBJECT";
TAG_ID[TAG_ID["OL"] = 80] = "OL";
TAG_ID[TAG_ID["OPTGROUP"] = 81] = "OPTGROUP";
TAG_ID[TAG_ID["OPTION"] = 82] = "OPTION";
TAG_ID[TAG_ID["P"] = 83] = "P";
TAG_ID[TAG_ID["PARAM"] = 84] = "PARAM";
TAG_ID[TAG_ID["PLAINTEXT"] = 85] = "PLAINTEXT";
TAG_ID[TAG_ID["PRE"] = 86] = "PRE";
TAG_ID[TAG_ID["RB"] = 87] = "RB";
TAG_ID[TAG_ID["RP"] = 88] = "RP";
TAG_ID[TAG_ID["RT"] = 89] = "RT";
TAG_ID[TAG_ID["RTC"] = 90] = "RTC";
TAG_ID[TAG_ID["RUBY"] = 91] = "RUBY";
TAG_ID[TAG_ID["S"] = 92] = "S";
TAG_ID[TAG_ID["SCRIPT"] = 93] = "SCRIPT";
TAG_ID[TAG_ID["SECTION"] = 94] = "SECTION";
TAG_ID[TAG_ID["SELECT"] = 95] = "SELECT";
TAG_ID[TAG_ID["SOURCE"] = 96] = "SOURCE";
TAG_ID[TAG_ID["SMALL"] = 97] = "SMALL";
TAG_ID[TAG_ID["SPAN"] = 98] = "SPAN";
TAG_ID[TAG_ID["STRIKE"] = 99] = "STRIKE";
TAG_ID[TAG_ID["STRONG"] = 100] = "STRONG";
TAG_ID[TAG_ID["STYLE"] = 101] = "STYLE";
TAG_ID[TAG_ID["SUB"] = 102] = "SUB";
TAG_ID[TAG_ID["SUMMARY"] = 103] = "SUMMARY";
TAG_ID[TAG_ID["SUP"] = 104] = "SUP";
TAG_ID[TAG_ID["TABLE"] = 105] = "TABLE";
TAG_ID[TAG_ID["TBODY"] = 106] = "TBODY";
TAG_ID[TAG_ID["TEMPLATE"] = 107] = "TEMPLATE";
TAG_ID[TAG_ID["TEXTAREA"] = 108] = "TEXTAREA";
TAG_ID[TAG_ID["TFOOT"] = 109] = "TFOOT";
TAG_ID[TAG_ID["TD"] = 110] = "TD";
TAG_ID[TAG_ID["TH"] = 111] = "TH";
TAG_ID[TAG_ID["THEAD"] = 112] = "THEAD";
TAG_ID[TAG_ID["TITLE"] = 113] = "TITLE";
TAG_ID[TAG_ID["TR"] = 114] = "TR";
TAG_ID[TAG_ID["TRACK"] = 115] = "TRACK";
TAG_ID[TAG_ID["TT"] = 116] = "TT";
TAG_ID[TAG_ID["U"] = 117] = "U";
TAG_ID[TAG_ID["UL"] = 118] = "UL";
TAG_ID[TAG_ID["SVG"] = 119] = "SVG";
TAG_ID[TAG_ID["VAR"] = 120] = "VAR";
TAG_ID[TAG_ID["WBR"] = 121] = "WBR";
TAG_ID[TAG_ID["XMP"] = 122] = "XMP";
})(TAG_ID = exports.TAG_ID || (exports.TAG_ID = {}));
const TAG_NAME_TO_ID = new Map([
[TAG_NAMES.A, TAG_ID.A],
[TAG_NAMES.ADDRESS, TAG_ID.ADDRESS],
[TAG_NAMES.ANNOTATION_XML, TAG_ID.ANNOTATION_XML],
[TAG_NAMES.APPLET, TAG_ID.APPLET],
[TAG_NAMES.AREA, TAG_ID.AREA],
[TAG_NAMES.ARTICLE, TAG_ID.ARTICLE],
[TAG_NAMES.ASIDE, TAG_ID.ASIDE],
[TAG_NAMES.B, TAG_ID.B],
[TAG_NAMES.BASE, TAG_ID.BASE],
[TAG_NAMES.BASEFONT, TAG_ID.BASEFONT],
[TAG_NAMES.BGSOUND, TAG_ID.BGSOUND],
[TAG_NAMES.BIG, TAG_ID.BIG],
[TAG_NAMES.BLOCKQUOTE, TAG_ID.BLOCKQUOTE],
[TAG_NAMES.BODY, TAG_ID.BODY],
[TAG_NAMES.BR, TAG_ID.BR],
[TAG_NAMES.BUTTON, TAG_ID.BUTTON],
[TAG_NAMES.CAPTION, TAG_ID.CAPTION],
[TAG_NAMES.CENTER, TAG_ID.CENTER],
[TAG_NAMES.CODE, TAG_ID.CODE],
[TAG_NAMES.COL, TAG_ID.COL],
[TAG_NAMES.COLGROUP, TAG_ID.COLGROUP],
[TAG_NAMES.DD, TAG_ID.DD],
[TAG_NAMES.DESC, TAG_ID.DESC],
[TAG_NAMES.DETAILS, TAG_ID.DETAILS],
[TAG_NAMES.DIALOG, TAG_ID.DIALOG],
[TAG_NAMES.DIR, TAG_ID.DIR],
[TAG_NAMES.DIV, TAG_ID.DIV],
[TAG_NAMES.DL, TAG_ID.DL],
[TAG_NAMES.DT, TAG_ID.DT],
[TAG_NAMES.EM, TAG_ID.EM],
[TAG_NAMES.EMBED, TAG_ID.EMBED],
[TAG_NAMES.FIELDSET, TAG_ID.FIELDSET],
[TAG_NAMES.FIGCAPTION, TAG_ID.FIGCAPTION],
[TAG_NAMES.FIGURE, TAG_ID.FIGURE],
[TAG_NAMES.FONT, TAG_ID.FONT],
[TAG_NAMES.FOOTER, TAG_ID.FOOTER],
[TAG_NAMES.FOREIGN_OBJECT, TAG_ID.FOREIGN_OBJECT],
[TAG_NAMES.FORM, TAG_ID.FORM],
[TAG_NAMES.FRAME, TAG_ID.FRAME],
[TAG_NAMES.FRAMESET, TAG_ID.FRAMESET],
[TAG_NAMES.H1, TAG_ID.H1],
[TAG_NAMES.H2, TAG_ID.H2],
[TAG_NAMES.H3, TAG_ID.H3],
[TAG_NAMES.H4, TAG_ID.H4],
[TAG_NAMES.H5, TAG_ID.H5],
[TAG_NAMES.H6, TAG_ID.H6],
[TAG_NAMES.HEAD, TAG_ID.HEAD],
[TAG_NAMES.HEADER, TAG_ID.HEADER],
[TAG_NAMES.HGROUP, TAG_ID.HGROUP],
[TAG_NAMES.HR, TAG_ID.HR],
[TAG_NAMES.HTML, TAG_ID.HTML],
[TAG_NAMES.I, TAG_ID.I],
[TAG_NAMES.IMG, TAG_ID.IMG],
[TAG_NAMES.IMAGE, TAG_ID.IMAGE],
[TAG_NAMES.INPUT, TAG_ID.INPUT],
[TAG_NAMES.IFRAME, TAG_ID.IFRAME],
[TAG_NAMES.KEYGEN, TAG_ID.KEYGEN],
[TAG_NAMES.LABEL, TAG_ID.LABEL],
[TAG_NAMES.LI, TAG_ID.LI],
[TAG_NAMES.LINK, TAG_ID.LINK],
[TAG_NAMES.LISTING, TAG_ID.LISTING],
[TAG_NAMES.MAIN, TAG_ID.MAIN],
[TAG_NAMES.MALIGNMARK, TAG_ID.MALIGNMARK],
[TAG_NAMES.MARQUEE, TAG_ID.MARQUEE],
[TAG_NAMES.MATH, TAG_ID.MATH],
[TAG_NAMES.MENU, TAG_ID.MENU],
[TAG_NAMES.META, TAG_ID.META],
[TAG_NAMES.MGLYPH, TAG_ID.MGLYPH],
[TAG_NAMES.MI, TAG_ID.MI],
[TAG_NAMES.MO, TAG_ID.MO],
[TAG_NAMES.MN, TAG_ID.MN],
[TAG_NAMES.MS, TAG_ID.MS],
[TAG_NAMES.MTEXT, TAG_ID.MTEXT],
[TAG_NAMES.NAV, TAG_ID.NAV],
[TAG_NAMES.NOBR, TAG_ID.NOBR],
[TAG_NAMES.NOFRAMES, TAG_ID.NOFRAMES],
[TAG_NAMES.NOEMBED, TAG_ID.NOEMBED],
[TAG_NAMES.NOSCRIPT, TAG_ID.NOSCRIPT],
[TAG_NAMES.OBJECT, TAG_ID.OBJECT],
[TAG_NAMES.OL, TAG_ID.OL],
[TAG_NAMES.OPTGROUP, TAG_ID.OPTGROUP],
[TAG_NAMES.OPTION, TAG_ID.OPTION],
[TAG_NAMES.P, TAG_ID.P],
[TAG_NAMES.PARAM, TAG_ID.PARAM],
[TAG_NAMES.PLAINTEXT, TAG_ID.PLAINTEXT],
[TAG_NAMES.PRE, TAG_ID.PRE],
[TAG_NAMES.RB, TAG_ID.RB],
[TAG_NAMES.RP, TAG_ID.RP],
[TAG_NAMES.RT, TAG_ID.RT],
[TAG_NAMES.RTC, TAG_ID.RTC],
[TAG_NAMES.RUBY, TAG_ID.RUBY],
[TAG_NAMES.S, TAG_ID.S],
[TAG_NAMES.SCRIPT, TAG_ID.SCRIPT],
[TAG_NAMES.SECTION, TAG_ID.SECTION],
[TAG_NAMES.SELECT, TAG_ID.SELECT],
[TAG_NAMES.SOURCE, TAG_ID.SOURCE],
[TAG_NAMES.SMALL, TAG_ID.SMALL],
[TAG_NAMES.SPAN, TAG_ID.SPAN],
[TAG_NAMES.STRIKE, TAG_ID.STRIKE],
[TAG_NAMES.STRONG, TAG_ID.STRONG],
[TAG_NAMES.STYLE, TAG_ID.STYLE],
[TAG_NAMES.SUB, TAG_ID.SUB],
[TAG_NAMES.SUMMARY, TAG_ID.SUMMARY],
[TAG_NAMES.SUP, TAG_ID.SUP],
[TAG_NAMES.TABLE, TAG_ID.TABLE],
[TAG_NAMES.TBODY, TAG_ID.TBODY],
[TAG_NAMES.TEMPLATE, TAG_ID.TEMPLATE],
[TAG_NAMES.TEXTAREA, TAG_ID.TEXTAREA],
[TAG_NAMES.TFOOT, TAG_ID.TFOOT],
[TAG_NAMES.TD, TAG_ID.TD],
[TAG_NAMES.TH, TAG_ID.TH],
[TAG_NAMES.THEAD, TAG_ID.THEAD],
[TAG_NAMES.TITLE, TAG_ID.TITLE],
[TAG_NAMES.TR, TAG_ID.TR],
[TAG_NAMES.TRACK, TAG_ID.TRACK],
[TAG_NAMES.TT, TAG_ID.TT],
[TAG_NAMES.U, TAG_ID.U],
[TAG_NAMES.UL, TAG_ID.UL],
[TAG_NAMES.SVG, TAG_ID.SVG],
[TAG_NAMES.VAR, TAG_ID.VAR],
[TAG_NAMES.WBR, TAG_ID.WBR],
[TAG_NAMES.XMP, TAG_ID.XMP],
]);
function getTagID(tagName) {
var _a;
return (_a = TAG_NAME_TO_ID.get(tagName)) !== null && _a !== void 0 ? _a : TAG_ID.UNKNOWN;
}
exports.getTagID = getTagID;
const $ = TAG_ID;
exports.SPECIAL_ELEMENTS = {
[NS.HTML]: new Set([
$.ADDRESS,
$.APPLET,
$.AREA,
$.ARTICLE,
$.ASIDE,
$.BASE,
$.BASEFONT,
$.BGSOUND,
$.BLOCKQUOTE,
$.BODY,
$.BR,
$.BUTTON,
$.CAPTION,
$.CENTER,
$.COL,
$.COLGROUP,
$.DD,
$.DETAILS,
$.DIR,
$.DIV,
$.DL,
$.DT,
$.EMBED,
$.FIELDSET,
$.FIGCAPTION,
$.FIGURE,
$.FOOTER,
$.FORM,
$.FRAME,
$.FRAMESET,
$.H1,
$.H2,
$.H3,
$.H4,
$.H5,
$.H6,
$.HEAD,
$.HEADER,
$.HGROUP,
$.HR,
$.HTML,
$.IFRAME,
$.IMG,
$.INPUT,
$.LI,
$.LINK,
$.LISTING,
$.MAIN,
$.MARQUEE,
$.MENU,
$.META,
$.NAV,
$.NOEMBED,
$.NOFRAMES,
$.NOSCRIPT,
$.OBJECT,
$.OL,
$.P,
$.PARAM,
$.PLAINTEXT,
$.PRE,
$.SCRIPT,
$.SECTION,
$.SELECT,
$.SOURCE,
$.STYLE,
$.SUMMARY,
$.TABLE,
$.TBODY,
$.TD,
$.TEMPLATE,
$.TEXTAREA,
$.TFOOT,
$.TH,
$.THEAD,
$.TITLE,
$.TR,
$.TRACK,
$.UL,
$.WBR,
$.XMP,
]),
[NS.MATHML]: new Set([$.MI, $.MO, $.MN, $.MS, $.MTEXT, $.ANNOTATION_XML]),
[NS.SVG]: new Set([$.TITLE, $.FOREIGN_OBJECT, $.DESC]),
[NS.XLINK]: new Set(),
[NS.XML]: new Set(),
[NS.XMLNS]: new Set(),
};
function isNumberedHeader(tn) {
return tn === $.H1 || tn === $.H2 || tn === $.H3 || tn === $.H4 || tn === $.H5 || tn === $.H6;
}
exports.isNumberedHeader = isNumberedHeader;
const UNESCAPED_TEXT = new Set([
TAG_NAMES.STYLE,
TAG_NAMES.SCRIPT,
TAG_NAMES.XMP,
TAG_NAMES.IFRAME,
TAG_NAMES.NOEMBED,
TAG_NAMES.NOFRAMES,
TAG_NAMES.PLAINTEXT,
]);
function hasUnescapedText(tn, scriptingEnabled) {
return UNESCAPED_TEXT.has(tn) || (scriptingEnabled && tn === TAG_NAMES.NOSCRIPT);
}
exports.hasUnescapedText = hasUnescapedText;
});
var tokenizer$1 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.Tokenizer = exports.TokenizerMode = void 0;
//C1 Unicode control character reference replacements
const C1_CONTROLS_REFERENCE_REPLACEMENTS = new Map([
[0x80, 8364],
[0x82, 8218],
[0x83, 402],
[0x84, 8222],
[0x85, 8230],
[0x86, 8224],
[0x87, 8225],
[0x88, 710],
[0x89, 8240],
[0x8a, 352],
[0x8b, 8249],
[0x8c, 338],
[0x8e, 381],
[0x91, 8216],
[0x92, 8217],
[0x93, 8220],
[0x94, 8221],
[0x95, 8226],
[0x96, 8211],
[0x97, 8212],
[0x98, 732],
[0x99, 8482],
[0x9a, 353],
[0x9b, 8250],
[0x9c, 339],
[0x9e, 382],
[0x9f, 376],
]);
//States
var State;
(function (State) {
State[State["DATA"] = 0] = "DATA";
State[State["RCDATA"] = 1] = "RCDATA";
State[State["RAWTEXT"] = 2] = "RAWTEXT";
State[State["SCRIPT_DATA"] = 3] = "SCRIPT_DATA";
State[State["PLAINTEXT"] = 4] = "PLAINTEXT";
State[State["TAG_OPEN"] = 5] = "TAG_OPEN";
State[State["END_TAG_OPEN"] = 6] = "END_TAG_OPEN";
State[State["TAG_NAME"] = 7] = "TAG_NAME";
State[State["RCDATA_LESS_THAN_SIGN"] = 8] = "RCDATA_LESS_THAN_SIGN";
State[State["RCDATA_END_TAG_OPEN"] = 9] = "RCDATA_END_TAG_OPEN";
State[State["RCDATA_END_TAG_NAME"] = 10] = "RCDATA_END_TAG_NAME";
State[State["RAWTEXT_LESS_THAN_SIGN"] = 11] = "RAWTEXT_LESS_THAN_SIGN";
State[State["RAWTEXT_END_TAG_OPEN"] = 12] = "RAWTEXT_END_TAG_OPEN";
State[State["RAWTEXT_END_TAG_NAME"] = 13] = "RAWTEXT_END_TAG_NAME";
State[State["SCRIPT_DATA_LESS_THAN_SIGN"] = 14] = "SCRIPT_DATA_LESS_THAN_SIGN";
State[State["SCRIPT_DATA_END_TAG_OPEN"] = 15] = "SCRIPT_DATA_END_TAG_OPEN";
State[State["SCRIPT_DATA_END_TAG_NAME"] = 16] = "SCRIPT_DATA_END_TAG_NAME";
State[State["SCRIPT_DATA_ESCAPE_START"] = 17] = "SCRIPT_DATA_ESCAPE_START";
State[State["SCRIPT_DATA_ESCAPE_START_DASH"] = 18] = "SCRIPT_DATA_ESCAPE_START_DASH";
State[State["SCRIPT_DATA_ESCAPED"] = 19] = "SCRIPT_DATA_ESCAPED";
State[State["SCRIPT_DATA_ESCAPED_DASH"] = 20] = "SCRIPT_DATA_ESCAPED_DASH";
State[State["SCRIPT_DATA_ESCAPED_DASH_DASH"] = 21] = "SCRIPT_DATA_ESCAPED_DASH_DASH";
State[State["SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN"] = 22] = "SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN";
State[State["SCRIPT_DATA_ESCAPED_END_TAG_OPEN"] = 23] = "SCRIPT_DATA_ESCAPED_END_TAG_OPEN";
State[State["SCRIPT_DATA_ESCAPED_END_TAG_NAME"] = 24] = "SCRIPT_DATA_ESCAPED_END_TAG_NAME";
State[State["SCRIPT_DATA_DOUBLE_ESCAPE_START"] = 25] = "SCRIPT_DATA_DOUBLE_ESCAPE_START";
State[State["SCRIPT_DATA_DOUBLE_ESCAPED"] = 26] = "SCRIPT_DATA_DOUBLE_ESCAPED";
State[State["SCRIPT_DATA_DOUBLE_ESCAPED_DASH"] = 27] = "SCRIPT_DATA_DOUBLE_ESCAPED_DASH";
State[State["SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH"] = 28] = "SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH";
State[State["SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN"] = 29] = "SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN";
State[State["SCRIPT_DATA_DOUBLE_ESCAPE_END"] = 30] = "SCRIPT_DATA_DOUBLE_ESCAPE_END";
State[State["BEFORE_ATTRIBUTE_NAME"] = 31] = "BEFORE_ATTRIBUTE_NAME";
State[State["ATTRIBUTE_NAME"] = 32] = "ATTRIBUTE_NAME";
State[State["AFTER_ATTRIBUTE_NAME"] = 33] = "AFTER_ATTRIBUTE_NAME";
State[State["BEFORE_ATTRIBUTE_VALUE"] = 34] = "BEFORE_ATTRIBUTE_VALUE";
State[State["ATTRIBUTE_VALUE_DOUBLE_QUOTED"] = 35] = "ATTRIBUTE_VALUE_DOUBLE_QUOTED";
State[State["ATTRIBUTE_VALUE_SINGLE_QUOTED"] = 36] = "ATTRIBUTE_VALUE_SINGLE_QUOTED";
State[State["ATTRIBUTE_VALUE_UNQUOTED"] = 37] = "ATTRIBUTE_VALUE_UNQUOTED";
State[State["AFTER_ATTRIBUTE_VALUE_QUOTED"] = 38] = "AFTER_ATTRIBUTE_VALUE_QUOTED";
State[State["SELF_CLOSING_START_TAG"] = 39] = "SELF_CLOSING_START_TAG";
State[State["BOGUS_COMMENT"] = 40] = "BOGUS_COMMENT";
State[State["MARKUP_DECLARATION_OPEN"] = 41] = "MARKUP_DECLARATION_OPEN";
State[State["COMMENT_START"] = 42] = "COMMENT_START";
State[State["COMMENT_START_DASH"] = 43] = "COMMENT_START_DASH";
State[State["COMMENT"] = 44] = "COMMENT";
State[State["COMMENT_LESS_THAN_SIGN"] = 45] = "COMMENT_LESS_THAN_SIGN";
State[State["COMMENT_LESS_THAN_SIGN_BANG"] = 46] = "COMMENT_LESS_THAN_SIGN_BANG";
State[State["COMMENT_LESS_THAN_SIGN_BANG_DASH"] = 47] = "COMMENT_LESS_THAN_SIGN_BANG_DASH";
State[State["COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH"] = 48] = "COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH";
State[State["COMMENT_END_DASH"] = 49] = "COMMENT_END_DASH";
State[State["COMMENT_END"] = 50] = "COMMENT_END";
State[State["COMMENT_END_BANG"] = 51] = "COMMENT_END_BANG";
State[State["DOCTYPE"] = 52] = "DOCTYPE";
State[State["BEFORE_DOCTYPE_NAME"] = 53] = "BEFORE_DOCTYPE_NAME";
State[State["DOCTYPE_NAME"] = 54] = "DOCTYPE_NAME";
State[State["AFTER_DOCTYPE_NAME"] = 55] = "AFTER_DOCTYPE_NAME";
State[State["AFTER_DOCTYPE_PUBLIC_KEYWORD"] = 56] = "AFTER_DOCTYPE_PUBLIC_KEYWORD";
State[State["BEFORE_DOCTYPE_PUBLIC_IDENTIFIER"] = 57] = "BEFORE_DOCTYPE_PUBLIC_IDENTIFIER";
State[State["DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED"] = 58] = "DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED";
State[State["DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED"] = 59] = "DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED";
State[State["AFTER_DOCTYPE_PUBLIC_IDENTIFIER"] = 60] = "AFTER_DOCTYPE_PUBLIC_IDENTIFIER";
State[State["BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS"] = 61] = "BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS";
State[State["AFTER_DOCTYPE_SYSTEM_KEYWORD"] = 62] = "AFTER_DOCTYPE_SYSTEM_KEYWORD";
State[State["BEFORE_DOCTYPE_SYSTEM_IDENTIFIER"] = 63] = "BEFORE_DOCTYPE_SYSTEM_IDENTIFIER";
State[State["DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED"] = 64] = "DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED";
State[State["DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED"] = 65] = "DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED";
State[State["AFTER_DOCTYPE_SYSTEM_IDENTIFIER"] = 66] = "AFTER_DOCTYPE_SYSTEM_IDENTIFIER";
State[State["BOGUS_DOCTYPE"] = 67] = "BOGUS_DOCTYPE";
State[State["CDATA_SECTION"] = 68] = "CDATA_SECTION";
State[State["CDATA_SECTION_BRACKET"] = 69] = "CDATA_SECTION_BRACKET";
State[State["CDATA_SECTION_END"] = 70] = "CDATA_SECTION_END";
State[State["CHARACTER_REFERENCE"] = 71] = "CHARACTER_REFERENCE";
State[State["NAMED_CHARACTER_REFERENCE"] = 72] = "NAMED_CHARACTER_REFERENCE";
State[State["AMBIGUOUS_AMPERSAND"] = 73] = "AMBIGUOUS_AMPERSAND";
State[State["NUMERIC_CHARACTER_REFERENCE"] = 74] = "NUMERIC_CHARACTER_REFERENCE";
State[State["HEXADEMICAL_CHARACTER_REFERENCE_START"] = 75] = "HEXADEMICAL_CHARACTER_REFERENCE_START";
State[State["HEXADEMICAL_CHARACTER_REFERENCE"] = 76] = "HEXADEMICAL_CHARACTER_REFERENCE";
State[State["DECIMAL_CHARACTER_REFERENCE"] = 77] = "DECIMAL_CHARACTER_REFERENCE";
State[State["NUMERIC_CHARACTER_REFERENCE_END"] = 78] = "NUMERIC_CHARACTER_REFERENCE_END";
})(State || (State = {}));
//Tokenizer initial states for different modes
exports.TokenizerMode = {
DATA: State.DATA,
RCDATA: State.RCDATA,
RAWTEXT: State.RAWTEXT,
SCRIPT_DATA: State.SCRIPT_DATA,
PLAINTEXT: State.PLAINTEXT,
CDATA_SECTION: State.CDATA_SECTION,
};
//Utils
//OPTIMIZATION: these utility functions should not be moved out of this module. V8 Crankshaft will not inline
//this functions if they will be situated in another module due to context switch.
//Always perform inlining check before modifying this functions ('node --trace-inlining').
function isAsciiDigit(cp) {
return cp >= unicode$1.CODE_POINTS.DIGIT_0 && cp <= unicode$1.CODE_POINTS.DIGIT_9;
}
function isAsciiUpper(cp) {
return cp >= unicode$1.CODE_POINTS.LATIN_CAPITAL_A && cp <= unicode$1.CODE_POINTS.LATIN_CAPITAL_Z;
}
function isAsciiLower(cp) {
return cp >= unicode$1.CODE_POINTS.LATIN_SMALL_A && cp <= unicode$1.CODE_POINTS.LATIN_SMALL_Z;
}
function isAsciiLetter(cp) {
return isAsciiLower(cp) || isAsciiUpper(cp);
}
function isAsciiAlphaNumeric(cp) {
return isAsciiLetter(cp) || isAsciiDigit(cp);
}
function isAsciiUpperHexDigit(cp) {
return cp >= unicode$1.CODE_POINTS.LATIN_CAPITAL_A && cp <= unicode$1.CODE_POINTS.LATIN_CAPITAL_F;
}
function isAsciiLowerHexDigit(cp) {
return cp >= unicode$1.CODE_POINTS.LATIN_SMALL_A && cp <= unicode$1.CODE_POINTS.LATIN_SMALL_F;
}
function isAsciiHexDigit(cp) {
return isAsciiDigit(cp) || isAsciiUpperHexDigit(cp) || isAsciiLowerHexDigit(cp);
}
function toAsciiLower(cp) {
return cp + 32;
}
function isWhitespace(cp) {
return cp === unicode$1.CODE_POINTS.SPACE || cp === unicode$1.CODE_POINTS.LINE_FEED || cp === unicode$1.CODE_POINTS.TABULATION || cp === unicode$1.CODE_POINTS.FORM_FEED;
}
function isEntityInAttributeInvalidEnd(nextCp) {
return nextCp === unicode$1.CODE_POINTS.EQUALS_SIGN || isAsciiAlphaNumeric(nextCp);
}
function isScriptDataDoubleEscapeSequenceEnd(cp) {
return isWhitespace(cp) || cp === unicode$1.CODE_POINTS.SOLIDUS || cp === unicode$1.CODE_POINTS.GREATER_THAN_SIGN;
}
//Tokenizer
class Tokenizer {
constructor(options, handler) {
this.options = options;
this.handler = handler;
this.paused = false;
/** Ensures that the parsing loop isn't run multiple times at once. */
this.inLoop = false;
/**
* Indicates that the current adjusted node exists, is not an element in the HTML namespace,
* and that it is not an integration point for either MathML or HTML.
*
* @see {@link https://html.spec.whatwg.org/multipage/parsing.html#tree-construction}
*/
this.inForeignNode = false;
this.lastStartTagName = '';
this.active = false;
this.state = State.DATA;
this.returnState = State.DATA;
this.charRefCode = -1;
this.consumedAfterSnapshot = -1;
this.currentCharacterToken = null;
this.currentToken = null;
this.currentAttr = { name: '', value: '' };
this.preprocessor = new preprocessor$1.Preprocessor(handler);
this.currentLocation = this.getCurrentLocation(-1);
}
//Errors
_err(code) {
var _a, _b;
(_b = (_a = this.handler).onParseError) === null || _b === void 0 ? void 0 : _b.call(_a, this.preprocessor.getError(code));
}
// NOTE: `offset` may never run across line boundaries.
getCurrentLocation(offset) {
if (!this.options.sourceCodeLocationInfo) {
return null;
}
return {
startLine: this.preprocessor.line,
startCol: this.preprocessor.col - offset,
startOffset: this.preprocessor.offset - offset,
endLine: -1,
endCol: -1,
endOffset: -1,
};
}
_runParsingLoop() {
if (this.inLoop)
return;
this.inLoop = true;
while (this.active && !this.paused) {
this.consumedAfterSnapshot = 0;
const cp = this._consume();
if (!this._ensureHibernation()) {
this._callState(cp);
}
}
this.inLoop = false;
}
//API
pause() {
this.paused = true;
}
resume(writeCallback) {
if (!this.paused) {
throw new Error('Parser was already resumed');
}
this.paused = false;
// Necessary for synchronous resume.
if (this.inLoop)
return;
this._runParsingLoop();
if (!this.paused) {
writeCallback === null || writeCallback === void 0 ? void 0 : writeCallback();
}
}
write(chunk, isLastChunk, writeCallback) {
this.active = true;
this.preprocessor.write(chunk, isLastChunk);
this._runParsingLoop();
if (!this.paused) {
writeCallback === null || writeCallback === void 0 ? void 0 : writeCallback();
}
}
insertHtmlAtCurrentPos(chunk) {
this.active = true;
this.preprocessor.insertHtmlAtCurrentPos(chunk);
this._runParsingLoop();
}
//Hibernation
_ensureHibernation() {
if (this.preprocessor.endOfChunkHit) {
this._unconsume(this.consumedAfterSnapshot);
this.active = false;
return true;
}
return false;
}
//Consumption
_consume() {
this.consumedAfterSnapshot++;
return this.preprocessor.advance();
}
_unconsume(count) {
this.consumedAfterSnapshot -= count;
this.preprocessor.retreat(count);
}
_reconsumeInState(state, cp) {
this.state = state;
this._callState(cp);
}
_advanceBy(count) {
this.consumedAfterSnapshot += count;
for (let i = 0; i < count; i++) {
this.preprocessor.advance();
}
}
_consumeSequenceIfMatch(pattern, caseSensitive) {
if (this.preprocessor.startsWith(pattern, caseSensitive)) {
// We will already have consumed one character before calling this method.
this._advanceBy(pattern.length - 1);
return true;
}
return false;
}
//Token creation
_createStartTagToken() {
this.currentToken = {
type: token$1.TokenType.START_TAG,
tagName: '',
tagID: html$1.TAG_ID.UNKNOWN,
selfClosing: false,
ackSelfClosing: false,
attrs: [],
location: this.getCurrentLocation(1),
};
}
_createEndTagToken() {
this.currentToken = {
type: token$1.TokenType.END_TAG,
tagName: '',
tagID: html$1.TAG_ID.UNKNOWN,
selfClosing: false,
ackSelfClosing: false,
attrs: [],
location: this.getCurrentLocation(2),
};
}
_createCommentToken(offset) {
this.currentToken = {
type: token$1.TokenType.COMMENT,
data: '',
location: this.getCurrentLocation(offset),
};
}
_createDoctypeToken(initialName) {
this.currentToken = {
type: token$1.TokenType.DOCTYPE,
name: initialName,
forceQuirks: false,
publicId: null,
systemId: null,
location: this.currentLocation,
};
}
_createCharacterToken(type, chars) {
this.currentCharacterToken = {
type,
chars,
location: this.currentLocation,
};
}
//Tag attributes
_createAttr(attrNameFirstCh) {
this.currentAttr = {
name: attrNameFirstCh,
value: '',
};
this.currentLocation = this.getCurrentLocation(0);
}
_leaveAttrName() {
var _a;
var _b;
const token = this.currentToken;
if ((0, token$1.getTokenAttr)(token, this.currentAttr.name) === null) {
token.attrs.push(this.currentAttr);
if (token.location && this.currentLocation) {
const attrLocations = ((_a = (_b = token.location).attrs) !== null && _a !== void 0 ? _a : (_b.attrs = Object.create(null)));
attrLocations[this.currentAttr.name] = this.currentLocation;
// Set end location
this._leaveAttrValue();
}
}
else {
this._err(errorCodes$1.ERR.duplicateAttribute);
}
}
_leaveAttrValue() {
if (this.currentLocation) {
this.currentLocation.endLine = this.preprocessor.line;
this.currentLocation.endCol = this.preprocessor.col;
this.currentLocation.endOffset = this.preprocessor.offset;
}
}
//Token emission
prepareToken(ct) {
this._emitCurrentCharacterToken(ct.location);
this.currentToken = null;
if (ct.location) {
ct.location.endLine = this.preprocessor.line;
ct.location.endCol = this.preprocessor.col + 1;
ct.location.endOffset = this.preprocessor.offset + 1;
}
this.currentLocation = this.getCurrentLocation(-1);
}
emitCurrentTagToken() {
const ct = this.currentToken;
this.prepareToken(ct);
ct.tagID = (0, html$1.getTagID)(ct.tagName);
if (ct.type === token$1.TokenType.START_TAG) {
this.lastStartTagName = ct.tagName;
this.handler.onStartTag(ct);
}
else {
if (ct.attrs.length > 0) {
this._err(errorCodes$1.ERR.endTagWithAttributes);
}
if (ct.selfClosing) {
this._err(errorCodes$1.ERR.endTagWithTrailingSolidus);
}
this.handler.onEndTag(ct);
}
this.preprocessor.dropParsedChunk();
}
emitCurrentComment(ct) {
this.prepareToken(ct);
this.handler.onComment(ct);
this.preprocessor.dropParsedChunk();
}
emitCurrentDoctype(ct) {
this.prepareToken(ct);
this.handler.onDoctype(ct);
this.preprocessor.dropParsedChunk();
}
_emitCurrentCharacterToken(nextLocation) {
if (this.currentCharacterToken) {
//NOTE: if we have a pending character token, make it's end location equal to the
//current token's start location.
if (nextLocation && this.currentCharacterToken.location) {
this.currentCharacterToken.location.endLine = nextLocation.startLine;
this.currentCharacterToken.location.endCol = nextLocation.startCol;
this.currentCharacterToken.location.endOffset = nextLocation.startOffset;
}
switch (this.currentCharacterToken.type) {
case token$1.TokenType.CHARACTER: {
this.handler.onCharacter(this.currentCharacterToken);
break;
}
case token$1.TokenType.NULL_CHARACTER: {
this.handler.onNullCharacter(this.currentCharacterToken);
break;
}
case token$1.TokenType.WHITESPACE_CHARACTER: {
this.handler.onWhitespaceCharacter(this.currentCharacterToken);
break;
}
}
this.currentCharacterToken = null;
}
}
_emitEOFToken() {
const location = this.getCurrentLocation(0);
if (location) {
location.endLine = location.startLine;
location.endCol = location.startCol;
location.endOffset = location.startOffset;
}
this._emitCurrentCharacterToken(location);
this.handler.onEof({ type: token$1.TokenType.EOF, location });
this.active = false;
}
//Characters emission
//OPTIMIZATION: specification uses only one type of character tokens (one token per character).
//This causes a huge memory overhead and a lot of unnecessary parser loops. parse5 uses 3 groups of characters.
//If we have a sequence of characters that belong to the same group, the parser can process it
//as a single solid character token.
//So, there are 3 types of character tokens in parse5:
//1)TokenType.NULL_CHARACTER - \u0000-character sequences (e.g. '\u0000\u0000\u0000')
//2)TokenType.WHITESPACE_CHARACTER - any whitespace/new-line character sequences (e.g. '\n \r\t \f')
//3)TokenType.CHARACTER - any character sequence which don't belong to groups 1 and 2 (e.g. 'abcdef1234@@#$%^')
_appendCharToCurrentCharacterToken(type, ch) {
if (this.currentCharacterToken) {
if (this.currentCharacterToken.type !== type) {
this.currentLocation = this.getCurrentLocation(0);
this._emitCurrentCharacterToken(this.currentLocation);
this.preprocessor.dropParsedChunk();
}
else {
this.currentCharacterToken.chars += ch;
return;
}
}
this._createCharacterToken(type, ch);
}
_emitCodePoint(cp) {
const type = isWhitespace(cp)
? token$1.TokenType.WHITESPACE_CHARACTER
: cp === unicode$1.CODE_POINTS.NULL
? token$1.TokenType.NULL_CHARACTER
: token$1.TokenType.CHARACTER;
this._appendCharToCurrentCharacterToken(type, String.fromCodePoint(cp));
}
//NOTE: used when we emit characters explicitly.
//This is always for non-whitespace and non-null characters, which allows us to avoid additional checks.
_emitChars(ch) {
this._appendCharToCurrentCharacterToken(token$1.TokenType.CHARACTER, ch);
}
// Character reference helpers
_matchNamedCharacterReference(cp) {
let result = null;
let excess = 0;
let withoutSemicolon = false;
for (let i = 0, current = decode_js_1.htmlDecodeTree[0]; i >= 0; cp = this._consume()) {
i = (0, decode_js_1.determineBranch)(decode_js_1.htmlDecodeTree, current, i + 1, cp);
if (i < 0)
break;
excess += 1;
current = decode_js_1.htmlDecodeTree[i];
const masked = current & decode_js_1.BinTrieFlags.VALUE_LENGTH;
// If the branch is a value, store it and continue
if (masked) {
// The mask is the number of bytes of the value, including the current byte.
const valueLength = (masked >> 14) - 1;
// Attribute values that aren't terminated properly aren't parsed, and shouldn't lead to a parser error.
// See the example in https://html.spec.whatwg.org/multipage/parsing.html#named-character-reference-state
if (cp !== unicode$1.CODE_POINTS.SEMICOLON &&
this._isCharacterReferenceInAttribute() &&
isEntityInAttributeInvalidEnd(this.preprocessor.peek(1))) {
//NOTE: we don't flush all consumed code points here, and instead switch back to the original state after
//emitting an ampersand. This is fine, as alphanumeric characters won't be parsed differently in attributes.
result = [unicode$1.CODE_POINTS.AMPERSAND];
// Skip over the value.
i += valueLength;
}
else {
// If this is a surrogate pair, consume the next two bytes.
result =
valueLength === 0
? [decode_js_1.htmlDecodeTree[i] & ~decode_js_1.BinTrieFlags.VALUE_LENGTH]
: valueLength === 1
? [decode_js_1.htmlDecodeTree[++i]]
: [decode_js_1.htmlDecodeTree[++i], decode_js_1.htmlDecodeTree[++i]];
excess = 0;
withoutSemicolon = cp !== unicode$1.CODE_POINTS.SEMICOLON;
}
if (valueLength === 0) {
// If the value is zero-length, we're done.
this._consume();
break;
}
}
}
this._unconsume(excess);
if (withoutSemicolon && !this.preprocessor.endOfChunkHit) {
this._err(errorCodes$1.ERR.missingSemicolonAfterCharacterReference);
}
// We want to emit the error above on the code point after the entity.
// We always consume one code point too many in the loop, and we wait to
// unconsume it until after the error is emitted.
this._unconsume(1);
return result;
}
_isCharacterReferenceInAttribute() {
return (this.returnState === State.ATTRIBUTE_VALUE_DOUBLE_QUOTED ||
this.returnState === State.ATTRIBUTE_VALUE_SINGLE_QUOTED ||
this.returnState === State.ATTRIBUTE_VALUE_UNQUOTED);
}
_flushCodePointConsumedAsCharacterReference(cp) {
if (this._isCharacterReferenceInAttribute()) {
this.currentAttr.value += String.fromCodePoint(cp);
}
else {
this._emitCodePoint(cp);
}
}
// Calling states this way turns out to be much faster than any other approach.
_callState(cp) {
switch (this.state) {
case State.DATA: {
this._stateData(cp);
break;
}
case State.RCDATA: {
this._stateRcdata(cp);
break;
}
case State.RAWTEXT: {
this._stateRawtext(cp);
break;
}
case State.SCRIPT_DATA: {
this._stateScriptData(cp);
break;
}
case State.PLAINTEXT: {
this._statePlaintext(cp);
break;
}
case State.TAG_OPEN: {
this._stateTagOpen(cp);
break;
}
case State.END_TAG_OPEN: {
this._stateEndTagOpen(cp);
break;
}
case State.TAG_NAME: {
this._stateTagName(cp);
break;
}
case State.RCDATA_LESS_THAN_SIGN: {
this._stateRcdataLessThanSign(cp);
break;
}
case State.RCDATA_END_TAG_OPEN: {
this._stateRcdataEndTagOpen(cp);
break;
}
case State.RCDATA_END_TAG_NAME: {
this._stateRcdataEndTagName(cp);
break;
}
case State.RAWTEXT_LESS_THAN_SIGN: {
this._stateRawtextLessThanSign(cp);
break;
}
case State.RAWTEXT_END_TAG_OPEN: {
this._stateRawtextEndTagOpen(cp);
break;
}
case State.RAWTEXT_END_TAG_NAME: {
this._stateRawtextEndTagName(cp);
break;
}
case State.SCRIPT_DATA_LESS_THAN_SIGN: {
this._stateScriptDataLessThanSign(cp);
break;
}
case State.SCRIPT_DATA_END_TAG_OPEN: {
this._stateScriptDataEndTagOpen(cp);
break;
}
case State.SCRIPT_DATA_END_TAG_NAME: {
this._stateScriptDataEndTagName(cp);
break;
}
case State.SCRIPT_DATA_ESCAPE_START: {
this._stateScriptDataEscapeStart(cp);
break;
}
case State.SCRIPT_DATA_ESCAPE_START_DASH: {
this._stateScriptDataEscapeStartDash(cp);
break;
}
case State.SCRIPT_DATA_ESCAPED: {
this._stateScriptDataEscaped(cp);
break;
}
case State.SCRIPT_DATA_ESCAPED_DASH: {
this._stateScriptDataEscapedDash(cp);
break;
}
case State.SCRIPT_DATA_ESCAPED_DASH_DASH: {
this._stateScriptDataEscapedDashDash(cp);
break;
}
case State.SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN: {
this._stateScriptDataEscapedLessThanSign(cp);
break;
}
case State.SCRIPT_DATA_ESCAPED_END_TAG_OPEN: {
this._stateScriptDataEscapedEndTagOpen(cp);
break;
}
case State.SCRIPT_DATA_ESCAPED_END_TAG_NAME: {
this._stateScriptDataEscapedEndTagName(cp);
break;
}
case State.SCRIPT_DATA_DOUBLE_ESCAPE_START: {
this._stateScriptDataDoubleEscapeStart(cp);
break;
}
case State.SCRIPT_DATA_DOUBLE_ESCAPED: {
this._stateScriptDataDoubleEscaped(cp);
break;
}
case State.SCRIPT_DATA_DOUBLE_ESCAPED_DASH: {
this._stateScriptDataDoubleEscapedDash(cp);
break;
}
case State.SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH: {
this._stateScriptDataDoubleEscapedDashDash(cp);
break;
}
case State.SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN: {
this._stateScriptDataDoubleEscapedLessThanSign(cp);
break;
}
case State.SCRIPT_DATA_DOUBLE_ESCAPE_END: {
this._stateScriptDataDoubleEscapeEnd(cp);
break;
}
case State.BEFORE_ATTRIBUTE_NAME: {
this._stateBeforeAttributeName(cp);
break;
}
case State.ATTRIBUTE_NAME: {
this._stateAttributeName(cp);
break;
}
case State.AFTER_ATTRIBUTE_NAME: {
this._stateAfterAttributeName(cp);
break;
}
case State.BEFORE_ATTRIBUTE_VALUE: {
this._stateBeforeAttributeValue(cp);
break;
}
case State.ATTRIBUTE_VALUE_DOUBLE_QUOTED: {
this._stateAttributeValueDoubleQuoted(cp);
break;
}
case State.ATTRIBUTE_VALUE_SINGLE_QUOTED: {
this._stateAttributeValueSingleQuoted(cp);
break;
}
case State.ATTRIBUTE_VALUE_UNQUOTED: {
this._stateAttributeValueUnquoted(cp);
break;
}
case State.AFTER_ATTRIBUTE_VALUE_QUOTED: {
this._stateAfterAttributeValueQuoted(cp);
break;
}
case State.SELF_CLOSING_START_TAG: {
this._stateSelfClosingStartTag(cp);
break;
}
case State.BOGUS_COMMENT: {
this._stateBogusComment(cp);
break;
}
case State.MARKUP_DECLARATION_OPEN: {
this._stateMarkupDeclarationOpen(cp);
break;
}
case State.COMMENT_START: {
this._stateCommentStart(cp);
break;
}
case State.COMMENT_START_DASH: {
this._stateCommentStartDash(cp);
break;
}
case State.COMMENT: {
this._stateComment(cp);
break;
}
case State.COMMENT_LESS_THAN_SIGN: {
this._stateCommentLessThanSign(cp);
break;
}
case State.COMMENT_LESS_THAN_SIGN_BANG: {
this._stateCommentLessThanSignBang(cp);
break;
}
case State.COMMENT_LESS_THAN_SIGN_BANG_DASH: {
this._stateCommentLessThanSignBangDash(cp);
break;
}
case State.COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH: {
this._stateCommentLessThanSignBangDashDash(cp);
break;
}
case State.COMMENT_END_DASH: {
this._stateCommentEndDash(cp);
break;
}
case State.COMMENT_END: {
this._stateCommentEnd(cp);
break;
}
case State.COMMENT_END_BANG: {
this._stateCommentEndBang(cp);
break;
}
case State.DOCTYPE: {
this._stateDoctype(cp);
break;
}
case State.BEFORE_DOCTYPE_NAME: {
this._stateBeforeDoctypeName(cp);
break;
}
case State.DOCTYPE_NAME: {
this._stateDoctypeName(cp);
break;
}
case State.AFTER_DOCTYPE_NAME: {
this._stateAfterDoctypeName(cp);
break;
}
case State.AFTER_DOCTYPE_PUBLIC_KEYWORD: {
this._stateAfterDoctypePublicKeyword(cp);
break;
}
case State.BEFORE_DOCTYPE_PUBLIC_IDENTIFIER: {
this._stateBeforeDoctypePublicIdentifier(cp);
break;
}
case State.DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED: {
this._stateDoctypePublicIdentifierDoubleQuoted(cp);
break;
}
case State.DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED: {
this._stateDoctypePublicIdentifierSingleQuoted(cp);
break;
}
case State.AFTER_DOCTYPE_PUBLIC_IDENTIFIER: {
this._stateAfterDoctypePublicIdentifier(cp);
break;
}
case State.BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS: {
this._stateBetweenDoctypePublicAndSystemIdentifiers(cp);
break;
}
case State.AFTER_DOCTYPE_SYSTEM_KEYWORD: {
this._stateAfterDoctypeSystemKeyword(cp);
break;
}
case State.BEFORE_DOCTYPE_SYSTEM_IDENTIFIER: {
this._stateBeforeDoctypeSystemIdentifier(cp);
break;
}
case State.DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED: {
this._stateDoctypeSystemIdentifierDoubleQuoted(cp);
break;
}
case State.DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED: {
this._stateDoctypeSystemIdentifierSingleQuoted(cp);
break;
}
case State.AFTER_DOCTYPE_SYSTEM_IDENTIFIER: {
this._stateAfterDoctypeSystemIdentifier(cp);
break;
}
case State.BOGUS_DOCTYPE: {
this._stateBogusDoctype(cp);
break;
}
case State.CDATA_SECTION: {
this._stateCdataSection(cp);
break;
}
case State.CDATA_SECTION_BRACKET: {
this._stateCdataSectionBracket(cp);
break;
}
case State.CDATA_SECTION_END: {
this._stateCdataSectionEnd(cp);
break;
}
case State.CHARACTER_REFERENCE: {
this._stateCharacterReference(cp);
break;
}
case State.NAMED_CHARACTER_REFERENCE: {
this._stateNamedCharacterReference(cp);
break;
}
case State.AMBIGUOUS_AMPERSAND: {
this._stateAmbiguousAmpersand(cp);
break;
}
case State.NUMERIC_CHARACTER_REFERENCE: {
this._stateNumericCharacterReference(cp);
break;
}
case State.HEXADEMICAL_CHARACTER_REFERENCE_START: {
this._stateHexademicalCharacterReferenceStart(cp);
break;
}
case State.HEXADEMICAL_CHARACTER_REFERENCE: {
this._stateHexademicalCharacterReference(cp);
break;
}
case State.DECIMAL_CHARACTER_REFERENCE: {
this._stateDecimalCharacterReference(cp);
break;
}
case State.NUMERIC_CHARACTER_REFERENCE_END: {
this._stateNumericCharacterReferenceEnd(cp);
break;
}
default: {
throw new Error('Unknown state');
}
}
}
// State machine
// Data state
//------------------------------------------------------------------
_stateData(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.TAG_OPEN;
break;
}
case unicode$1.CODE_POINTS.AMPERSAND: {
this.returnState = State.DATA;
this.state = State.CHARACTER_REFERENCE;
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
this._emitCodePoint(cp);
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// RCDATA state
//------------------------------------------------------------------
_stateRcdata(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.AMPERSAND: {
this.returnState = State.RCDATA;
this.state = State.CHARACTER_REFERENCE;
break;
}
case unicode$1.CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.RCDATA_LESS_THAN_SIGN;
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
this._emitChars(unicode$1.REPLACEMENT_CHARACTER);
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// RAWTEXT state
//------------------------------------------------------------------
_stateRawtext(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.RAWTEXT_LESS_THAN_SIGN;
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
this._emitChars(unicode$1.REPLACEMENT_CHARACTER);
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// Script data state
//------------------------------------------------------------------
_stateScriptData(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.SCRIPT_DATA_LESS_THAN_SIGN;
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
this._emitChars(unicode$1.REPLACEMENT_CHARACTER);
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// PLAINTEXT state
//------------------------------------------------------------------
_statePlaintext(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
this._emitChars(unicode$1.REPLACEMENT_CHARACTER);
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// Tag open state
//------------------------------------------------------------------
_stateTagOpen(cp) {
if (isAsciiLetter(cp)) {
this._createStartTagToken();
this.state = State.TAG_NAME;
this._stateTagName(cp);
}
else
switch (cp) {
case unicode$1.CODE_POINTS.EXCLAMATION_MARK: {
this.state = State.MARKUP_DECLARATION_OPEN;
break;
}
case unicode$1.CODE_POINTS.SOLIDUS: {
this.state = State.END_TAG_OPEN;
break;
}
case unicode$1.CODE_POINTS.QUESTION_MARK: {
this._err(errorCodes$1.ERR.unexpectedQuestionMarkInsteadOfTagName);
this._createCommentToken(1);
this.state = State.BOGUS_COMMENT;
this._stateBogusComment(cp);
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofBeforeTagName);
this._emitChars('<');
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes$1.ERR.invalidFirstCharacterOfTagName);
this._emitChars('<');
this.state = State.DATA;
this._stateData(cp);
}
}
}
// End tag open state
//------------------------------------------------------------------
_stateEndTagOpen(cp) {
if (isAsciiLetter(cp)) {
this._createEndTagToken();
this.state = State.TAG_NAME;
this._stateTagName(cp);
}
else
switch (cp) {
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes$1.ERR.missingEndTagName);
this.state = State.DATA;
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofBeforeTagName);
this._emitChars('</');
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes$1.ERR.invalidFirstCharacterOfTagName);
this._createCommentToken(2);
this.state = State.BOGUS_COMMENT;
this._stateBogusComment(cp);
}
}
}
// Tag name state
//------------------------------------------------------------------
_stateTagName(cp) {
const token = this.currentToken;
switch (cp) {
case unicode$1.CODE_POINTS.SPACE:
case unicode$1.CODE_POINTS.LINE_FEED:
case unicode$1.CODE_POINTS.TABULATION:
case unicode$1.CODE_POINTS.FORM_FEED: {
this.state = State.BEFORE_ATTRIBUTE_NAME;
break;
}
case unicode$1.CODE_POINTS.SOLIDUS: {
this.state = State.SELF_CLOSING_START_TAG;
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
this.emitCurrentTagToken();
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
token.tagName += unicode$1.REPLACEMENT_CHARACTER;
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInTag);
this._emitEOFToken();
break;
}
default: {
token.tagName += String.fromCodePoint(isAsciiUpper(cp) ? toAsciiLower(cp) : cp);
}
}
}
// RCDATA less-than sign state
//------------------------------------------------------------------
_stateRcdataLessThanSign(cp) {
if (cp === unicode$1.CODE_POINTS.SOLIDUS) {
this.state = State.RCDATA_END_TAG_OPEN;
}
else {
this._emitChars('<');
this.state = State.RCDATA;
this._stateRcdata(cp);
}
}
// RCDATA end tag open state
//------------------------------------------------------------------
_stateRcdataEndTagOpen(cp) {
if (isAsciiLetter(cp)) {
this.state = State.RCDATA_END_TAG_NAME;
this._stateRcdataEndTagName(cp);
}
else {
this._emitChars('</');
this.state = State.RCDATA;
this._stateRcdata(cp);
}
}
handleSpecialEndTag(_cp) {
if (!this.preprocessor.startsWith(this.lastStartTagName, false)) {
return !this._ensureHibernation();
}
this._createEndTagToken();
const token = this.currentToken;
token.tagName = this.lastStartTagName;
const cp = this.preprocessor.peek(this.lastStartTagName.length);
switch (cp) {
case unicode$1.CODE_POINTS.SPACE:
case unicode$1.CODE_POINTS.LINE_FEED:
case unicode$1.CODE_POINTS.TABULATION:
case unicode$1.CODE_POINTS.FORM_FEED: {
this._advanceBy(this.lastStartTagName.length);
this.state = State.BEFORE_ATTRIBUTE_NAME;
return false;
}
case unicode$1.CODE_POINTS.SOLIDUS: {
this._advanceBy(this.lastStartTagName.length);
this.state = State.SELF_CLOSING_START_TAG;
return false;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this._advanceBy(this.lastStartTagName.length);
this.emitCurrentTagToken();
this.state = State.DATA;
return false;
}
default: {
return !this._ensureHibernation();
}
}
}
// RCDATA end tag name state
//------------------------------------------------------------------
_stateRcdataEndTagName(cp) {
if (this.handleSpecialEndTag(cp)) {
this._emitChars('</');
this.state = State.RCDATA;
this._stateRcdata(cp);
}
}
// RAWTEXT less-than sign state
//------------------------------------------------------------------
_stateRawtextLessThanSign(cp) {
if (cp === unicode$1.CODE_POINTS.SOLIDUS) {
this.state = State.RAWTEXT_END_TAG_OPEN;
}
else {
this._emitChars('<');
this.state = State.RAWTEXT;
this._stateRawtext(cp);
}
}
// RAWTEXT end tag open state
//------------------------------------------------------------------
_stateRawtextEndTagOpen(cp) {
if (isAsciiLetter(cp)) {
this.state = State.RAWTEXT_END_TAG_NAME;
this._stateRawtextEndTagName(cp);
}
else {
this._emitChars('</');
this.state = State.RAWTEXT;
this._stateRawtext(cp);
}
}
// RAWTEXT end tag name state
//------------------------------------------------------------------
_stateRawtextEndTagName(cp) {
if (this.handleSpecialEndTag(cp)) {
this._emitChars('</');
this.state = State.RAWTEXT;
this._stateRawtext(cp);
}
}
// Script data less-than sign state
//------------------------------------------------------------------
_stateScriptDataLessThanSign(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.SOLIDUS: {
this.state = State.SCRIPT_DATA_END_TAG_OPEN;
break;
}
case unicode$1.CODE_POINTS.EXCLAMATION_MARK: {
this.state = State.SCRIPT_DATA_ESCAPE_START;
this._emitChars('<!');
break;
}
default: {
this._emitChars('<');
this.state = State.SCRIPT_DATA;
this._stateScriptData(cp);
}
}
}
// Script data end tag open state
//------------------------------------------------------------------
_stateScriptDataEndTagOpen(cp) {
if (isAsciiLetter(cp)) {
this.state = State.SCRIPT_DATA_END_TAG_NAME;
this._stateScriptDataEndTagName(cp);
}
else {
this._emitChars('</');
this.state = State.SCRIPT_DATA;
this._stateScriptData(cp);
}
}
// Script data end tag name state
//------------------------------------------------------------------
_stateScriptDataEndTagName(cp) {
if (this.handleSpecialEndTag(cp)) {
this._emitChars('</');
this.state = State.SCRIPT_DATA;
this._stateScriptData(cp);
}
}
// Script data escape start state
//------------------------------------------------------------------
_stateScriptDataEscapeStart(cp) {
if (cp === unicode$1.CODE_POINTS.HYPHEN_MINUS) {
this.state = State.SCRIPT_DATA_ESCAPE_START_DASH;
this._emitChars('-');
}
else {
this.state = State.SCRIPT_DATA;
this._stateScriptData(cp);
}
}
// Script data escape start dash state
//------------------------------------------------------------------
_stateScriptDataEscapeStartDash(cp) {
if (cp === unicode$1.CODE_POINTS.HYPHEN_MINUS) {
this.state = State.SCRIPT_DATA_ESCAPED_DASH_DASH;
this._emitChars('-');
}
else {
this.state = State.SCRIPT_DATA;
this._stateScriptData(cp);
}
}
// Script data escaped state
//------------------------------------------------------------------
_stateScriptDataEscaped(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.HYPHEN_MINUS: {
this.state = State.SCRIPT_DATA_ESCAPED_DASH;
this._emitChars('-');
break;
}
case unicode$1.CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN;
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
this._emitChars(unicode$1.REPLACEMENT_CHARACTER);
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInScriptHtmlCommentLikeText);
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// Script data escaped dash state
//------------------------------------------------------------------
_stateScriptDataEscapedDash(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.HYPHEN_MINUS: {
this.state = State.SCRIPT_DATA_ESCAPED_DASH_DASH;
this._emitChars('-');
break;
}
case unicode$1.CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN;
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
this.state = State.SCRIPT_DATA_ESCAPED;
this._emitChars(unicode$1.REPLACEMENT_CHARACTER);
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInScriptHtmlCommentLikeText);
this._emitEOFToken();
break;
}
default: {
this.state = State.SCRIPT_DATA_ESCAPED;
this._emitCodePoint(cp);
}
}
}
// Script data escaped dash dash state
//------------------------------------------------------------------
_stateScriptDataEscapedDashDash(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.HYPHEN_MINUS: {
this._emitChars('-');
break;
}
case unicode$1.CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN;
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.SCRIPT_DATA;
this._emitChars('>');
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
this.state = State.SCRIPT_DATA_ESCAPED;
this._emitChars(unicode$1.REPLACEMENT_CHARACTER);
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInScriptHtmlCommentLikeText);
this._emitEOFToken();
break;
}
default: {
this.state = State.SCRIPT_DATA_ESCAPED;
this._emitCodePoint(cp);
}
}
}
// Script data escaped less-than sign state
//------------------------------------------------------------------
_stateScriptDataEscapedLessThanSign(cp) {
if (cp === unicode$1.CODE_POINTS.SOLIDUS) {
this.state = State.SCRIPT_DATA_ESCAPED_END_TAG_OPEN;
}
else if (isAsciiLetter(cp)) {
this._emitChars('<');
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPE_START;
this._stateScriptDataDoubleEscapeStart(cp);
}
else {
this._emitChars('<');
this.state = State.SCRIPT_DATA_ESCAPED;
this._stateScriptDataEscaped(cp);
}
}
// Script data escaped end tag open state
//------------------------------------------------------------------
_stateScriptDataEscapedEndTagOpen(cp) {
if (isAsciiLetter(cp)) {
this.state = State.SCRIPT_DATA_ESCAPED_END_TAG_NAME;
this._stateScriptDataEscapedEndTagName(cp);
}
else {
this._emitChars('</');
this.state = State.SCRIPT_DATA_ESCAPED;
this._stateScriptDataEscaped(cp);
}
}
// Script data escaped end tag name state
//------------------------------------------------------------------
_stateScriptDataEscapedEndTagName(cp) {
if (this.handleSpecialEndTag(cp)) {
this._emitChars('</');
this.state = State.SCRIPT_DATA_ESCAPED;
this._stateScriptDataEscaped(cp);
}
}
// Script data double escape start state
//------------------------------------------------------------------
_stateScriptDataDoubleEscapeStart(cp) {
if (this.preprocessor.startsWith(unicode$1.SEQUENCES.SCRIPT, false) &&
isScriptDataDoubleEscapeSequenceEnd(this.preprocessor.peek(unicode$1.SEQUENCES.SCRIPT.length))) {
this._emitCodePoint(cp);
for (let i = 0; i < unicode$1.SEQUENCES.SCRIPT.length; i++) {
this._emitCodePoint(this._consume());
}
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED;
}
else if (!this._ensureHibernation()) {
this.state = State.SCRIPT_DATA_ESCAPED;
this._stateScriptDataEscaped(cp);
}
}
// Script data double escaped state
//------------------------------------------------------------------
_stateScriptDataDoubleEscaped(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.HYPHEN_MINUS: {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED_DASH;
this._emitChars('-');
break;
}
case unicode$1.CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN;
this._emitChars('<');
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
this._emitChars(unicode$1.REPLACEMENT_CHARACTER);
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInScriptHtmlCommentLikeText);
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// Script data double escaped dash state
//------------------------------------------------------------------
_stateScriptDataDoubleEscapedDash(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.HYPHEN_MINUS: {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH;
this._emitChars('-');
break;
}
case unicode$1.CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN;
this._emitChars('<');
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED;
this._emitChars(unicode$1.REPLACEMENT_CHARACTER);
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInScriptHtmlCommentLikeText);
this._emitEOFToken();
break;
}
default: {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED;
this._emitCodePoint(cp);
}
}
}
// Script data double escaped dash dash state
//------------------------------------------------------------------
_stateScriptDataDoubleEscapedDashDash(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.HYPHEN_MINUS: {
this._emitChars('-');
break;
}
case unicode$1.CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN;
this._emitChars('<');
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.SCRIPT_DATA;
this._emitChars('>');
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED;
this._emitChars(unicode$1.REPLACEMENT_CHARACTER);
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInScriptHtmlCommentLikeText);
this._emitEOFToken();
break;
}
default: {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED;
this._emitCodePoint(cp);
}
}
}
// Script data double escaped less-than sign state
//------------------------------------------------------------------
_stateScriptDataDoubleEscapedLessThanSign(cp) {
if (cp === unicode$1.CODE_POINTS.SOLIDUS) {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPE_END;
this._emitChars('/');
}
else {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED;
this._stateScriptDataDoubleEscaped(cp);
}
}
// Script data double escape end state
//------------------------------------------------------------------
_stateScriptDataDoubleEscapeEnd(cp) {
if (this.preprocessor.startsWith(unicode$1.SEQUENCES.SCRIPT, false) &&
isScriptDataDoubleEscapeSequenceEnd(this.preprocessor.peek(unicode$1.SEQUENCES.SCRIPT.length))) {
this._emitCodePoint(cp);
for (let i = 0; i < unicode$1.SEQUENCES.SCRIPT.length; i++) {
this._emitCodePoint(this._consume());
}
this.state = State.SCRIPT_DATA_ESCAPED;
}
else if (!this._ensureHibernation()) {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED;
this._stateScriptDataDoubleEscaped(cp);
}
}
// Before attribute name state
//------------------------------------------------------------------
_stateBeforeAttributeName(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.SPACE:
case unicode$1.CODE_POINTS.LINE_FEED:
case unicode$1.CODE_POINTS.TABULATION:
case unicode$1.CODE_POINTS.FORM_FEED: {
// Ignore whitespace
break;
}
case unicode$1.CODE_POINTS.SOLIDUS:
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN:
case unicode$1.CODE_POINTS.EOF: {
this.state = State.AFTER_ATTRIBUTE_NAME;
this._stateAfterAttributeName(cp);
break;
}
case unicode$1.CODE_POINTS.EQUALS_SIGN: {
this._err(errorCodes$1.ERR.unexpectedEqualsSignBeforeAttributeName);
this._createAttr('=');
this.state = State.ATTRIBUTE_NAME;
break;
}
default: {
this._createAttr('');
this.state = State.ATTRIBUTE_NAME;
this._stateAttributeName(cp);
}
}
}
// Attribute name state
//------------------------------------------------------------------
_stateAttributeName(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.SPACE:
case unicode$1.CODE_POINTS.LINE_FEED:
case unicode$1.CODE_POINTS.TABULATION:
case unicode$1.CODE_POINTS.FORM_FEED:
case unicode$1.CODE_POINTS.SOLIDUS:
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN:
case unicode$1.CODE_POINTS.EOF: {
this._leaveAttrName();
this.state = State.AFTER_ATTRIBUTE_NAME;
this._stateAfterAttributeName(cp);
break;
}
case unicode$1.CODE_POINTS.EQUALS_SIGN: {
this._leaveAttrName();
this.state = State.BEFORE_ATTRIBUTE_VALUE;
break;
}
case unicode$1.CODE_POINTS.QUOTATION_MARK:
case unicode$1.CODE_POINTS.APOSTROPHE:
case unicode$1.CODE_POINTS.LESS_THAN_SIGN: {
this._err(errorCodes$1.ERR.unexpectedCharacterInAttributeName);
this.currentAttr.name += String.fromCodePoint(cp);
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
this.currentAttr.name += unicode$1.REPLACEMENT_CHARACTER;
break;
}
default: {
this.currentAttr.name += String.fromCodePoint(isAsciiUpper(cp) ? toAsciiLower(cp) : cp);
}
}
}
// After attribute name state
//------------------------------------------------------------------
_stateAfterAttributeName(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.SPACE:
case unicode$1.CODE_POINTS.LINE_FEED:
case unicode$1.CODE_POINTS.TABULATION:
case unicode$1.CODE_POINTS.FORM_FEED: {
// Ignore whitespace
break;
}
case unicode$1.CODE_POINTS.SOLIDUS: {
this.state = State.SELF_CLOSING_START_TAG;
break;
}
case unicode$1.CODE_POINTS.EQUALS_SIGN: {
this.state = State.BEFORE_ATTRIBUTE_VALUE;
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
this.emitCurrentTagToken();
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInTag);
this._emitEOFToken();
break;
}
default: {
this._createAttr('');
this.state = State.ATTRIBUTE_NAME;
this._stateAttributeName(cp);
}
}
}
// Before attribute value state
//------------------------------------------------------------------
_stateBeforeAttributeValue(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.SPACE:
case unicode$1.CODE_POINTS.LINE_FEED:
case unicode$1.CODE_POINTS.TABULATION:
case unicode$1.CODE_POINTS.FORM_FEED: {
// Ignore whitespace
break;
}
case unicode$1.CODE_POINTS.QUOTATION_MARK: {
this.state = State.ATTRIBUTE_VALUE_DOUBLE_QUOTED;
break;
}
case unicode$1.CODE_POINTS.APOSTROPHE: {
this.state = State.ATTRIBUTE_VALUE_SINGLE_QUOTED;
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes$1.ERR.missingAttributeValue);
this.state = State.DATA;
this.emitCurrentTagToken();
break;
}
default: {
this.state = State.ATTRIBUTE_VALUE_UNQUOTED;
this._stateAttributeValueUnquoted(cp);
}
}
}
// Attribute value (double-quoted) state
//------------------------------------------------------------------
_stateAttributeValueDoubleQuoted(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.QUOTATION_MARK: {
this.state = State.AFTER_ATTRIBUTE_VALUE_QUOTED;
break;
}
case unicode$1.CODE_POINTS.AMPERSAND: {
this.returnState = State.ATTRIBUTE_VALUE_DOUBLE_QUOTED;
this.state = State.CHARACTER_REFERENCE;
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
this.currentAttr.value += unicode$1.REPLACEMENT_CHARACTER;
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInTag);
this._emitEOFToken();
break;
}
default: {
this.currentAttr.value += String.fromCodePoint(cp);
}
}
}
// Attribute value (single-quoted) state
//------------------------------------------------------------------
_stateAttributeValueSingleQuoted(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.APOSTROPHE: {
this.state = State.AFTER_ATTRIBUTE_VALUE_QUOTED;
break;
}
case unicode$1.CODE_POINTS.AMPERSAND: {
this.returnState = State.ATTRIBUTE_VALUE_SINGLE_QUOTED;
this.state = State.CHARACTER_REFERENCE;
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
this.currentAttr.value += unicode$1.REPLACEMENT_CHARACTER;
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInTag);
this._emitEOFToken();
break;
}
default: {
this.currentAttr.value += String.fromCodePoint(cp);
}
}
}
// Attribute value (unquoted) state
//------------------------------------------------------------------
_stateAttributeValueUnquoted(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.SPACE:
case unicode$1.CODE_POINTS.LINE_FEED:
case unicode$1.CODE_POINTS.TABULATION:
case unicode$1.CODE_POINTS.FORM_FEED: {
this._leaveAttrValue();
this.state = State.BEFORE_ATTRIBUTE_NAME;
break;
}
case unicode$1.CODE_POINTS.AMPERSAND: {
this.returnState = State.ATTRIBUTE_VALUE_UNQUOTED;
this.state = State.CHARACTER_REFERENCE;
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this._leaveAttrValue();
this.state = State.DATA;
this.emitCurrentTagToken();
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
this.currentAttr.value += unicode$1.REPLACEMENT_CHARACTER;
break;
}
case unicode$1.CODE_POINTS.QUOTATION_MARK:
case unicode$1.CODE_POINTS.APOSTROPHE:
case unicode$1.CODE_POINTS.LESS_THAN_SIGN:
case unicode$1.CODE_POINTS.EQUALS_SIGN:
case unicode$1.CODE_POINTS.GRAVE_ACCENT: {
this._err(errorCodes$1.ERR.unexpectedCharacterInUnquotedAttributeValue);
this.currentAttr.value += String.fromCodePoint(cp);
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInTag);
this._emitEOFToken();
break;
}
default: {
this.currentAttr.value += String.fromCodePoint(cp);
}
}
}
// After attribute value (quoted) state
//------------------------------------------------------------------
_stateAfterAttributeValueQuoted(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.SPACE:
case unicode$1.CODE_POINTS.LINE_FEED:
case unicode$1.CODE_POINTS.TABULATION:
case unicode$1.CODE_POINTS.FORM_FEED: {
this._leaveAttrValue();
this.state = State.BEFORE_ATTRIBUTE_NAME;
break;
}
case unicode$1.CODE_POINTS.SOLIDUS: {
this._leaveAttrValue();
this.state = State.SELF_CLOSING_START_TAG;
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this._leaveAttrValue();
this.state = State.DATA;
this.emitCurrentTagToken();
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInTag);
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes$1.ERR.missingWhitespaceBetweenAttributes);
this.state = State.BEFORE_ATTRIBUTE_NAME;
this._stateBeforeAttributeName(cp);
}
}
}
// Self-closing start tag state
//------------------------------------------------------------------
_stateSelfClosingStartTag(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
const token = this.currentToken;
token.selfClosing = true;
this.state = State.DATA;
this.emitCurrentTagToken();
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInTag);
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes$1.ERR.unexpectedSolidusInTag);
this.state = State.BEFORE_ATTRIBUTE_NAME;
this._stateBeforeAttributeName(cp);
}
}
}
// Bogus comment state
//------------------------------------------------------------------
_stateBogusComment(cp) {
const token = this.currentToken;
switch (cp) {
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
this.emitCurrentComment(token);
break;
}
case unicode$1.CODE_POINTS.EOF: {
this.emitCurrentComment(token);
this._emitEOFToken();
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
token.data += unicode$1.REPLACEMENT_CHARACTER;
break;
}
default: {
token.data += String.fromCodePoint(cp);
}
}
}
// Markup declaration open state
//------------------------------------------------------------------
_stateMarkupDeclarationOpen(cp) {
if (this._consumeSequenceIfMatch(unicode$1.SEQUENCES.DASH_DASH, true)) {
this._createCommentToken(unicode$1.SEQUENCES.DASH_DASH.length + 1);
this.state = State.COMMENT_START;
}
else if (this._consumeSequenceIfMatch(unicode$1.SEQUENCES.DOCTYPE, false)) {
// NOTE: Doctypes tokens are created without fixed offsets. We keep track of the moment a doctype *might* start here.
this.currentLocation = this.getCurrentLocation(unicode$1.SEQUENCES.DOCTYPE.length + 1);
this.state = State.DOCTYPE;
}
else if (this._consumeSequenceIfMatch(unicode$1.SEQUENCES.CDATA_START, true)) {
if (this.inForeignNode) {
this.state = State.CDATA_SECTION;
}
else {
this._err(errorCodes$1.ERR.cdataInHtmlContent);
this._createCommentToken(unicode$1.SEQUENCES.CDATA_START.length + 1);
this.currentToken.data = '[CDATA[';
this.state = State.BOGUS_COMMENT;
}
}
//NOTE: Sequence lookups can be abrupted by hibernation. In that case, lookup
//results are no longer valid and we will need to start over.
else if (!this._ensureHibernation()) {
this._err(errorCodes$1.ERR.incorrectlyOpenedComment);
this._createCommentToken(2);
this.state = State.BOGUS_COMMENT;
this._stateBogusComment(cp);
}
}
// Comment start state
//------------------------------------------------------------------
_stateCommentStart(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.HYPHEN_MINUS: {
this.state = State.COMMENT_START_DASH;
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes$1.ERR.abruptClosingOfEmptyComment);
this.state = State.DATA;
const token = this.currentToken;
this.emitCurrentComment(token);
break;
}
default: {
this.state = State.COMMENT;
this._stateComment(cp);
}
}
}
// Comment start dash state
//------------------------------------------------------------------
_stateCommentStartDash(cp) {
const token = this.currentToken;
switch (cp) {
case unicode$1.CODE_POINTS.HYPHEN_MINUS: {
this.state = State.COMMENT_END;
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes$1.ERR.abruptClosingOfEmptyComment);
this.state = State.DATA;
this.emitCurrentComment(token);
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInComment);
this.emitCurrentComment(token);
this._emitEOFToken();
break;
}
default: {
token.data += '-';
this.state = State.COMMENT;
this._stateComment(cp);
}
}
}
// Comment state
//------------------------------------------------------------------
_stateComment(cp) {
const token = this.currentToken;
switch (cp) {
case unicode$1.CODE_POINTS.HYPHEN_MINUS: {
this.state = State.COMMENT_END_DASH;
break;
}
case unicode$1.CODE_POINTS.LESS_THAN_SIGN: {
token.data += '<';
this.state = State.COMMENT_LESS_THAN_SIGN;
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
token.data += unicode$1.REPLACEMENT_CHARACTER;
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInComment);
this.emitCurrentComment(token);
this._emitEOFToken();
break;
}
default: {
token.data += String.fromCodePoint(cp);
}
}
}
// Comment less-than sign state
//------------------------------------------------------------------
_stateCommentLessThanSign(cp) {
const token = this.currentToken;
switch (cp) {
case unicode$1.CODE_POINTS.EXCLAMATION_MARK: {
token.data += '!';
this.state = State.COMMENT_LESS_THAN_SIGN_BANG;
break;
}
case unicode$1.CODE_POINTS.LESS_THAN_SIGN: {
token.data += '<';
break;
}
default: {
this.state = State.COMMENT;
this._stateComment(cp);
}
}
}
// Comment less-than sign bang state
//------------------------------------------------------------------
_stateCommentLessThanSignBang(cp) {
if (cp === unicode$1.CODE_POINTS.HYPHEN_MINUS) {
this.state = State.COMMENT_LESS_THAN_SIGN_BANG_DASH;
}
else {
this.state = State.COMMENT;
this._stateComment(cp);
}
}
// Comment less-than sign bang dash state
//------------------------------------------------------------------
_stateCommentLessThanSignBangDash(cp) {
if (cp === unicode$1.CODE_POINTS.HYPHEN_MINUS) {
this.state = State.COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH;
}
else {
this.state = State.COMMENT_END_DASH;
this._stateCommentEndDash(cp);
}
}
// Comment less-than sign bang dash dash state
//------------------------------------------------------------------
_stateCommentLessThanSignBangDashDash(cp) {
if (cp !== unicode$1.CODE_POINTS.GREATER_THAN_SIGN && cp !== unicode$1.CODE_POINTS.EOF) {
this._err(errorCodes$1.ERR.nestedComment);
}
this.state = State.COMMENT_END;
this._stateCommentEnd(cp);
}
// Comment end dash state
//------------------------------------------------------------------
_stateCommentEndDash(cp) {
const token = this.currentToken;
switch (cp) {
case unicode$1.CODE_POINTS.HYPHEN_MINUS: {
this.state = State.COMMENT_END;
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInComment);
this.emitCurrentComment(token);
this._emitEOFToken();
break;
}
default: {
token.data += '-';
this.state = State.COMMENT;
this._stateComment(cp);
}
}
}
// Comment end state
//------------------------------------------------------------------
_stateCommentEnd(cp) {
const token = this.currentToken;
switch (cp) {
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
this.emitCurrentComment(token);
break;
}
case unicode$1.CODE_POINTS.EXCLAMATION_MARK: {
this.state = State.COMMENT_END_BANG;
break;
}
case unicode$1.CODE_POINTS.HYPHEN_MINUS: {
token.data += '-';
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInComment);
this.emitCurrentComment(token);
this._emitEOFToken();
break;
}
default: {
token.data += '--';
this.state = State.COMMENT;
this._stateComment(cp);
}
}
}
// Comment end bang state
//------------------------------------------------------------------
_stateCommentEndBang(cp) {
const token = this.currentToken;
switch (cp) {
case unicode$1.CODE_POINTS.HYPHEN_MINUS: {
token.data += '--!';
this.state = State.COMMENT_END_DASH;
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes$1.ERR.incorrectlyClosedComment);
this.state = State.DATA;
this.emitCurrentComment(token);
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInComment);
this.emitCurrentComment(token);
this._emitEOFToken();
break;
}
default: {
token.data += '--!';
this.state = State.COMMENT;
this._stateComment(cp);
}
}
}
// DOCTYPE state
//------------------------------------------------------------------
_stateDoctype(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.SPACE:
case unicode$1.CODE_POINTS.LINE_FEED:
case unicode$1.CODE_POINTS.TABULATION:
case unicode$1.CODE_POINTS.FORM_FEED: {
this.state = State.BEFORE_DOCTYPE_NAME;
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.BEFORE_DOCTYPE_NAME;
this._stateBeforeDoctypeName(cp);
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInDoctype);
this._createDoctypeToken(null);
const token = this.currentToken;
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes$1.ERR.missingWhitespaceBeforeDoctypeName);
this.state = State.BEFORE_DOCTYPE_NAME;
this._stateBeforeDoctypeName(cp);
}
}
}
// Before DOCTYPE name state
//------------------------------------------------------------------
_stateBeforeDoctypeName(cp) {
if (isAsciiUpper(cp)) {
this._createDoctypeToken(String.fromCharCode(toAsciiLower(cp)));
this.state = State.DOCTYPE_NAME;
}
else
switch (cp) {
case unicode$1.CODE_POINTS.SPACE:
case unicode$1.CODE_POINTS.LINE_FEED:
case unicode$1.CODE_POINTS.TABULATION:
case unicode$1.CODE_POINTS.FORM_FEED: {
// Ignore whitespace
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
this._createDoctypeToken(unicode$1.REPLACEMENT_CHARACTER);
this.state = State.DOCTYPE_NAME;
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes$1.ERR.missingDoctypeName);
this._createDoctypeToken(null);
const token = this.currentToken;
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInDoctype);
this._createDoctypeToken(null);
const token = this.currentToken;
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._createDoctypeToken(String.fromCodePoint(cp));
this.state = State.DOCTYPE_NAME;
}
}
}
// DOCTYPE name state
//------------------------------------------------------------------
_stateDoctypeName(cp) {
const token = this.currentToken;
switch (cp) {
case unicode$1.CODE_POINTS.SPACE:
case unicode$1.CODE_POINTS.LINE_FEED:
case unicode$1.CODE_POINTS.TABULATION:
case unicode$1.CODE_POINTS.FORM_FEED: {
this.state = State.AFTER_DOCTYPE_NAME;
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
this.emitCurrentDoctype(token);
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
token.name += unicode$1.REPLACEMENT_CHARACTER;
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
token.name += String.fromCodePoint(isAsciiUpper(cp) ? toAsciiLower(cp) : cp);
}
}
}
// After DOCTYPE name state
//------------------------------------------------------------------
_stateAfterDoctypeName(cp) {
const token = this.currentToken;
switch (cp) {
case unicode$1.CODE_POINTS.SPACE:
case unicode$1.CODE_POINTS.LINE_FEED:
case unicode$1.CODE_POINTS.TABULATION:
case unicode$1.CODE_POINTS.FORM_FEED: {
// Ignore whitespace
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
this.emitCurrentDoctype(token);
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
if (this._consumeSequenceIfMatch(unicode$1.SEQUENCES.PUBLIC, false)) {
this.state = State.AFTER_DOCTYPE_PUBLIC_KEYWORD;
}
else if (this._consumeSequenceIfMatch(unicode$1.SEQUENCES.SYSTEM, false)) {
this.state = State.AFTER_DOCTYPE_SYSTEM_KEYWORD;
}
//NOTE: sequence lookup can be abrupted by hibernation. In that case lookup
//results are no longer valid and we will need to start over.
else if (!this._ensureHibernation()) {
this._err(errorCodes$1.ERR.invalidCharacterSequenceAfterDoctypeName);
token.forceQuirks = true;
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
}
// After DOCTYPE public keyword state
//------------------------------------------------------------------
_stateAfterDoctypePublicKeyword(cp) {
const token = this.currentToken;
switch (cp) {
case unicode$1.CODE_POINTS.SPACE:
case unicode$1.CODE_POINTS.LINE_FEED:
case unicode$1.CODE_POINTS.TABULATION:
case unicode$1.CODE_POINTS.FORM_FEED: {
this.state = State.BEFORE_DOCTYPE_PUBLIC_IDENTIFIER;
break;
}
case unicode$1.CODE_POINTS.QUOTATION_MARK: {
this._err(errorCodes$1.ERR.missingWhitespaceAfterDoctypePublicKeyword);
token.publicId = '';
this.state = State.DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED;
break;
}
case unicode$1.CODE_POINTS.APOSTROPHE: {
this._err(errorCodes$1.ERR.missingWhitespaceAfterDoctypePublicKeyword);
token.publicId = '';
this.state = State.DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED;
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes$1.ERR.missingDoctypePublicIdentifier);
token.forceQuirks = true;
this.state = State.DATA;
this.emitCurrentDoctype(token);
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes$1.ERR.missingQuoteBeforeDoctypePublicIdentifier);
token.forceQuirks = true;
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
// Before DOCTYPE public identifier state
//------------------------------------------------------------------
_stateBeforeDoctypePublicIdentifier(cp) {
const token = this.currentToken;
switch (cp) {
case unicode$1.CODE_POINTS.SPACE:
case unicode$1.CODE_POINTS.LINE_FEED:
case unicode$1.CODE_POINTS.TABULATION:
case unicode$1.CODE_POINTS.FORM_FEED: {
// Ignore whitespace
break;
}
case unicode$1.CODE_POINTS.QUOTATION_MARK: {
token.publicId = '';
this.state = State.DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED;
break;
}
case unicode$1.CODE_POINTS.APOSTROPHE: {
token.publicId = '';
this.state = State.DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED;
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes$1.ERR.missingDoctypePublicIdentifier);
token.forceQuirks = true;
this.state = State.DATA;
this.emitCurrentDoctype(token);
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes$1.ERR.missingQuoteBeforeDoctypePublicIdentifier);
token.forceQuirks = true;
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
// DOCTYPE public identifier (double-quoted) state
//------------------------------------------------------------------
_stateDoctypePublicIdentifierDoubleQuoted(cp) {
const token = this.currentToken;
switch (cp) {
case unicode$1.CODE_POINTS.QUOTATION_MARK: {
this.state = State.AFTER_DOCTYPE_PUBLIC_IDENTIFIER;
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
token.publicId += unicode$1.REPLACEMENT_CHARACTER;
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes$1.ERR.abruptDoctypePublicIdentifier);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
token.publicId += String.fromCodePoint(cp);
}
}
}
// DOCTYPE public identifier (single-quoted) state
//------------------------------------------------------------------
_stateDoctypePublicIdentifierSingleQuoted(cp) {
const token = this.currentToken;
switch (cp) {
case unicode$1.CODE_POINTS.APOSTROPHE: {
this.state = State.AFTER_DOCTYPE_PUBLIC_IDENTIFIER;
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
token.publicId += unicode$1.REPLACEMENT_CHARACTER;
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes$1.ERR.abruptDoctypePublicIdentifier);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
token.publicId += String.fromCodePoint(cp);
}
}
}
// After DOCTYPE public identifier state
//------------------------------------------------------------------
_stateAfterDoctypePublicIdentifier(cp) {
const token = this.currentToken;
switch (cp) {
case unicode$1.CODE_POINTS.SPACE:
case unicode$1.CODE_POINTS.LINE_FEED:
case unicode$1.CODE_POINTS.TABULATION:
case unicode$1.CODE_POINTS.FORM_FEED: {
this.state = State.BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS;
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
this.emitCurrentDoctype(token);
break;
}
case unicode$1.CODE_POINTS.QUOTATION_MARK: {
this._err(errorCodes$1.ERR.missingWhitespaceBetweenDoctypePublicAndSystemIdentifiers);
token.systemId = '';
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED;
break;
}
case unicode$1.CODE_POINTS.APOSTROPHE: {
this._err(errorCodes$1.ERR.missingWhitespaceBetweenDoctypePublicAndSystemIdentifiers);
token.systemId = '';
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED;
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes$1.ERR.missingQuoteBeforeDoctypeSystemIdentifier);
token.forceQuirks = true;
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
// Between DOCTYPE public and system identifiers state
//------------------------------------------------------------------
_stateBetweenDoctypePublicAndSystemIdentifiers(cp) {
const token = this.currentToken;
switch (cp) {
case unicode$1.CODE_POINTS.SPACE:
case unicode$1.CODE_POINTS.LINE_FEED:
case unicode$1.CODE_POINTS.TABULATION:
case unicode$1.CODE_POINTS.FORM_FEED: {
// Ignore whitespace
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case unicode$1.CODE_POINTS.QUOTATION_MARK: {
token.systemId = '';
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED;
break;
}
case unicode$1.CODE_POINTS.APOSTROPHE: {
token.systemId = '';
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED;
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes$1.ERR.missingQuoteBeforeDoctypeSystemIdentifier);
token.forceQuirks = true;
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
// After DOCTYPE system keyword state
//------------------------------------------------------------------
_stateAfterDoctypeSystemKeyword(cp) {
const token = this.currentToken;
switch (cp) {
case unicode$1.CODE_POINTS.SPACE:
case unicode$1.CODE_POINTS.LINE_FEED:
case unicode$1.CODE_POINTS.TABULATION:
case unicode$1.CODE_POINTS.FORM_FEED: {
this.state = State.BEFORE_DOCTYPE_SYSTEM_IDENTIFIER;
break;
}
case unicode$1.CODE_POINTS.QUOTATION_MARK: {
this._err(errorCodes$1.ERR.missingWhitespaceAfterDoctypeSystemKeyword);
token.systemId = '';
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED;
break;
}
case unicode$1.CODE_POINTS.APOSTROPHE: {
this._err(errorCodes$1.ERR.missingWhitespaceAfterDoctypeSystemKeyword);
token.systemId = '';
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED;
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes$1.ERR.missingDoctypeSystemIdentifier);
token.forceQuirks = true;
this.state = State.DATA;
this.emitCurrentDoctype(token);
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes$1.ERR.missingQuoteBeforeDoctypeSystemIdentifier);
token.forceQuirks = true;
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
// Before DOCTYPE system identifier state
//------------------------------------------------------------------
_stateBeforeDoctypeSystemIdentifier(cp) {
const token = this.currentToken;
switch (cp) {
case unicode$1.CODE_POINTS.SPACE:
case unicode$1.CODE_POINTS.LINE_FEED:
case unicode$1.CODE_POINTS.TABULATION:
case unicode$1.CODE_POINTS.FORM_FEED: {
// Ignore whitespace
break;
}
case unicode$1.CODE_POINTS.QUOTATION_MARK: {
token.systemId = '';
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED;
break;
}
case unicode$1.CODE_POINTS.APOSTROPHE: {
token.systemId = '';
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED;
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes$1.ERR.missingDoctypeSystemIdentifier);
token.forceQuirks = true;
this.state = State.DATA;
this.emitCurrentDoctype(token);
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes$1.ERR.missingQuoteBeforeDoctypeSystemIdentifier);
token.forceQuirks = true;
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
// DOCTYPE system identifier (double-quoted) state
//------------------------------------------------------------------
_stateDoctypeSystemIdentifierDoubleQuoted(cp) {
const token = this.currentToken;
switch (cp) {
case unicode$1.CODE_POINTS.QUOTATION_MARK: {
this.state = State.AFTER_DOCTYPE_SYSTEM_IDENTIFIER;
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
token.systemId += unicode$1.REPLACEMENT_CHARACTER;
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes$1.ERR.abruptDoctypeSystemIdentifier);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
token.systemId += String.fromCodePoint(cp);
}
}
}
// DOCTYPE system identifier (single-quoted) state
//------------------------------------------------------------------
_stateDoctypeSystemIdentifierSingleQuoted(cp) {
const token = this.currentToken;
switch (cp) {
case unicode$1.CODE_POINTS.APOSTROPHE: {
this.state = State.AFTER_DOCTYPE_SYSTEM_IDENTIFIER;
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
token.systemId += unicode$1.REPLACEMENT_CHARACTER;
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes$1.ERR.abruptDoctypeSystemIdentifier);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
token.systemId += String.fromCodePoint(cp);
}
}
}
// After DOCTYPE system identifier state
//------------------------------------------------------------------
_stateAfterDoctypeSystemIdentifier(cp) {
const token = this.currentToken;
switch (cp) {
case unicode$1.CODE_POINTS.SPACE:
case unicode$1.CODE_POINTS.LINE_FEED:
case unicode$1.CODE_POINTS.TABULATION:
case unicode$1.CODE_POINTS.FORM_FEED: {
// Ignore whitespace
break;
}
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes$1.ERR.unexpectedCharacterAfterDoctypeSystemIdentifier);
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
// Bogus DOCTYPE state
//------------------------------------------------------------------
_stateBogusDoctype(cp) {
const token = this.currentToken;
switch (cp) {
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case unicode$1.CODE_POINTS.NULL: {
this._err(errorCodes$1.ERR.unexpectedNullCharacter);
break;
}
case unicode$1.CODE_POINTS.EOF: {
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
// Do nothing
}
}
// CDATA section state
//------------------------------------------------------------------
_stateCdataSection(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.RIGHT_SQUARE_BRACKET: {
this.state = State.CDATA_SECTION_BRACKET;
break;
}
case unicode$1.CODE_POINTS.EOF: {
this._err(errorCodes$1.ERR.eofInCdata);
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// CDATA section bracket state
//------------------------------------------------------------------
_stateCdataSectionBracket(cp) {
if (cp === unicode$1.CODE_POINTS.RIGHT_SQUARE_BRACKET) {
this.state = State.CDATA_SECTION_END;
}
else {
this._emitChars(']');
this.state = State.CDATA_SECTION;
this._stateCdataSection(cp);
}
}
// CDATA section end state
//------------------------------------------------------------------
_stateCdataSectionEnd(cp) {
switch (cp) {
case unicode$1.CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
break;
}
case unicode$1.CODE_POINTS.RIGHT_SQUARE_BRACKET: {
this._emitChars(']');
break;
}
default: {
this._emitChars(']]');
this.state = State.CDATA_SECTION;
this._stateCdataSection(cp);
}
}
}
// Character reference state
//------------------------------------------------------------------
_stateCharacterReference(cp) {
if (cp === unicode$1.CODE_POINTS.NUMBER_SIGN) {
this.state = State.NUMERIC_CHARACTER_REFERENCE;
}
else if (isAsciiAlphaNumeric(cp)) {
this.state = State.NAMED_CHARACTER_REFERENCE;
this._stateNamedCharacterReference(cp);
}
else {
this._flushCodePointConsumedAsCharacterReference(unicode$1.CODE_POINTS.AMPERSAND);
this._reconsumeInState(this.returnState, cp);
}
}
// Named character reference state
//------------------------------------------------------------------
_stateNamedCharacterReference(cp) {
const matchResult = this._matchNamedCharacterReference(cp);
//NOTE: Matching can be abrupted by hibernation. In that case, match
//results are no longer valid and we will need to start over.
if (this._ensureHibernation()) ;
else if (matchResult) {
for (let i = 0; i < matchResult.length; i++) {
this._flushCodePointConsumedAsCharacterReference(matchResult[i]);
}
this.state = this.returnState;
}
else {
this._flushCodePointConsumedAsCharacterReference(unicode$1.CODE_POINTS.AMPERSAND);
this.state = State.AMBIGUOUS_AMPERSAND;
}
}
// Ambiguos ampersand state
//------------------------------------------------------------------
_stateAmbiguousAmpersand(cp) {
if (isAsciiAlphaNumeric(cp)) {
this._flushCodePointConsumedAsCharacterReference(cp);
}
else {
if (cp === unicode$1.CODE_POINTS.SEMICOLON) {
this._err(errorCodes$1.ERR.unknownNamedCharacterReference);
}
this._reconsumeInState(this.returnState, cp);
}
}
// Numeric character reference state
//------------------------------------------------------------------
_stateNumericCharacterReference(cp) {
this.charRefCode = 0;
if (cp === unicode$1.CODE_POINTS.LATIN_SMALL_X || cp === unicode$1.CODE_POINTS.LATIN_CAPITAL_X) {
this.state = State.HEXADEMICAL_CHARACTER_REFERENCE_START;
}
// Inlined decimal character reference start state
else if (isAsciiDigit(cp)) {
this.state = State.DECIMAL_CHARACTER_REFERENCE;
this._stateDecimalCharacterReference(cp);
}
else {
this._err(errorCodes$1.ERR.absenceOfDigitsInNumericCharacterReference);
this._flushCodePointConsumedAsCharacterReference(unicode$1.CODE_POINTS.AMPERSAND);
this._flushCodePointConsumedAsCharacterReference(unicode$1.CODE_POINTS.NUMBER_SIGN);
this._reconsumeInState(this.returnState, cp);
}
}
// Hexademical character reference start state
//------------------------------------------------------------------
_stateHexademicalCharacterReferenceStart(cp) {
if (isAsciiHexDigit(cp)) {
this.state = State.HEXADEMICAL_CHARACTER_REFERENCE;
this._stateHexademicalCharacterReference(cp);
}
else {
this._err(errorCodes$1.ERR.absenceOfDigitsInNumericCharacterReference);
this._flushCodePointConsumedAsCharacterReference(unicode$1.CODE_POINTS.AMPERSAND);
this._flushCodePointConsumedAsCharacterReference(unicode$1.CODE_POINTS.NUMBER_SIGN);
this._unconsume(2);
this.state = this.returnState;
}
}
// Hexademical character reference state
//------------------------------------------------------------------
_stateHexademicalCharacterReference(cp) {
if (isAsciiUpperHexDigit(cp)) {
this.charRefCode = this.charRefCode * 16 + cp - 0x37;
}
else if (isAsciiLowerHexDigit(cp)) {
this.charRefCode = this.charRefCode * 16 + cp - 0x57;
}
else if (isAsciiDigit(cp)) {
this.charRefCode = this.charRefCode * 16 + cp - 0x30;
}
else if (cp === unicode$1.CODE_POINTS.SEMICOLON) {
this.state = State.NUMERIC_CHARACTER_REFERENCE_END;
}
else {
this._err(errorCodes$1.ERR.missingSemicolonAfterCharacterReference);
this.state = State.NUMERIC_CHARACTER_REFERENCE_END;
this._stateNumericCharacterReferenceEnd(cp);
}
}
// Decimal character reference state
//------------------------------------------------------------------
_stateDecimalCharacterReference(cp) {
if (isAsciiDigit(cp)) {
this.charRefCode = this.charRefCode * 10 + cp - 0x30;
}
else if (cp === unicode$1.CODE_POINTS.SEMICOLON) {
this.state = State.NUMERIC_CHARACTER_REFERENCE_END;
}
else {
this._err(errorCodes$1.ERR.missingSemicolonAfterCharacterReference);
this.state = State.NUMERIC_CHARACTER_REFERENCE_END;
this._stateNumericCharacterReferenceEnd(cp);
}
}
// Numeric character reference end state
//------------------------------------------------------------------
_stateNumericCharacterReferenceEnd(cp) {
if (this.charRefCode === unicode$1.CODE_POINTS.NULL) {
this._err(errorCodes$1.ERR.nullCharacterReference);
this.charRefCode = unicode$1.CODE_POINTS.REPLACEMENT_CHARACTER;
}
else if (this.charRefCode > 1114111) {
this._err(errorCodes$1.ERR.characterReferenceOutsideUnicodeRange);
this.charRefCode = unicode$1.CODE_POINTS.REPLACEMENT_CHARACTER;
}
else if ((0, unicode$1.isSurrogate)(this.charRefCode)) {
this._err(errorCodes$1.ERR.surrogateCharacterReference);
this.charRefCode = unicode$1.CODE_POINTS.REPLACEMENT_CHARACTER;
}
else if ((0, unicode$1.isUndefinedCodePoint)(this.charRefCode)) {
this._err(errorCodes$1.ERR.noncharacterCharacterReference);
}
else if ((0, unicode$1.isControlCodePoint)(this.charRefCode) || this.charRefCode === unicode$1.CODE_POINTS.CARRIAGE_RETURN) {
this._err(errorCodes$1.ERR.controlCharacterReference);
const replacement = C1_CONTROLS_REFERENCE_REPLACEMENTS.get(this.charRefCode);
if (replacement !== undefined) {
this.charRefCode = replacement;
}
}
this._flushCodePointConsumedAsCharacterReference(this.charRefCode);
this._reconsumeInState(this.returnState, cp);
}
}
exports.Tokenizer = Tokenizer;
});
var openElementStack$1 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.OpenElementStack = void 0;
//Element utils
const IMPLICIT_END_TAG_REQUIRED = new Set([html$1.TAG_ID.DD, html$1.TAG_ID.DT, html$1.TAG_ID.LI, html$1.TAG_ID.OPTGROUP, html$1.TAG_ID.OPTION, html$1.TAG_ID.P, html$1.TAG_ID.RB, html$1.TAG_ID.RP, html$1.TAG_ID.RT, html$1.TAG_ID.RTC]);
const IMPLICIT_END_TAG_REQUIRED_THOROUGHLY = new Set([
...IMPLICIT_END_TAG_REQUIRED,
html$1.TAG_ID.CAPTION,
html$1.TAG_ID.COLGROUP,
html$1.TAG_ID.TBODY,
html$1.TAG_ID.TD,
html$1.TAG_ID.TFOOT,
html$1.TAG_ID.TH,
html$1.TAG_ID.THEAD,
html$1.TAG_ID.TR,
]);
const SCOPING_ELEMENT_NS = new Map([
[html$1.TAG_ID.APPLET, html$1.NS.HTML],
[html$1.TAG_ID.CAPTION, html$1.NS.HTML],
[html$1.TAG_ID.HTML, html$1.NS.HTML],
[html$1.TAG_ID.MARQUEE, html$1.NS.HTML],
[html$1.TAG_ID.OBJECT, html$1.NS.HTML],
[html$1.TAG_ID.TABLE, html$1.NS.HTML],
[html$1.TAG_ID.TD, html$1.NS.HTML],
[html$1.TAG_ID.TEMPLATE, html$1.NS.HTML],
[html$1.TAG_ID.TH, html$1.NS.HTML],
[html$1.TAG_ID.ANNOTATION_XML, html$1.NS.MATHML],
[html$1.TAG_ID.MI, html$1.NS.MATHML],
[html$1.TAG_ID.MN, html$1.NS.MATHML],
[html$1.TAG_ID.MO, html$1.NS.MATHML],
[html$1.TAG_ID.MS, html$1.NS.MATHML],
[html$1.TAG_ID.MTEXT, html$1.NS.MATHML],
[html$1.TAG_ID.DESC, html$1.NS.SVG],
[html$1.TAG_ID.FOREIGN_OBJECT, html$1.NS.SVG],
[html$1.TAG_ID.TITLE, html$1.NS.SVG],
]);
const NAMED_HEADERS = [html$1.TAG_ID.H1, html$1.TAG_ID.H2, html$1.TAG_ID.H3, html$1.TAG_ID.H4, html$1.TAG_ID.H5, html$1.TAG_ID.H6];
const TABLE_ROW_CONTEXT = [html$1.TAG_ID.TR, html$1.TAG_ID.TEMPLATE, html$1.TAG_ID.HTML];
const TABLE_BODY_CONTEXT = [html$1.TAG_ID.TBODY, html$1.TAG_ID.TFOOT, html$1.TAG_ID.THEAD, html$1.TAG_ID.TEMPLATE, html$1.TAG_ID.HTML];
const TABLE_CONTEXT = [html$1.TAG_ID.TABLE, html$1.TAG_ID.TEMPLATE, html$1.TAG_ID.HTML];
const TABLE_CELLS = [html$1.TAG_ID.TD, html$1.TAG_ID.TH];
//Stack of open elements
class OpenElementStack {
get currentTmplContentOrNode() {
return this._isInTemplate() ? this.treeAdapter.getTemplateContent(this.current) : this.current;
}
constructor(document, treeAdapter, handler) {
this.treeAdapter = treeAdapter;
this.handler = handler;
this.items = [];
this.tagIDs = [];
this.stackTop = -1;
this.tmplCount = 0;
this.currentTagId = html$1.TAG_ID.UNKNOWN;
this.current = document;
}
//Index of element
_indexOf(element) {
return this.items.lastIndexOf(element, this.stackTop);
}
//Update current element
_isInTemplate() {
return this.currentTagId === html$1.TAG_ID.TEMPLATE && this.treeAdapter.getNamespaceURI(this.current) === html$1.NS.HTML;
}
_updateCurrentElement() {
this.current = this.items[this.stackTop];
this.currentTagId = this.tagIDs[this.stackTop];
}
//Mutations
push(element, tagID) {
this.stackTop++;
this.items[this.stackTop] = element;
this.current = element;
this.tagIDs[this.stackTop] = tagID;
this.currentTagId = tagID;
if (this._isInTemplate()) {
this.tmplCount++;
}
this.handler.onItemPush(element, tagID, true);
}
pop() {
const popped = this.current;
if (this.tmplCount > 0 && this._isInTemplate()) {
this.tmplCount--;
}
this.stackTop--;
this._updateCurrentElement();
this.handler.onItemPop(popped, true);
}
replace(oldElement, newElement) {
const idx = this._indexOf(oldElement);
this.items[idx] = newElement;
if (idx === this.stackTop) {
this.current = newElement;
}
}
insertAfter(referenceElement, newElement, newElementID) {
const insertionIdx = this._indexOf(referenceElement) + 1;
this.items.splice(insertionIdx, 0, newElement);
this.tagIDs.splice(insertionIdx, 0, newElementID);
this.stackTop++;
if (insertionIdx === this.stackTop) {
this._updateCurrentElement();
}
this.handler.onItemPush(this.current, this.currentTagId, insertionIdx === this.stackTop);
}
popUntilTagNamePopped(tagName) {
let targetIdx = this.stackTop + 1;
do {
targetIdx = this.tagIDs.lastIndexOf(tagName, targetIdx - 1);
} while (targetIdx > 0 && this.treeAdapter.getNamespaceURI(this.items[targetIdx]) !== html$1.NS.HTML);
this.shortenToLength(targetIdx < 0 ? 0 : targetIdx);
}
shortenToLength(idx) {
while (this.stackTop >= idx) {
const popped = this.current;
if (this.tmplCount > 0 && this._isInTemplate()) {
this.tmplCount -= 1;
}
this.stackTop--;
this._updateCurrentElement();
this.handler.onItemPop(popped, this.stackTop < idx);
}
}
popUntilElementPopped(element) {
const idx = this._indexOf(element);
this.shortenToLength(idx < 0 ? 0 : idx);
}
popUntilPopped(tagNames, targetNS) {
const idx = this._indexOfTagNames(tagNames, targetNS);
this.shortenToLength(idx < 0 ? 0 : idx);
}
popUntilNumberedHeaderPopped() {
this.popUntilPopped(NAMED_HEADERS, html$1.NS.HTML);
}
popUntilTableCellPopped() {
this.popUntilPopped(TABLE_CELLS, html$1.NS.HTML);
}
popAllUpToHtmlElement() {
//NOTE: here we assume that the root <html> element is always first in the open element stack, so
//we perform this fast stack clean up.
this.tmplCount = 0;
this.shortenToLength(1);
}
_indexOfTagNames(tagNames, namespace) {
for (let i = this.stackTop; i >= 0; i--) {
if (tagNames.includes(this.tagIDs[i]) && this.treeAdapter.getNamespaceURI(this.items[i]) === namespace) {
return i;
}
}
return -1;
}
clearBackTo(tagNames, targetNS) {
const idx = this._indexOfTagNames(tagNames, targetNS);
this.shortenToLength(idx + 1);
}
clearBackToTableContext() {
this.clearBackTo(TABLE_CONTEXT, html$1.NS.HTML);
}
clearBackToTableBodyContext() {
this.clearBackTo(TABLE_BODY_CONTEXT, html$1.NS.HTML);
}
clearBackToTableRowContext() {
this.clearBackTo(TABLE_ROW_CONTEXT, html$1.NS.HTML);
}
remove(element) {
const idx = this._indexOf(element);
if (idx >= 0) {
if (idx === this.stackTop) {
this.pop();
}
else {
this.items.splice(idx, 1);
this.tagIDs.splice(idx, 1);
this.stackTop--;
this._updateCurrentElement();
this.handler.onItemPop(element, false);
}
}
}
//Search
tryPeekProperlyNestedBodyElement() {
//Properly nested <body> element (should be second element in stack).
return this.stackTop >= 1 && this.tagIDs[1] === html$1.TAG_ID.BODY ? this.items[1] : null;
}
contains(element) {
return this._indexOf(element) > -1;
}
getCommonAncestor(element) {
const elementIdx = this._indexOf(element) - 1;
return elementIdx >= 0 ? this.items[elementIdx] : null;
}
isRootHtmlElementCurrent() {
return this.stackTop === 0 && this.tagIDs[0] === html$1.TAG_ID.HTML;
}
//Element in scope
hasInScope(tagName) {
for (let i = this.stackTop; i >= 0; i--) {
const tn = this.tagIDs[i];
const ns = this.treeAdapter.getNamespaceURI(this.items[i]);
if (tn === tagName && ns === html$1.NS.HTML) {
return true;
}
if (SCOPING_ELEMENT_NS.get(tn) === ns) {
return false;
}
}
return true;
}
hasNumberedHeaderInScope() {
for (let i = this.stackTop; i >= 0; i--) {
const tn = this.tagIDs[i];
const ns = this.treeAdapter.getNamespaceURI(this.items[i]);
if ((0, html$1.isNumberedHeader)(tn) && ns === html$1.NS.HTML) {
return true;
}
if (SCOPING_ELEMENT_NS.get(tn) === ns) {
return false;
}
}
return true;
}
hasInListItemScope(tagName) {
for (let i = this.stackTop; i >= 0; i--) {
const tn = this.tagIDs[i];
const ns = this.treeAdapter.getNamespaceURI(this.items[i]);
if (tn === tagName && ns === html$1.NS.HTML) {
return true;
}
if (((tn === html$1.TAG_ID.UL || tn === html$1.TAG_ID.OL) && ns === html$1.NS.HTML) || SCOPING_ELEMENT_NS.get(tn) === ns) {
return false;
}
}
return true;
}
hasInButtonScope(tagName) {
for (let i = this.stackTop; i >= 0; i--) {
const tn = this.tagIDs[i];
const ns = this.treeAdapter.getNamespaceURI(this.items[i]);
if (tn === tagName && ns === html$1.NS.HTML) {
return true;
}
if ((tn === html$1.TAG_ID.BUTTON && ns === html$1.NS.HTML) || SCOPING_ELEMENT_NS.get(tn) === ns) {
return false;
}
}
return true;
}
hasInTableScope(tagName) {
for (let i = this.stackTop; i >= 0; i--) {
const tn = this.tagIDs[i];
const ns = this.treeAdapter.getNamespaceURI(this.items[i]);
if (ns !== html$1.NS.HTML) {
continue;
}
if (tn === tagName) {
return true;
}
if (tn === html$1.TAG_ID.TABLE || tn === html$1.TAG_ID.TEMPLATE || tn === html$1.TAG_ID.HTML) {
return false;
}
}
return true;
}
hasTableBodyContextInTableScope() {
for (let i = this.stackTop; i >= 0; i--) {
const tn = this.tagIDs[i];
const ns = this.treeAdapter.getNamespaceURI(this.items[i]);
if (ns !== html$1.NS.HTML) {
continue;
}
if (tn === html$1.TAG_ID.TBODY || tn === html$1.TAG_ID.THEAD || tn === html$1.TAG_ID.TFOOT) {
return true;
}
if (tn === html$1.TAG_ID.TABLE || tn === html$1.TAG_ID.HTML) {
return false;
}
}
return true;
}
hasInSelectScope(tagName) {
for (let i = this.stackTop; i >= 0; i--) {
const tn = this.tagIDs[i];
const ns = this.treeAdapter.getNamespaceURI(this.items[i]);
if (ns !== html$1.NS.HTML) {
continue;
}
if (tn === tagName) {
return true;
}
if (tn !== html$1.TAG_ID.OPTION && tn !== html$1.TAG_ID.OPTGROUP) {
return false;
}
}
return true;
}
//Implied end tags
generateImpliedEndTags() {
while (IMPLICIT_END_TAG_REQUIRED.has(this.currentTagId)) {
this.pop();
}
}
generateImpliedEndTagsThoroughly() {
while (IMPLICIT_END_TAG_REQUIRED_THOROUGHLY.has(this.currentTagId)) {
this.pop();
}
}
generateImpliedEndTagsWithExclusion(exclusionId) {
while (this.currentTagId !== exclusionId && IMPLICIT_END_TAG_REQUIRED_THOROUGHLY.has(this.currentTagId)) {
this.pop();
}
}
}
exports.OpenElementStack = OpenElementStack;
});
var formattingElementList$1 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.FormattingElementList = exports.EntryType = void 0;
//Const
const NOAH_ARK_CAPACITY = 3;
var EntryType;
(function (EntryType) {
EntryType[EntryType["Marker"] = 0] = "Marker";
EntryType[EntryType["Element"] = 1] = "Element";
})(EntryType = exports.EntryType || (exports.EntryType = {}));
const MARKER = { type: EntryType.Marker };
//List of formatting elements
class FormattingElementList {
constructor(treeAdapter) {
this.treeAdapter = treeAdapter;
this.entries = [];
this.bookmark = null;
}
//Noah Ark's condition
//OPTIMIZATION: at first we try to find possible candidates for exclusion using
//lightweight heuristics without thorough attributes check.
_getNoahArkConditionCandidates(newElement, neAttrs) {
const candidates = [];
const neAttrsLength = neAttrs.length;
const neTagName = this.treeAdapter.getTagName(newElement);
const neNamespaceURI = this.treeAdapter.getNamespaceURI(newElement);
for (let i = 0; i < this.entries.length; i++) {
const entry = this.entries[i];
if (entry.type === EntryType.Marker) {
break;
}
const { element } = entry;
if (this.treeAdapter.getTagName(element) === neTagName &&
this.treeAdapter.getNamespaceURI(element) === neNamespaceURI) {
const elementAttrs = this.treeAdapter.getAttrList(element);
if (elementAttrs.length === neAttrsLength) {
candidates.push({ idx: i, attrs: elementAttrs });
}
}
}
return candidates;
}
_ensureNoahArkCondition(newElement) {
if (this.entries.length < NOAH_ARK_CAPACITY)
return;
const neAttrs = this.treeAdapter.getAttrList(newElement);
const candidates = this._getNoahArkConditionCandidates(newElement, neAttrs);
if (candidates.length < NOAH_ARK_CAPACITY)
return;
//NOTE: build attrs map for the new element, so we can perform fast lookups
const neAttrsMap = new Map(neAttrs.map((neAttr) => [neAttr.name, neAttr.value]));
let validCandidates = 0;
//NOTE: remove bottommost candidates, until Noah's Ark condition will not be met
for (let i = 0; i < candidates.length; i++) {
const candidate = candidates[i];
// We know that `candidate.attrs.length === neAttrs.length`
if (candidate.attrs.every((cAttr) => neAttrsMap.get(cAttr.name) === cAttr.value)) {
validCandidates += 1;
if (validCandidates >= NOAH_ARK_CAPACITY) {
this.entries.splice(candidate.idx, 1);
}
}
}
}
//Mutations
insertMarker() {
this.entries.unshift(MARKER);
}
pushElement(element, token) {
this._ensureNoahArkCondition(element);
this.entries.unshift({
type: EntryType.Element,
element,
token,
});
}
insertElementAfterBookmark(element, token) {
const bookmarkIdx = this.entries.indexOf(this.bookmark);
this.entries.splice(bookmarkIdx, 0, {
type: EntryType.Element,
element,
token,
});
}
removeEntry(entry) {
const entryIndex = this.entries.indexOf(entry);
if (entryIndex >= 0) {
this.entries.splice(entryIndex, 1);
}
}
/**
* Clears the list of formatting elements up to the last marker.
*
* @see https://html.spec.whatwg.org/multipage/parsing.html#clear-the-list-of-active-formatting-elements-up-to-the-last-marker
*/
clearToLastMarker() {
const markerIdx = this.entries.indexOf(MARKER);
if (markerIdx >= 0) {
this.entries.splice(0, markerIdx + 1);
}
else {
this.entries.length = 0;
}
}
//Search
getElementEntryInScopeWithTagName(tagName) {
const entry = this.entries.find((entry) => entry.type === EntryType.Marker || this.treeAdapter.getTagName(entry.element) === tagName);
return entry && entry.type === EntryType.Element ? entry : null;
}
getElementEntry(element) {
return this.entries.find((entry) => entry.type === EntryType.Element && entry.element === element);
}
}
exports.FormattingElementList = FormattingElementList;
});
var _default$2 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.defaultTreeAdapter = void 0;
function createTextNode(value) {
return {
nodeName: '#text',
value,
parentNode: null,
};
}
exports.defaultTreeAdapter = {
//Node construction
createDocument() {
return {
nodeName: '#document',
mode: html$1.DOCUMENT_MODE.NO_QUIRKS,
childNodes: [],
};
},
createDocumentFragment() {
return {
nodeName: '#document-fragment',
childNodes: [],
};
},
createElement(tagName, namespaceURI, attrs) {
return {
nodeName: tagName,
tagName,
attrs,
namespaceURI,
childNodes: [],
parentNode: null,
};
},
createCommentNode(data) {
return {
nodeName: '#comment',
data,
parentNode: null,
};
},
//Tree mutation
appendChild(parentNode, newNode) {
parentNode.childNodes.push(newNode);
newNode.parentNode = parentNode;
},
insertBefore(parentNode, newNode, referenceNode) {
const insertionIdx = parentNode.childNodes.indexOf(referenceNode);
parentNode.childNodes.splice(insertionIdx, 0, newNode);
newNode.parentNode = parentNode;
},
setTemplateContent(templateElement, contentElement) {
templateElement.content = contentElement;
},
getTemplateContent(templateElement) {
return templateElement.content;
},
setDocumentType(document, name, publicId, systemId) {
const doctypeNode = document.childNodes.find((node) => node.nodeName === '#documentType');
if (doctypeNode) {
doctypeNode.name = name;
doctypeNode.publicId = publicId;
doctypeNode.systemId = systemId;
}
else {
const node = {
nodeName: '#documentType',
name,
publicId,
systemId,
parentNode: null,
};
exports.defaultTreeAdapter.appendChild(document, node);
}
},
setDocumentMode(document, mode) {
document.mode = mode;
},
getDocumentMode(document) {
return document.mode;
},
detachNode(node) {
if (node.parentNode) {
const idx = node.parentNode.childNodes.indexOf(node);
node.parentNode.childNodes.splice(idx, 1);
node.parentNode = null;
}
},
insertText(parentNode, text) {
if (parentNode.childNodes.length > 0) {
const prevNode = parentNode.childNodes[parentNode.childNodes.length - 1];
if (exports.defaultTreeAdapter.isTextNode(prevNode)) {
prevNode.value += text;
return;
}
}
exports.defaultTreeAdapter.appendChild(parentNode, createTextNode(text));
},
insertTextBefore(parentNode, text, referenceNode) {
const prevNode = parentNode.childNodes[parentNode.childNodes.indexOf(referenceNode) - 1];
if (prevNode && exports.defaultTreeAdapter.isTextNode(prevNode)) {
prevNode.value += text;
}
else {
exports.defaultTreeAdapter.insertBefore(parentNode, createTextNode(text), referenceNode);
}
},
adoptAttributes(recipient, attrs) {
const recipientAttrsMap = new Set(recipient.attrs.map((attr) => attr.name));
for (let j = 0; j < attrs.length; j++) {
if (!recipientAttrsMap.has(attrs[j].name)) {
recipient.attrs.push(attrs[j]);
}
}
},
//Tree traversing
getFirstChild(node) {
return node.childNodes[0];
},
getChildNodes(node) {
return node.childNodes;
},
getParentNode(node) {
return node.parentNode;
},
getAttrList(element) {
return element.attrs;
},
//Node data
getTagName(element) {
return element.tagName;
},
getNamespaceURI(element) {
return element.namespaceURI;
},
getTextNodeContent(textNode) {
return textNode.value;
},
getCommentNodeContent(commentNode) {
return commentNode.data;
},
getDocumentTypeNodeName(doctypeNode) {
return doctypeNode.name;
},
getDocumentTypeNodePublicId(doctypeNode) {
return doctypeNode.publicId;
},
getDocumentTypeNodeSystemId(doctypeNode) {
return doctypeNode.systemId;
},
//Node types
isTextNode(node) {
return node.nodeName === '#text';
},
isCommentNode(node) {
return node.nodeName === '#comment';
},
isDocumentTypeNode(node) {
return node.nodeName === '#documentType';
},
isElementNode(node) {
return Object.prototype.hasOwnProperty.call(node, 'tagName');
},
// Source code location
setNodeSourceCodeLocation(node, location) {
node.sourceCodeLocation = location;
},
getNodeSourceCodeLocation(node) {
return node.sourceCodeLocation;
},
updateNodeSourceCodeLocation(node, endLocation) {
node.sourceCodeLocation = Object.assign(Object.assign({}, node.sourceCodeLocation), endLocation);
},
};
});
var doctype$1 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.getDocumentMode = exports.isConforming = void 0;
//Const
const VALID_DOCTYPE_NAME = 'html';
const VALID_SYSTEM_ID = 'about:legacy-compat';
const QUIRKS_MODE_SYSTEM_ID = 'http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd';
const QUIRKS_MODE_PUBLIC_ID_PREFIXES = [
'+//silmaril//dtd html pro v0r11 19970101//',
'-//as//dtd html 3.0 aswedit + extensions//',
'-//advasoft ltd//dtd html 3.0 aswedit + extensions//',
'-//ietf//dtd html 2.0 level 1//',
'-//ietf//dtd html 2.0 level 2//',
'-//ietf//dtd html 2.0 strict level 1//',
'-//ietf//dtd html 2.0 strict level 2//',
'-//ietf//dtd html 2.0 strict//',
'-//ietf//dtd html 2.0//',
'-//ietf//dtd html 2.1e//',
'-//ietf//dtd html 3.0//',
'-//ietf//dtd html 3.2 final//',
'-//ietf//dtd html 3.2//',
'-//ietf//dtd html 3//',
'-//ietf//dtd html level 0//',
'-//ietf//dtd html level 1//',
'-//ietf//dtd html level 2//',
'-//ietf//dtd html level 3//',
'-//ietf//dtd html strict level 0//',
'-//ietf//dtd html strict level 1//',
'-//ietf//dtd html strict level 2//',
'-//ietf//dtd html strict level 3//',
'-//ietf//dtd html strict//',
'-//ietf//dtd html//',
'-//metrius//dtd metrius presentational//',
'-//microsoft//dtd internet explorer 2.0 html strict//',
'-//microsoft//dtd internet explorer 2.0 html//',
'-//microsoft//dtd internet explorer 2.0 tables//',
'-//microsoft//dtd internet explorer 3.0 html strict//',
'-//microsoft//dtd internet explorer 3.0 html//',
'-//microsoft//dtd internet explorer 3.0 tables//',
'-//netscape comm. corp.//dtd html//',
'-//netscape comm. corp.//dtd strict html//',
"-//o'reilly and associates//dtd html 2.0//",
"-//o'reilly and associates//dtd html extended 1.0//",
"-//o'reilly and associates//dtd html extended relaxed 1.0//",
'-//sq//dtd html 2.0 hotmetal + extensions//',
'-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//',
'-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//',
'-//spyglass//dtd html 2.0 extended//',
'-//sun microsystems corp.//dtd hotjava html//',
'-//sun microsystems corp.//dtd hotjava strict html//',
'-//w3c//dtd html 3 1995-03-24//',
'-//w3c//dtd html 3.2 draft//',
'-//w3c//dtd html 3.2 final//',
'-//w3c//dtd html 3.2//',
'-//w3c//dtd html 3.2s draft//',
'-//w3c//dtd html 4.0 frameset//',
'-//w3c//dtd html 4.0 transitional//',
'-//w3c//dtd html experimental 19960712//',
'-//w3c//dtd html experimental 970421//',
'-//w3c//dtd w3 html//',
'-//w3o//dtd w3 html 3.0//',
'-//webtechs//dtd mozilla html 2.0//',
'-//webtechs//dtd mozilla html//',
];
const QUIRKS_MODE_NO_SYSTEM_ID_PUBLIC_ID_PREFIXES = [
...QUIRKS_MODE_PUBLIC_ID_PREFIXES,
'-//w3c//dtd html 4.01 frameset//',
'-//w3c//dtd html 4.01 transitional//',
];
const QUIRKS_MODE_PUBLIC_IDS = new Set([
'-//w3o//dtd w3 html strict 3.0//en//',
'-/w3c/dtd html 4.0 transitional/en',
'html',
]);
const LIMITED_QUIRKS_PUBLIC_ID_PREFIXES = ['-//w3c//dtd xhtml 1.0 frameset//', '-//w3c//dtd xhtml 1.0 transitional//'];
const LIMITED_QUIRKS_WITH_SYSTEM_ID_PUBLIC_ID_PREFIXES = [
...LIMITED_QUIRKS_PUBLIC_ID_PREFIXES,
'-//w3c//dtd html 4.01 frameset//',
'-//w3c//dtd html 4.01 transitional//',
];
//Utils
function hasPrefix(publicId, prefixes) {
return prefixes.some((prefix) => publicId.startsWith(prefix));
}
//API
function isConforming(token) {
return (token.name === VALID_DOCTYPE_NAME &&
token.publicId === null &&
(token.systemId === null || token.systemId === VALID_SYSTEM_ID));
}
exports.isConforming = isConforming;
function getDocumentMode(token) {
if (token.name !== VALID_DOCTYPE_NAME) {
return html$1.DOCUMENT_MODE.QUIRKS;
}
const { systemId } = token;
if (systemId && systemId.toLowerCase() === QUIRKS_MODE_SYSTEM_ID) {
return html$1.DOCUMENT_MODE.QUIRKS;
}
let { publicId } = token;
if (publicId !== null) {
publicId = publicId.toLowerCase();
if (QUIRKS_MODE_PUBLIC_IDS.has(publicId)) {
return html$1.DOCUMENT_MODE.QUIRKS;
}
let prefixes = systemId === null ? QUIRKS_MODE_NO_SYSTEM_ID_PUBLIC_ID_PREFIXES : QUIRKS_MODE_PUBLIC_ID_PREFIXES;
if (hasPrefix(publicId, prefixes)) {
return html$1.DOCUMENT_MODE.QUIRKS;
}
prefixes =
systemId === null ? LIMITED_QUIRKS_PUBLIC_ID_PREFIXES : LIMITED_QUIRKS_WITH_SYSTEM_ID_PUBLIC_ID_PREFIXES;
if (hasPrefix(publicId, prefixes)) {
return html$1.DOCUMENT_MODE.LIMITED_QUIRKS;
}
}
return html$1.DOCUMENT_MODE.NO_QUIRKS;
}
exports.getDocumentMode = getDocumentMode;
});
var foreignContent$1 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.isIntegrationPoint = exports.adjustTokenSVGTagName = exports.adjustTokenXMLAttrs = exports.adjustTokenSVGAttrs = exports.adjustTokenMathMLAttrs = exports.causesExit = exports.SVG_TAG_NAMES_ADJUSTMENT_MAP = void 0;
//MIME types
const MIME_TYPES = {
TEXT_HTML: 'text/html',
APPLICATION_XML: 'application/xhtml+xml',
};
//Attributes
const DEFINITION_URL_ATTR = 'definitionurl';
const ADJUSTED_DEFINITION_URL_ATTR = 'definitionURL';
const SVG_ATTRS_ADJUSTMENT_MAP = new Map([
'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((attr) => [attr.toLowerCase(), attr]));
const XML_ATTRS_ADJUSTMENT_MAP = new Map([
['xlink:actuate', { prefix: 'xlink', name: 'actuate', namespace: html$1.NS.XLINK }],
['xlink:arcrole', { prefix: 'xlink', name: 'arcrole', namespace: html$1.NS.XLINK }],
['xlink:href', { prefix: 'xlink', name: 'href', namespace: html$1.NS.XLINK }],
['xlink:role', { prefix: 'xlink', name: 'role', namespace: html$1.NS.XLINK }],
['xlink:show', { prefix: 'xlink', name: 'show', namespace: html$1.NS.XLINK }],
['xlink:title', { prefix: 'xlink', name: 'title', namespace: html$1.NS.XLINK }],
['xlink:type', { prefix: 'xlink', name: 'type', namespace: html$1.NS.XLINK }],
['xml:base', { prefix: 'xml', name: 'base', namespace: html$1.NS.XML }],
['xml:lang', { prefix: 'xml', name: 'lang', namespace: html$1.NS.XML }],
['xml:space', { prefix: 'xml', name: 'space', namespace: html$1.NS.XML }],
['xmlns', { prefix: '', name: 'xmlns', namespace: html$1.NS.XMLNS }],
['xmlns:xlink', { prefix: 'xmlns', name: 'xlink', namespace: html$1.NS.XMLNS }],
]);
//SVG tag names adjustment map
exports.SVG_TAG_NAMES_ADJUSTMENT_MAP = new Map([
'altGlyph',
'altGlyphDef',
'altGlyphItem',
'animateColor',
'animateMotion',
'animateTransform',
'clipPath',
'feBlend',
'feColorMatrix',
'feComponentTransfer',
'feComposite',
'feConvolveMatrix',
'feDiffuseLighting',
'feDisplacementMap',
'feDistantLight',
'feFlood',
'feFuncA',
'feFuncB',
'feFuncG',
'feFuncR',
'feGaussianBlur',
'feImage',
'feMerge',
'feMergeNode',
'feMorphology',
'feOffset',
'fePointLight',
'feSpecularLighting',
'feSpotLight',
'feTile',
'feTurbulence',
'foreignObject',
'glyphRef',
'linearGradient',
'radialGradient',
'textPath',
].map((tn) => [tn.toLowerCase(), tn]));
//Tags that causes exit from foreign content
const EXITS_FOREIGN_CONTENT = new Set([
html$1.TAG_ID.B,
html$1.TAG_ID.BIG,
html$1.TAG_ID.BLOCKQUOTE,
html$1.TAG_ID.BODY,
html$1.TAG_ID.BR,
html$1.TAG_ID.CENTER,
html$1.TAG_ID.CODE,
html$1.TAG_ID.DD,
html$1.TAG_ID.DIV,
html$1.TAG_ID.DL,
html$1.TAG_ID.DT,
html$1.TAG_ID.EM,
html$1.TAG_ID.EMBED,
html$1.TAG_ID.H1,
html$1.TAG_ID.H2,
html$1.TAG_ID.H3,
html$1.TAG_ID.H4,
html$1.TAG_ID.H5,
html$1.TAG_ID.H6,
html$1.TAG_ID.HEAD,
html$1.TAG_ID.HR,
html$1.TAG_ID.I,
html$1.TAG_ID.IMG,
html$1.TAG_ID.LI,
html$1.TAG_ID.LISTING,
html$1.TAG_ID.MENU,
html$1.TAG_ID.META,
html$1.TAG_ID.NOBR,
html$1.TAG_ID.OL,
html$1.TAG_ID.P,
html$1.TAG_ID.PRE,
html$1.TAG_ID.RUBY,
html$1.TAG_ID.S,
html$1.TAG_ID.SMALL,
html$1.TAG_ID.SPAN,
html$1.TAG_ID.STRONG,
html$1.TAG_ID.STRIKE,
html$1.TAG_ID.SUB,
html$1.TAG_ID.SUP,
html$1.TAG_ID.TABLE,
html$1.TAG_ID.TT,
html$1.TAG_ID.U,
html$1.TAG_ID.UL,
html$1.TAG_ID.VAR,
]);
//Check exit from foreign content
function causesExit(startTagToken) {
const tn = startTagToken.tagID;
const isFontWithAttrs = tn === html$1.TAG_ID.FONT &&
startTagToken.attrs.some(({ name }) => name === html$1.ATTRS.COLOR || name === html$1.ATTRS.SIZE || name === html$1.ATTRS.FACE);
return isFontWithAttrs || EXITS_FOREIGN_CONTENT.has(tn);
}
exports.causesExit = causesExit;
//Token adjustments
function adjustTokenMathMLAttrs(token) {
for (let i = 0; i < token.attrs.length; i++) {
if (token.attrs[i].name === DEFINITION_URL_ATTR) {
token.attrs[i].name = ADJUSTED_DEFINITION_URL_ATTR;
break;
}
}
}
exports.adjustTokenMathMLAttrs = adjustTokenMathMLAttrs;
function adjustTokenSVGAttrs(token) {
for (let i = 0; i < token.attrs.length; i++) {
const adjustedAttrName = SVG_ATTRS_ADJUSTMENT_MAP.get(token.attrs[i].name);
if (adjustedAttrName != null) {
token.attrs[i].name = adjustedAttrName;
}
}
}
exports.adjustTokenSVGAttrs = adjustTokenSVGAttrs;
function adjustTokenXMLAttrs(token) {
for (let i = 0; i < token.attrs.length; i++) {
const adjustedAttrEntry = XML_ATTRS_ADJUSTMENT_MAP.get(token.attrs[i].name);
if (adjustedAttrEntry) {
token.attrs[i].prefix = adjustedAttrEntry.prefix;
token.attrs[i].name = adjustedAttrEntry.name;
token.attrs[i].namespace = adjustedAttrEntry.namespace;
}
}
}
exports.adjustTokenXMLAttrs = adjustTokenXMLAttrs;
function adjustTokenSVGTagName(token) {
const adjustedTagName = exports.SVG_TAG_NAMES_ADJUSTMENT_MAP.get(token.tagName);
if (adjustedTagName != null) {
token.tagName = adjustedTagName;
token.tagID = (0, html$1.getTagID)(token.tagName);
}
}
exports.adjustTokenSVGTagName = adjustTokenSVGTagName;
//Integration points
function isMathMLTextIntegrationPoint(tn, ns) {
return ns === html$1.NS.MATHML && (tn === html$1.TAG_ID.MI || tn === html$1.TAG_ID.MO || tn === html$1.TAG_ID.MN || tn === html$1.TAG_ID.MS || tn === html$1.TAG_ID.MTEXT);
}
function isHtmlIntegrationPoint(tn, ns, attrs) {
if (ns === html$1.NS.MATHML && tn === html$1.TAG_ID.ANNOTATION_XML) {
for (let i = 0; i < attrs.length; i++) {
if (attrs[i].name === html$1.ATTRS.ENCODING) {
const value = attrs[i].value.toLowerCase();
return value === MIME_TYPES.TEXT_HTML || value === MIME_TYPES.APPLICATION_XML;
}
}
}
return ns === html$1.NS.SVG && (tn === html$1.TAG_ID.FOREIGN_OBJECT || tn === html$1.TAG_ID.DESC || tn === html$1.TAG_ID.TITLE);
}
function isIntegrationPoint(tn, ns, attrs, foreignNS) {
return (((!foreignNS || foreignNS === html$1.NS.HTML) && isHtmlIntegrationPoint(tn, ns, attrs)) ||
((!foreignNS || foreignNS === html$1.NS.MATHML) && isMathMLTextIntegrationPoint(tn, ns)));
}
exports.isIntegrationPoint = isIntegrationPoint;
});
var parser$1 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.Parser = void 0;
//Misc constants
const HIDDEN_INPUT_TYPE = 'hidden';
//Adoption agency loops iteration count
const AA_OUTER_LOOP_ITER = 8;
const AA_INNER_LOOP_ITER = 3;
//Insertion modes
var InsertionMode;
(function (InsertionMode) {
InsertionMode[InsertionMode["INITIAL"] = 0] = "INITIAL";
InsertionMode[InsertionMode["BEFORE_HTML"] = 1] = "BEFORE_HTML";
InsertionMode[InsertionMode["BEFORE_HEAD"] = 2] = "BEFORE_HEAD";
InsertionMode[InsertionMode["IN_HEAD"] = 3] = "IN_HEAD";
InsertionMode[InsertionMode["IN_HEAD_NO_SCRIPT"] = 4] = "IN_HEAD_NO_SCRIPT";
InsertionMode[InsertionMode["AFTER_HEAD"] = 5] = "AFTER_HEAD";
InsertionMode[InsertionMode["IN_BODY"] = 6] = "IN_BODY";
InsertionMode[InsertionMode["TEXT"] = 7] = "TEXT";
InsertionMode[InsertionMode["IN_TABLE"] = 8] = "IN_TABLE";
InsertionMode[InsertionMode["IN_TABLE_TEXT"] = 9] = "IN_TABLE_TEXT";
InsertionMode[InsertionMode["IN_CAPTION"] = 10] = "IN_CAPTION";
InsertionMode[InsertionMode["IN_COLUMN_GROUP"] = 11] = "IN_COLUMN_GROUP";
InsertionMode[InsertionMode["IN_TABLE_BODY"] = 12] = "IN_TABLE_BODY";
InsertionMode[InsertionMode["IN_ROW"] = 13] = "IN_ROW";
InsertionMode[InsertionMode["IN_CELL"] = 14] = "IN_CELL";
InsertionMode[InsertionMode["IN_SELECT"] = 15] = "IN_SELECT";
InsertionMode[InsertionMode["IN_SELECT_IN_TABLE"] = 16] = "IN_SELECT_IN_TABLE";
InsertionMode[InsertionMode["IN_TEMPLATE"] = 17] = "IN_TEMPLATE";
InsertionMode[InsertionMode["AFTER_BODY"] = 18] = "AFTER_BODY";
InsertionMode[InsertionMode["IN_FRAMESET"] = 19] = "IN_FRAMESET";
InsertionMode[InsertionMode["AFTER_FRAMESET"] = 20] = "AFTER_FRAMESET";
InsertionMode[InsertionMode["AFTER_AFTER_BODY"] = 21] = "AFTER_AFTER_BODY";
InsertionMode[InsertionMode["AFTER_AFTER_FRAMESET"] = 22] = "AFTER_AFTER_FRAMESET";
})(InsertionMode || (InsertionMode = {}));
const BASE_LOC = {
startLine: -1,
startCol: -1,
startOffset: -1,
endLine: -1,
endCol: -1,
endOffset: -1,
};
const TABLE_STRUCTURE_TAGS = new Set([html$1.TAG_ID.TABLE, html$1.TAG_ID.TBODY, html$1.TAG_ID.TFOOT, html$1.TAG_ID.THEAD, html$1.TAG_ID.TR]);
const defaultParserOptions = {
scriptingEnabled: true,
sourceCodeLocationInfo: false,
treeAdapter: _default$2.defaultTreeAdapter,
onParseError: null,
};
//Parser
class Parser {
constructor(options, document, fragmentContext = null, scriptHandler = null) {
this.fragmentContext = fragmentContext;
this.scriptHandler = scriptHandler;
this.currentToken = null;
this.stopped = false;
this.insertionMode = InsertionMode.INITIAL;
this.originalInsertionMode = InsertionMode.INITIAL;
this.headElement = null;
this.formElement = null;
/** Indicates that the current node is not an element in the HTML namespace */
this.currentNotInHTML = false;
/**
* The template insertion mode stack is maintained from the left.
* Ie. the topmost element will always have index 0.
*/
this.tmplInsertionModeStack = [];
this.pendingCharacterTokens = [];
this.hasNonWhitespacePendingCharacterToken = false;
this.framesetOk = true;
this.skipNextNewLine = false;
this.fosterParentingEnabled = false;
this.options = Object.assign(Object.assign({}, defaultParserOptions), options);
this.treeAdapter = this.options.treeAdapter;
this.onParseError = this.options.onParseError;
// Always enable location info if we report parse errors.
if (this.onParseError) {
this.options.sourceCodeLocationInfo = true;
}
this.document = document !== null && document !== void 0 ? document : this.treeAdapter.createDocument();
this.tokenizer = new tokenizer$1.Tokenizer(this.options, this);
this.activeFormattingElements = new formattingElementList$1.FormattingElementList(this.treeAdapter);
this.fragmentContextID = fragmentContext ? (0, html$1.getTagID)(this.treeAdapter.getTagName(fragmentContext)) : html$1.TAG_ID.UNKNOWN;
this._setContextModes(fragmentContext !== null && fragmentContext !== void 0 ? fragmentContext : this.document, this.fragmentContextID);
this.openElements = new openElementStack$1.OpenElementStack(this.document, this.treeAdapter, this);
}
// API
static parse(html, options) {
const parser = new this(options);
parser.tokenizer.write(html, true);
return parser.document;
}
static getFragmentParser(fragmentContext, options) {
const opts = Object.assign(Object.assign({}, defaultParserOptions), options);
//NOTE: use a <template> element as the fragment context if no context element was provided,
//so we will parse in a "forgiving" manner
fragmentContext !== null && fragmentContext !== void 0 ? fragmentContext : (fragmentContext = opts.treeAdapter.createElement(html$1.TAG_NAMES.TEMPLATE, html$1.NS.HTML, []));
//NOTE: create a fake element which will be used as the `document` for fragment parsing.
//This is important for jsdom, where a new `document` cannot be created. This led to
//fragment parsing messing with the main `document`.
const documentMock = opts.treeAdapter.createElement('documentmock', html$1.NS.HTML, []);
const parser = new this(opts, documentMock, fragmentContext);
if (parser.fragmentContextID === html$1.TAG_ID.TEMPLATE) {
parser.tmplInsertionModeStack.unshift(InsertionMode.IN_TEMPLATE);
}
parser._initTokenizerForFragmentParsing();
parser._insertFakeRootElement();
parser._resetInsertionMode();
parser._findFormInFragmentContext();
return parser;
}
getFragment() {
const rootElement = this.treeAdapter.getFirstChild(this.document);
const fragment = this.treeAdapter.createDocumentFragment();
this._adoptNodes(rootElement, fragment);
return fragment;
}
//Errors
_err(token, code, beforeToken) {
var _a;
if (!this.onParseError)
return;
const loc = (_a = token.location) !== null && _a !== void 0 ? _a : BASE_LOC;
const err = {
code,
startLine: loc.startLine,
startCol: loc.startCol,
startOffset: loc.startOffset,
endLine: beforeToken ? loc.startLine : loc.endLine,
endCol: beforeToken ? loc.startCol : loc.endCol,
endOffset: beforeToken ? loc.startOffset : loc.endOffset,
};
this.onParseError(err);
}
//Stack events
onItemPush(node, tid, isTop) {
var _a, _b;
(_b = (_a = this.treeAdapter).onItemPush) === null || _b === void 0 ? void 0 : _b.call(_a, node);
if (isTop && this.openElements.stackTop > 0)
this._setContextModes(node, tid);
}
onItemPop(node, isTop) {
var _a, _b;
if (this.options.sourceCodeLocationInfo) {
this._setEndLocation(node, this.currentToken);
}
(_b = (_a = this.treeAdapter).onItemPop) === null || _b === void 0 ? void 0 : _b.call(_a, node, this.openElements.current);
if (isTop) {
let current;
let currentTagId;
if (this.openElements.stackTop === 0 && this.fragmentContext) {
current = this.fragmentContext;
currentTagId = this.fragmentContextID;
}
else {
({ current, currentTagId } = this.openElements);
}
this._setContextModes(current, currentTagId);
}
}
_setContextModes(current, tid) {
const isHTML = current === this.document || this.treeAdapter.getNamespaceURI(current) === html$1.NS.HTML;
this.currentNotInHTML = !isHTML;
this.tokenizer.inForeignNode = !isHTML && !this._isIntegrationPoint(tid, current);
}
_switchToTextParsing(currentToken, nextTokenizerState) {
this._insertElement(currentToken, html$1.NS.HTML);
this.tokenizer.state = nextTokenizerState;
this.originalInsertionMode = this.insertionMode;
this.insertionMode = InsertionMode.TEXT;
}
switchToPlaintextParsing() {
this.insertionMode = InsertionMode.TEXT;
this.originalInsertionMode = InsertionMode.IN_BODY;
this.tokenizer.state = tokenizer$1.TokenizerMode.PLAINTEXT;
}
//Fragment parsing
_getAdjustedCurrentElement() {
return this.openElements.stackTop === 0 && this.fragmentContext
? this.fragmentContext
: this.openElements.current;
}
_findFormInFragmentContext() {
let node = this.fragmentContext;
while (node) {
if (this.treeAdapter.getTagName(node) === html$1.TAG_NAMES.FORM) {
this.formElement = node;
break;
}
node = this.treeAdapter.getParentNode(node);
}
}
_initTokenizerForFragmentParsing() {
if (!this.fragmentContext || this.treeAdapter.getNamespaceURI(this.fragmentContext) !== html$1.NS.HTML) {
return;
}
switch (this.fragmentContextID) {
case html$1.TAG_ID.TITLE:
case html$1.TAG_ID.TEXTAREA: {
this.tokenizer.state = tokenizer$1.TokenizerMode.RCDATA;
break;
}
case html$1.TAG_ID.STYLE:
case html$1.TAG_ID.XMP:
case html$1.TAG_ID.IFRAME:
case html$1.TAG_ID.NOEMBED:
case html$1.TAG_ID.NOFRAMES:
case html$1.TAG_ID.NOSCRIPT: {
this.tokenizer.state = tokenizer$1.TokenizerMode.RAWTEXT;
break;
}
case html$1.TAG_ID.SCRIPT: {
this.tokenizer.state = tokenizer$1.TokenizerMode.SCRIPT_DATA;
break;
}
case html$1.TAG_ID.PLAINTEXT: {
this.tokenizer.state = tokenizer$1.TokenizerMode.PLAINTEXT;
break;
}
// Do nothing
}
}
//Tree mutation
_setDocumentType(token) {
const name = token.name || '';
const publicId = token.publicId || '';
const systemId = token.systemId || '';
this.treeAdapter.setDocumentType(this.document, name, publicId, systemId);
if (token.location) {
const documentChildren = this.treeAdapter.getChildNodes(this.document);
const docTypeNode = documentChildren.find((node) => this.treeAdapter.isDocumentTypeNode(node));
if (docTypeNode) {
this.treeAdapter.setNodeSourceCodeLocation(docTypeNode, token.location);
}
}
}
_attachElementToTree(element, location) {
if (this.options.sourceCodeLocationInfo) {
const loc = location && Object.assign(Object.assign({}, location), { startTag: location });
this.treeAdapter.setNodeSourceCodeLocation(element, loc);
}
if (this._shouldFosterParentOnInsertion()) {
this._fosterParentElement(element);
}
else {
const parent = this.openElements.currentTmplContentOrNode;
this.treeAdapter.appendChild(parent, element);
}
}
_appendElement(token, namespaceURI) {
const element = this.treeAdapter.createElement(token.tagName, namespaceURI, token.attrs);
this._attachElementToTree(element, token.location);
}
_insertElement(token, namespaceURI) {
const element = this.treeAdapter.createElement(token.tagName, namespaceURI, token.attrs);
this._attachElementToTree(element, token.location);
this.openElements.push(element, token.tagID);
}
_insertFakeElement(tagName, tagID) {
const element = this.treeAdapter.createElement(tagName, html$1.NS.HTML, []);
this._attachElementToTree(element, null);
this.openElements.push(element, tagID);
}
_insertTemplate(token) {
const tmpl = this.treeAdapter.createElement(token.tagName, html$1.NS.HTML, token.attrs);
const content = this.treeAdapter.createDocumentFragment();
this.treeAdapter.setTemplateContent(tmpl, content);
this._attachElementToTree(tmpl, token.location);
this.openElements.push(tmpl, token.tagID);
if (this.options.sourceCodeLocationInfo)
this.treeAdapter.setNodeSourceCodeLocation(content, null);
}
_insertFakeRootElement() {
const element = this.treeAdapter.createElement(html$1.TAG_NAMES.HTML, html$1.NS.HTML, []);
if (this.options.sourceCodeLocationInfo)
this.treeAdapter.setNodeSourceCodeLocation(element, null);
this.treeAdapter.appendChild(this.openElements.current, element);
this.openElements.push(element, html$1.TAG_ID.HTML);
}
_appendCommentNode(token, parent) {
const commentNode = this.treeAdapter.createCommentNode(token.data);
this.treeAdapter.appendChild(parent, commentNode);
if (this.options.sourceCodeLocationInfo) {
this.treeAdapter.setNodeSourceCodeLocation(commentNode, token.location);
}
}
_insertCharacters(token) {
let parent;
let beforeElement;
if (this._shouldFosterParentOnInsertion()) {
({ parent, beforeElement } = this._findFosterParentingLocation());
if (beforeElement) {
this.treeAdapter.insertTextBefore(parent, token.chars, beforeElement);
}
else {
this.treeAdapter.insertText(parent, token.chars);
}
}
else {
parent = this.openElements.currentTmplContentOrNode;
this.treeAdapter.insertText(parent, token.chars);
}
if (!token.location)
return;
const siblings = this.treeAdapter.getChildNodes(parent);
const textNodeIdx = beforeElement ? siblings.lastIndexOf(beforeElement) : siblings.length;
const textNode = siblings[textNodeIdx - 1];
//NOTE: if we have a location assigned by another token, then just update the end position
const tnLoc = this.treeAdapter.getNodeSourceCodeLocation(textNode);
if (tnLoc) {
const { endLine, endCol, endOffset } = token.location;
this.treeAdapter.updateNodeSourceCodeLocation(textNode, { endLine, endCol, endOffset });
}
else if (this.options.sourceCodeLocationInfo) {
this.treeAdapter.setNodeSourceCodeLocation(textNode, token.location);
}
}
_adoptNodes(donor, recipient) {
for (let child = this.treeAdapter.getFirstChild(donor); child; child = this.treeAdapter.getFirstChild(donor)) {
this.treeAdapter.detachNode(child);
this.treeAdapter.appendChild(recipient, child);
}
}
_setEndLocation(element, closingToken) {
if (this.treeAdapter.getNodeSourceCodeLocation(element) && closingToken.location) {
const ctLoc = closingToken.location;
const tn = this.treeAdapter.getTagName(element);
const endLoc =
// NOTE: For cases like <p> <p> </p> - First 'p' closes without a closing
// tag and for cases like <td> <p> </td> - 'p' closes without a closing tag.
closingToken.type === token$1.TokenType.END_TAG && tn === closingToken.tagName
? {
endTag: Object.assign({}, ctLoc),
endLine: ctLoc.endLine,
endCol: ctLoc.endCol,
endOffset: ctLoc.endOffset,
}
: {
endLine: ctLoc.startLine,
endCol: ctLoc.startCol,
endOffset: ctLoc.startOffset,
};
this.treeAdapter.updateNodeSourceCodeLocation(element, endLoc);
}
}
//Token processing
shouldProcessStartTagTokenInForeignContent(token) {
// Check that neither current === document, or ns === NS.HTML
if (!this.currentNotInHTML)
return false;
let current;
let currentTagId;
if (this.openElements.stackTop === 0 && this.fragmentContext) {
current = this.fragmentContext;
currentTagId = this.fragmentContextID;
}
else {
({ current, currentTagId } = this.openElements);
}
if (token.tagID === html$1.TAG_ID.SVG &&
this.treeAdapter.getTagName(current) === html$1.TAG_NAMES.ANNOTATION_XML &&
this.treeAdapter.getNamespaceURI(current) === html$1.NS.MATHML) {
return false;
}
return (
// Check that `current` is not an integration point for HTML or MathML elements.
this.tokenizer.inForeignNode ||
// If it _is_ an integration point, then we might have to check that it is not an HTML
// integration point.
((token.tagID === html$1.TAG_ID.MGLYPH || token.tagID === html$1.TAG_ID.MALIGNMARK) &&
!this._isIntegrationPoint(currentTagId, current, html$1.NS.HTML)));
}
_processToken(token) {
switch (token.type) {
case token$1.TokenType.CHARACTER: {
this.onCharacter(token);
break;
}
case token$1.TokenType.NULL_CHARACTER: {
this.onNullCharacter(token);
break;
}
case token$1.TokenType.COMMENT: {
this.onComment(token);
break;
}
case token$1.TokenType.DOCTYPE: {
this.onDoctype(token);
break;
}
case token$1.TokenType.START_TAG: {
this._processStartTag(token);
break;
}
case token$1.TokenType.END_TAG: {
this.onEndTag(token);
break;
}
case token$1.TokenType.EOF: {
this.onEof(token);
break;
}
case token$1.TokenType.WHITESPACE_CHARACTER: {
this.onWhitespaceCharacter(token);
break;
}
}
}
//Integration points
_isIntegrationPoint(tid, element, foreignNS) {
const ns = this.treeAdapter.getNamespaceURI(element);
const attrs = this.treeAdapter.getAttrList(element);
return foreignContent$1.isIntegrationPoint(tid, ns, attrs, foreignNS);
}
//Active formatting elements reconstruction
_reconstructActiveFormattingElements() {
const listLength = this.activeFormattingElements.entries.length;
if (listLength) {
const endIndex = this.activeFormattingElements.entries.findIndex((entry) => entry.type === formattingElementList$1.EntryType.Marker || this.openElements.contains(entry.element));
const unopenIdx = endIndex < 0 ? listLength - 1 : endIndex - 1;
for (let i = unopenIdx; i >= 0; i--) {
const entry = this.activeFormattingElements.entries[i];
this._insertElement(entry.token, this.treeAdapter.getNamespaceURI(entry.element));
entry.element = this.openElements.current;
}
}
}
//Close elements
_closeTableCell() {
this.openElements.generateImpliedEndTags();
this.openElements.popUntilTableCellPopped();
this.activeFormattingElements.clearToLastMarker();
this.insertionMode = InsertionMode.IN_ROW;
}
_closePElement() {
this.openElements.generateImpliedEndTagsWithExclusion(html$1.TAG_ID.P);
this.openElements.popUntilTagNamePopped(html$1.TAG_ID.P);
}
//Insertion modes
_resetInsertionMode() {
for (let i = this.openElements.stackTop; i >= 0; i--) {
//Insertion mode reset map
switch (i === 0 && this.fragmentContext ? this.fragmentContextID : this.openElements.tagIDs[i]) {
case html$1.TAG_ID.TR: {
this.insertionMode = InsertionMode.IN_ROW;
return;
}
case html$1.TAG_ID.TBODY:
case html$1.TAG_ID.THEAD:
case html$1.TAG_ID.TFOOT: {
this.insertionMode = InsertionMode.IN_TABLE_BODY;
return;
}
case html$1.TAG_ID.CAPTION: {
this.insertionMode = InsertionMode.IN_CAPTION;
return;
}
case html$1.TAG_ID.COLGROUP: {
this.insertionMode = InsertionMode.IN_COLUMN_GROUP;
return;
}
case html$1.TAG_ID.TABLE: {
this.insertionMode = InsertionMode.IN_TABLE;
return;
}
case html$1.TAG_ID.BODY: {
this.insertionMode = InsertionMode.IN_BODY;
return;
}
case html$1.TAG_ID.FRAMESET: {
this.insertionMode = InsertionMode.IN_FRAMESET;
return;
}
case html$1.TAG_ID.SELECT: {
this._resetInsertionModeForSelect(i);
return;
}
case html$1.TAG_ID.TEMPLATE: {
this.insertionMode = this.tmplInsertionModeStack[0];
return;
}
case html$1.TAG_ID.HTML: {
this.insertionMode = this.headElement ? InsertionMode.AFTER_HEAD : InsertionMode.BEFORE_HEAD;
return;
}
case html$1.TAG_ID.TD:
case html$1.TAG_ID.TH: {
if (i > 0) {
this.insertionMode = InsertionMode.IN_CELL;
return;
}
break;
}
case html$1.TAG_ID.HEAD: {
if (i > 0) {
this.insertionMode = InsertionMode.IN_HEAD;
return;
}
break;
}
}
}
this.insertionMode = InsertionMode.IN_BODY;
}
_resetInsertionModeForSelect(selectIdx) {
if (selectIdx > 0) {
for (let i = selectIdx - 1; i > 0; i--) {
const tn = this.openElements.tagIDs[i];
if (tn === html$1.TAG_ID.TEMPLATE) {
break;
}
else if (tn === html$1.TAG_ID.TABLE) {
this.insertionMode = InsertionMode.IN_SELECT_IN_TABLE;
return;
}
}
}
this.insertionMode = InsertionMode.IN_SELECT;
}
//Foster parenting
_isElementCausesFosterParenting(tn) {
return TABLE_STRUCTURE_TAGS.has(tn);
}
_shouldFosterParentOnInsertion() {
return this.fosterParentingEnabled && this._isElementCausesFosterParenting(this.openElements.currentTagId);
}
_findFosterParentingLocation() {
for (let i = this.openElements.stackTop; i >= 0; i--) {
const openElement = this.openElements.items[i];
switch (this.openElements.tagIDs[i]) {
case html$1.TAG_ID.TEMPLATE: {
if (this.treeAdapter.getNamespaceURI(openElement) === html$1.NS.HTML) {
return { parent: this.treeAdapter.getTemplateContent(openElement), beforeElement: null };
}
break;
}
case html$1.TAG_ID.TABLE: {
const parent = this.treeAdapter.getParentNode(openElement);
if (parent) {
return { parent, beforeElement: openElement };
}
return { parent: this.openElements.items[i - 1], beforeElement: null };
}
// Do nothing
}
}
return { parent: this.openElements.items[0], beforeElement: null };
}
_fosterParentElement(element) {
const location = this._findFosterParentingLocation();
if (location.beforeElement) {
this.treeAdapter.insertBefore(location.parent, element, location.beforeElement);
}
else {
this.treeAdapter.appendChild(location.parent, element);
}
}
//Special elements
_isSpecialElement(element, id) {
const ns = this.treeAdapter.getNamespaceURI(element);
return html$1.SPECIAL_ELEMENTS[ns].has(id);
}
onCharacter(token) {
this.skipNextNewLine = false;
if (this.tokenizer.inForeignNode) {
characterInForeignContent(this, token);
return;
}
switch (this.insertionMode) {
case InsertionMode.INITIAL: {
tokenInInitialMode(this, token);
break;
}
case InsertionMode.BEFORE_HTML: {
tokenBeforeHtml(this, token);
break;
}
case InsertionMode.BEFORE_HEAD: {
tokenBeforeHead(this, token);
break;
}
case InsertionMode.IN_HEAD: {
tokenInHead(this, token);
break;
}
case InsertionMode.IN_HEAD_NO_SCRIPT: {
tokenInHeadNoScript(this, token);
break;
}
case InsertionMode.AFTER_HEAD: {
tokenAfterHead(this, token);
break;
}
case InsertionMode.IN_BODY:
case InsertionMode.IN_CAPTION:
case InsertionMode.IN_CELL:
case InsertionMode.IN_TEMPLATE: {
characterInBody(this, token);
break;
}
case InsertionMode.TEXT:
case InsertionMode.IN_SELECT:
case InsertionMode.IN_SELECT_IN_TABLE: {
this._insertCharacters(token);
break;
}
case InsertionMode.IN_TABLE:
case InsertionMode.IN_TABLE_BODY:
case InsertionMode.IN_ROW: {
characterInTable(this, token);
break;
}
case InsertionMode.IN_TABLE_TEXT: {
characterInTableText(this, token);
break;
}
case InsertionMode.IN_COLUMN_GROUP: {
tokenInColumnGroup(this, token);
break;
}
case InsertionMode.AFTER_BODY: {
tokenAfterBody(this, token);
break;
}
case InsertionMode.AFTER_AFTER_BODY: {
tokenAfterAfterBody(this, token);
break;
}
// Do nothing
}
}
onNullCharacter(token) {
this.skipNextNewLine = false;
if (this.tokenizer.inForeignNode) {
nullCharacterInForeignContent(this, token);
return;
}
switch (this.insertionMode) {
case InsertionMode.INITIAL: {
tokenInInitialMode(this, token);
break;
}
case InsertionMode.BEFORE_HTML: {
tokenBeforeHtml(this, token);
break;
}
case InsertionMode.BEFORE_HEAD: {
tokenBeforeHead(this, token);
break;
}
case InsertionMode.IN_HEAD: {
tokenInHead(this, token);
break;
}
case InsertionMode.IN_HEAD_NO_SCRIPT: {
tokenInHeadNoScript(this, token);
break;
}
case InsertionMode.AFTER_HEAD: {
tokenAfterHead(this, token);
break;
}
case InsertionMode.TEXT: {
this._insertCharacters(token);
break;
}
case InsertionMode.IN_TABLE:
case InsertionMode.IN_TABLE_BODY:
case InsertionMode.IN_ROW: {
characterInTable(this, token);
break;
}
case InsertionMode.IN_COLUMN_GROUP: {
tokenInColumnGroup(this, token);
break;
}
case InsertionMode.AFTER_BODY: {
tokenAfterBody(this, token);
break;
}
case InsertionMode.AFTER_AFTER_BODY: {
tokenAfterAfterBody(this, token);
break;
}
// Do nothing
}
}
onComment(token) {
this.skipNextNewLine = false;
if (this.currentNotInHTML) {
appendComment(this, token);
return;
}
switch (this.insertionMode) {
case InsertionMode.INITIAL:
case InsertionMode.BEFORE_HTML:
case InsertionMode.BEFORE_HEAD:
case InsertionMode.IN_HEAD:
case InsertionMode.IN_HEAD_NO_SCRIPT:
case InsertionMode.AFTER_HEAD:
case InsertionMode.IN_BODY:
case InsertionMode.IN_TABLE:
case InsertionMode.IN_CAPTION:
case InsertionMode.IN_COLUMN_GROUP:
case InsertionMode.IN_TABLE_BODY:
case InsertionMode.IN_ROW:
case InsertionMode.IN_CELL:
case InsertionMode.IN_SELECT:
case InsertionMode.IN_SELECT_IN_TABLE:
case InsertionMode.IN_TEMPLATE:
case InsertionMode.IN_FRAMESET:
case InsertionMode.AFTER_FRAMESET: {
appendComment(this, token);
break;
}
case InsertionMode.IN_TABLE_TEXT: {
tokenInTableText(this, token);
break;
}
case InsertionMode.AFTER_BODY: {
appendCommentToRootHtmlElement(this, token);
break;
}
case InsertionMode.AFTER_AFTER_BODY:
case InsertionMode.AFTER_AFTER_FRAMESET: {
appendCommentToDocument(this, token);
break;
}
// Do nothing
}
}
onDoctype(token) {
this.skipNextNewLine = false;
switch (this.insertionMode) {
case InsertionMode.INITIAL: {
doctypeInInitialMode(this, token);
break;
}
case InsertionMode.BEFORE_HEAD:
case InsertionMode.IN_HEAD:
case InsertionMode.IN_HEAD_NO_SCRIPT:
case InsertionMode.AFTER_HEAD: {
this._err(token, errorCodes$1.ERR.misplacedDoctype);
break;
}
case InsertionMode.IN_TABLE_TEXT: {
tokenInTableText(this, token);
break;
}
// Do nothing
}
}
onStartTag(token) {
this.skipNextNewLine = false;
this.currentToken = token;
this._processStartTag(token);
if (token.selfClosing && !token.ackSelfClosing) {
this._err(token, errorCodes$1.ERR.nonVoidHtmlElementStartTagWithTrailingSolidus);
}
}
/**
* Processes a given start tag.
*
* `onStartTag` checks if a self-closing tag was recognized. When a token
* is moved inbetween multiple insertion modes, this check for self-closing
* could lead to false positives. To avoid this, `_processStartTag` is used
* for nested calls.
*
* @param token The token to process.
*/
_processStartTag(token) {
if (this.shouldProcessStartTagTokenInForeignContent(token)) {
startTagInForeignContent(this, token);
}
else {
this._startTagOutsideForeignContent(token);
}
}
_startTagOutsideForeignContent(token) {
switch (this.insertionMode) {
case InsertionMode.INITIAL: {
tokenInInitialMode(this, token);
break;
}
case InsertionMode.BEFORE_HTML: {
startTagBeforeHtml(this, token);
break;
}
case InsertionMode.BEFORE_HEAD: {
startTagBeforeHead(this, token);
break;
}
case InsertionMode.IN_HEAD: {
startTagInHead(this, token);
break;
}
case InsertionMode.IN_HEAD_NO_SCRIPT: {
startTagInHeadNoScript(this, token);
break;
}
case InsertionMode.AFTER_HEAD: {
startTagAfterHead(this, token);
break;
}
case InsertionMode.IN_BODY: {
startTagInBody(this, token);
break;
}
case InsertionMode.IN_TABLE: {
startTagInTable(this, token);
break;
}
case InsertionMode.IN_TABLE_TEXT: {
tokenInTableText(this, token);
break;
}
case InsertionMode.IN_CAPTION: {
startTagInCaption(this, token);
break;
}
case InsertionMode.IN_COLUMN_GROUP: {
startTagInColumnGroup(this, token);
break;
}
case InsertionMode.IN_TABLE_BODY: {
startTagInTableBody(this, token);
break;
}
case InsertionMode.IN_ROW: {
startTagInRow(this, token);
break;
}
case InsertionMode.IN_CELL: {
startTagInCell(this, token);
break;
}
case InsertionMode.IN_SELECT: {
startTagInSelect(this, token);
break;
}
case InsertionMode.IN_SELECT_IN_TABLE: {
startTagInSelectInTable(this, token);
break;
}
case InsertionMode.IN_TEMPLATE: {
startTagInTemplate(this, token);
break;
}
case InsertionMode.AFTER_BODY: {
startTagAfterBody(this, token);
break;
}
case InsertionMode.IN_FRAMESET: {
startTagInFrameset(this, token);
break;
}
case InsertionMode.AFTER_FRAMESET: {
startTagAfterFrameset(this, token);
break;
}
case InsertionMode.AFTER_AFTER_BODY: {
startTagAfterAfterBody(this, token);
break;
}
case InsertionMode.AFTER_AFTER_FRAMESET: {
startTagAfterAfterFrameset(this, token);
break;
}
// Do nothing
}
}
onEndTag(token) {
this.skipNextNewLine = false;
this.currentToken = token;
if (this.currentNotInHTML) {
endTagInForeignContent(this, token);
}
else {
this._endTagOutsideForeignContent(token);
}
}
_endTagOutsideForeignContent(token) {
switch (this.insertionMode) {
case InsertionMode.INITIAL: {
tokenInInitialMode(this, token);
break;
}
case InsertionMode.BEFORE_HTML: {
endTagBeforeHtml(this, token);
break;
}
case InsertionMode.BEFORE_HEAD: {
endTagBeforeHead(this, token);
break;
}
case InsertionMode.IN_HEAD: {
endTagInHead(this, token);
break;
}
case InsertionMode.IN_HEAD_NO_SCRIPT: {
endTagInHeadNoScript(this, token);
break;
}
case InsertionMode.AFTER_HEAD: {
endTagAfterHead(this, token);
break;
}
case InsertionMode.IN_BODY: {
endTagInBody(this, token);
break;
}
case InsertionMode.TEXT: {
endTagInText(this, token);
break;
}
case InsertionMode.IN_TABLE: {
endTagInTable(this, token);
break;
}
case InsertionMode.IN_TABLE_TEXT: {
tokenInTableText(this, token);
break;
}
case InsertionMode.IN_CAPTION: {
endTagInCaption(this, token);
break;
}
case InsertionMode.IN_COLUMN_GROUP: {
endTagInColumnGroup(this, token);
break;
}
case InsertionMode.IN_TABLE_BODY: {
endTagInTableBody(this, token);
break;
}
case InsertionMode.IN_ROW: {
endTagInRow(this, token);
break;
}
case InsertionMode.IN_CELL: {
endTagInCell(this, token);
break;
}
case InsertionMode.IN_SELECT: {
endTagInSelect(this, token);
break;
}
case InsertionMode.IN_SELECT_IN_TABLE: {
endTagInSelectInTable(this, token);
break;
}
case InsertionMode.IN_TEMPLATE: {
endTagInTemplate(this, token);
break;
}
case InsertionMode.AFTER_BODY: {
endTagAfterBody(this, token);
break;
}
case InsertionMode.IN_FRAMESET: {
endTagInFrameset(this, token);
break;
}
case InsertionMode.AFTER_FRAMESET: {
endTagAfterFrameset(this, token);
break;
}
case InsertionMode.AFTER_AFTER_BODY: {
tokenAfterAfterBody(this, token);
break;
}
// Do nothing
}
}
onEof(token) {
switch (this.insertionMode) {
case InsertionMode.INITIAL: {
tokenInInitialMode(this, token);
break;
}
case InsertionMode.BEFORE_HTML: {
tokenBeforeHtml(this, token);
break;
}
case InsertionMode.BEFORE_HEAD: {
tokenBeforeHead(this, token);
break;
}
case InsertionMode.IN_HEAD: {
tokenInHead(this, token);
break;
}
case InsertionMode.IN_HEAD_NO_SCRIPT: {
tokenInHeadNoScript(this, token);
break;
}
case InsertionMode.AFTER_HEAD: {
tokenAfterHead(this, token);
break;
}
case InsertionMode.IN_BODY:
case InsertionMode.IN_TABLE:
case InsertionMode.IN_CAPTION:
case InsertionMode.IN_COLUMN_GROUP:
case InsertionMode.IN_TABLE_BODY:
case InsertionMode.IN_ROW:
case InsertionMode.IN_CELL:
case InsertionMode.IN_SELECT:
case InsertionMode.IN_SELECT_IN_TABLE: {
eofInBody(this, token);
break;
}
case InsertionMode.TEXT: {
eofInText(this, token);
break;
}
case InsertionMode.IN_TABLE_TEXT: {
tokenInTableText(this, token);
break;
}
case InsertionMode.IN_TEMPLATE: {
eofInTemplate(this, token);
break;
}
case InsertionMode.AFTER_BODY:
case InsertionMode.IN_FRAMESET:
case InsertionMode.AFTER_FRAMESET:
case InsertionMode.AFTER_AFTER_BODY:
case InsertionMode.AFTER_AFTER_FRAMESET: {
stopParsing(this, token);
break;
}
// Do nothing
}
}
onWhitespaceCharacter(token) {
if (this.skipNextNewLine) {
this.skipNextNewLine = false;
if (token.chars.charCodeAt(0) === unicode$1.CODE_POINTS.LINE_FEED) {
if (token.chars.length === 1) {
return;
}
token.chars = token.chars.substr(1);
}
}
if (this.tokenizer.inForeignNode) {
this._insertCharacters(token);
return;
}
switch (this.insertionMode) {
case InsertionMode.IN_HEAD:
case InsertionMode.IN_HEAD_NO_SCRIPT:
case InsertionMode.AFTER_HEAD:
case InsertionMode.TEXT:
case InsertionMode.IN_COLUMN_GROUP:
case InsertionMode.IN_SELECT:
case InsertionMode.IN_SELECT_IN_TABLE:
case InsertionMode.IN_FRAMESET:
case InsertionMode.AFTER_FRAMESET: {
this._insertCharacters(token);
break;
}
case InsertionMode.IN_BODY:
case InsertionMode.IN_CAPTION:
case InsertionMode.IN_CELL:
case InsertionMode.IN_TEMPLATE:
case InsertionMode.AFTER_BODY:
case InsertionMode.AFTER_AFTER_BODY:
case InsertionMode.AFTER_AFTER_FRAMESET: {
whitespaceCharacterInBody(this, token);
break;
}
case InsertionMode.IN_TABLE:
case InsertionMode.IN_TABLE_BODY:
case InsertionMode.IN_ROW: {
characterInTable(this, token);
break;
}
case InsertionMode.IN_TABLE_TEXT: {
whitespaceCharacterInTableText(this, token);
break;
}
// Do nothing
}
}
}
exports.Parser = Parser;
//Adoption agency algorithm
//(see: http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#adoptionAgency)
//------------------------------------------------------------------
//Steps 5-8 of the algorithm
function aaObtainFormattingElementEntry(p, token) {
let formattingElementEntry = p.activeFormattingElements.getElementEntryInScopeWithTagName(token.tagName);
if (formattingElementEntry) {
if (!p.openElements.contains(formattingElementEntry.element)) {
p.activeFormattingElements.removeEntry(formattingElementEntry);
formattingElementEntry = null;
}
else if (!p.openElements.hasInScope(token.tagID)) {
formattingElementEntry = null;
}
}
else {
genericEndTagInBody(p, token);
}
return formattingElementEntry;
}
//Steps 9 and 10 of the algorithm
function aaObtainFurthestBlock(p, formattingElementEntry) {
let furthestBlock = null;
let idx = p.openElements.stackTop;
for (; idx >= 0; idx--) {
const element = p.openElements.items[idx];
if (element === formattingElementEntry.element) {
break;
}
if (p._isSpecialElement(element, p.openElements.tagIDs[idx])) {
furthestBlock = element;
}
}
if (!furthestBlock) {
p.openElements.shortenToLength(idx < 0 ? 0 : idx);
p.activeFormattingElements.removeEntry(formattingElementEntry);
}
return furthestBlock;
}
//Step 13 of the algorithm
function aaInnerLoop(p, furthestBlock, formattingElement) {
let lastElement = furthestBlock;
let nextElement = p.openElements.getCommonAncestor(furthestBlock);
for (let i = 0, element = nextElement; element !== formattingElement; i++, element = nextElement) {
//NOTE: store the next element for the next loop iteration (it may be deleted from the stack by step 9.5)
nextElement = p.openElements.getCommonAncestor(element);
const elementEntry = p.activeFormattingElements.getElementEntry(element);
const counterOverflow = elementEntry && i >= AA_INNER_LOOP_ITER;
const shouldRemoveFromOpenElements = !elementEntry || counterOverflow;
if (shouldRemoveFromOpenElements) {
if (counterOverflow) {
p.activeFormattingElements.removeEntry(elementEntry);
}
p.openElements.remove(element);
}
else {
element = aaRecreateElementFromEntry(p, elementEntry);
if (lastElement === furthestBlock) {
p.activeFormattingElements.bookmark = elementEntry;
}
p.treeAdapter.detachNode(lastElement);
p.treeAdapter.appendChild(element, lastElement);
lastElement = element;
}
}
return lastElement;
}
//Step 13.7 of the algorithm
function aaRecreateElementFromEntry(p, elementEntry) {
const ns = p.treeAdapter.getNamespaceURI(elementEntry.element);
const newElement = p.treeAdapter.createElement(elementEntry.token.tagName, ns, elementEntry.token.attrs);
p.openElements.replace(elementEntry.element, newElement);
elementEntry.element = newElement;
return newElement;
}
//Step 14 of the algorithm
function aaInsertLastNodeInCommonAncestor(p, commonAncestor, lastElement) {
const tn = p.treeAdapter.getTagName(commonAncestor);
const tid = (0, html$1.getTagID)(tn);
if (p._isElementCausesFosterParenting(tid)) {
p._fosterParentElement(lastElement);
}
else {
const ns = p.treeAdapter.getNamespaceURI(commonAncestor);
if (tid === html$1.TAG_ID.TEMPLATE && ns === html$1.NS.HTML) {
commonAncestor = p.treeAdapter.getTemplateContent(commonAncestor);
}
p.treeAdapter.appendChild(commonAncestor, lastElement);
}
}
//Steps 15-19 of the algorithm
function aaReplaceFormattingElement(p, furthestBlock, formattingElementEntry) {
const ns = p.treeAdapter.getNamespaceURI(formattingElementEntry.element);
const { token } = formattingElementEntry;
const newElement = p.treeAdapter.createElement(token.tagName, ns, token.attrs);
p._adoptNodes(furthestBlock, newElement);
p.treeAdapter.appendChild(furthestBlock, newElement);
p.activeFormattingElements.insertElementAfterBookmark(newElement, token);
p.activeFormattingElements.removeEntry(formattingElementEntry);
p.openElements.remove(formattingElementEntry.element);
p.openElements.insertAfter(furthestBlock, newElement, token.tagID);
}
//Algorithm entry point
function callAdoptionAgency(p, token) {
for (let i = 0; i < AA_OUTER_LOOP_ITER; i++) {
const formattingElementEntry = aaObtainFormattingElementEntry(p, token);
if (!formattingElementEntry) {
break;
}
const furthestBlock = aaObtainFurthestBlock(p, formattingElementEntry);
if (!furthestBlock) {
break;
}
p.activeFormattingElements.bookmark = formattingElementEntry;
const lastElement = aaInnerLoop(p, furthestBlock, formattingElementEntry.element);
const commonAncestor = p.openElements.getCommonAncestor(formattingElementEntry.element);
p.treeAdapter.detachNode(lastElement);
if (commonAncestor)
aaInsertLastNodeInCommonAncestor(p, commonAncestor, lastElement);
aaReplaceFormattingElement(p, furthestBlock, formattingElementEntry);
}
}
//Generic token handlers
//------------------------------------------------------------------
function appendComment(p, token) {
p._appendCommentNode(token, p.openElements.currentTmplContentOrNode);
}
function appendCommentToRootHtmlElement(p, token) {
p._appendCommentNode(token, p.openElements.items[0]);
}
function appendCommentToDocument(p, token) {
p._appendCommentNode(token, p.document);
}
function stopParsing(p, token) {
p.stopped = true;
// NOTE: Set end locations for elements that remain on the open element stack.
if (token.location) {
// NOTE: If we are not in a fragment, `html` and `body` will stay on the stack.
// This is a problem, as we might overwrite their end position here.
const target = p.fragmentContext ? 0 : 2;
for (let i = p.openElements.stackTop; i >= target; i--) {
p._setEndLocation(p.openElements.items[i], token);
}
// Handle `html` and `body`
if (!p.fragmentContext && p.openElements.stackTop >= 0) {
const htmlElement = p.openElements.items[0];
const htmlLocation = p.treeAdapter.getNodeSourceCodeLocation(htmlElement);
if (htmlLocation && !htmlLocation.endTag) {
p._setEndLocation(htmlElement, token);
if (p.openElements.stackTop >= 1) {
const bodyElement = p.openElements.items[1];
const bodyLocation = p.treeAdapter.getNodeSourceCodeLocation(bodyElement);
if (bodyLocation && !bodyLocation.endTag) {
p._setEndLocation(bodyElement, token);
}
}
}
}
}
}
// The "initial" insertion mode
//------------------------------------------------------------------
function doctypeInInitialMode(p, token) {
p._setDocumentType(token);
const mode = token.forceQuirks ? html$1.DOCUMENT_MODE.QUIRKS : doctype$1.getDocumentMode(token);
if (!doctype$1.isConforming(token)) {
p._err(token, errorCodes$1.ERR.nonConformingDoctype);
}
p.treeAdapter.setDocumentMode(p.document, mode);
p.insertionMode = InsertionMode.BEFORE_HTML;
}
function tokenInInitialMode(p, token) {
p._err(token, errorCodes$1.ERR.missingDoctype, true);
p.treeAdapter.setDocumentMode(p.document, html$1.DOCUMENT_MODE.QUIRKS);
p.insertionMode = InsertionMode.BEFORE_HTML;
p._processToken(token);
}
// The "before html" insertion mode
//------------------------------------------------------------------
function startTagBeforeHtml(p, token) {
if (token.tagID === html$1.TAG_ID.HTML) {
p._insertElement(token, html$1.NS.HTML);
p.insertionMode = InsertionMode.BEFORE_HEAD;
}
else {
tokenBeforeHtml(p, token);
}
}
function endTagBeforeHtml(p, token) {
const tn = token.tagID;
if (tn === html$1.TAG_ID.HTML || tn === html$1.TAG_ID.HEAD || tn === html$1.TAG_ID.BODY || tn === html$1.TAG_ID.BR) {
tokenBeforeHtml(p, token);
}
}
function tokenBeforeHtml(p, token) {
p._insertFakeRootElement();
p.insertionMode = InsertionMode.BEFORE_HEAD;
p._processToken(token);
}
// The "before head" insertion mode
//------------------------------------------------------------------
function startTagBeforeHead(p, token) {
switch (token.tagID) {
case html$1.TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case html$1.TAG_ID.HEAD: {
p._insertElement(token, html$1.NS.HTML);
p.headElement = p.openElements.current;
p.insertionMode = InsertionMode.IN_HEAD;
break;
}
default: {
tokenBeforeHead(p, token);
}
}
}
function endTagBeforeHead(p, token) {
const tn = token.tagID;
if (tn === html$1.TAG_ID.HEAD || tn === html$1.TAG_ID.BODY || tn === html$1.TAG_ID.HTML || tn === html$1.TAG_ID.BR) {
tokenBeforeHead(p, token);
}
else {
p._err(token, errorCodes$1.ERR.endTagWithoutMatchingOpenElement);
}
}
function tokenBeforeHead(p, token) {
p._insertFakeElement(html$1.TAG_NAMES.HEAD, html$1.TAG_ID.HEAD);
p.headElement = p.openElements.current;
p.insertionMode = InsertionMode.IN_HEAD;
p._processToken(token);
}
// The "in head" insertion mode
//------------------------------------------------------------------
function startTagInHead(p, token) {
switch (token.tagID) {
case html$1.TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case html$1.TAG_ID.BASE:
case html$1.TAG_ID.BASEFONT:
case html$1.TAG_ID.BGSOUND:
case html$1.TAG_ID.LINK:
case html$1.TAG_ID.META: {
p._appendElement(token, html$1.NS.HTML);
token.ackSelfClosing = true;
break;
}
case html$1.TAG_ID.TITLE: {
p._switchToTextParsing(token, tokenizer$1.TokenizerMode.RCDATA);
break;
}
case html$1.TAG_ID.NOSCRIPT: {
if (p.options.scriptingEnabled) {
p._switchToTextParsing(token, tokenizer$1.TokenizerMode.RAWTEXT);
}
else {
p._insertElement(token, html$1.NS.HTML);
p.insertionMode = InsertionMode.IN_HEAD_NO_SCRIPT;
}
break;
}
case html$1.TAG_ID.NOFRAMES:
case html$1.TAG_ID.STYLE: {
p._switchToTextParsing(token, tokenizer$1.TokenizerMode.RAWTEXT);
break;
}
case html$1.TAG_ID.SCRIPT: {
p._switchToTextParsing(token, tokenizer$1.TokenizerMode.SCRIPT_DATA);
break;
}
case html$1.TAG_ID.TEMPLATE: {
p._insertTemplate(token);
p.activeFormattingElements.insertMarker();
p.framesetOk = false;
p.insertionMode = InsertionMode.IN_TEMPLATE;
p.tmplInsertionModeStack.unshift(InsertionMode.IN_TEMPLATE);
break;
}
case html$1.TAG_ID.HEAD: {
p._err(token, errorCodes$1.ERR.misplacedStartTagForHeadElement);
break;
}
default: {
tokenInHead(p, token);
}
}
}
function endTagInHead(p, token) {
switch (token.tagID) {
case html$1.TAG_ID.HEAD: {
p.openElements.pop();
p.insertionMode = InsertionMode.AFTER_HEAD;
break;
}
case html$1.TAG_ID.BODY:
case html$1.TAG_ID.BR:
case html$1.TAG_ID.HTML: {
tokenInHead(p, token);
break;
}
case html$1.TAG_ID.TEMPLATE: {
templateEndTagInHead(p, token);
break;
}
default: {
p._err(token, errorCodes$1.ERR.endTagWithoutMatchingOpenElement);
}
}
}
function templateEndTagInHead(p, token) {
if (p.openElements.tmplCount > 0) {
p.openElements.generateImpliedEndTagsThoroughly();
if (p.openElements.currentTagId !== html$1.TAG_ID.TEMPLATE) {
p._err(token, errorCodes$1.ERR.closingOfElementWithOpenChildElements);
}
p.openElements.popUntilTagNamePopped(html$1.TAG_ID.TEMPLATE);
p.activeFormattingElements.clearToLastMarker();
p.tmplInsertionModeStack.shift();
p._resetInsertionMode();
}
else {
p._err(token, errorCodes$1.ERR.endTagWithoutMatchingOpenElement);
}
}
function tokenInHead(p, token) {
p.openElements.pop();
p.insertionMode = InsertionMode.AFTER_HEAD;
p._processToken(token);
}
// The "in head no script" insertion mode
//------------------------------------------------------------------
function startTagInHeadNoScript(p, token) {
switch (token.tagID) {
case html$1.TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case html$1.TAG_ID.BASEFONT:
case html$1.TAG_ID.BGSOUND:
case html$1.TAG_ID.HEAD:
case html$1.TAG_ID.LINK:
case html$1.TAG_ID.META:
case html$1.TAG_ID.NOFRAMES:
case html$1.TAG_ID.STYLE: {
startTagInHead(p, token);
break;
}
case html$1.TAG_ID.NOSCRIPT: {
p._err(token, errorCodes$1.ERR.nestedNoscriptInHead);
break;
}
default: {
tokenInHeadNoScript(p, token);
}
}
}
function endTagInHeadNoScript(p, token) {
switch (token.tagID) {
case html$1.TAG_ID.NOSCRIPT: {
p.openElements.pop();
p.insertionMode = InsertionMode.IN_HEAD;
break;
}
case html$1.TAG_ID.BR: {
tokenInHeadNoScript(p, token);
break;
}
default: {
p._err(token, errorCodes$1.ERR.endTagWithoutMatchingOpenElement);
}
}
}
function tokenInHeadNoScript(p, token) {
const errCode = token.type === token$1.TokenType.EOF ? errorCodes$1.ERR.openElementsLeftAfterEof : errorCodes$1.ERR.disallowedContentInNoscriptInHead;
p._err(token, errCode);
p.openElements.pop();
p.insertionMode = InsertionMode.IN_HEAD;
p._processToken(token);
}
// The "after head" insertion mode
//------------------------------------------------------------------
function startTagAfterHead(p, token) {
switch (token.tagID) {
case html$1.TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case html$1.TAG_ID.BODY: {
p._insertElement(token, html$1.NS.HTML);
p.framesetOk = false;
p.insertionMode = InsertionMode.IN_BODY;
break;
}
case html$1.TAG_ID.FRAMESET: {
p._insertElement(token, html$1.NS.HTML);
p.insertionMode = InsertionMode.IN_FRAMESET;
break;
}
case html$1.TAG_ID.BASE:
case html$1.TAG_ID.BASEFONT:
case html$1.TAG_ID.BGSOUND:
case html$1.TAG_ID.LINK:
case html$1.TAG_ID.META:
case html$1.TAG_ID.NOFRAMES:
case html$1.TAG_ID.SCRIPT:
case html$1.TAG_ID.STYLE:
case html$1.TAG_ID.TEMPLATE:
case html$1.TAG_ID.TITLE: {
p._err(token, errorCodes$1.ERR.abandonedHeadElementChild);
p.openElements.push(p.headElement, html$1.TAG_ID.HEAD);
startTagInHead(p, token);
p.openElements.remove(p.headElement);
break;
}
case html$1.TAG_ID.HEAD: {
p._err(token, errorCodes$1.ERR.misplacedStartTagForHeadElement);
break;
}
default: {
tokenAfterHead(p, token);
}
}
}
function endTagAfterHead(p, token) {
switch (token.tagID) {
case html$1.TAG_ID.BODY:
case html$1.TAG_ID.HTML:
case html$1.TAG_ID.BR: {
tokenAfterHead(p, token);
break;
}
case html$1.TAG_ID.TEMPLATE: {
templateEndTagInHead(p, token);
break;
}
default: {
p._err(token, errorCodes$1.ERR.endTagWithoutMatchingOpenElement);
}
}
}
function tokenAfterHead(p, token) {
p._insertFakeElement(html$1.TAG_NAMES.BODY, html$1.TAG_ID.BODY);
p.insertionMode = InsertionMode.IN_BODY;
modeInBody(p, token);
}
// The "in body" insertion mode
//------------------------------------------------------------------
function modeInBody(p, token) {
switch (token.type) {
case token$1.TokenType.CHARACTER: {
characterInBody(p, token);
break;
}
case token$1.TokenType.WHITESPACE_CHARACTER: {
whitespaceCharacterInBody(p, token);
break;
}
case token$1.TokenType.COMMENT: {
appendComment(p, token);
break;
}
case token$1.TokenType.START_TAG: {
startTagInBody(p, token);
break;
}
case token$1.TokenType.END_TAG: {
endTagInBody(p, token);
break;
}
case token$1.TokenType.EOF: {
eofInBody(p, token);
break;
}
// Do nothing
}
}
function whitespaceCharacterInBody(p, token) {
p._reconstructActiveFormattingElements();
p._insertCharacters(token);
}
function characterInBody(p, token) {
p._reconstructActiveFormattingElements();
p._insertCharacters(token);
p.framesetOk = false;
}
function htmlStartTagInBody(p, token) {
if (p.openElements.tmplCount === 0) {
p.treeAdapter.adoptAttributes(p.openElements.items[0], token.attrs);
}
}
function bodyStartTagInBody(p, token) {
const bodyElement = p.openElements.tryPeekProperlyNestedBodyElement();
if (bodyElement && p.openElements.tmplCount === 0) {
p.framesetOk = false;
p.treeAdapter.adoptAttributes(bodyElement, token.attrs);
}
}
function framesetStartTagInBody(p, token) {
const bodyElement = p.openElements.tryPeekProperlyNestedBodyElement();
if (p.framesetOk && bodyElement) {
p.treeAdapter.detachNode(bodyElement);
p.openElements.popAllUpToHtmlElement();
p._insertElement(token, html$1.NS.HTML);
p.insertionMode = InsertionMode.IN_FRAMESET;
}
}
function addressStartTagInBody(p, token) {
if (p.openElements.hasInButtonScope(html$1.TAG_ID.P)) {
p._closePElement();
}
p._insertElement(token, html$1.NS.HTML);
}
function numberedHeaderStartTagInBody(p, token) {
if (p.openElements.hasInButtonScope(html$1.TAG_ID.P)) {
p._closePElement();
}
if ((0, html$1.isNumberedHeader)(p.openElements.currentTagId)) {
p.openElements.pop();
}
p._insertElement(token, html$1.NS.HTML);
}
function preStartTagInBody(p, token) {
if (p.openElements.hasInButtonScope(html$1.TAG_ID.P)) {
p._closePElement();
}
p._insertElement(token, html$1.NS.HTML);
//NOTE: If the next token is a U+000A LINE FEED (LF) character token, then ignore that token and move
//on to the next one. (Newlines at the start of pre blocks are ignored as an authoring convenience.)
p.skipNextNewLine = true;
p.framesetOk = false;
}
function formStartTagInBody(p, token) {
const inTemplate = p.openElements.tmplCount > 0;
if (!p.formElement || inTemplate) {
if (p.openElements.hasInButtonScope(html$1.TAG_ID.P)) {
p._closePElement();
}
p._insertElement(token, html$1.NS.HTML);
if (!inTemplate) {
p.formElement = p.openElements.current;
}
}
}
function listItemStartTagInBody(p, token) {
p.framesetOk = false;
const tn = token.tagID;
for (let i = p.openElements.stackTop; i >= 0; i--) {
const elementId = p.openElements.tagIDs[i];
if ((tn === html$1.TAG_ID.LI && elementId === html$1.TAG_ID.LI) ||
((tn === html$1.TAG_ID.DD || tn === html$1.TAG_ID.DT) && (elementId === html$1.TAG_ID.DD || elementId === html$1.TAG_ID.DT))) {
p.openElements.generateImpliedEndTagsWithExclusion(elementId);
p.openElements.popUntilTagNamePopped(elementId);
break;
}
if (elementId !== html$1.TAG_ID.ADDRESS &&
elementId !== html$1.TAG_ID.DIV &&
elementId !== html$1.TAG_ID.P &&
p._isSpecialElement(p.openElements.items[i], elementId)) {
break;
}
}
if (p.openElements.hasInButtonScope(html$1.TAG_ID.P)) {
p._closePElement();
}
p._insertElement(token, html$1.NS.HTML);
}
function plaintextStartTagInBody(p, token) {
if (p.openElements.hasInButtonScope(html$1.TAG_ID.P)) {
p._closePElement();
}
p._insertElement(token, html$1.NS.HTML);
p.tokenizer.state = tokenizer$1.TokenizerMode.PLAINTEXT;
}
function buttonStartTagInBody(p, token) {
if (p.openElements.hasInScope(html$1.TAG_ID.BUTTON)) {
p.openElements.generateImpliedEndTags();
p.openElements.popUntilTagNamePopped(html$1.TAG_ID.BUTTON);
}
p._reconstructActiveFormattingElements();
p._insertElement(token, html$1.NS.HTML);
p.framesetOk = false;
}
function aStartTagInBody(p, token) {
const activeElementEntry = p.activeFormattingElements.getElementEntryInScopeWithTagName(html$1.TAG_NAMES.A);
if (activeElementEntry) {
callAdoptionAgency(p, token);
p.openElements.remove(activeElementEntry.element);
p.activeFormattingElements.removeEntry(activeElementEntry);
}
p._reconstructActiveFormattingElements();
p._insertElement(token, html$1.NS.HTML);
p.activeFormattingElements.pushElement(p.openElements.current, token);
}
function bStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
p._insertElement(token, html$1.NS.HTML);
p.activeFormattingElements.pushElement(p.openElements.current, token);
}
function nobrStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
if (p.openElements.hasInScope(html$1.TAG_ID.NOBR)) {
callAdoptionAgency(p, token);
p._reconstructActiveFormattingElements();
}
p._insertElement(token, html$1.NS.HTML);
p.activeFormattingElements.pushElement(p.openElements.current, token);
}
function appletStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
p._insertElement(token, html$1.NS.HTML);
p.activeFormattingElements.insertMarker();
p.framesetOk = false;
}
function tableStartTagInBody(p, token) {
if (p.treeAdapter.getDocumentMode(p.document) !== html$1.DOCUMENT_MODE.QUIRKS && p.openElements.hasInButtonScope(html$1.TAG_ID.P)) {
p._closePElement();
}
p._insertElement(token, html$1.NS.HTML);
p.framesetOk = false;
p.insertionMode = InsertionMode.IN_TABLE;
}
function areaStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
p._appendElement(token, html$1.NS.HTML);
p.framesetOk = false;
token.ackSelfClosing = true;
}
function isHiddenInput(token) {
const inputType = (0, token$1.getTokenAttr)(token, html$1.ATTRS.TYPE);
return inputType != null && inputType.toLowerCase() === HIDDEN_INPUT_TYPE;
}
function inputStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
p._appendElement(token, html$1.NS.HTML);
if (!isHiddenInput(token)) {
p.framesetOk = false;
}
token.ackSelfClosing = true;
}
function paramStartTagInBody(p, token) {
p._appendElement(token, html$1.NS.HTML);
token.ackSelfClosing = true;
}
function hrStartTagInBody(p, token) {
if (p.openElements.hasInButtonScope(html$1.TAG_ID.P)) {
p._closePElement();
}
p._appendElement(token, html$1.NS.HTML);
p.framesetOk = false;
token.ackSelfClosing = true;
}
function imageStartTagInBody(p, token) {
token.tagName = html$1.TAG_NAMES.IMG;
token.tagID = html$1.TAG_ID.IMG;
areaStartTagInBody(p, token);
}
function textareaStartTagInBody(p, token) {
p._insertElement(token, html$1.NS.HTML);
//NOTE: If the next token is a U+000A LINE FEED (LF) character token, then ignore that token and move
//on to the next one. (Newlines at the start of textarea elements are ignored as an authoring convenience.)
p.skipNextNewLine = true;
p.tokenizer.state = tokenizer$1.TokenizerMode.RCDATA;
p.originalInsertionMode = p.insertionMode;
p.framesetOk = false;
p.insertionMode = InsertionMode.TEXT;
}
function xmpStartTagInBody(p, token) {
if (p.openElements.hasInButtonScope(html$1.TAG_ID.P)) {
p._closePElement();
}
p._reconstructActiveFormattingElements();
p.framesetOk = false;
p._switchToTextParsing(token, tokenizer$1.TokenizerMode.RAWTEXT);
}
function iframeStartTagInBody(p, token) {
p.framesetOk = false;
p._switchToTextParsing(token, tokenizer$1.TokenizerMode.RAWTEXT);
}
//NOTE: here we assume that we always act as an user agent with enabled plugins, so we parse
//<noembed> as rawtext.
function noembedStartTagInBody(p, token) {
p._switchToTextParsing(token, tokenizer$1.TokenizerMode.RAWTEXT);
}
function selectStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
p._insertElement(token, html$1.NS.HTML);
p.framesetOk = false;
p.insertionMode =
p.insertionMode === InsertionMode.IN_TABLE ||
p.insertionMode === InsertionMode.IN_CAPTION ||
p.insertionMode === InsertionMode.IN_TABLE_BODY ||
p.insertionMode === InsertionMode.IN_ROW ||
p.insertionMode === InsertionMode.IN_CELL
? InsertionMode.IN_SELECT_IN_TABLE
: InsertionMode.IN_SELECT;
}
function optgroupStartTagInBody(p, token) {
if (p.openElements.currentTagId === html$1.TAG_ID.OPTION) {
p.openElements.pop();
}
p._reconstructActiveFormattingElements();
p._insertElement(token, html$1.NS.HTML);
}
function rbStartTagInBody(p, token) {
if (p.openElements.hasInScope(html$1.TAG_ID.RUBY)) {
p.openElements.generateImpliedEndTags();
}
p._insertElement(token, html$1.NS.HTML);
}
function rtStartTagInBody(p, token) {
if (p.openElements.hasInScope(html$1.TAG_ID.RUBY)) {
p.openElements.generateImpliedEndTagsWithExclusion(html$1.TAG_ID.RTC);
}
p._insertElement(token, html$1.NS.HTML);
}
function mathStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
foreignContent$1.adjustTokenMathMLAttrs(token);
foreignContent$1.adjustTokenXMLAttrs(token);
if (token.selfClosing) {
p._appendElement(token, html$1.NS.MATHML);
}
else {
p._insertElement(token, html$1.NS.MATHML);
}
token.ackSelfClosing = true;
}
function svgStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
foreignContent$1.adjustTokenSVGAttrs(token);
foreignContent$1.adjustTokenXMLAttrs(token);
if (token.selfClosing) {
p._appendElement(token, html$1.NS.SVG);
}
else {
p._insertElement(token, html$1.NS.SVG);
}
token.ackSelfClosing = true;
}
function genericStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
p._insertElement(token, html$1.NS.HTML);
}
function startTagInBody(p, token) {
switch (token.tagID) {
case html$1.TAG_ID.I:
case html$1.TAG_ID.S:
case html$1.TAG_ID.B:
case html$1.TAG_ID.U:
case html$1.TAG_ID.EM:
case html$1.TAG_ID.TT:
case html$1.TAG_ID.BIG:
case html$1.TAG_ID.CODE:
case html$1.TAG_ID.FONT:
case html$1.TAG_ID.SMALL:
case html$1.TAG_ID.STRIKE:
case html$1.TAG_ID.STRONG: {
bStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.A: {
aStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.H1:
case html$1.TAG_ID.H2:
case html$1.TAG_ID.H3:
case html$1.TAG_ID.H4:
case html$1.TAG_ID.H5:
case html$1.TAG_ID.H6: {
numberedHeaderStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.P:
case html$1.TAG_ID.DL:
case html$1.TAG_ID.OL:
case html$1.TAG_ID.UL:
case html$1.TAG_ID.DIV:
case html$1.TAG_ID.DIR:
case html$1.TAG_ID.NAV:
case html$1.TAG_ID.MAIN:
case html$1.TAG_ID.MENU:
case html$1.TAG_ID.ASIDE:
case html$1.TAG_ID.CENTER:
case html$1.TAG_ID.FIGURE:
case html$1.TAG_ID.FOOTER:
case html$1.TAG_ID.HEADER:
case html$1.TAG_ID.HGROUP:
case html$1.TAG_ID.DIALOG:
case html$1.TAG_ID.DETAILS:
case html$1.TAG_ID.ADDRESS:
case html$1.TAG_ID.ARTICLE:
case html$1.TAG_ID.SECTION:
case html$1.TAG_ID.SUMMARY:
case html$1.TAG_ID.FIELDSET:
case html$1.TAG_ID.BLOCKQUOTE:
case html$1.TAG_ID.FIGCAPTION: {
addressStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.LI:
case html$1.TAG_ID.DD:
case html$1.TAG_ID.DT: {
listItemStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.BR:
case html$1.TAG_ID.IMG:
case html$1.TAG_ID.WBR:
case html$1.TAG_ID.AREA:
case html$1.TAG_ID.EMBED:
case html$1.TAG_ID.KEYGEN: {
areaStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.HR: {
hrStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.RB:
case html$1.TAG_ID.RTC: {
rbStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.RT:
case html$1.TAG_ID.RP: {
rtStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.PRE:
case html$1.TAG_ID.LISTING: {
preStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.XMP: {
xmpStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.SVG: {
svgStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.HTML: {
htmlStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.BASE:
case html$1.TAG_ID.LINK:
case html$1.TAG_ID.META:
case html$1.TAG_ID.STYLE:
case html$1.TAG_ID.TITLE:
case html$1.TAG_ID.SCRIPT:
case html$1.TAG_ID.BGSOUND:
case html$1.TAG_ID.BASEFONT:
case html$1.TAG_ID.TEMPLATE: {
startTagInHead(p, token);
break;
}
case html$1.TAG_ID.BODY: {
bodyStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.FORM: {
formStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.NOBR: {
nobrStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.MATH: {
mathStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.TABLE: {
tableStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.INPUT: {
inputStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.PARAM:
case html$1.TAG_ID.TRACK:
case html$1.TAG_ID.SOURCE: {
paramStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.IMAGE: {
imageStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.BUTTON: {
buttonStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.APPLET:
case html$1.TAG_ID.OBJECT:
case html$1.TAG_ID.MARQUEE: {
appletStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.IFRAME: {
iframeStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.SELECT: {
selectStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.OPTION:
case html$1.TAG_ID.OPTGROUP: {
optgroupStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.NOEMBED: {
noembedStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.FRAMESET: {
framesetStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.TEXTAREA: {
textareaStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.NOSCRIPT: {
if (p.options.scriptingEnabled) {
noembedStartTagInBody(p, token);
}
else {
genericStartTagInBody(p, token);
}
break;
}
case html$1.TAG_ID.PLAINTEXT: {
plaintextStartTagInBody(p, token);
break;
}
case html$1.TAG_ID.COL:
case html$1.TAG_ID.TH:
case html$1.TAG_ID.TD:
case html$1.TAG_ID.TR:
case html$1.TAG_ID.HEAD:
case html$1.TAG_ID.FRAME:
case html$1.TAG_ID.TBODY:
case html$1.TAG_ID.TFOOT:
case html$1.TAG_ID.THEAD:
case html$1.TAG_ID.CAPTION:
case html$1.TAG_ID.COLGROUP: {
// Ignore token
break;
}
default: {
genericStartTagInBody(p, token);
}
}
}
function bodyEndTagInBody(p, token) {
if (p.openElements.hasInScope(html$1.TAG_ID.BODY)) {
p.insertionMode = InsertionMode.AFTER_BODY;
//NOTE: <body> is never popped from the stack, so we need to updated
//the end location explicitly.
if (p.options.sourceCodeLocationInfo) {
const bodyElement = p.openElements.tryPeekProperlyNestedBodyElement();
if (bodyElement) {
p._setEndLocation(bodyElement, token);
}
}
}
}
function htmlEndTagInBody(p, token) {
if (p.openElements.hasInScope(html$1.TAG_ID.BODY)) {
p.insertionMode = InsertionMode.AFTER_BODY;
endTagAfterBody(p, token);
}
}
function addressEndTagInBody(p, token) {
const tn = token.tagID;
if (p.openElements.hasInScope(tn)) {
p.openElements.generateImpliedEndTags();
p.openElements.popUntilTagNamePopped(tn);
}
}
function formEndTagInBody(p) {
const inTemplate = p.openElements.tmplCount > 0;
const { formElement } = p;
if (!inTemplate) {
p.formElement = null;
}
if ((formElement || inTemplate) && p.openElements.hasInScope(html$1.TAG_ID.FORM)) {
p.openElements.generateImpliedEndTags();
if (inTemplate) {
p.openElements.popUntilTagNamePopped(html$1.TAG_ID.FORM);
}
else if (formElement) {
p.openElements.remove(formElement);
}
}
}
function pEndTagInBody(p) {
if (!p.openElements.hasInButtonScope(html$1.TAG_ID.P)) {
p._insertFakeElement(html$1.TAG_NAMES.P, html$1.TAG_ID.P);
}
p._closePElement();
}
function liEndTagInBody(p) {
if (p.openElements.hasInListItemScope(html$1.TAG_ID.LI)) {
p.openElements.generateImpliedEndTagsWithExclusion(html$1.TAG_ID.LI);
p.openElements.popUntilTagNamePopped(html$1.TAG_ID.LI);
}
}
function ddEndTagInBody(p, token) {
const tn = token.tagID;
if (p.openElements.hasInScope(tn)) {
p.openElements.generateImpliedEndTagsWithExclusion(tn);
p.openElements.popUntilTagNamePopped(tn);
}
}
function numberedHeaderEndTagInBody(p) {
if (p.openElements.hasNumberedHeaderInScope()) {
p.openElements.generateImpliedEndTags();
p.openElements.popUntilNumberedHeaderPopped();
}
}
function appletEndTagInBody(p, token) {
const tn = token.tagID;
if (p.openElements.hasInScope(tn)) {
p.openElements.generateImpliedEndTags();
p.openElements.popUntilTagNamePopped(tn);
p.activeFormattingElements.clearToLastMarker();
}
}
function brEndTagInBody(p) {
p._reconstructActiveFormattingElements();
p._insertFakeElement(html$1.TAG_NAMES.BR, html$1.TAG_ID.BR);
p.openElements.pop();
p.framesetOk = false;
}
function genericEndTagInBody(p, token) {
const tn = token.tagName;
const tid = token.tagID;
for (let i = p.openElements.stackTop; i > 0; i--) {
const element = p.openElements.items[i];
const elementId = p.openElements.tagIDs[i];
// Compare the tag name here, as the tag might not be a known tag with an ID.
if (tid === elementId && (tid !== html$1.TAG_ID.UNKNOWN || p.treeAdapter.getTagName(element) === tn)) {
p.openElements.generateImpliedEndTagsWithExclusion(tid);
if (p.openElements.stackTop >= i)
p.openElements.shortenToLength(i);
break;
}
if (p._isSpecialElement(element, elementId)) {
break;
}
}
}
function endTagInBody(p, token) {
switch (token.tagID) {
case html$1.TAG_ID.A:
case html$1.TAG_ID.B:
case html$1.TAG_ID.I:
case html$1.TAG_ID.S:
case html$1.TAG_ID.U:
case html$1.TAG_ID.EM:
case html$1.TAG_ID.TT:
case html$1.TAG_ID.BIG:
case html$1.TAG_ID.CODE:
case html$1.TAG_ID.FONT:
case html$1.TAG_ID.NOBR:
case html$1.TAG_ID.SMALL:
case html$1.TAG_ID.STRIKE:
case html$1.TAG_ID.STRONG: {
callAdoptionAgency(p, token);
break;
}
case html$1.TAG_ID.P: {
pEndTagInBody(p);
break;
}
case html$1.TAG_ID.DL:
case html$1.TAG_ID.UL:
case html$1.TAG_ID.OL:
case html$1.TAG_ID.DIR:
case html$1.TAG_ID.DIV:
case html$1.TAG_ID.NAV:
case html$1.TAG_ID.PRE:
case html$1.TAG_ID.MAIN:
case html$1.TAG_ID.MENU:
case html$1.TAG_ID.ASIDE:
case html$1.TAG_ID.BUTTON:
case html$1.TAG_ID.CENTER:
case html$1.TAG_ID.FIGURE:
case html$1.TAG_ID.FOOTER:
case html$1.TAG_ID.HEADER:
case html$1.TAG_ID.HGROUP:
case html$1.TAG_ID.DIALOG:
case html$1.TAG_ID.ADDRESS:
case html$1.TAG_ID.ARTICLE:
case html$1.TAG_ID.DETAILS:
case html$1.TAG_ID.SECTION:
case html$1.TAG_ID.SUMMARY:
case html$1.TAG_ID.LISTING:
case html$1.TAG_ID.FIELDSET:
case html$1.TAG_ID.BLOCKQUOTE:
case html$1.TAG_ID.FIGCAPTION: {
addressEndTagInBody(p, token);
break;
}
case html$1.TAG_ID.LI: {
liEndTagInBody(p);
break;
}
case html$1.TAG_ID.DD:
case html$1.TAG_ID.DT: {
ddEndTagInBody(p, token);
break;
}
case html$1.TAG_ID.H1:
case html$1.TAG_ID.H2:
case html$1.TAG_ID.H3:
case html$1.TAG_ID.H4:
case html$1.TAG_ID.H5:
case html$1.TAG_ID.H6: {
numberedHeaderEndTagInBody(p);
break;
}
case html$1.TAG_ID.BR: {
brEndTagInBody(p);
break;
}
case html$1.TAG_ID.BODY: {
bodyEndTagInBody(p, token);
break;
}
case html$1.TAG_ID.HTML: {
htmlEndTagInBody(p, token);
break;
}
case html$1.TAG_ID.FORM: {
formEndTagInBody(p);
break;
}
case html$1.TAG_ID.APPLET:
case html$1.TAG_ID.OBJECT:
case html$1.TAG_ID.MARQUEE: {
appletEndTagInBody(p, token);
break;
}
case html$1.TAG_ID.TEMPLATE: {
templateEndTagInHead(p, token);
break;
}
default: {
genericEndTagInBody(p, token);
}
}
}
function eofInBody(p, token) {
if (p.tmplInsertionModeStack.length > 0) {
eofInTemplate(p, token);
}
else {
stopParsing(p, token);
}
}
// The "text" insertion mode
//------------------------------------------------------------------
function endTagInText(p, token) {
var _a;
if (token.tagID === html$1.TAG_ID.SCRIPT) {
(_a = p.scriptHandler) === null || _a === void 0 ? void 0 : _a.call(p, p.openElements.current);
}
p.openElements.pop();
p.insertionMode = p.originalInsertionMode;
}
function eofInText(p, token) {
p._err(token, errorCodes$1.ERR.eofInElementThatCanContainOnlyText);
p.openElements.pop();
p.insertionMode = p.originalInsertionMode;
p.onEof(token);
}
// The "in table" insertion mode
//------------------------------------------------------------------
function characterInTable(p, token) {
if (TABLE_STRUCTURE_TAGS.has(p.openElements.currentTagId)) {
p.pendingCharacterTokens.length = 0;
p.hasNonWhitespacePendingCharacterToken = false;
p.originalInsertionMode = p.insertionMode;
p.insertionMode = InsertionMode.IN_TABLE_TEXT;
switch (token.type) {
case token$1.TokenType.CHARACTER: {
characterInTableText(p, token);
break;
}
case token$1.TokenType.WHITESPACE_CHARACTER: {
whitespaceCharacterInTableText(p, token);
break;
}
// Ignore null
}
}
else {
tokenInTable(p, token);
}
}
function captionStartTagInTable(p, token) {
p.openElements.clearBackToTableContext();
p.activeFormattingElements.insertMarker();
p._insertElement(token, html$1.NS.HTML);
p.insertionMode = InsertionMode.IN_CAPTION;
}
function colgroupStartTagInTable(p, token) {
p.openElements.clearBackToTableContext();
p._insertElement(token, html$1.NS.HTML);
p.insertionMode = InsertionMode.IN_COLUMN_GROUP;
}
function colStartTagInTable(p, token) {
p.openElements.clearBackToTableContext();
p._insertFakeElement(html$1.TAG_NAMES.COLGROUP, html$1.TAG_ID.COLGROUP);
p.insertionMode = InsertionMode.IN_COLUMN_GROUP;
startTagInColumnGroup(p, token);
}
function tbodyStartTagInTable(p, token) {
p.openElements.clearBackToTableContext();
p._insertElement(token, html$1.NS.HTML);
p.insertionMode = InsertionMode.IN_TABLE_BODY;
}
function tdStartTagInTable(p, token) {
p.openElements.clearBackToTableContext();
p._insertFakeElement(html$1.TAG_NAMES.TBODY, html$1.TAG_ID.TBODY);
p.insertionMode = InsertionMode.IN_TABLE_BODY;
startTagInTableBody(p, token);
}
function tableStartTagInTable(p, token) {
if (p.openElements.hasInTableScope(html$1.TAG_ID.TABLE)) {
p.openElements.popUntilTagNamePopped(html$1.TAG_ID.TABLE);
p._resetInsertionMode();
p._processStartTag(token);
}
}
function inputStartTagInTable(p, token) {
if (isHiddenInput(token)) {
p._appendElement(token, html$1.NS.HTML);
}
else {
tokenInTable(p, token);
}
token.ackSelfClosing = true;
}
function formStartTagInTable(p, token) {
if (!p.formElement && p.openElements.tmplCount === 0) {
p._insertElement(token, html$1.NS.HTML);
p.formElement = p.openElements.current;
p.openElements.pop();
}
}
function startTagInTable(p, token) {
switch (token.tagID) {
case html$1.TAG_ID.TD:
case html$1.TAG_ID.TH:
case html$1.TAG_ID.TR: {
tdStartTagInTable(p, token);
break;
}
case html$1.TAG_ID.STYLE:
case html$1.TAG_ID.SCRIPT:
case html$1.TAG_ID.TEMPLATE: {
startTagInHead(p, token);
break;
}
case html$1.TAG_ID.COL: {
colStartTagInTable(p, token);
break;
}
case html$1.TAG_ID.FORM: {
formStartTagInTable(p, token);
break;
}
case html$1.TAG_ID.TABLE: {
tableStartTagInTable(p, token);
break;
}
case html$1.TAG_ID.TBODY:
case html$1.TAG_ID.TFOOT:
case html$1.TAG_ID.THEAD: {
tbodyStartTagInTable(p, token);
break;
}
case html$1.TAG_ID.INPUT: {
inputStartTagInTable(p, token);
break;
}
case html$1.TAG_ID.CAPTION: {
captionStartTagInTable(p, token);
break;
}
case html$1.TAG_ID.COLGROUP: {
colgroupStartTagInTable(p, token);
break;
}
default: {
tokenInTable(p, token);
}
}
}
function endTagInTable(p, token) {
switch (token.tagID) {
case html$1.TAG_ID.TABLE: {
if (p.openElements.hasInTableScope(html$1.TAG_ID.TABLE)) {
p.openElements.popUntilTagNamePopped(html$1.TAG_ID.TABLE);
p._resetInsertionMode();
}
break;
}
case html$1.TAG_ID.TEMPLATE: {
templateEndTagInHead(p, token);
break;
}
case html$1.TAG_ID.BODY:
case html$1.TAG_ID.CAPTION:
case html$1.TAG_ID.COL:
case html$1.TAG_ID.COLGROUP:
case html$1.TAG_ID.HTML:
case html$1.TAG_ID.TBODY:
case html$1.TAG_ID.TD:
case html$1.TAG_ID.TFOOT:
case html$1.TAG_ID.TH:
case html$1.TAG_ID.THEAD:
case html$1.TAG_ID.TR: {
// Ignore token
break;
}
default: {
tokenInTable(p, token);
}
}
}
function tokenInTable(p, token) {
const savedFosterParentingState = p.fosterParentingEnabled;
p.fosterParentingEnabled = true;
// Process token in `In Body` mode
modeInBody(p, token);
p.fosterParentingEnabled = savedFosterParentingState;
}
// The "in table text" insertion mode
//------------------------------------------------------------------
function whitespaceCharacterInTableText(p, token) {
p.pendingCharacterTokens.push(token);
}
function characterInTableText(p, token) {
p.pendingCharacterTokens.push(token);
p.hasNonWhitespacePendingCharacterToken = true;
}
function tokenInTableText(p, token) {
let i = 0;
if (p.hasNonWhitespacePendingCharacterToken) {
for (; i < p.pendingCharacterTokens.length; i++) {
tokenInTable(p, p.pendingCharacterTokens[i]);
}
}
else {
for (; i < p.pendingCharacterTokens.length; i++) {
p._insertCharacters(p.pendingCharacterTokens[i]);
}
}
p.insertionMode = p.originalInsertionMode;
p._processToken(token);
}
// The "in caption" insertion mode
//------------------------------------------------------------------
const TABLE_VOID_ELEMENTS = new Set([html$1.TAG_ID.CAPTION, html$1.TAG_ID.COL, html$1.TAG_ID.COLGROUP, html$1.TAG_ID.TBODY, html$1.TAG_ID.TD, html$1.TAG_ID.TFOOT, html$1.TAG_ID.TH, html$1.TAG_ID.THEAD, html$1.TAG_ID.TR]);
function startTagInCaption(p, token) {
const tn = token.tagID;
if (TABLE_VOID_ELEMENTS.has(tn)) {
if (p.openElements.hasInTableScope(html$1.TAG_ID.CAPTION)) {
p.openElements.generateImpliedEndTags();
p.openElements.popUntilTagNamePopped(html$1.TAG_ID.CAPTION);
p.activeFormattingElements.clearToLastMarker();
p.insertionMode = InsertionMode.IN_TABLE;
startTagInTable(p, token);
}
}
else {
startTagInBody(p, token);
}
}
function endTagInCaption(p, token) {
const tn = token.tagID;
switch (tn) {
case html$1.TAG_ID.CAPTION:
case html$1.TAG_ID.TABLE: {
if (p.openElements.hasInTableScope(html$1.TAG_ID.CAPTION)) {
p.openElements.generateImpliedEndTags();
p.openElements.popUntilTagNamePopped(html$1.TAG_ID.CAPTION);
p.activeFormattingElements.clearToLastMarker();
p.insertionMode = InsertionMode.IN_TABLE;
if (tn === html$1.TAG_ID.TABLE) {
endTagInTable(p, token);
}
}
break;
}
case html$1.TAG_ID.BODY:
case html$1.TAG_ID.COL:
case html$1.TAG_ID.COLGROUP:
case html$1.TAG_ID.HTML:
case html$1.TAG_ID.TBODY:
case html$1.TAG_ID.TD:
case html$1.TAG_ID.TFOOT:
case html$1.TAG_ID.TH:
case html$1.TAG_ID.THEAD:
case html$1.TAG_ID.TR: {
// Ignore token
break;
}
default: {
endTagInBody(p, token);
}
}
}
// The "in column group" insertion mode
//------------------------------------------------------------------
function startTagInColumnGroup(p, token) {
switch (token.tagID) {
case html$1.TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case html$1.TAG_ID.COL: {
p._appendElement(token, html$1.NS.HTML);
token.ackSelfClosing = true;
break;
}
case html$1.TAG_ID.TEMPLATE: {
startTagInHead(p, token);
break;
}
default: {
tokenInColumnGroup(p, token);
}
}
}
function endTagInColumnGroup(p, token) {
switch (token.tagID) {
case html$1.TAG_ID.COLGROUP: {
if (p.openElements.currentTagId === html$1.TAG_ID.COLGROUP) {
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE;
}
break;
}
case html$1.TAG_ID.TEMPLATE: {
templateEndTagInHead(p, token);
break;
}
case html$1.TAG_ID.COL: {
// Ignore token
break;
}
default: {
tokenInColumnGroup(p, token);
}
}
}
function tokenInColumnGroup(p, token) {
if (p.openElements.currentTagId === html$1.TAG_ID.COLGROUP) {
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE;
p._processToken(token);
}
}
// The "in table body" insertion mode
//------------------------------------------------------------------
function startTagInTableBody(p, token) {
switch (token.tagID) {
case html$1.TAG_ID.TR: {
p.openElements.clearBackToTableBodyContext();
p._insertElement(token, html$1.NS.HTML);
p.insertionMode = InsertionMode.IN_ROW;
break;
}
case html$1.TAG_ID.TH:
case html$1.TAG_ID.TD: {
p.openElements.clearBackToTableBodyContext();
p._insertFakeElement(html$1.TAG_NAMES.TR, html$1.TAG_ID.TR);
p.insertionMode = InsertionMode.IN_ROW;
startTagInRow(p, token);
break;
}
case html$1.TAG_ID.CAPTION:
case html$1.TAG_ID.COL:
case html$1.TAG_ID.COLGROUP:
case html$1.TAG_ID.TBODY:
case html$1.TAG_ID.TFOOT:
case html$1.TAG_ID.THEAD: {
if (p.openElements.hasTableBodyContextInTableScope()) {
p.openElements.clearBackToTableBodyContext();
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE;
startTagInTable(p, token);
}
break;
}
default: {
startTagInTable(p, token);
}
}
}
function endTagInTableBody(p, token) {
const tn = token.tagID;
switch (token.tagID) {
case html$1.TAG_ID.TBODY:
case html$1.TAG_ID.TFOOT:
case html$1.TAG_ID.THEAD: {
if (p.openElements.hasInTableScope(tn)) {
p.openElements.clearBackToTableBodyContext();
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE;
}
break;
}
case html$1.TAG_ID.TABLE: {
if (p.openElements.hasTableBodyContextInTableScope()) {
p.openElements.clearBackToTableBodyContext();
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE;
endTagInTable(p, token);
}
break;
}
case html$1.TAG_ID.BODY:
case html$1.TAG_ID.CAPTION:
case html$1.TAG_ID.COL:
case html$1.TAG_ID.COLGROUP:
case html$1.TAG_ID.HTML:
case html$1.TAG_ID.TD:
case html$1.TAG_ID.TH:
case html$1.TAG_ID.TR: {
// Ignore token
break;
}
default: {
endTagInTable(p, token);
}
}
}
// The "in row" insertion mode
//------------------------------------------------------------------
function startTagInRow(p, token) {
switch (token.tagID) {
case html$1.TAG_ID.TH:
case html$1.TAG_ID.TD: {
p.openElements.clearBackToTableRowContext();
p._insertElement(token, html$1.NS.HTML);
p.insertionMode = InsertionMode.IN_CELL;
p.activeFormattingElements.insertMarker();
break;
}
case html$1.TAG_ID.CAPTION:
case html$1.TAG_ID.COL:
case html$1.TAG_ID.COLGROUP:
case html$1.TAG_ID.TBODY:
case html$1.TAG_ID.TFOOT:
case html$1.TAG_ID.THEAD:
case html$1.TAG_ID.TR: {
if (p.openElements.hasInTableScope(html$1.TAG_ID.TR)) {
p.openElements.clearBackToTableRowContext();
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE_BODY;
startTagInTableBody(p, token);
}
break;
}
default: {
startTagInTable(p, token);
}
}
}
function endTagInRow(p, token) {
switch (token.tagID) {
case html$1.TAG_ID.TR: {
if (p.openElements.hasInTableScope(html$1.TAG_ID.TR)) {
p.openElements.clearBackToTableRowContext();
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE_BODY;
}
break;
}
case html$1.TAG_ID.TABLE: {
if (p.openElements.hasInTableScope(html$1.TAG_ID.TR)) {
p.openElements.clearBackToTableRowContext();
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE_BODY;
endTagInTableBody(p, token);
}
break;
}
case html$1.TAG_ID.TBODY:
case html$1.TAG_ID.TFOOT:
case html$1.TAG_ID.THEAD: {
if (p.openElements.hasInTableScope(token.tagID) || p.openElements.hasInTableScope(html$1.TAG_ID.TR)) {
p.openElements.clearBackToTableRowContext();
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE_BODY;
endTagInTableBody(p, token);
}
break;
}
case html$1.TAG_ID.BODY:
case html$1.TAG_ID.CAPTION:
case html$1.TAG_ID.COL:
case html$1.TAG_ID.COLGROUP:
case html$1.TAG_ID.HTML:
case html$1.TAG_ID.TD:
case html$1.TAG_ID.TH: {
// Ignore end tag
break;
}
default: {
endTagInTable(p, token);
}
}
}
// The "in cell" insertion mode
//------------------------------------------------------------------
function startTagInCell(p, token) {
const tn = token.tagID;
if (TABLE_VOID_ELEMENTS.has(tn)) {
if (p.openElements.hasInTableScope(html$1.TAG_ID.TD) || p.openElements.hasInTableScope(html$1.TAG_ID.TH)) {
p._closeTableCell();
startTagInRow(p, token);
}
}
else {
startTagInBody(p, token);
}
}
function endTagInCell(p, token) {
const tn = token.tagID;
switch (tn) {
case html$1.TAG_ID.TD:
case html$1.TAG_ID.TH: {
if (p.openElements.hasInTableScope(tn)) {
p.openElements.generateImpliedEndTags();
p.openElements.popUntilTagNamePopped(tn);
p.activeFormattingElements.clearToLastMarker();
p.insertionMode = InsertionMode.IN_ROW;
}
break;
}
case html$1.TAG_ID.TABLE:
case html$1.TAG_ID.TBODY:
case html$1.TAG_ID.TFOOT:
case html$1.TAG_ID.THEAD:
case html$1.TAG_ID.TR: {
if (p.openElements.hasInTableScope(tn)) {
p._closeTableCell();
endTagInRow(p, token);
}
break;
}
case html$1.TAG_ID.BODY:
case html$1.TAG_ID.CAPTION:
case html$1.TAG_ID.COL:
case html$1.TAG_ID.COLGROUP:
case html$1.TAG_ID.HTML: {
// Ignore token
break;
}
default: {
endTagInBody(p, token);
}
}
}
// The "in select" insertion mode
//------------------------------------------------------------------
function startTagInSelect(p, token) {
switch (token.tagID) {
case html$1.TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case html$1.TAG_ID.OPTION: {
if (p.openElements.currentTagId === html$1.TAG_ID.OPTION) {
p.openElements.pop();
}
p._insertElement(token, html$1.NS.HTML);
break;
}
case html$1.TAG_ID.OPTGROUP: {
if (p.openElements.currentTagId === html$1.TAG_ID.OPTION) {
p.openElements.pop();
}
if (p.openElements.currentTagId === html$1.TAG_ID.OPTGROUP) {
p.openElements.pop();
}
p._insertElement(token, html$1.NS.HTML);
break;
}
case html$1.TAG_ID.INPUT:
case html$1.TAG_ID.KEYGEN:
case html$1.TAG_ID.TEXTAREA:
case html$1.TAG_ID.SELECT: {
if (p.openElements.hasInSelectScope(html$1.TAG_ID.SELECT)) {
p.openElements.popUntilTagNamePopped(html$1.TAG_ID.SELECT);
p._resetInsertionMode();
if (token.tagID !== html$1.TAG_ID.SELECT) {
p._processStartTag(token);
}
}
break;
}
case html$1.TAG_ID.SCRIPT:
case html$1.TAG_ID.TEMPLATE: {
startTagInHead(p, token);
break;
}
// Do nothing
}
}
function endTagInSelect(p, token) {
switch (token.tagID) {
case html$1.TAG_ID.OPTGROUP: {
if (p.openElements.stackTop > 0 &&
p.openElements.currentTagId === html$1.TAG_ID.OPTION &&
p.openElements.tagIDs[p.openElements.stackTop - 1] === html$1.TAG_ID.OPTGROUP) {
p.openElements.pop();
}
if (p.openElements.currentTagId === html$1.TAG_ID.OPTGROUP) {
p.openElements.pop();
}
break;
}
case html$1.TAG_ID.OPTION: {
if (p.openElements.currentTagId === html$1.TAG_ID.OPTION) {
p.openElements.pop();
}
break;
}
case html$1.TAG_ID.SELECT: {
if (p.openElements.hasInSelectScope(html$1.TAG_ID.SELECT)) {
p.openElements.popUntilTagNamePopped(html$1.TAG_ID.SELECT);
p._resetInsertionMode();
}
break;
}
case html$1.TAG_ID.TEMPLATE: {
templateEndTagInHead(p, token);
break;
}
// Do nothing
}
}
// The "in select in table" insertion mode
//------------------------------------------------------------------
function startTagInSelectInTable(p, token) {
const tn = token.tagID;
if (tn === html$1.TAG_ID.CAPTION ||
tn === html$1.TAG_ID.TABLE ||
tn === html$1.TAG_ID.TBODY ||
tn === html$1.TAG_ID.TFOOT ||
tn === html$1.TAG_ID.THEAD ||
tn === html$1.TAG_ID.TR ||
tn === html$1.TAG_ID.TD ||
tn === html$1.TAG_ID.TH) {
p.openElements.popUntilTagNamePopped(html$1.TAG_ID.SELECT);
p._resetInsertionMode();
p._processStartTag(token);
}
else {
startTagInSelect(p, token);
}
}
function endTagInSelectInTable(p, token) {
const tn = token.tagID;
if (tn === html$1.TAG_ID.CAPTION ||
tn === html$1.TAG_ID.TABLE ||
tn === html$1.TAG_ID.TBODY ||
tn === html$1.TAG_ID.TFOOT ||
tn === html$1.TAG_ID.THEAD ||
tn === html$1.TAG_ID.TR ||
tn === html$1.TAG_ID.TD ||
tn === html$1.TAG_ID.TH) {
if (p.openElements.hasInTableScope(tn)) {
p.openElements.popUntilTagNamePopped(html$1.TAG_ID.SELECT);
p._resetInsertionMode();
p.onEndTag(token);
}
}
else {
endTagInSelect(p, token);
}
}
// The "in template" insertion mode
//------------------------------------------------------------------
function startTagInTemplate(p, token) {
switch (token.tagID) {
// First, handle tags that can start without a mode change
case html$1.TAG_ID.BASE:
case html$1.TAG_ID.BASEFONT:
case html$1.TAG_ID.BGSOUND:
case html$1.TAG_ID.LINK:
case html$1.TAG_ID.META:
case html$1.TAG_ID.NOFRAMES:
case html$1.TAG_ID.SCRIPT:
case html$1.TAG_ID.STYLE:
case html$1.TAG_ID.TEMPLATE:
case html$1.TAG_ID.TITLE: {
startTagInHead(p, token);
break;
}
// Re-process the token in the appropriate mode
case html$1.TAG_ID.CAPTION:
case html$1.TAG_ID.COLGROUP:
case html$1.TAG_ID.TBODY:
case html$1.TAG_ID.TFOOT:
case html$1.TAG_ID.THEAD: {
p.tmplInsertionModeStack[0] = InsertionMode.IN_TABLE;
p.insertionMode = InsertionMode.IN_TABLE;
startTagInTable(p, token);
break;
}
case html$1.TAG_ID.COL: {
p.tmplInsertionModeStack[0] = InsertionMode.IN_COLUMN_GROUP;
p.insertionMode = InsertionMode.IN_COLUMN_GROUP;
startTagInColumnGroup(p, token);
break;
}
case html$1.TAG_ID.TR: {
p.tmplInsertionModeStack[0] = InsertionMode.IN_TABLE_BODY;
p.insertionMode = InsertionMode.IN_TABLE_BODY;
startTagInTableBody(p, token);
break;
}
case html$1.TAG_ID.TD:
case html$1.TAG_ID.TH: {
p.tmplInsertionModeStack[0] = InsertionMode.IN_ROW;
p.insertionMode = InsertionMode.IN_ROW;
startTagInRow(p, token);
break;
}
default: {
p.tmplInsertionModeStack[0] = InsertionMode.IN_BODY;
p.insertionMode = InsertionMode.IN_BODY;
startTagInBody(p, token);
}
}
}
function endTagInTemplate(p, token) {
if (token.tagID === html$1.TAG_ID.TEMPLATE) {
templateEndTagInHead(p, token);
}
}
function eofInTemplate(p, token) {
if (p.openElements.tmplCount > 0) {
p.openElements.popUntilTagNamePopped(html$1.TAG_ID.TEMPLATE);
p.activeFormattingElements.clearToLastMarker();
p.tmplInsertionModeStack.shift();
p._resetInsertionMode();
p.onEof(token);
}
else {
stopParsing(p, token);
}
}
// The "after body" insertion mode
//------------------------------------------------------------------
function startTagAfterBody(p, token) {
if (token.tagID === html$1.TAG_ID.HTML) {
startTagInBody(p, token);
}
else {
tokenAfterBody(p, token);
}
}
function endTagAfterBody(p, token) {
var _a;
if (token.tagID === html$1.TAG_ID.HTML) {
if (!p.fragmentContext) {
p.insertionMode = InsertionMode.AFTER_AFTER_BODY;
}
//NOTE: <html> is never popped from the stack, so we need to updated
//the end location explicitly.
if (p.options.sourceCodeLocationInfo && p.openElements.tagIDs[0] === html$1.TAG_ID.HTML) {
p._setEndLocation(p.openElements.items[0], token);
// Update the body element, if it doesn't have an end tag
const bodyElement = p.openElements.items[1];
if (bodyElement && !((_a = p.treeAdapter.getNodeSourceCodeLocation(bodyElement)) === null || _a === void 0 ? void 0 : _a.endTag)) {
p._setEndLocation(bodyElement, token);
}
}
}
else {
tokenAfterBody(p, token);
}
}
function tokenAfterBody(p, token) {
p.insertionMode = InsertionMode.IN_BODY;
modeInBody(p, token);
}
// The "in frameset" insertion mode
//------------------------------------------------------------------
function startTagInFrameset(p, token) {
switch (token.tagID) {
case html$1.TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case html$1.TAG_ID.FRAMESET: {
p._insertElement(token, html$1.NS.HTML);
break;
}
case html$1.TAG_ID.FRAME: {
p._appendElement(token, html$1.NS.HTML);
token.ackSelfClosing = true;
break;
}
case html$1.TAG_ID.NOFRAMES: {
startTagInHead(p, token);
break;
}
// Do nothing
}
}
function endTagInFrameset(p, token) {
if (token.tagID === html$1.TAG_ID.FRAMESET && !p.openElements.isRootHtmlElementCurrent()) {
p.openElements.pop();
if (!p.fragmentContext && p.openElements.currentTagId !== html$1.TAG_ID.FRAMESET) {
p.insertionMode = InsertionMode.AFTER_FRAMESET;
}
}
}
// The "after frameset" insertion mode
//------------------------------------------------------------------
function startTagAfterFrameset(p, token) {
switch (token.tagID) {
case html$1.TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case html$1.TAG_ID.NOFRAMES: {
startTagInHead(p, token);
break;
}
// Do nothing
}
}
function endTagAfterFrameset(p, token) {
if (token.tagID === html$1.TAG_ID.HTML) {
p.insertionMode = InsertionMode.AFTER_AFTER_FRAMESET;
}
}
// The "after after body" insertion mode
//------------------------------------------------------------------
function startTagAfterAfterBody(p, token) {
if (token.tagID === html$1.TAG_ID.HTML) {
startTagInBody(p, token);
}
else {
tokenAfterAfterBody(p, token);
}
}
function tokenAfterAfterBody(p, token) {
p.insertionMode = InsertionMode.IN_BODY;
modeInBody(p, token);
}
// The "after after frameset" insertion mode
//------------------------------------------------------------------
function startTagAfterAfterFrameset(p, token) {
switch (token.tagID) {
case html$1.TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case html$1.TAG_ID.NOFRAMES: {
startTagInHead(p, token);
break;
}
// Do nothing
}
}
// The rules for parsing tokens in foreign content
//------------------------------------------------------------------
function nullCharacterInForeignContent(p, token) {
token.chars = unicode$1.REPLACEMENT_CHARACTER;
p._insertCharacters(token);
}
function characterInForeignContent(p, token) {
p._insertCharacters(token);
p.framesetOk = false;
}
function popUntilHtmlOrIntegrationPoint(p) {
while (p.treeAdapter.getNamespaceURI(p.openElements.current) !== html$1.NS.HTML &&
!p._isIntegrationPoint(p.openElements.currentTagId, p.openElements.current)) {
p.openElements.pop();
}
}
function startTagInForeignContent(p, token) {
if (foreignContent$1.causesExit(token)) {
popUntilHtmlOrIntegrationPoint(p);
p._startTagOutsideForeignContent(token);
}
else {
const current = p._getAdjustedCurrentElement();
const currentNs = p.treeAdapter.getNamespaceURI(current);
if (currentNs === html$1.NS.MATHML) {
foreignContent$1.adjustTokenMathMLAttrs(token);
}
else if (currentNs === html$1.NS.SVG) {
foreignContent$1.adjustTokenSVGTagName(token);
foreignContent$1.adjustTokenSVGAttrs(token);
}
foreignContent$1.adjustTokenXMLAttrs(token);
if (token.selfClosing) {
p._appendElement(token, currentNs);
}
else {
p._insertElement(token, currentNs);
}
token.ackSelfClosing = true;
}
}
function endTagInForeignContent(p, token) {
if (token.tagID === html$1.TAG_ID.P || token.tagID === html$1.TAG_ID.BR) {
popUntilHtmlOrIntegrationPoint(p);
p._endTagOutsideForeignContent(token);
return;
}
for (let i = p.openElements.stackTop; i > 0; i--) {
const element = p.openElements.items[i];
if (p.treeAdapter.getNamespaceURI(element) === html$1.NS.HTML) {
p._endTagOutsideForeignContent(token);
break;
}
const tagName = p.treeAdapter.getTagName(element);
if (tagName.toLowerCase() === token.tagName) {
//NOTE: update the token tag name for `_setEndLocation`.
token.tagName = tagName;
p.openElements.shortenToLength(i);
break;
}
}
}
});
var serializer$1 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.serializeOuter = exports.serialize = void 0;
// Sets
const VOID_ELEMENTS = new Set([
html$1.TAG_NAMES.AREA,
html$1.TAG_NAMES.BASE,
html$1.TAG_NAMES.BASEFONT,
html$1.TAG_NAMES.BGSOUND,
html$1.TAG_NAMES.BR,
html$1.TAG_NAMES.COL,
html$1.TAG_NAMES.EMBED,
html$1.TAG_NAMES.FRAME,
html$1.TAG_NAMES.HR,
html$1.TAG_NAMES.IMG,
html$1.TAG_NAMES.INPUT,
html$1.TAG_NAMES.KEYGEN,
html$1.TAG_NAMES.LINK,
html$1.TAG_NAMES.META,
html$1.TAG_NAMES.PARAM,
html$1.TAG_NAMES.SOURCE,
html$1.TAG_NAMES.TRACK,
html$1.TAG_NAMES.WBR,
]);
function isVoidElement(node, options) {
return (options.treeAdapter.isElementNode(node) &&
options.treeAdapter.getNamespaceURI(node) === html$1.NS.HTML &&
VOID_ELEMENTS.has(options.treeAdapter.getTagName(node)));
}
const defaultOpts = { treeAdapter: _default$2.defaultTreeAdapter, scriptingEnabled: true };
/**
* Serializes an AST node to an HTML string.
*
* @example
*
* ```js
* const parse5 = require('parse5');
*
* const document = parse5.parse('<!DOCTYPE html><html><head></head><body>Hi there!</body></html>');
*
* // Serializes a document.
* const html = parse5.serialize(document);
*
* // Serializes the <html> element content.
* const str = parse5.serialize(document.childNodes[1]);
*
* console.log(str); //> '<head></head><body>Hi there!</body>'
* ```
*
* @param node Node to serialize.
* @param options Serialization options.
*/
function serialize(node, options) {
const opts = Object.assign(Object.assign({}, defaultOpts), options);
if (isVoidElement(node, opts)) {
return '';
}
return serializeChildNodes(node, opts);
}
exports.serialize = serialize;
/**
* Serializes an AST element node to an HTML string, including the element node.
*
* @example
*
* ```js
* const parse5 = require('parse5');
*
* const document = parse5.parseFragment('<div>Hello, <b>world</b>!</div>');
*
* // Serializes the <div> element.
* const html = parse5.serializeOuter(document.childNodes[0]);
*
* console.log(str); //> '<div>Hello, <b>world</b>!</div>'
* ```
*
* @param node Node to serialize.
* @param options Serialization options.
*/
function serializeOuter(node, options) {
const opts = Object.assign(Object.assign({}, defaultOpts), options);
return serializeNode(node, opts);
}
exports.serializeOuter = serializeOuter;
function serializeChildNodes(parentNode, options) {
let html = '';
// Get container of the child nodes
const container = options.treeAdapter.isElementNode(parentNode) &&
options.treeAdapter.getTagName(parentNode) === html$1.TAG_NAMES.TEMPLATE &&
options.treeAdapter.getNamespaceURI(parentNode) === html$1.NS.HTML
? options.treeAdapter.getTemplateContent(parentNode)
: parentNode;
const childNodes = options.treeAdapter.getChildNodes(container);
if (childNodes) {
for (const currentNode of childNodes) {
html += serializeNode(currentNode, options);
}
}
return html;
}
function serializeNode(node, options) {
if (options.treeAdapter.isElementNode(node)) {
return serializeElement(node, options);
}
if (options.treeAdapter.isTextNode(node)) {
return serializeTextNode(node, options);
}
if (options.treeAdapter.isCommentNode(node)) {
return serializeCommentNode(node, options);
}
if (options.treeAdapter.isDocumentTypeNode(node)) {
return serializeDocumentTypeNode(node, options);
}
// Return an empty string for unknown nodes
return '';
}
function serializeElement(node, options) {
const tn = options.treeAdapter.getTagName(node);
return `<${tn}${serializeAttributes(node, options)}>${isVoidElement(node, options) ? '' : `${serializeChildNodes(node, options)}</${tn}>`}`;
}
function serializeAttributes(node, { treeAdapter }) {
let html = '';
for (const attr of treeAdapter.getAttrList(node)) {
html += ' ';
if (!attr.namespace) {
html += attr.name;
}
else
switch (attr.namespace) {
case html$1.NS.XML: {
html += `xml:${attr.name}`;
break;
}
case html$1.NS.XMLNS: {
if (attr.name !== 'xmlns') {
html += 'xmlns:';
}
html += attr.name;
break;
}
case html$1.NS.XLINK: {
html += `xlink:${attr.name}`;
break;
}
default: {
html += `${attr.prefix}:${attr.name}`;
}
}
html += `="${(0, escape_js_1.escapeAttribute)(attr.value)}"`;
}
return html;
}
function serializeTextNode(node, options) {
const { treeAdapter } = options;
const content = treeAdapter.getTextNodeContent(node);
const parent = treeAdapter.getParentNode(node);
const parentTn = parent && treeAdapter.isElementNode(parent) && treeAdapter.getTagName(parent);
return parentTn &&
treeAdapter.getNamespaceURI(parent) === html$1.NS.HTML &&
(0, html$1.hasUnescapedText)(parentTn, options.scriptingEnabled)
? content
: (0, escape_js_1.escapeText)(content);
}
function serializeCommentNode(node, { treeAdapter }) {
return `<!--${treeAdapter.getCommentNodeContent(node)}-->`;
}
function serializeDocumentTypeNode(node, { treeAdapter }) {
return `<!DOCTYPE ${treeAdapter.getDocumentTypeNodeName(node)}>`;
}
});
var cjs$2 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseFragment = exports.parse = exports.TokenizerMode = exports.Tokenizer = exports.Token = exports.html = exports.foreignContent = exports.ErrorCodes = exports.serializeOuter = exports.serialize = exports.Parser = exports.defaultTreeAdapter = void 0;
Object.defineProperty(exports, "defaultTreeAdapter", { enumerable: true, get: function () { return _default$2.defaultTreeAdapter; } });
var index_js_2 = parser$1;
Object.defineProperty(exports, "Parser", { enumerable: true, get: function () { return index_js_2.Parser; } });
Object.defineProperty(exports, "serialize", { enumerable: true, get: function () { return serializer$1.serialize; } });
Object.defineProperty(exports, "serializeOuter", { enumerable: true, get: function () { return serializer$1.serializeOuter; } });
Object.defineProperty(exports, "ErrorCodes", { enumerable: true, get: function () { return errorCodes$1.ERR; } });
/** @internal */
exports.foreignContent = foreignContent$1;
/** @internal */
exports.html = html$1;
/** @internal */
exports.Token = token$1;
/** @internal */
Object.defineProperty(exports, "Tokenizer", { enumerable: true, get: function () { return tokenizer$1.Tokenizer; } });
Object.defineProperty(exports, "TokenizerMode", { enumerable: true, get: function () { return tokenizer$1.TokenizerMode; } });
// Shorthands
/**
* Parses an HTML string.
*
* @param html Input HTML string.
* @param options Parsing options.
* @returns Document
*
* @example
*
* ```js
* const parse5 = require('parse5');
*
* const document = parse5.parse('<!DOCTYPE html><html><head></head><body>Hi there!</body></html>');
*
* console.log(document.childNodes[1].tagName); //> 'html'
*```
*/
function parse(html, options) {
return parser$1.Parser.parse(html, options);
}
exports.parse = parse;
function parseFragment(fragmentContext, html, options) {
if (typeof fragmentContext === 'string') {
options = html;
html = fragmentContext;
fragmentContext = null;
}
const parser = parser$1.Parser.getFragmentParser(fragmentContext, options);
parser.tokenizer.write(html, true);
return parser.getFragment();
}
exports.parseFragment = parseFragment;
});
var unicode = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.isUndefinedCodePoint = exports.isControlCodePoint = exports.getSurrogatePairCodePoint = exports.isSurrogatePair = exports.isSurrogate = exports.SEQUENCES = exports.CODE_POINTS = exports.REPLACEMENT_CHARACTER = void 0;
const UNDEFINED_CODE_POINTS = new Set([
65534, 65535, 131070, 131071, 196606, 196607, 262142, 262143, 327678, 327679, 393214,
393215, 458750, 458751, 524286, 524287, 589822, 589823, 655358, 655359, 720894,
720895, 786430, 786431, 851966, 851967, 917502, 917503, 983038, 983039, 1048574,
1048575, 1114110, 1114111,
]);
exports.REPLACEMENT_CHARACTER = '\uFFFD';
(function (CODE_POINTS) {
CODE_POINTS[CODE_POINTS["EOF"] = -1] = "EOF";
CODE_POINTS[CODE_POINTS["NULL"] = 0] = "NULL";
CODE_POINTS[CODE_POINTS["TABULATION"] = 9] = "TABULATION";
CODE_POINTS[CODE_POINTS["CARRIAGE_RETURN"] = 13] = "CARRIAGE_RETURN";
CODE_POINTS[CODE_POINTS["LINE_FEED"] = 10] = "LINE_FEED";
CODE_POINTS[CODE_POINTS["FORM_FEED"] = 12] = "FORM_FEED";
CODE_POINTS[CODE_POINTS["SPACE"] = 32] = "SPACE";
CODE_POINTS[CODE_POINTS["EXCLAMATION_MARK"] = 33] = "EXCLAMATION_MARK";
CODE_POINTS[CODE_POINTS["QUOTATION_MARK"] = 34] = "QUOTATION_MARK";
CODE_POINTS[CODE_POINTS["NUMBER_SIGN"] = 35] = "NUMBER_SIGN";
CODE_POINTS[CODE_POINTS["AMPERSAND"] = 38] = "AMPERSAND";
CODE_POINTS[CODE_POINTS["APOSTROPHE"] = 39] = "APOSTROPHE";
CODE_POINTS[CODE_POINTS["HYPHEN_MINUS"] = 45] = "HYPHEN_MINUS";
CODE_POINTS[CODE_POINTS["SOLIDUS"] = 47] = "SOLIDUS";
CODE_POINTS[CODE_POINTS["DIGIT_0"] = 48] = "DIGIT_0";
CODE_POINTS[CODE_POINTS["DIGIT_9"] = 57] = "DIGIT_9";
CODE_POINTS[CODE_POINTS["SEMICOLON"] = 59] = "SEMICOLON";
CODE_POINTS[CODE_POINTS["LESS_THAN_SIGN"] = 60] = "LESS_THAN_SIGN";
CODE_POINTS[CODE_POINTS["EQUALS_SIGN"] = 61] = "EQUALS_SIGN";
CODE_POINTS[CODE_POINTS["GREATER_THAN_SIGN"] = 62] = "GREATER_THAN_SIGN";
CODE_POINTS[CODE_POINTS["QUESTION_MARK"] = 63] = "QUESTION_MARK";
CODE_POINTS[CODE_POINTS["LATIN_CAPITAL_A"] = 65] = "LATIN_CAPITAL_A";
CODE_POINTS[CODE_POINTS["LATIN_CAPITAL_F"] = 70] = "LATIN_CAPITAL_F";
CODE_POINTS[CODE_POINTS["LATIN_CAPITAL_X"] = 88] = "LATIN_CAPITAL_X";
CODE_POINTS[CODE_POINTS["LATIN_CAPITAL_Z"] = 90] = "LATIN_CAPITAL_Z";
CODE_POINTS[CODE_POINTS["RIGHT_SQUARE_BRACKET"] = 93] = "RIGHT_SQUARE_BRACKET";
CODE_POINTS[CODE_POINTS["GRAVE_ACCENT"] = 96] = "GRAVE_ACCENT";
CODE_POINTS[CODE_POINTS["LATIN_SMALL_A"] = 97] = "LATIN_SMALL_A";
CODE_POINTS[CODE_POINTS["LATIN_SMALL_F"] = 102] = "LATIN_SMALL_F";
CODE_POINTS[CODE_POINTS["LATIN_SMALL_X"] = 120] = "LATIN_SMALL_X";
CODE_POINTS[CODE_POINTS["LATIN_SMALL_Z"] = 122] = "LATIN_SMALL_Z";
CODE_POINTS[CODE_POINTS["REPLACEMENT_CHARACTER"] = 65533] = "REPLACEMENT_CHARACTER";
})(exports.CODE_POINTS || (exports.CODE_POINTS = {}));
exports.SEQUENCES = {
DASH_DASH: '--',
CDATA_START: '[CDATA[',
DOCTYPE: 'doctype',
SCRIPT: 'script',
PUBLIC: 'public',
SYSTEM: 'system',
};
//Surrogates
function isSurrogate(cp) {
return cp >= 55296 && cp <= 57343;
}
exports.isSurrogate = isSurrogate;
function isSurrogatePair(cp) {
return cp >= 56320 && cp <= 57343;
}
exports.isSurrogatePair = isSurrogatePair;
function getSurrogatePairCodePoint(cp1, cp2) {
return (cp1 - 55296) * 1024 + 9216 + cp2;
}
exports.getSurrogatePairCodePoint = getSurrogatePairCodePoint;
//NOTE: excluding NULL and ASCII whitespace
function isControlCodePoint(cp) {
return ((cp !== 0x20 && cp !== 0x0a && cp !== 0x0d && cp !== 0x09 && cp !== 0x0c && cp >= 0x01 && cp <= 0x1f) ||
(cp >= 0x7f && cp <= 0x9f));
}
exports.isControlCodePoint = isControlCodePoint;
function isUndefinedCodePoint(cp) {
return (cp >= 64976 && cp <= 65007) || UNDEFINED_CODE_POINTS.has(cp);
}
exports.isUndefinedCodePoint = isUndefinedCodePoint;
});
var errorCodes = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.ERR = void 0;
(function (ERR) {
ERR["controlCharacterInInputStream"] = "control-character-in-input-stream";
ERR["noncharacterInInputStream"] = "noncharacter-in-input-stream";
ERR["surrogateInInputStream"] = "surrogate-in-input-stream";
ERR["nonVoidHtmlElementStartTagWithTrailingSolidus"] = "non-void-html-element-start-tag-with-trailing-solidus";
ERR["endTagWithAttributes"] = "end-tag-with-attributes";
ERR["endTagWithTrailingSolidus"] = "end-tag-with-trailing-solidus";
ERR["unexpectedSolidusInTag"] = "unexpected-solidus-in-tag";
ERR["unexpectedNullCharacter"] = "unexpected-null-character";
ERR["unexpectedQuestionMarkInsteadOfTagName"] = "unexpected-question-mark-instead-of-tag-name";
ERR["invalidFirstCharacterOfTagName"] = "invalid-first-character-of-tag-name";
ERR["unexpectedEqualsSignBeforeAttributeName"] = "unexpected-equals-sign-before-attribute-name";
ERR["missingEndTagName"] = "missing-end-tag-name";
ERR["unexpectedCharacterInAttributeName"] = "unexpected-character-in-attribute-name";
ERR["unknownNamedCharacterReference"] = "unknown-named-character-reference";
ERR["missingSemicolonAfterCharacterReference"] = "missing-semicolon-after-character-reference";
ERR["unexpectedCharacterAfterDoctypeSystemIdentifier"] = "unexpected-character-after-doctype-system-identifier";
ERR["unexpectedCharacterInUnquotedAttributeValue"] = "unexpected-character-in-unquoted-attribute-value";
ERR["eofBeforeTagName"] = "eof-before-tag-name";
ERR["eofInTag"] = "eof-in-tag";
ERR["missingAttributeValue"] = "missing-attribute-value";
ERR["missingWhitespaceBetweenAttributes"] = "missing-whitespace-between-attributes";
ERR["missingWhitespaceAfterDoctypePublicKeyword"] = "missing-whitespace-after-doctype-public-keyword";
ERR["missingWhitespaceBetweenDoctypePublicAndSystemIdentifiers"] = "missing-whitespace-between-doctype-public-and-system-identifiers";
ERR["missingWhitespaceAfterDoctypeSystemKeyword"] = "missing-whitespace-after-doctype-system-keyword";
ERR["missingQuoteBeforeDoctypePublicIdentifier"] = "missing-quote-before-doctype-public-identifier";
ERR["missingQuoteBeforeDoctypeSystemIdentifier"] = "missing-quote-before-doctype-system-identifier";
ERR["missingDoctypePublicIdentifier"] = "missing-doctype-public-identifier";
ERR["missingDoctypeSystemIdentifier"] = "missing-doctype-system-identifier";
ERR["abruptDoctypePublicIdentifier"] = "abrupt-doctype-public-identifier";
ERR["abruptDoctypeSystemIdentifier"] = "abrupt-doctype-system-identifier";
ERR["cdataInHtmlContent"] = "cdata-in-html-content";
ERR["incorrectlyOpenedComment"] = "incorrectly-opened-comment";
ERR["eofInScriptHtmlCommentLikeText"] = "eof-in-script-html-comment-like-text";
ERR["eofInDoctype"] = "eof-in-doctype";
ERR["nestedComment"] = "nested-comment";
ERR["abruptClosingOfEmptyComment"] = "abrupt-closing-of-empty-comment";
ERR["eofInComment"] = "eof-in-comment";
ERR["incorrectlyClosedComment"] = "incorrectly-closed-comment";
ERR["eofInCdata"] = "eof-in-cdata";
ERR["absenceOfDigitsInNumericCharacterReference"] = "absence-of-digits-in-numeric-character-reference";
ERR["nullCharacterReference"] = "null-character-reference";
ERR["surrogateCharacterReference"] = "surrogate-character-reference";
ERR["characterReferenceOutsideUnicodeRange"] = "character-reference-outside-unicode-range";
ERR["controlCharacterReference"] = "control-character-reference";
ERR["noncharacterCharacterReference"] = "noncharacter-character-reference";
ERR["missingWhitespaceBeforeDoctypeName"] = "missing-whitespace-before-doctype-name";
ERR["missingDoctypeName"] = "missing-doctype-name";
ERR["invalidCharacterSequenceAfterDoctypeName"] = "invalid-character-sequence-after-doctype-name";
ERR["duplicateAttribute"] = "duplicate-attribute";
ERR["nonConformingDoctype"] = "non-conforming-doctype";
ERR["missingDoctype"] = "missing-doctype";
ERR["misplacedDoctype"] = "misplaced-doctype";
ERR["endTagWithoutMatchingOpenElement"] = "end-tag-without-matching-open-element";
ERR["closingOfElementWithOpenChildElements"] = "closing-of-element-with-open-child-elements";
ERR["disallowedContentInNoscriptInHead"] = "disallowed-content-in-noscript-in-head";
ERR["openElementsLeftAfterEof"] = "open-elements-left-after-eof";
ERR["abandonedHeadElementChild"] = "abandoned-head-element-child";
ERR["misplacedStartTagForHeadElement"] = "misplaced-start-tag-for-head-element";
ERR["nestedNoscriptInHead"] = "nested-noscript-in-head";
ERR["eofInElementThatCanContainOnlyText"] = "eof-in-element-that-can-contain-only-text";
})(exports.ERR || (exports.ERR = {}));
});
var preprocessor = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.Preprocessor = void 0;
//Const
const DEFAULT_BUFFER_WATERLINE = 1 << 16;
//Preprocessor
//NOTE: HTML input preprocessing
//(see: http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#preprocessing-the-input-stream)
class Preprocessor {
constructor(handler) {
this.handler = handler;
this.html = '';
this.pos = -1;
// NOTE: Initial `lastGapPos` is -2, to ensure `col` on initialisation is 0
this.lastGapPos = -2;
this.gapStack = [];
this.skipNextNewLine = false;
this.lastChunkWritten = false;
this.endOfChunkHit = false;
this.bufferWaterline = DEFAULT_BUFFER_WATERLINE;
this.isEol = false;
this.lineStartPos = 0;
this.droppedBufferSize = 0;
this.line = 1;
//NOTE: avoid reporting errors twice on advance/retreat
this.lastErrOffset = -1;
}
/** The column on the current line. If we just saw a gap (eg. a surrogate pair), return the index before. */
get col() {
return this.pos - this.lineStartPos + Number(this.lastGapPos !== this.pos);
}
get offset() {
return this.droppedBufferSize + this.pos;
}
getError(code) {
const { line, col, offset } = this;
return {
code,
startLine: line,
endLine: line,
startCol: col,
endCol: col,
startOffset: offset,
endOffset: offset,
};
}
_err(code) {
if (this.handler.onParseError && this.lastErrOffset !== this.offset) {
this.lastErrOffset = this.offset;
this.handler.onParseError(this.getError(code));
}
}
_addGap() {
this.gapStack.push(this.lastGapPos);
this.lastGapPos = this.pos;
}
_processSurrogate(cp) {
//NOTE: try to peek a surrogate pair
if (this.pos !== this.html.length - 1) {
const nextCp = this.html.charCodeAt(this.pos + 1);
if ((0, unicode.isSurrogatePair)(nextCp)) {
//NOTE: we have a surrogate pair. Peek pair character and recalculate code point.
this.pos++;
//NOTE: add a gap that should be avoided during retreat
this._addGap();
return (0, unicode.getSurrogatePairCodePoint)(cp, nextCp);
}
}
//NOTE: we are at the end of a chunk, therefore we can't infer the surrogate pair yet.
else if (!this.lastChunkWritten) {
this.endOfChunkHit = true;
return unicode.CODE_POINTS.EOF;
}
//NOTE: isolated surrogate
this._err(errorCodes.ERR.surrogateInInputStream);
return cp;
}
willDropParsedChunk() {
return this.pos > this.bufferWaterline;
}
dropParsedChunk() {
if (this.willDropParsedChunk()) {
this.html = this.html.substring(this.pos);
this.lineStartPos -= this.pos;
this.droppedBufferSize += this.pos;
this.pos = 0;
this.lastGapPos = -2;
this.gapStack.length = 0;
}
}
write(chunk, isLastChunk) {
if (this.html.length > 0) {
this.html += chunk;
}
else {
this.html = chunk;
}
this.endOfChunkHit = false;
this.lastChunkWritten = isLastChunk;
}
insertHtmlAtCurrentPos(chunk) {
this.html = this.html.substring(0, this.pos + 1) + chunk + this.html.substring(this.pos + 1);
this.endOfChunkHit = false;
}
startsWith(pattern, caseSensitive) {
// Check if our buffer has enough characters
if (this.pos + pattern.length > this.html.length) {
this.endOfChunkHit = !this.lastChunkWritten;
return false;
}
if (caseSensitive) {
return this.html.startsWith(pattern, this.pos);
}
for (let i = 0; i < pattern.length; i++) {
const cp = this.html.charCodeAt(this.pos + i) | 0x20;
if (cp !== pattern.charCodeAt(i)) {
return false;
}
}
return true;
}
peek(offset) {
const pos = this.pos + offset;
if (pos >= this.html.length) {
this.endOfChunkHit = !this.lastChunkWritten;
return unicode.CODE_POINTS.EOF;
}
const code = this.html.charCodeAt(pos);
return code === unicode.CODE_POINTS.CARRIAGE_RETURN ? unicode.CODE_POINTS.LINE_FEED : code;
}
advance() {
this.pos++;
//NOTE: LF should be in the last column of the line
if (this.isEol) {
this.isEol = false;
this.line++;
this.lineStartPos = this.pos;
}
if (this.pos >= this.html.length) {
this.endOfChunkHit = !this.lastChunkWritten;
return unicode.CODE_POINTS.EOF;
}
let cp = this.html.charCodeAt(this.pos);
//NOTE: all U+000D CARRIAGE RETURN (CR) characters must be converted to U+000A LINE FEED (LF) characters
if (cp === unicode.CODE_POINTS.CARRIAGE_RETURN) {
this.isEol = true;
this.skipNextNewLine = true;
return unicode.CODE_POINTS.LINE_FEED;
}
//NOTE: any U+000A LINE FEED (LF) characters that immediately follow a U+000D CARRIAGE RETURN (CR) character
//must be ignored.
if (cp === unicode.CODE_POINTS.LINE_FEED) {
this.isEol = true;
if (this.skipNextNewLine) {
// `line` will be bumped again in the recursive call.
this.line--;
this.skipNextNewLine = false;
this._addGap();
return this.advance();
}
}
this.skipNextNewLine = false;
if ((0, unicode.isSurrogate)(cp)) {
cp = this._processSurrogate(cp);
}
//OPTIMIZATION: first check if code point is in the common allowed
//range (ASCII alphanumeric, whitespaces, big chunk of BMP)
//before going into detailed performance cost validation.
const isCommonValidRange = this.handler.onParseError === null ||
(cp > 0x1f && cp < 0x7f) ||
cp === unicode.CODE_POINTS.LINE_FEED ||
cp === unicode.CODE_POINTS.CARRIAGE_RETURN ||
(cp > 0x9f && cp < 64976);
if (!isCommonValidRange) {
this._checkForProblematicCharacters(cp);
}
return cp;
}
_checkForProblematicCharacters(cp) {
if ((0, unicode.isControlCodePoint)(cp)) {
this._err(errorCodes.ERR.controlCharacterInInputStream);
}
else if ((0, unicode.isUndefinedCodePoint)(cp)) {
this._err(errorCodes.ERR.noncharacterInInputStream);
}
}
retreat(count) {
this.pos -= count;
while (this.pos < this.lastGapPos) {
this.lastGapPos = this.gapStack.pop();
this.pos--;
}
this.isEol = false;
}
}
exports.Preprocessor = Preprocessor;
});
var token = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.getTokenAttr = exports.TokenType = void 0;
(function (TokenType) {
TokenType[TokenType["CHARACTER"] = 0] = "CHARACTER";
TokenType[TokenType["NULL_CHARACTER"] = 1] = "NULL_CHARACTER";
TokenType[TokenType["WHITESPACE_CHARACTER"] = 2] = "WHITESPACE_CHARACTER";
TokenType[TokenType["START_TAG"] = 3] = "START_TAG";
TokenType[TokenType["END_TAG"] = 4] = "END_TAG";
TokenType[TokenType["COMMENT"] = 5] = "COMMENT";
TokenType[TokenType["DOCTYPE"] = 6] = "DOCTYPE";
TokenType[TokenType["EOF"] = 7] = "EOF";
TokenType[TokenType["HIBERNATION"] = 8] = "HIBERNATION";
})(exports.TokenType || (exports.TokenType = {}));
function getTokenAttr(token, attrName) {
for (let i = token.attrs.length - 1; i >= 0; i--) {
if (token.attrs[i].name === attrName) {
return token.attrs[i].value;
}
}
return null;
}
exports.getTokenAttr = getTokenAttr;
});
var html = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.hasUnescapedText = exports.isNumberedHeader = exports.SPECIAL_ELEMENTS = exports.getTagID = exports.TAG_ID = exports.TAG_NAMES = exports.DOCUMENT_MODE = exports.ATTRS = exports.NS = void 0;
/** All valid namespaces in HTML. */
var NS;
(function (NS) {
NS["HTML"] = "http://www.w3.org/1999/xhtml";
NS["MATHML"] = "http://www.w3.org/1998/Math/MathML";
NS["SVG"] = "http://www.w3.org/2000/svg";
NS["XLINK"] = "http://www.w3.org/1999/xlink";
NS["XML"] = "http://www.w3.org/XML/1998/namespace";
NS["XMLNS"] = "http://www.w3.org/2000/xmlns/";
})(NS = exports.NS || (exports.NS = {}));
(function (ATTRS) {
ATTRS["TYPE"] = "type";
ATTRS["ACTION"] = "action";
ATTRS["ENCODING"] = "encoding";
ATTRS["PROMPT"] = "prompt";
ATTRS["NAME"] = "name";
ATTRS["COLOR"] = "color";
ATTRS["FACE"] = "face";
ATTRS["SIZE"] = "size";
})(exports.ATTRS || (exports.ATTRS = {}));
(function (DOCUMENT_MODE) {
DOCUMENT_MODE["NO_QUIRKS"] = "no-quirks";
DOCUMENT_MODE["QUIRKS"] = "quirks";
DOCUMENT_MODE["LIMITED_QUIRKS"] = "limited-quirks";
})(exports.DOCUMENT_MODE || (exports.DOCUMENT_MODE = {}));
var TAG_NAMES;
(function (TAG_NAMES) {
TAG_NAMES["A"] = "a";
TAG_NAMES["ADDRESS"] = "address";
TAG_NAMES["ANNOTATION_XML"] = "annotation-xml";
TAG_NAMES["APPLET"] = "applet";
TAG_NAMES["AREA"] = "area";
TAG_NAMES["ARTICLE"] = "article";
TAG_NAMES["ASIDE"] = "aside";
TAG_NAMES["B"] = "b";
TAG_NAMES["BASE"] = "base";
TAG_NAMES["BASEFONT"] = "basefont";
TAG_NAMES["BGSOUND"] = "bgsound";
TAG_NAMES["BIG"] = "big";
TAG_NAMES["BLOCKQUOTE"] = "blockquote";
TAG_NAMES["BODY"] = "body";
TAG_NAMES["BR"] = "br";
TAG_NAMES["BUTTON"] = "button";
TAG_NAMES["CAPTION"] = "caption";
TAG_NAMES["CENTER"] = "center";
TAG_NAMES["CODE"] = "code";
TAG_NAMES["COL"] = "col";
TAG_NAMES["COLGROUP"] = "colgroup";
TAG_NAMES["DD"] = "dd";
TAG_NAMES["DESC"] = "desc";
TAG_NAMES["DETAILS"] = "details";
TAG_NAMES["DIALOG"] = "dialog";
TAG_NAMES["DIR"] = "dir";
TAG_NAMES["DIV"] = "div";
TAG_NAMES["DL"] = "dl";
TAG_NAMES["DT"] = "dt";
TAG_NAMES["EM"] = "em";
TAG_NAMES["EMBED"] = "embed";
TAG_NAMES["FIELDSET"] = "fieldset";
TAG_NAMES["FIGCAPTION"] = "figcaption";
TAG_NAMES["FIGURE"] = "figure";
TAG_NAMES["FONT"] = "font";
TAG_NAMES["FOOTER"] = "footer";
TAG_NAMES["FOREIGN_OBJECT"] = "foreignObject";
TAG_NAMES["FORM"] = "form";
TAG_NAMES["FRAME"] = "frame";
TAG_NAMES["FRAMESET"] = "frameset";
TAG_NAMES["H1"] = "h1";
TAG_NAMES["H2"] = "h2";
TAG_NAMES["H3"] = "h3";
TAG_NAMES["H4"] = "h4";
TAG_NAMES["H5"] = "h5";
TAG_NAMES["H6"] = "h6";
TAG_NAMES["HEAD"] = "head";
TAG_NAMES["HEADER"] = "header";
TAG_NAMES["HGROUP"] = "hgroup";
TAG_NAMES["HR"] = "hr";
TAG_NAMES["HTML"] = "html";
TAG_NAMES["I"] = "i";
TAG_NAMES["IMG"] = "img";
TAG_NAMES["IMAGE"] = "image";
TAG_NAMES["INPUT"] = "input";
TAG_NAMES["IFRAME"] = "iframe";
TAG_NAMES["KEYGEN"] = "keygen";
TAG_NAMES["LABEL"] = "label";
TAG_NAMES["LI"] = "li";
TAG_NAMES["LINK"] = "link";
TAG_NAMES["LISTING"] = "listing";
TAG_NAMES["MAIN"] = "main";
TAG_NAMES["MALIGNMARK"] = "malignmark";
TAG_NAMES["MARQUEE"] = "marquee";
TAG_NAMES["MATH"] = "math";
TAG_NAMES["MENU"] = "menu";
TAG_NAMES["META"] = "meta";
TAG_NAMES["MGLYPH"] = "mglyph";
TAG_NAMES["MI"] = "mi";
TAG_NAMES["MO"] = "mo";
TAG_NAMES["MN"] = "mn";
TAG_NAMES["MS"] = "ms";
TAG_NAMES["MTEXT"] = "mtext";
TAG_NAMES["NAV"] = "nav";
TAG_NAMES["NOBR"] = "nobr";
TAG_NAMES["NOFRAMES"] = "noframes";
TAG_NAMES["NOEMBED"] = "noembed";
TAG_NAMES["NOSCRIPT"] = "noscript";
TAG_NAMES["OBJECT"] = "object";
TAG_NAMES["OL"] = "ol";
TAG_NAMES["OPTGROUP"] = "optgroup";
TAG_NAMES["OPTION"] = "option";
TAG_NAMES["P"] = "p";
TAG_NAMES["PARAM"] = "param";
TAG_NAMES["PLAINTEXT"] = "plaintext";
TAG_NAMES["PRE"] = "pre";
TAG_NAMES["RB"] = "rb";
TAG_NAMES["RP"] = "rp";
TAG_NAMES["RT"] = "rt";
TAG_NAMES["RTC"] = "rtc";
TAG_NAMES["RUBY"] = "ruby";
TAG_NAMES["S"] = "s";
TAG_NAMES["SCRIPT"] = "script";
TAG_NAMES["SECTION"] = "section";
TAG_NAMES["SELECT"] = "select";
TAG_NAMES["SOURCE"] = "source";
TAG_NAMES["SMALL"] = "small";
TAG_NAMES["SPAN"] = "span";
TAG_NAMES["STRIKE"] = "strike";
TAG_NAMES["STRONG"] = "strong";
TAG_NAMES["STYLE"] = "style";
TAG_NAMES["SUB"] = "sub";
TAG_NAMES["SUMMARY"] = "summary";
TAG_NAMES["SUP"] = "sup";
TAG_NAMES["TABLE"] = "table";
TAG_NAMES["TBODY"] = "tbody";
TAG_NAMES["TEMPLATE"] = "template";
TAG_NAMES["TEXTAREA"] = "textarea";
TAG_NAMES["TFOOT"] = "tfoot";
TAG_NAMES["TD"] = "td";
TAG_NAMES["TH"] = "th";
TAG_NAMES["THEAD"] = "thead";
TAG_NAMES["TITLE"] = "title";
TAG_NAMES["TR"] = "tr";
TAG_NAMES["TRACK"] = "track";
TAG_NAMES["TT"] = "tt";
TAG_NAMES["U"] = "u";
TAG_NAMES["UL"] = "ul";
TAG_NAMES["SVG"] = "svg";
TAG_NAMES["VAR"] = "var";
TAG_NAMES["WBR"] = "wbr";
TAG_NAMES["XMP"] = "xmp";
})(TAG_NAMES = exports.TAG_NAMES || (exports.TAG_NAMES = {}));
/**
* Tag IDs are numeric IDs for known tag names.
*
* We use tag IDs to improve the performance of tag name comparisons.
*/
var TAG_ID;
(function (TAG_ID) {
TAG_ID[TAG_ID["UNKNOWN"] = 0] = "UNKNOWN";
TAG_ID[TAG_ID["A"] = 1] = "A";
TAG_ID[TAG_ID["ADDRESS"] = 2] = "ADDRESS";
TAG_ID[TAG_ID["ANNOTATION_XML"] = 3] = "ANNOTATION_XML";
TAG_ID[TAG_ID["APPLET"] = 4] = "APPLET";
TAG_ID[TAG_ID["AREA"] = 5] = "AREA";
TAG_ID[TAG_ID["ARTICLE"] = 6] = "ARTICLE";
TAG_ID[TAG_ID["ASIDE"] = 7] = "ASIDE";
TAG_ID[TAG_ID["B"] = 8] = "B";
TAG_ID[TAG_ID["BASE"] = 9] = "BASE";
TAG_ID[TAG_ID["BASEFONT"] = 10] = "BASEFONT";
TAG_ID[TAG_ID["BGSOUND"] = 11] = "BGSOUND";
TAG_ID[TAG_ID["BIG"] = 12] = "BIG";
TAG_ID[TAG_ID["BLOCKQUOTE"] = 13] = "BLOCKQUOTE";
TAG_ID[TAG_ID["BODY"] = 14] = "BODY";
TAG_ID[TAG_ID["BR"] = 15] = "BR";
TAG_ID[TAG_ID["BUTTON"] = 16] = "BUTTON";
TAG_ID[TAG_ID["CAPTION"] = 17] = "CAPTION";
TAG_ID[TAG_ID["CENTER"] = 18] = "CENTER";
TAG_ID[TAG_ID["CODE"] = 19] = "CODE";
TAG_ID[TAG_ID["COL"] = 20] = "COL";
TAG_ID[TAG_ID["COLGROUP"] = 21] = "COLGROUP";
TAG_ID[TAG_ID["DD"] = 22] = "DD";
TAG_ID[TAG_ID["DESC"] = 23] = "DESC";
TAG_ID[TAG_ID["DETAILS"] = 24] = "DETAILS";
TAG_ID[TAG_ID["DIALOG"] = 25] = "DIALOG";
TAG_ID[TAG_ID["DIR"] = 26] = "DIR";
TAG_ID[TAG_ID["DIV"] = 27] = "DIV";
TAG_ID[TAG_ID["DL"] = 28] = "DL";
TAG_ID[TAG_ID["DT"] = 29] = "DT";
TAG_ID[TAG_ID["EM"] = 30] = "EM";
TAG_ID[TAG_ID["EMBED"] = 31] = "EMBED";
TAG_ID[TAG_ID["FIELDSET"] = 32] = "FIELDSET";
TAG_ID[TAG_ID["FIGCAPTION"] = 33] = "FIGCAPTION";
TAG_ID[TAG_ID["FIGURE"] = 34] = "FIGURE";
TAG_ID[TAG_ID["FONT"] = 35] = "FONT";
TAG_ID[TAG_ID["FOOTER"] = 36] = "FOOTER";
TAG_ID[TAG_ID["FOREIGN_OBJECT"] = 37] = "FOREIGN_OBJECT";
TAG_ID[TAG_ID["FORM"] = 38] = "FORM";
TAG_ID[TAG_ID["FRAME"] = 39] = "FRAME";
TAG_ID[TAG_ID["FRAMESET"] = 40] = "FRAMESET";
TAG_ID[TAG_ID["H1"] = 41] = "H1";
TAG_ID[TAG_ID["H2"] = 42] = "H2";
TAG_ID[TAG_ID["H3"] = 43] = "H3";
TAG_ID[TAG_ID["H4"] = 44] = "H4";
TAG_ID[TAG_ID["H5"] = 45] = "H5";
TAG_ID[TAG_ID["H6"] = 46] = "H6";
TAG_ID[TAG_ID["HEAD"] = 47] = "HEAD";
TAG_ID[TAG_ID["HEADER"] = 48] = "HEADER";
TAG_ID[TAG_ID["HGROUP"] = 49] = "HGROUP";
TAG_ID[TAG_ID["HR"] = 50] = "HR";
TAG_ID[TAG_ID["HTML"] = 51] = "HTML";
TAG_ID[TAG_ID["I"] = 52] = "I";
TAG_ID[TAG_ID["IMG"] = 53] = "IMG";
TAG_ID[TAG_ID["IMAGE"] = 54] = "IMAGE";
TAG_ID[TAG_ID["INPUT"] = 55] = "INPUT";
TAG_ID[TAG_ID["IFRAME"] = 56] = "IFRAME";
TAG_ID[TAG_ID["KEYGEN"] = 57] = "KEYGEN";
TAG_ID[TAG_ID["LABEL"] = 58] = "LABEL";
TAG_ID[TAG_ID["LI"] = 59] = "LI";
TAG_ID[TAG_ID["LINK"] = 60] = "LINK";
TAG_ID[TAG_ID["LISTING"] = 61] = "LISTING";
TAG_ID[TAG_ID["MAIN"] = 62] = "MAIN";
TAG_ID[TAG_ID["MALIGNMARK"] = 63] = "MALIGNMARK";
TAG_ID[TAG_ID["MARQUEE"] = 64] = "MARQUEE";
TAG_ID[TAG_ID["MATH"] = 65] = "MATH";
TAG_ID[TAG_ID["MENU"] = 66] = "MENU";
TAG_ID[TAG_ID["META"] = 67] = "META";
TAG_ID[TAG_ID["MGLYPH"] = 68] = "MGLYPH";
TAG_ID[TAG_ID["MI"] = 69] = "MI";
TAG_ID[TAG_ID["MO"] = 70] = "MO";
TAG_ID[TAG_ID["MN"] = 71] = "MN";
TAG_ID[TAG_ID["MS"] = 72] = "MS";
TAG_ID[TAG_ID["MTEXT"] = 73] = "MTEXT";
TAG_ID[TAG_ID["NAV"] = 74] = "NAV";
TAG_ID[TAG_ID["NOBR"] = 75] = "NOBR";
TAG_ID[TAG_ID["NOFRAMES"] = 76] = "NOFRAMES";
TAG_ID[TAG_ID["NOEMBED"] = 77] = "NOEMBED";
TAG_ID[TAG_ID["NOSCRIPT"] = 78] = "NOSCRIPT";
TAG_ID[TAG_ID["OBJECT"] = 79] = "OBJECT";
TAG_ID[TAG_ID["OL"] = 80] = "OL";
TAG_ID[TAG_ID["OPTGROUP"] = 81] = "OPTGROUP";
TAG_ID[TAG_ID["OPTION"] = 82] = "OPTION";
TAG_ID[TAG_ID["P"] = 83] = "P";
TAG_ID[TAG_ID["PARAM"] = 84] = "PARAM";
TAG_ID[TAG_ID["PLAINTEXT"] = 85] = "PLAINTEXT";
TAG_ID[TAG_ID["PRE"] = 86] = "PRE";
TAG_ID[TAG_ID["RB"] = 87] = "RB";
TAG_ID[TAG_ID["RP"] = 88] = "RP";
TAG_ID[TAG_ID["RT"] = 89] = "RT";
TAG_ID[TAG_ID["RTC"] = 90] = "RTC";
TAG_ID[TAG_ID["RUBY"] = 91] = "RUBY";
TAG_ID[TAG_ID["S"] = 92] = "S";
TAG_ID[TAG_ID["SCRIPT"] = 93] = "SCRIPT";
TAG_ID[TAG_ID["SECTION"] = 94] = "SECTION";
TAG_ID[TAG_ID["SELECT"] = 95] = "SELECT";
TAG_ID[TAG_ID["SOURCE"] = 96] = "SOURCE";
TAG_ID[TAG_ID["SMALL"] = 97] = "SMALL";
TAG_ID[TAG_ID["SPAN"] = 98] = "SPAN";
TAG_ID[TAG_ID["STRIKE"] = 99] = "STRIKE";
TAG_ID[TAG_ID["STRONG"] = 100] = "STRONG";
TAG_ID[TAG_ID["STYLE"] = 101] = "STYLE";
TAG_ID[TAG_ID["SUB"] = 102] = "SUB";
TAG_ID[TAG_ID["SUMMARY"] = 103] = "SUMMARY";
TAG_ID[TAG_ID["SUP"] = 104] = "SUP";
TAG_ID[TAG_ID["TABLE"] = 105] = "TABLE";
TAG_ID[TAG_ID["TBODY"] = 106] = "TBODY";
TAG_ID[TAG_ID["TEMPLATE"] = 107] = "TEMPLATE";
TAG_ID[TAG_ID["TEXTAREA"] = 108] = "TEXTAREA";
TAG_ID[TAG_ID["TFOOT"] = 109] = "TFOOT";
TAG_ID[TAG_ID["TD"] = 110] = "TD";
TAG_ID[TAG_ID["TH"] = 111] = "TH";
TAG_ID[TAG_ID["THEAD"] = 112] = "THEAD";
TAG_ID[TAG_ID["TITLE"] = 113] = "TITLE";
TAG_ID[TAG_ID["TR"] = 114] = "TR";
TAG_ID[TAG_ID["TRACK"] = 115] = "TRACK";
TAG_ID[TAG_ID["TT"] = 116] = "TT";
TAG_ID[TAG_ID["U"] = 117] = "U";
TAG_ID[TAG_ID["UL"] = 118] = "UL";
TAG_ID[TAG_ID["SVG"] = 119] = "SVG";
TAG_ID[TAG_ID["VAR"] = 120] = "VAR";
TAG_ID[TAG_ID["WBR"] = 121] = "WBR";
TAG_ID[TAG_ID["XMP"] = 122] = "XMP";
})(TAG_ID = exports.TAG_ID || (exports.TAG_ID = {}));
const TAG_NAME_TO_ID = new Map([
[TAG_NAMES.A, TAG_ID.A],
[TAG_NAMES.ADDRESS, TAG_ID.ADDRESS],
[TAG_NAMES.ANNOTATION_XML, TAG_ID.ANNOTATION_XML],
[TAG_NAMES.APPLET, TAG_ID.APPLET],
[TAG_NAMES.AREA, TAG_ID.AREA],
[TAG_NAMES.ARTICLE, TAG_ID.ARTICLE],
[TAG_NAMES.ASIDE, TAG_ID.ASIDE],
[TAG_NAMES.B, TAG_ID.B],
[TAG_NAMES.BASE, TAG_ID.BASE],
[TAG_NAMES.BASEFONT, TAG_ID.BASEFONT],
[TAG_NAMES.BGSOUND, TAG_ID.BGSOUND],
[TAG_NAMES.BIG, TAG_ID.BIG],
[TAG_NAMES.BLOCKQUOTE, TAG_ID.BLOCKQUOTE],
[TAG_NAMES.BODY, TAG_ID.BODY],
[TAG_NAMES.BR, TAG_ID.BR],
[TAG_NAMES.BUTTON, TAG_ID.BUTTON],
[TAG_NAMES.CAPTION, TAG_ID.CAPTION],
[TAG_NAMES.CENTER, TAG_ID.CENTER],
[TAG_NAMES.CODE, TAG_ID.CODE],
[TAG_NAMES.COL, TAG_ID.COL],
[TAG_NAMES.COLGROUP, TAG_ID.COLGROUP],
[TAG_NAMES.DD, TAG_ID.DD],
[TAG_NAMES.DESC, TAG_ID.DESC],
[TAG_NAMES.DETAILS, TAG_ID.DETAILS],
[TAG_NAMES.DIALOG, TAG_ID.DIALOG],
[TAG_NAMES.DIR, TAG_ID.DIR],
[TAG_NAMES.DIV, TAG_ID.DIV],
[TAG_NAMES.DL, TAG_ID.DL],
[TAG_NAMES.DT, TAG_ID.DT],
[TAG_NAMES.EM, TAG_ID.EM],
[TAG_NAMES.EMBED, TAG_ID.EMBED],
[TAG_NAMES.FIELDSET, TAG_ID.FIELDSET],
[TAG_NAMES.FIGCAPTION, TAG_ID.FIGCAPTION],
[TAG_NAMES.FIGURE, TAG_ID.FIGURE],
[TAG_NAMES.FONT, TAG_ID.FONT],
[TAG_NAMES.FOOTER, TAG_ID.FOOTER],
[TAG_NAMES.FOREIGN_OBJECT, TAG_ID.FOREIGN_OBJECT],
[TAG_NAMES.FORM, TAG_ID.FORM],
[TAG_NAMES.FRAME, TAG_ID.FRAME],
[TAG_NAMES.FRAMESET, TAG_ID.FRAMESET],
[TAG_NAMES.H1, TAG_ID.H1],
[TAG_NAMES.H2, TAG_ID.H2],
[TAG_NAMES.H3, TAG_ID.H3],
[TAG_NAMES.H4, TAG_ID.H4],
[TAG_NAMES.H5, TAG_ID.H5],
[TAG_NAMES.H6, TAG_ID.H6],
[TAG_NAMES.HEAD, TAG_ID.HEAD],
[TAG_NAMES.HEADER, TAG_ID.HEADER],
[TAG_NAMES.HGROUP, TAG_ID.HGROUP],
[TAG_NAMES.HR, TAG_ID.HR],
[TAG_NAMES.HTML, TAG_ID.HTML],
[TAG_NAMES.I, TAG_ID.I],
[TAG_NAMES.IMG, TAG_ID.IMG],
[TAG_NAMES.IMAGE, TAG_ID.IMAGE],
[TAG_NAMES.INPUT, TAG_ID.INPUT],
[TAG_NAMES.IFRAME, TAG_ID.IFRAME],
[TAG_NAMES.KEYGEN, TAG_ID.KEYGEN],
[TAG_NAMES.LABEL, TAG_ID.LABEL],
[TAG_NAMES.LI, TAG_ID.LI],
[TAG_NAMES.LINK, TAG_ID.LINK],
[TAG_NAMES.LISTING, TAG_ID.LISTING],
[TAG_NAMES.MAIN, TAG_ID.MAIN],
[TAG_NAMES.MALIGNMARK, TAG_ID.MALIGNMARK],
[TAG_NAMES.MARQUEE, TAG_ID.MARQUEE],
[TAG_NAMES.MATH, TAG_ID.MATH],
[TAG_NAMES.MENU, TAG_ID.MENU],
[TAG_NAMES.META, TAG_ID.META],
[TAG_NAMES.MGLYPH, TAG_ID.MGLYPH],
[TAG_NAMES.MI, TAG_ID.MI],
[TAG_NAMES.MO, TAG_ID.MO],
[TAG_NAMES.MN, TAG_ID.MN],
[TAG_NAMES.MS, TAG_ID.MS],
[TAG_NAMES.MTEXT, TAG_ID.MTEXT],
[TAG_NAMES.NAV, TAG_ID.NAV],
[TAG_NAMES.NOBR, TAG_ID.NOBR],
[TAG_NAMES.NOFRAMES, TAG_ID.NOFRAMES],
[TAG_NAMES.NOEMBED, TAG_ID.NOEMBED],
[TAG_NAMES.NOSCRIPT, TAG_ID.NOSCRIPT],
[TAG_NAMES.OBJECT, TAG_ID.OBJECT],
[TAG_NAMES.OL, TAG_ID.OL],
[TAG_NAMES.OPTGROUP, TAG_ID.OPTGROUP],
[TAG_NAMES.OPTION, TAG_ID.OPTION],
[TAG_NAMES.P, TAG_ID.P],
[TAG_NAMES.PARAM, TAG_ID.PARAM],
[TAG_NAMES.PLAINTEXT, TAG_ID.PLAINTEXT],
[TAG_NAMES.PRE, TAG_ID.PRE],
[TAG_NAMES.RB, TAG_ID.RB],
[TAG_NAMES.RP, TAG_ID.RP],
[TAG_NAMES.RT, TAG_ID.RT],
[TAG_NAMES.RTC, TAG_ID.RTC],
[TAG_NAMES.RUBY, TAG_ID.RUBY],
[TAG_NAMES.S, TAG_ID.S],
[TAG_NAMES.SCRIPT, TAG_ID.SCRIPT],
[TAG_NAMES.SECTION, TAG_ID.SECTION],
[TAG_NAMES.SELECT, TAG_ID.SELECT],
[TAG_NAMES.SOURCE, TAG_ID.SOURCE],
[TAG_NAMES.SMALL, TAG_ID.SMALL],
[TAG_NAMES.SPAN, TAG_ID.SPAN],
[TAG_NAMES.STRIKE, TAG_ID.STRIKE],
[TAG_NAMES.STRONG, TAG_ID.STRONG],
[TAG_NAMES.STYLE, TAG_ID.STYLE],
[TAG_NAMES.SUB, TAG_ID.SUB],
[TAG_NAMES.SUMMARY, TAG_ID.SUMMARY],
[TAG_NAMES.SUP, TAG_ID.SUP],
[TAG_NAMES.TABLE, TAG_ID.TABLE],
[TAG_NAMES.TBODY, TAG_ID.TBODY],
[TAG_NAMES.TEMPLATE, TAG_ID.TEMPLATE],
[TAG_NAMES.TEXTAREA, TAG_ID.TEXTAREA],
[TAG_NAMES.TFOOT, TAG_ID.TFOOT],
[TAG_NAMES.TD, TAG_ID.TD],
[TAG_NAMES.TH, TAG_ID.TH],
[TAG_NAMES.THEAD, TAG_ID.THEAD],
[TAG_NAMES.TITLE, TAG_ID.TITLE],
[TAG_NAMES.TR, TAG_ID.TR],
[TAG_NAMES.TRACK, TAG_ID.TRACK],
[TAG_NAMES.TT, TAG_ID.TT],
[TAG_NAMES.U, TAG_ID.U],
[TAG_NAMES.UL, TAG_ID.UL],
[TAG_NAMES.SVG, TAG_ID.SVG],
[TAG_NAMES.VAR, TAG_ID.VAR],
[TAG_NAMES.WBR, TAG_ID.WBR],
[TAG_NAMES.XMP, TAG_ID.XMP],
]);
function getTagID(tagName) {
var _a;
return (_a = TAG_NAME_TO_ID.get(tagName)) !== null && _a !== void 0 ? _a : TAG_ID.UNKNOWN;
}
exports.getTagID = getTagID;
const $ = TAG_ID;
exports.SPECIAL_ELEMENTS = {
[NS.HTML]: new Set([
$.ADDRESS,
$.APPLET,
$.AREA,
$.ARTICLE,
$.ASIDE,
$.BASE,
$.BASEFONT,
$.BGSOUND,
$.BLOCKQUOTE,
$.BODY,
$.BR,
$.BUTTON,
$.CAPTION,
$.CENTER,
$.COL,
$.COLGROUP,
$.DD,
$.DETAILS,
$.DIR,
$.DIV,
$.DL,
$.DT,
$.EMBED,
$.FIELDSET,
$.FIGCAPTION,
$.FIGURE,
$.FOOTER,
$.FORM,
$.FRAME,
$.FRAMESET,
$.H1,
$.H2,
$.H3,
$.H4,
$.H5,
$.H6,
$.HEAD,
$.HEADER,
$.HGROUP,
$.HR,
$.HTML,
$.IFRAME,
$.IMG,
$.INPUT,
$.LI,
$.LINK,
$.LISTING,
$.MAIN,
$.MARQUEE,
$.MENU,
$.META,
$.NAV,
$.NOEMBED,
$.NOFRAMES,
$.NOSCRIPT,
$.OBJECT,
$.OL,
$.P,
$.PARAM,
$.PLAINTEXT,
$.PRE,
$.SCRIPT,
$.SECTION,
$.SELECT,
$.SOURCE,
$.STYLE,
$.SUMMARY,
$.TABLE,
$.TBODY,
$.TD,
$.TEMPLATE,
$.TEXTAREA,
$.TFOOT,
$.TH,
$.THEAD,
$.TITLE,
$.TR,
$.TRACK,
$.UL,
$.WBR,
$.XMP,
]),
[NS.MATHML]: new Set([$.MI, $.MO, $.MN, $.MS, $.MTEXT, $.ANNOTATION_XML]),
[NS.SVG]: new Set([$.TITLE, $.FOREIGN_OBJECT, $.DESC]),
[NS.XLINK]: new Set(),
[NS.XML]: new Set(),
[NS.XMLNS]: new Set(),
};
function isNumberedHeader(tn) {
return tn === $.H1 || tn === $.H2 || tn === $.H3 || tn === $.H4 || tn === $.H5 || tn === $.H6;
}
exports.isNumberedHeader = isNumberedHeader;
const UNESCAPED_TEXT = new Set([
TAG_NAMES.STYLE,
TAG_NAMES.SCRIPT,
TAG_NAMES.XMP,
TAG_NAMES.IFRAME,
TAG_NAMES.NOEMBED,
TAG_NAMES.NOFRAMES,
TAG_NAMES.PLAINTEXT,
]);
function hasUnescapedText(tn, scriptingEnabled) {
return UNESCAPED_TEXT.has(tn) || (scriptingEnabled && tn === TAG_NAMES.NOSCRIPT);
}
exports.hasUnescapedText = hasUnescapedText;
});
var tokenizer = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.Tokenizer = exports.TokenizerMode = void 0;
//C1 Unicode control character reference replacements
const C1_CONTROLS_REFERENCE_REPLACEMENTS = new Map([
[0x80, 8364],
[0x82, 8218],
[0x83, 402],
[0x84, 8222],
[0x85, 8230],
[0x86, 8224],
[0x87, 8225],
[0x88, 710],
[0x89, 8240],
[0x8a, 352],
[0x8b, 8249],
[0x8c, 338],
[0x8e, 381],
[0x91, 8216],
[0x92, 8217],
[0x93, 8220],
[0x94, 8221],
[0x95, 8226],
[0x96, 8211],
[0x97, 8212],
[0x98, 732],
[0x99, 8482],
[0x9a, 353],
[0x9b, 8250],
[0x9c, 339],
[0x9e, 382],
[0x9f, 376],
]);
//States
var State;
(function (State) {
State[State["DATA"] = 0] = "DATA";
State[State["RCDATA"] = 1] = "RCDATA";
State[State["RAWTEXT"] = 2] = "RAWTEXT";
State[State["SCRIPT_DATA"] = 3] = "SCRIPT_DATA";
State[State["PLAINTEXT"] = 4] = "PLAINTEXT";
State[State["TAG_OPEN"] = 5] = "TAG_OPEN";
State[State["END_TAG_OPEN"] = 6] = "END_TAG_OPEN";
State[State["TAG_NAME"] = 7] = "TAG_NAME";
State[State["RCDATA_LESS_THAN_SIGN"] = 8] = "RCDATA_LESS_THAN_SIGN";
State[State["RCDATA_END_TAG_OPEN"] = 9] = "RCDATA_END_TAG_OPEN";
State[State["RCDATA_END_TAG_NAME"] = 10] = "RCDATA_END_TAG_NAME";
State[State["RAWTEXT_LESS_THAN_SIGN"] = 11] = "RAWTEXT_LESS_THAN_SIGN";
State[State["RAWTEXT_END_TAG_OPEN"] = 12] = "RAWTEXT_END_TAG_OPEN";
State[State["RAWTEXT_END_TAG_NAME"] = 13] = "RAWTEXT_END_TAG_NAME";
State[State["SCRIPT_DATA_LESS_THAN_SIGN"] = 14] = "SCRIPT_DATA_LESS_THAN_SIGN";
State[State["SCRIPT_DATA_END_TAG_OPEN"] = 15] = "SCRIPT_DATA_END_TAG_OPEN";
State[State["SCRIPT_DATA_END_TAG_NAME"] = 16] = "SCRIPT_DATA_END_TAG_NAME";
State[State["SCRIPT_DATA_ESCAPE_START"] = 17] = "SCRIPT_DATA_ESCAPE_START";
State[State["SCRIPT_DATA_ESCAPE_START_DASH"] = 18] = "SCRIPT_DATA_ESCAPE_START_DASH";
State[State["SCRIPT_DATA_ESCAPED"] = 19] = "SCRIPT_DATA_ESCAPED";
State[State["SCRIPT_DATA_ESCAPED_DASH"] = 20] = "SCRIPT_DATA_ESCAPED_DASH";
State[State["SCRIPT_DATA_ESCAPED_DASH_DASH"] = 21] = "SCRIPT_DATA_ESCAPED_DASH_DASH";
State[State["SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN"] = 22] = "SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN";
State[State["SCRIPT_DATA_ESCAPED_END_TAG_OPEN"] = 23] = "SCRIPT_DATA_ESCAPED_END_TAG_OPEN";
State[State["SCRIPT_DATA_ESCAPED_END_TAG_NAME"] = 24] = "SCRIPT_DATA_ESCAPED_END_TAG_NAME";
State[State["SCRIPT_DATA_DOUBLE_ESCAPE_START"] = 25] = "SCRIPT_DATA_DOUBLE_ESCAPE_START";
State[State["SCRIPT_DATA_DOUBLE_ESCAPED"] = 26] = "SCRIPT_DATA_DOUBLE_ESCAPED";
State[State["SCRIPT_DATA_DOUBLE_ESCAPED_DASH"] = 27] = "SCRIPT_DATA_DOUBLE_ESCAPED_DASH";
State[State["SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH"] = 28] = "SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH";
State[State["SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN"] = 29] = "SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN";
State[State["SCRIPT_DATA_DOUBLE_ESCAPE_END"] = 30] = "SCRIPT_DATA_DOUBLE_ESCAPE_END";
State[State["BEFORE_ATTRIBUTE_NAME"] = 31] = "BEFORE_ATTRIBUTE_NAME";
State[State["ATTRIBUTE_NAME"] = 32] = "ATTRIBUTE_NAME";
State[State["AFTER_ATTRIBUTE_NAME"] = 33] = "AFTER_ATTRIBUTE_NAME";
State[State["BEFORE_ATTRIBUTE_VALUE"] = 34] = "BEFORE_ATTRIBUTE_VALUE";
State[State["ATTRIBUTE_VALUE_DOUBLE_QUOTED"] = 35] = "ATTRIBUTE_VALUE_DOUBLE_QUOTED";
State[State["ATTRIBUTE_VALUE_SINGLE_QUOTED"] = 36] = "ATTRIBUTE_VALUE_SINGLE_QUOTED";
State[State["ATTRIBUTE_VALUE_UNQUOTED"] = 37] = "ATTRIBUTE_VALUE_UNQUOTED";
State[State["AFTER_ATTRIBUTE_VALUE_QUOTED"] = 38] = "AFTER_ATTRIBUTE_VALUE_QUOTED";
State[State["SELF_CLOSING_START_TAG"] = 39] = "SELF_CLOSING_START_TAG";
State[State["BOGUS_COMMENT"] = 40] = "BOGUS_COMMENT";
State[State["MARKUP_DECLARATION_OPEN"] = 41] = "MARKUP_DECLARATION_OPEN";
State[State["COMMENT_START"] = 42] = "COMMENT_START";
State[State["COMMENT_START_DASH"] = 43] = "COMMENT_START_DASH";
State[State["COMMENT"] = 44] = "COMMENT";
State[State["COMMENT_LESS_THAN_SIGN"] = 45] = "COMMENT_LESS_THAN_SIGN";
State[State["COMMENT_LESS_THAN_SIGN_BANG"] = 46] = "COMMENT_LESS_THAN_SIGN_BANG";
State[State["COMMENT_LESS_THAN_SIGN_BANG_DASH"] = 47] = "COMMENT_LESS_THAN_SIGN_BANG_DASH";
State[State["COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH"] = 48] = "COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH";
State[State["COMMENT_END_DASH"] = 49] = "COMMENT_END_DASH";
State[State["COMMENT_END"] = 50] = "COMMENT_END";
State[State["COMMENT_END_BANG"] = 51] = "COMMENT_END_BANG";
State[State["DOCTYPE"] = 52] = "DOCTYPE";
State[State["BEFORE_DOCTYPE_NAME"] = 53] = "BEFORE_DOCTYPE_NAME";
State[State["DOCTYPE_NAME"] = 54] = "DOCTYPE_NAME";
State[State["AFTER_DOCTYPE_NAME"] = 55] = "AFTER_DOCTYPE_NAME";
State[State["AFTER_DOCTYPE_PUBLIC_KEYWORD"] = 56] = "AFTER_DOCTYPE_PUBLIC_KEYWORD";
State[State["BEFORE_DOCTYPE_PUBLIC_IDENTIFIER"] = 57] = "BEFORE_DOCTYPE_PUBLIC_IDENTIFIER";
State[State["DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED"] = 58] = "DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED";
State[State["DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED"] = 59] = "DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED";
State[State["AFTER_DOCTYPE_PUBLIC_IDENTIFIER"] = 60] = "AFTER_DOCTYPE_PUBLIC_IDENTIFIER";
State[State["BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS"] = 61] = "BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS";
State[State["AFTER_DOCTYPE_SYSTEM_KEYWORD"] = 62] = "AFTER_DOCTYPE_SYSTEM_KEYWORD";
State[State["BEFORE_DOCTYPE_SYSTEM_IDENTIFIER"] = 63] = "BEFORE_DOCTYPE_SYSTEM_IDENTIFIER";
State[State["DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED"] = 64] = "DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED";
State[State["DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED"] = 65] = "DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED";
State[State["AFTER_DOCTYPE_SYSTEM_IDENTIFIER"] = 66] = "AFTER_DOCTYPE_SYSTEM_IDENTIFIER";
State[State["BOGUS_DOCTYPE"] = 67] = "BOGUS_DOCTYPE";
State[State["CDATA_SECTION"] = 68] = "CDATA_SECTION";
State[State["CDATA_SECTION_BRACKET"] = 69] = "CDATA_SECTION_BRACKET";
State[State["CDATA_SECTION_END"] = 70] = "CDATA_SECTION_END";
State[State["CHARACTER_REFERENCE"] = 71] = "CHARACTER_REFERENCE";
State[State["NAMED_CHARACTER_REFERENCE"] = 72] = "NAMED_CHARACTER_REFERENCE";
State[State["AMBIGUOUS_AMPERSAND"] = 73] = "AMBIGUOUS_AMPERSAND";
State[State["NUMERIC_CHARACTER_REFERENCE"] = 74] = "NUMERIC_CHARACTER_REFERENCE";
State[State["HEXADEMICAL_CHARACTER_REFERENCE_START"] = 75] = "HEXADEMICAL_CHARACTER_REFERENCE_START";
State[State["HEXADEMICAL_CHARACTER_REFERENCE"] = 76] = "HEXADEMICAL_CHARACTER_REFERENCE";
State[State["DECIMAL_CHARACTER_REFERENCE"] = 77] = "DECIMAL_CHARACTER_REFERENCE";
State[State["NUMERIC_CHARACTER_REFERENCE_END"] = 78] = "NUMERIC_CHARACTER_REFERENCE_END";
})(State || (State = {}));
//Tokenizer initial states for different modes
exports.TokenizerMode = {
DATA: State.DATA,
RCDATA: State.RCDATA,
RAWTEXT: State.RAWTEXT,
SCRIPT_DATA: State.SCRIPT_DATA,
PLAINTEXT: State.PLAINTEXT,
CDATA_SECTION: State.CDATA_SECTION,
};
//Utils
//OPTIMIZATION: these utility functions should not be moved out of this module. V8 Crankshaft will not inline
//this functions if they will be situated in another module due to context switch.
//Always perform inlining check before modifying this functions ('node --trace-inlining').
function isAsciiDigit(cp) {
return cp >= unicode.CODE_POINTS.DIGIT_0 && cp <= unicode.CODE_POINTS.DIGIT_9;
}
function isAsciiUpper(cp) {
return cp >= unicode.CODE_POINTS.LATIN_CAPITAL_A && cp <= unicode.CODE_POINTS.LATIN_CAPITAL_Z;
}
function isAsciiLower(cp) {
return cp >= unicode.CODE_POINTS.LATIN_SMALL_A && cp <= unicode.CODE_POINTS.LATIN_SMALL_Z;
}
function isAsciiLetter(cp) {
return isAsciiLower(cp) || isAsciiUpper(cp);
}
function isAsciiAlphaNumeric(cp) {
return isAsciiLetter(cp) || isAsciiDigit(cp);
}
function isAsciiUpperHexDigit(cp) {
return cp >= unicode.CODE_POINTS.LATIN_CAPITAL_A && cp <= unicode.CODE_POINTS.LATIN_CAPITAL_F;
}
function isAsciiLowerHexDigit(cp) {
return cp >= unicode.CODE_POINTS.LATIN_SMALL_A && cp <= unicode.CODE_POINTS.LATIN_SMALL_F;
}
function isAsciiHexDigit(cp) {
return isAsciiDigit(cp) || isAsciiUpperHexDigit(cp) || isAsciiLowerHexDigit(cp);
}
function toAsciiLower(cp) {
return cp + 32;
}
function isWhitespace(cp) {
return cp === unicode.CODE_POINTS.SPACE || cp === unicode.CODE_POINTS.LINE_FEED || cp === unicode.CODE_POINTS.TABULATION || cp === unicode.CODE_POINTS.FORM_FEED;
}
function isEntityInAttributeInvalidEnd(nextCp) {
return nextCp === unicode.CODE_POINTS.EQUALS_SIGN || isAsciiAlphaNumeric(nextCp);
}
function isScriptDataDoubleEscapeSequenceEnd(cp) {
return isWhitespace(cp) || cp === unicode.CODE_POINTS.SOLIDUS || cp === unicode.CODE_POINTS.GREATER_THAN_SIGN;
}
//Tokenizer
class Tokenizer {
constructor(options, handler) {
this.options = options;
this.handler = handler;
this.paused = false;
/** Ensures that the parsing loop isn't run multiple times at once. */
this.inLoop = false;
/**
* Indicates that the current adjusted node exists, is not an element in the HTML namespace,
* and that it is not an integration point for either MathML or HTML.
*
* @see {@link https://html.spec.whatwg.org/multipage/parsing.html#tree-construction}
*/
this.inForeignNode = false;
this.lastStartTagName = '';
this.active = false;
this.state = State.DATA;
this.returnState = State.DATA;
this.charRefCode = -1;
this.consumedAfterSnapshot = -1;
this.currentCharacterToken = null;
this.currentToken = null;
this.currentAttr = { name: '', value: '' };
this.preprocessor = new preprocessor.Preprocessor(handler);
this.currentLocation = this.getCurrentLocation(-1);
}
//Errors
_err(code) {
var _a, _b;
(_b = (_a = this.handler).onParseError) === null || _b === void 0 ? void 0 : _b.call(_a, this.preprocessor.getError(code));
}
// NOTE: `offset` may never run across line boundaries.
getCurrentLocation(offset) {
if (!this.options.sourceCodeLocationInfo) {
return null;
}
return {
startLine: this.preprocessor.line,
startCol: this.preprocessor.col - offset,
startOffset: this.preprocessor.offset - offset,
endLine: -1,
endCol: -1,
endOffset: -1,
};
}
_runParsingLoop() {
if (this.inLoop)
return;
this.inLoop = true;
while (this.active && !this.paused) {
this.consumedAfterSnapshot = 0;
const cp = this._consume();
if (!this._ensureHibernation()) {
this._callState(cp);
}
}
this.inLoop = false;
}
//API
pause() {
this.paused = true;
}
resume(writeCallback) {
if (!this.paused) {
throw new Error('Parser was already resumed');
}
this.paused = false;
// Necessary for synchronous resume.
if (this.inLoop)
return;
this._runParsingLoop();
if (!this.paused) {
writeCallback === null || writeCallback === void 0 ? void 0 : writeCallback();
}
}
write(chunk, isLastChunk, writeCallback) {
this.active = true;
this.preprocessor.write(chunk, isLastChunk);
this._runParsingLoop();
if (!this.paused) {
writeCallback === null || writeCallback === void 0 ? void 0 : writeCallback();
}
}
insertHtmlAtCurrentPos(chunk) {
this.active = true;
this.preprocessor.insertHtmlAtCurrentPos(chunk);
this._runParsingLoop();
}
//Hibernation
_ensureHibernation() {
if (this.preprocessor.endOfChunkHit) {
this._unconsume(this.consumedAfterSnapshot);
this.active = false;
return true;
}
return false;
}
//Consumption
_consume() {
this.consumedAfterSnapshot++;
return this.preprocessor.advance();
}
_unconsume(count) {
this.consumedAfterSnapshot -= count;
this.preprocessor.retreat(count);
}
_reconsumeInState(state, cp) {
this.state = state;
this._callState(cp);
}
_advanceBy(count) {
this.consumedAfterSnapshot += count;
for (let i = 0; i < count; i++) {
this.preprocessor.advance();
}
}
_consumeSequenceIfMatch(pattern, caseSensitive) {
if (this.preprocessor.startsWith(pattern, caseSensitive)) {
// We will already have consumed one character before calling this method.
this._advanceBy(pattern.length - 1);
return true;
}
return false;
}
//Token creation
_createStartTagToken() {
this.currentToken = {
type: token.TokenType.START_TAG,
tagName: '',
tagID: html.TAG_ID.UNKNOWN,
selfClosing: false,
ackSelfClosing: false,
attrs: [],
location: this.getCurrentLocation(1),
};
}
_createEndTagToken() {
this.currentToken = {
type: token.TokenType.END_TAG,
tagName: '',
tagID: html.TAG_ID.UNKNOWN,
selfClosing: false,
ackSelfClosing: false,
attrs: [],
location: this.getCurrentLocation(2),
};
}
_createCommentToken(offset) {
this.currentToken = {
type: token.TokenType.COMMENT,
data: '',
location: this.getCurrentLocation(offset),
};
}
_createDoctypeToken(initialName) {
this.currentToken = {
type: token.TokenType.DOCTYPE,
name: initialName,
forceQuirks: false,
publicId: null,
systemId: null,
location: this.currentLocation,
};
}
_createCharacterToken(type, chars) {
this.currentCharacterToken = {
type,
chars,
location: this.currentLocation,
};
}
//Tag attributes
_createAttr(attrNameFirstCh) {
this.currentAttr = {
name: attrNameFirstCh,
value: '',
};
this.currentLocation = this.getCurrentLocation(0);
}
_leaveAttrName() {
var _a;
var _b;
const token$1 = this.currentToken;
if ((0, token.getTokenAttr)(token$1, this.currentAttr.name) === null) {
token$1.attrs.push(this.currentAttr);
if (token$1.location && this.currentLocation) {
const attrLocations = ((_a = (_b = token$1.location).attrs) !== null && _a !== void 0 ? _a : (_b.attrs = Object.create(null)));
attrLocations[this.currentAttr.name] = this.currentLocation;
// Set end location
this._leaveAttrValue();
}
}
else {
this._err(errorCodes.ERR.duplicateAttribute);
}
}
_leaveAttrValue() {
if (this.currentLocation) {
this.currentLocation.endLine = this.preprocessor.line;
this.currentLocation.endCol = this.preprocessor.col;
this.currentLocation.endOffset = this.preprocessor.offset;
}
}
//Token emission
prepareToken(ct) {
this._emitCurrentCharacterToken(ct.location);
this.currentToken = null;
if (ct.location) {
ct.location.endLine = this.preprocessor.line;
ct.location.endCol = this.preprocessor.col + 1;
ct.location.endOffset = this.preprocessor.offset + 1;
}
this.currentLocation = this.getCurrentLocation(-1);
}
emitCurrentTagToken() {
const ct = this.currentToken;
this.prepareToken(ct);
ct.tagID = (0, html.getTagID)(ct.tagName);
if (ct.type === token.TokenType.START_TAG) {
this.lastStartTagName = ct.tagName;
this.handler.onStartTag(ct);
}
else {
if (ct.attrs.length > 0) {
this._err(errorCodes.ERR.endTagWithAttributes);
}
if (ct.selfClosing) {
this._err(errorCodes.ERR.endTagWithTrailingSolidus);
}
this.handler.onEndTag(ct);
}
this.preprocessor.dropParsedChunk();
}
emitCurrentComment(ct) {
this.prepareToken(ct);
this.handler.onComment(ct);
this.preprocessor.dropParsedChunk();
}
emitCurrentDoctype(ct) {
this.prepareToken(ct);
this.handler.onDoctype(ct);
this.preprocessor.dropParsedChunk();
}
_emitCurrentCharacterToken(nextLocation) {
if (this.currentCharacterToken) {
//NOTE: if we have a pending character token, make it's end location equal to the
//current token's start location.
if (nextLocation && this.currentCharacterToken.location) {
this.currentCharacterToken.location.endLine = nextLocation.startLine;
this.currentCharacterToken.location.endCol = nextLocation.startCol;
this.currentCharacterToken.location.endOffset = nextLocation.startOffset;
}
switch (this.currentCharacterToken.type) {
case token.TokenType.CHARACTER: {
this.handler.onCharacter(this.currentCharacterToken);
break;
}
case token.TokenType.NULL_CHARACTER: {
this.handler.onNullCharacter(this.currentCharacterToken);
break;
}
case token.TokenType.WHITESPACE_CHARACTER: {
this.handler.onWhitespaceCharacter(this.currentCharacterToken);
break;
}
}
this.currentCharacterToken = null;
}
}
_emitEOFToken() {
const location = this.getCurrentLocation(0);
if (location) {
location.endLine = location.startLine;
location.endCol = location.startCol;
location.endOffset = location.startOffset;
}
this._emitCurrentCharacterToken(location);
this.handler.onEof({ type: token.TokenType.EOF, location });
this.active = false;
}
//Characters emission
//OPTIMIZATION: specification uses only one type of character tokens (one token per character).
//This causes a huge memory overhead and a lot of unnecessary parser loops. parse5 uses 3 groups of characters.
//If we have a sequence of characters that belong to the same group, the parser can process it
//as a single solid character token.
//So, there are 3 types of character tokens in parse5:
//1)TokenType.NULL_CHARACTER - \u0000-character sequences (e.g. '\u0000\u0000\u0000')
//2)TokenType.WHITESPACE_CHARACTER - any whitespace/new-line character sequences (e.g. '\n \r\t \f')
//3)TokenType.CHARACTER - any character sequence which don't belong to groups 1 and 2 (e.g. 'abcdef1234@@#$%^')
_appendCharToCurrentCharacterToken(type, ch) {
if (this.currentCharacterToken) {
if (this.currentCharacterToken.type !== type) {
this.currentLocation = this.getCurrentLocation(0);
this._emitCurrentCharacterToken(this.currentLocation);
this.preprocessor.dropParsedChunk();
}
else {
this.currentCharacterToken.chars += ch;
return;
}
}
this._createCharacterToken(type, ch);
}
_emitCodePoint(cp) {
const type = isWhitespace(cp)
? token.TokenType.WHITESPACE_CHARACTER
: cp === unicode.CODE_POINTS.NULL
? token.TokenType.NULL_CHARACTER
: token.TokenType.CHARACTER;
this._appendCharToCurrentCharacterToken(type, String.fromCodePoint(cp));
}
//NOTE: used when we emit characters explicitly.
//This is always for non-whitespace and non-null characters, which allows us to avoid additional checks.
_emitChars(ch) {
this._appendCharToCurrentCharacterToken(token.TokenType.CHARACTER, ch);
}
// Character reference helpers
_matchNamedCharacterReference(cp) {
let result = null;
let excess = 0;
let withoutSemicolon = false;
for (let i = 0, current = decode_js_1.htmlDecodeTree[0]; i >= 0; cp = this._consume()) {
i = (0, decode_js_1.determineBranch)(decode_js_1.htmlDecodeTree, current, i + 1, cp);
if (i < 0)
break;
excess += 1;
current = decode_js_1.htmlDecodeTree[i];
const masked = current & decode_js_1.BinTrieFlags.VALUE_LENGTH;
// If the branch is a value, store it and continue
if (masked) {
// The mask is the number of bytes of the value, including the current byte.
const valueLength = (masked >> 14) - 1;
// Attribute values that aren't terminated properly aren't parsed, and shouldn't lead to a parser error.
// See the example in https://html.spec.whatwg.org/multipage/parsing.html#named-character-reference-state
if (cp !== unicode.CODE_POINTS.SEMICOLON &&
this._isCharacterReferenceInAttribute() &&
isEntityInAttributeInvalidEnd(this.preprocessor.peek(1))) {
//NOTE: we don't flush all consumed code points here, and instead switch back to the original state after
//emitting an ampersand. This is fine, as alphanumeric characters won't be parsed differently in attributes.
result = [unicode.CODE_POINTS.AMPERSAND];
// Skip over the value.
i += valueLength;
}
else {
// If this is a surrogate pair, consume the next two bytes.
result =
valueLength === 0
? [decode_js_1.htmlDecodeTree[i] & ~decode_js_1.BinTrieFlags.VALUE_LENGTH]
: valueLength === 1
? [decode_js_1.htmlDecodeTree[++i]]
: [decode_js_1.htmlDecodeTree[++i], decode_js_1.htmlDecodeTree[++i]];
excess = 0;
withoutSemicolon = cp !== unicode.CODE_POINTS.SEMICOLON;
}
if (valueLength === 0) {
// If the value is zero-length, we're done.
this._consume();
break;
}
}
}
this._unconsume(excess);
if (withoutSemicolon && !this.preprocessor.endOfChunkHit) {
this._err(errorCodes.ERR.missingSemicolonAfterCharacterReference);
}
// We want to emit the error above on the code point after the entity.
// We always consume one code point too many in the loop, and we wait to
// unconsume it until after the error is emitted.
this._unconsume(1);
return result;
}
_isCharacterReferenceInAttribute() {
return (this.returnState === State.ATTRIBUTE_VALUE_DOUBLE_QUOTED ||
this.returnState === State.ATTRIBUTE_VALUE_SINGLE_QUOTED ||
this.returnState === State.ATTRIBUTE_VALUE_UNQUOTED);
}
_flushCodePointConsumedAsCharacterReference(cp) {
if (this._isCharacterReferenceInAttribute()) {
this.currentAttr.value += String.fromCodePoint(cp);
}
else {
this._emitCodePoint(cp);
}
}
// Calling states this way turns out to be much faster than any other approach.
_callState(cp) {
switch (this.state) {
case State.DATA: {
this._stateData(cp);
break;
}
case State.RCDATA: {
this._stateRcdata(cp);
break;
}
case State.RAWTEXT: {
this._stateRawtext(cp);
break;
}
case State.SCRIPT_DATA: {
this._stateScriptData(cp);
break;
}
case State.PLAINTEXT: {
this._statePlaintext(cp);
break;
}
case State.TAG_OPEN: {
this._stateTagOpen(cp);
break;
}
case State.END_TAG_OPEN: {
this._stateEndTagOpen(cp);
break;
}
case State.TAG_NAME: {
this._stateTagName(cp);
break;
}
case State.RCDATA_LESS_THAN_SIGN: {
this._stateRcdataLessThanSign(cp);
break;
}
case State.RCDATA_END_TAG_OPEN: {
this._stateRcdataEndTagOpen(cp);
break;
}
case State.RCDATA_END_TAG_NAME: {
this._stateRcdataEndTagName(cp);
break;
}
case State.RAWTEXT_LESS_THAN_SIGN: {
this._stateRawtextLessThanSign(cp);
break;
}
case State.RAWTEXT_END_TAG_OPEN: {
this._stateRawtextEndTagOpen(cp);
break;
}
case State.RAWTEXT_END_TAG_NAME: {
this._stateRawtextEndTagName(cp);
break;
}
case State.SCRIPT_DATA_LESS_THAN_SIGN: {
this._stateScriptDataLessThanSign(cp);
break;
}
case State.SCRIPT_DATA_END_TAG_OPEN: {
this._stateScriptDataEndTagOpen(cp);
break;
}
case State.SCRIPT_DATA_END_TAG_NAME: {
this._stateScriptDataEndTagName(cp);
break;
}
case State.SCRIPT_DATA_ESCAPE_START: {
this._stateScriptDataEscapeStart(cp);
break;
}
case State.SCRIPT_DATA_ESCAPE_START_DASH: {
this._stateScriptDataEscapeStartDash(cp);
break;
}
case State.SCRIPT_DATA_ESCAPED: {
this._stateScriptDataEscaped(cp);
break;
}
case State.SCRIPT_DATA_ESCAPED_DASH: {
this._stateScriptDataEscapedDash(cp);
break;
}
case State.SCRIPT_DATA_ESCAPED_DASH_DASH: {
this._stateScriptDataEscapedDashDash(cp);
break;
}
case State.SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN: {
this._stateScriptDataEscapedLessThanSign(cp);
break;
}
case State.SCRIPT_DATA_ESCAPED_END_TAG_OPEN: {
this._stateScriptDataEscapedEndTagOpen(cp);
break;
}
case State.SCRIPT_DATA_ESCAPED_END_TAG_NAME: {
this._stateScriptDataEscapedEndTagName(cp);
break;
}
case State.SCRIPT_DATA_DOUBLE_ESCAPE_START: {
this._stateScriptDataDoubleEscapeStart(cp);
break;
}
case State.SCRIPT_DATA_DOUBLE_ESCAPED: {
this._stateScriptDataDoubleEscaped(cp);
break;
}
case State.SCRIPT_DATA_DOUBLE_ESCAPED_DASH: {
this._stateScriptDataDoubleEscapedDash(cp);
break;
}
case State.SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH: {
this._stateScriptDataDoubleEscapedDashDash(cp);
break;
}
case State.SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN: {
this._stateScriptDataDoubleEscapedLessThanSign(cp);
break;
}
case State.SCRIPT_DATA_DOUBLE_ESCAPE_END: {
this._stateScriptDataDoubleEscapeEnd(cp);
break;
}
case State.BEFORE_ATTRIBUTE_NAME: {
this._stateBeforeAttributeName(cp);
break;
}
case State.ATTRIBUTE_NAME: {
this._stateAttributeName(cp);
break;
}
case State.AFTER_ATTRIBUTE_NAME: {
this._stateAfterAttributeName(cp);
break;
}
case State.BEFORE_ATTRIBUTE_VALUE: {
this._stateBeforeAttributeValue(cp);
break;
}
case State.ATTRIBUTE_VALUE_DOUBLE_QUOTED: {
this._stateAttributeValueDoubleQuoted(cp);
break;
}
case State.ATTRIBUTE_VALUE_SINGLE_QUOTED: {
this._stateAttributeValueSingleQuoted(cp);
break;
}
case State.ATTRIBUTE_VALUE_UNQUOTED: {
this._stateAttributeValueUnquoted(cp);
break;
}
case State.AFTER_ATTRIBUTE_VALUE_QUOTED: {
this._stateAfterAttributeValueQuoted(cp);
break;
}
case State.SELF_CLOSING_START_TAG: {
this._stateSelfClosingStartTag(cp);
break;
}
case State.BOGUS_COMMENT: {
this._stateBogusComment(cp);
break;
}
case State.MARKUP_DECLARATION_OPEN: {
this._stateMarkupDeclarationOpen(cp);
break;
}
case State.COMMENT_START: {
this._stateCommentStart(cp);
break;
}
case State.COMMENT_START_DASH: {
this._stateCommentStartDash(cp);
break;
}
case State.COMMENT: {
this._stateComment(cp);
break;
}
case State.COMMENT_LESS_THAN_SIGN: {
this._stateCommentLessThanSign(cp);
break;
}
case State.COMMENT_LESS_THAN_SIGN_BANG: {
this._stateCommentLessThanSignBang(cp);
break;
}
case State.COMMENT_LESS_THAN_SIGN_BANG_DASH: {
this._stateCommentLessThanSignBangDash(cp);
break;
}
case State.COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH: {
this._stateCommentLessThanSignBangDashDash(cp);
break;
}
case State.COMMENT_END_DASH: {
this._stateCommentEndDash(cp);
break;
}
case State.COMMENT_END: {
this._stateCommentEnd(cp);
break;
}
case State.COMMENT_END_BANG: {
this._stateCommentEndBang(cp);
break;
}
case State.DOCTYPE: {
this._stateDoctype(cp);
break;
}
case State.BEFORE_DOCTYPE_NAME: {
this._stateBeforeDoctypeName(cp);
break;
}
case State.DOCTYPE_NAME: {
this._stateDoctypeName(cp);
break;
}
case State.AFTER_DOCTYPE_NAME: {
this._stateAfterDoctypeName(cp);
break;
}
case State.AFTER_DOCTYPE_PUBLIC_KEYWORD: {
this._stateAfterDoctypePublicKeyword(cp);
break;
}
case State.BEFORE_DOCTYPE_PUBLIC_IDENTIFIER: {
this._stateBeforeDoctypePublicIdentifier(cp);
break;
}
case State.DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED: {
this._stateDoctypePublicIdentifierDoubleQuoted(cp);
break;
}
case State.DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED: {
this._stateDoctypePublicIdentifierSingleQuoted(cp);
break;
}
case State.AFTER_DOCTYPE_PUBLIC_IDENTIFIER: {
this._stateAfterDoctypePublicIdentifier(cp);
break;
}
case State.BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS: {
this._stateBetweenDoctypePublicAndSystemIdentifiers(cp);
break;
}
case State.AFTER_DOCTYPE_SYSTEM_KEYWORD: {
this._stateAfterDoctypeSystemKeyword(cp);
break;
}
case State.BEFORE_DOCTYPE_SYSTEM_IDENTIFIER: {
this._stateBeforeDoctypeSystemIdentifier(cp);
break;
}
case State.DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED: {
this._stateDoctypeSystemIdentifierDoubleQuoted(cp);
break;
}
case State.DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED: {
this._stateDoctypeSystemIdentifierSingleQuoted(cp);
break;
}
case State.AFTER_DOCTYPE_SYSTEM_IDENTIFIER: {
this._stateAfterDoctypeSystemIdentifier(cp);
break;
}
case State.BOGUS_DOCTYPE: {
this._stateBogusDoctype(cp);
break;
}
case State.CDATA_SECTION: {
this._stateCdataSection(cp);
break;
}
case State.CDATA_SECTION_BRACKET: {
this._stateCdataSectionBracket(cp);
break;
}
case State.CDATA_SECTION_END: {
this._stateCdataSectionEnd(cp);
break;
}
case State.CHARACTER_REFERENCE: {
this._stateCharacterReference(cp);
break;
}
case State.NAMED_CHARACTER_REFERENCE: {
this._stateNamedCharacterReference(cp);
break;
}
case State.AMBIGUOUS_AMPERSAND: {
this._stateAmbiguousAmpersand(cp);
break;
}
case State.NUMERIC_CHARACTER_REFERENCE: {
this._stateNumericCharacterReference(cp);
break;
}
case State.HEXADEMICAL_CHARACTER_REFERENCE_START: {
this._stateHexademicalCharacterReferenceStart(cp);
break;
}
case State.HEXADEMICAL_CHARACTER_REFERENCE: {
this._stateHexademicalCharacterReference(cp);
break;
}
case State.DECIMAL_CHARACTER_REFERENCE: {
this._stateDecimalCharacterReference(cp);
break;
}
case State.NUMERIC_CHARACTER_REFERENCE_END: {
this._stateNumericCharacterReferenceEnd(cp);
break;
}
default: {
throw new Error('Unknown state');
}
}
}
// State machine
// Data state
//------------------------------------------------------------------
_stateData(cp) {
switch (cp) {
case unicode.CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.TAG_OPEN;
break;
}
case unicode.CODE_POINTS.AMPERSAND: {
this.returnState = State.DATA;
this.state = State.CHARACTER_REFERENCE;
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
this._emitCodePoint(cp);
break;
}
case unicode.CODE_POINTS.EOF: {
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// RCDATA state
//------------------------------------------------------------------
_stateRcdata(cp) {
switch (cp) {
case unicode.CODE_POINTS.AMPERSAND: {
this.returnState = State.RCDATA;
this.state = State.CHARACTER_REFERENCE;
break;
}
case unicode.CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.RCDATA_LESS_THAN_SIGN;
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
this._emitChars(unicode.REPLACEMENT_CHARACTER);
break;
}
case unicode.CODE_POINTS.EOF: {
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// RAWTEXT state
//------------------------------------------------------------------
_stateRawtext(cp) {
switch (cp) {
case unicode.CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.RAWTEXT_LESS_THAN_SIGN;
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
this._emitChars(unicode.REPLACEMENT_CHARACTER);
break;
}
case unicode.CODE_POINTS.EOF: {
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// Script data state
//------------------------------------------------------------------
_stateScriptData(cp) {
switch (cp) {
case unicode.CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.SCRIPT_DATA_LESS_THAN_SIGN;
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
this._emitChars(unicode.REPLACEMENT_CHARACTER);
break;
}
case unicode.CODE_POINTS.EOF: {
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// PLAINTEXT state
//------------------------------------------------------------------
_statePlaintext(cp) {
switch (cp) {
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
this._emitChars(unicode.REPLACEMENT_CHARACTER);
break;
}
case unicode.CODE_POINTS.EOF: {
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// Tag open state
//------------------------------------------------------------------
_stateTagOpen(cp) {
if (isAsciiLetter(cp)) {
this._createStartTagToken();
this.state = State.TAG_NAME;
this._stateTagName(cp);
}
else
switch (cp) {
case unicode.CODE_POINTS.EXCLAMATION_MARK: {
this.state = State.MARKUP_DECLARATION_OPEN;
break;
}
case unicode.CODE_POINTS.SOLIDUS: {
this.state = State.END_TAG_OPEN;
break;
}
case unicode.CODE_POINTS.QUESTION_MARK: {
this._err(errorCodes.ERR.unexpectedQuestionMarkInsteadOfTagName);
this._createCommentToken(1);
this.state = State.BOGUS_COMMENT;
this._stateBogusComment(cp);
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofBeforeTagName);
this._emitChars('<');
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes.ERR.invalidFirstCharacterOfTagName);
this._emitChars('<');
this.state = State.DATA;
this._stateData(cp);
}
}
}
// End tag open state
//------------------------------------------------------------------
_stateEndTagOpen(cp) {
if (isAsciiLetter(cp)) {
this._createEndTagToken();
this.state = State.TAG_NAME;
this._stateTagName(cp);
}
else
switch (cp) {
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes.ERR.missingEndTagName);
this.state = State.DATA;
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofBeforeTagName);
this._emitChars('</');
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes.ERR.invalidFirstCharacterOfTagName);
this._createCommentToken(2);
this.state = State.BOGUS_COMMENT;
this._stateBogusComment(cp);
}
}
}
// Tag name state
//------------------------------------------------------------------
_stateTagName(cp) {
const token = this.currentToken;
switch (cp) {
case unicode.CODE_POINTS.SPACE:
case unicode.CODE_POINTS.LINE_FEED:
case unicode.CODE_POINTS.TABULATION:
case unicode.CODE_POINTS.FORM_FEED: {
this.state = State.BEFORE_ATTRIBUTE_NAME;
break;
}
case unicode.CODE_POINTS.SOLIDUS: {
this.state = State.SELF_CLOSING_START_TAG;
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
this.emitCurrentTagToken();
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
token.tagName += unicode.REPLACEMENT_CHARACTER;
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInTag);
this._emitEOFToken();
break;
}
default: {
token.tagName += String.fromCodePoint(isAsciiUpper(cp) ? toAsciiLower(cp) : cp);
}
}
}
// RCDATA less-than sign state
//------------------------------------------------------------------
_stateRcdataLessThanSign(cp) {
if (cp === unicode.CODE_POINTS.SOLIDUS) {
this.state = State.RCDATA_END_TAG_OPEN;
}
else {
this._emitChars('<');
this.state = State.RCDATA;
this._stateRcdata(cp);
}
}
// RCDATA end tag open state
//------------------------------------------------------------------
_stateRcdataEndTagOpen(cp) {
if (isAsciiLetter(cp)) {
this.state = State.RCDATA_END_TAG_NAME;
this._stateRcdataEndTagName(cp);
}
else {
this._emitChars('</');
this.state = State.RCDATA;
this._stateRcdata(cp);
}
}
handleSpecialEndTag(_cp) {
if (!this.preprocessor.startsWith(this.lastStartTagName, false)) {
return !this._ensureHibernation();
}
this._createEndTagToken();
const token = this.currentToken;
token.tagName = this.lastStartTagName;
const cp = this.preprocessor.peek(this.lastStartTagName.length);
switch (cp) {
case unicode.CODE_POINTS.SPACE:
case unicode.CODE_POINTS.LINE_FEED:
case unicode.CODE_POINTS.TABULATION:
case unicode.CODE_POINTS.FORM_FEED: {
this._advanceBy(this.lastStartTagName.length);
this.state = State.BEFORE_ATTRIBUTE_NAME;
return false;
}
case unicode.CODE_POINTS.SOLIDUS: {
this._advanceBy(this.lastStartTagName.length);
this.state = State.SELF_CLOSING_START_TAG;
return false;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this._advanceBy(this.lastStartTagName.length);
this.emitCurrentTagToken();
this.state = State.DATA;
return false;
}
default: {
return !this._ensureHibernation();
}
}
}
// RCDATA end tag name state
//------------------------------------------------------------------
_stateRcdataEndTagName(cp) {
if (this.handleSpecialEndTag(cp)) {
this._emitChars('</');
this.state = State.RCDATA;
this._stateRcdata(cp);
}
}
// RAWTEXT less-than sign state
//------------------------------------------------------------------
_stateRawtextLessThanSign(cp) {
if (cp === unicode.CODE_POINTS.SOLIDUS) {
this.state = State.RAWTEXT_END_TAG_OPEN;
}
else {
this._emitChars('<');
this.state = State.RAWTEXT;
this._stateRawtext(cp);
}
}
// RAWTEXT end tag open state
//------------------------------------------------------------------
_stateRawtextEndTagOpen(cp) {
if (isAsciiLetter(cp)) {
this.state = State.RAWTEXT_END_TAG_NAME;
this._stateRawtextEndTagName(cp);
}
else {
this._emitChars('</');
this.state = State.RAWTEXT;
this._stateRawtext(cp);
}
}
// RAWTEXT end tag name state
//------------------------------------------------------------------
_stateRawtextEndTagName(cp) {
if (this.handleSpecialEndTag(cp)) {
this._emitChars('</');
this.state = State.RAWTEXT;
this._stateRawtext(cp);
}
}
// Script data less-than sign state
//------------------------------------------------------------------
_stateScriptDataLessThanSign(cp) {
switch (cp) {
case unicode.CODE_POINTS.SOLIDUS: {
this.state = State.SCRIPT_DATA_END_TAG_OPEN;
break;
}
case unicode.CODE_POINTS.EXCLAMATION_MARK: {
this.state = State.SCRIPT_DATA_ESCAPE_START;
this._emitChars('<!');
break;
}
default: {
this._emitChars('<');
this.state = State.SCRIPT_DATA;
this._stateScriptData(cp);
}
}
}
// Script data end tag open state
//------------------------------------------------------------------
_stateScriptDataEndTagOpen(cp) {
if (isAsciiLetter(cp)) {
this.state = State.SCRIPT_DATA_END_TAG_NAME;
this._stateScriptDataEndTagName(cp);
}
else {
this._emitChars('</');
this.state = State.SCRIPT_DATA;
this._stateScriptData(cp);
}
}
// Script data end tag name state
//------------------------------------------------------------------
_stateScriptDataEndTagName(cp) {
if (this.handleSpecialEndTag(cp)) {
this._emitChars('</');
this.state = State.SCRIPT_DATA;
this._stateScriptData(cp);
}
}
// Script data escape start state
//------------------------------------------------------------------
_stateScriptDataEscapeStart(cp) {
if (cp === unicode.CODE_POINTS.HYPHEN_MINUS) {
this.state = State.SCRIPT_DATA_ESCAPE_START_DASH;
this._emitChars('-');
}
else {
this.state = State.SCRIPT_DATA;
this._stateScriptData(cp);
}
}
// Script data escape start dash state
//------------------------------------------------------------------
_stateScriptDataEscapeStartDash(cp) {
if (cp === unicode.CODE_POINTS.HYPHEN_MINUS) {
this.state = State.SCRIPT_DATA_ESCAPED_DASH_DASH;
this._emitChars('-');
}
else {
this.state = State.SCRIPT_DATA;
this._stateScriptData(cp);
}
}
// Script data escaped state
//------------------------------------------------------------------
_stateScriptDataEscaped(cp) {
switch (cp) {
case unicode.CODE_POINTS.HYPHEN_MINUS: {
this.state = State.SCRIPT_DATA_ESCAPED_DASH;
this._emitChars('-');
break;
}
case unicode.CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN;
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
this._emitChars(unicode.REPLACEMENT_CHARACTER);
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInScriptHtmlCommentLikeText);
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// Script data escaped dash state
//------------------------------------------------------------------
_stateScriptDataEscapedDash(cp) {
switch (cp) {
case unicode.CODE_POINTS.HYPHEN_MINUS: {
this.state = State.SCRIPT_DATA_ESCAPED_DASH_DASH;
this._emitChars('-');
break;
}
case unicode.CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN;
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
this.state = State.SCRIPT_DATA_ESCAPED;
this._emitChars(unicode.REPLACEMENT_CHARACTER);
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInScriptHtmlCommentLikeText);
this._emitEOFToken();
break;
}
default: {
this.state = State.SCRIPT_DATA_ESCAPED;
this._emitCodePoint(cp);
}
}
}
// Script data escaped dash dash state
//------------------------------------------------------------------
_stateScriptDataEscapedDashDash(cp) {
switch (cp) {
case unicode.CODE_POINTS.HYPHEN_MINUS: {
this._emitChars('-');
break;
}
case unicode.CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN;
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.SCRIPT_DATA;
this._emitChars('>');
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
this.state = State.SCRIPT_DATA_ESCAPED;
this._emitChars(unicode.REPLACEMENT_CHARACTER);
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInScriptHtmlCommentLikeText);
this._emitEOFToken();
break;
}
default: {
this.state = State.SCRIPT_DATA_ESCAPED;
this._emitCodePoint(cp);
}
}
}
// Script data escaped less-than sign state
//------------------------------------------------------------------
_stateScriptDataEscapedLessThanSign(cp) {
if (cp === unicode.CODE_POINTS.SOLIDUS) {
this.state = State.SCRIPT_DATA_ESCAPED_END_TAG_OPEN;
}
else if (isAsciiLetter(cp)) {
this._emitChars('<');
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPE_START;
this._stateScriptDataDoubleEscapeStart(cp);
}
else {
this._emitChars('<');
this.state = State.SCRIPT_DATA_ESCAPED;
this._stateScriptDataEscaped(cp);
}
}
// Script data escaped end tag open state
//------------------------------------------------------------------
_stateScriptDataEscapedEndTagOpen(cp) {
if (isAsciiLetter(cp)) {
this.state = State.SCRIPT_DATA_ESCAPED_END_TAG_NAME;
this._stateScriptDataEscapedEndTagName(cp);
}
else {
this._emitChars('</');
this.state = State.SCRIPT_DATA_ESCAPED;
this._stateScriptDataEscaped(cp);
}
}
// Script data escaped end tag name state
//------------------------------------------------------------------
_stateScriptDataEscapedEndTagName(cp) {
if (this.handleSpecialEndTag(cp)) {
this._emitChars('</');
this.state = State.SCRIPT_DATA_ESCAPED;
this._stateScriptDataEscaped(cp);
}
}
// Script data double escape start state
//------------------------------------------------------------------
_stateScriptDataDoubleEscapeStart(cp) {
if (this.preprocessor.startsWith(unicode.SEQUENCES.SCRIPT, false) &&
isScriptDataDoubleEscapeSequenceEnd(this.preprocessor.peek(unicode.SEQUENCES.SCRIPT.length))) {
this._emitCodePoint(cp);
for (let i = 0; i < unicode.SEQUENCES.SCRIPT.length; i++) {
this._emitCodePoint(this._consume());
}
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED;
}
else if (!this._ensureHibernation()) {
this.state = State.SCRIPT_DATA_ESCAPED;
this._stateScriptDataEscaped(cp);
}
}
// Script data double escaped state
//------------------------------------------------------------------
_stateScriptDataDoubleEscaped(cp) {
switch (cp) {
case unicode.CODE_POINTS.HYPHEN_MINUS: {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED_DASH;
this._emitChars('-');
break;
}
case unicode.CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN;
this._emitChars('<');
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
this._emitChars(unicode.REPLACEMENT_CHARACTER);
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInScriptHtmlCommentLikeText);
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// Script data double escaped dash state
//------------------------------------------------------------------
_stateScriptDataDoubleEscapedDash(cp) {
switch (cp) {
case unicode.CODE_POINTS.HYPHEN_MINUS: {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH;
this._emitChars('-');
break;
}
case unicode.CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN;
this._emitChars('<');
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED;
this._emitChars(unicode.REPLACEMENT_CHARACTER);
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInScriptHtmlCommentLikeText);
this._emitEOFToken();
break;
}
default: {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED;
this._emitCodePoint(cp);
}
}
}
// Script data double escaped dash dash state
//------------------------------------------------------------------
_stateScriptDataDoubleEscapedDashDash(cp) {
switch (cp) {
case unicode.CODE_POINTS.HYPHEN_MINUS: {
this._emitChars('-');
break;
}
case unicode.CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN;
this._emitChars('<');
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.SCRIPT_DATA;
this._emitChars('>');
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED;
this._emitChars(unicode.REPLACEMENT_CHARACTER);
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInScriptHtmlCommentLikeText);
this._emitEOFToken();
break;
}
default: {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED;
this._emitCodePoint(cp);
}
}
}
// Script data double escaped less-than sign state
//------------------------------------------------------------------
_stateScriptDataDoubleEscapedLessThanSign(cp) {
if (cp === unicode.CODE_POINTS.SOLIDUS) {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPE_END;
this._emitChars('/');
}
else {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED;
this._stateScriptDataDoubleEscaped(cp);
}
}
// Script data double escape end state
//------------------------------------------------------------------
_stateScriptDataDoubleEscapeEnd(cp) {
if (this.preprocessor.startsWith(unicode.SEQUENCES.SCRIPT, false) &&
isScriptDataDoubleEscapeSequenceEnd(this.preprocessor.peek(unicode.SEQUENCES.SCRIPT.length))) {
this._emitCodePoint(cp);
for (let i = 0; i < unicode.SEQUENCES.SCRIPT.length; i++) {
this._emitCodePoint(this._consume());
}
this.state = State.SCRIPT_DATA_ESCAPED;
}
else if (!this._ensureHibernation()) {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED;
this._stateScriptDataDoubleEscaped(cp);
}
}
// Before attribute name state
//------------------------------------------------------------------
_stateBeforeAttributeName(cp) {
switch (cp) {
case unicode.CODE_POINTS.SPACE:
case unicode.CODE_POINTS.LINE_FEED:
case unicode.CODE_POINTS.TABULATION:
case unicode.CODE_POINTS.FORM_FEED: {
// Ignore whitespace
break;
}
case unicode.CODE_POINTS.SOLIDUS:
case unicode.CODE_POINTS.GREATER_THAN_SIGN:
case unicode.CODE_POINTS.EOF: {
this.state = State.AFTER_ATTRIBUTE_NAME;
this._stateAfterAttributeName(cp);
break;
}
case unicode.CODE_POINTS.EQUALS_SIGN: {
this._err(errorCodes.ERR.unexpectedEqualsSignBeforeAttributeName);
this._createAttr('=');
this.state = State.ATTRIBUTE_NAME;
break;
}
default: {
this._createAttr('');
this.state = State.ATTRIBUTE_NAME;
this._stateAttributeName(cp);
}
}
}
// Attribute name state
//------------------------------------------------------------------
_stateAttributeName(cp) {
switch (cp) {
case unicode.CODE_POINTS.SPACE:
case unicode.CODE_POINTS.LINE_FEED:
case unicode.CODE_POINTS.TABULATION:
case unicode.CODE_POINTS.FORM_FEED:
case unicode.CODE_POINTS.SOLIDUS:
case unicode.CODE_POINTS.GREATER_THAN_SIGN:
case unicode.CODE_POINTS.EOF: {
this._leaveAttrName();
this.state = State.AFTER_ATTRIBUTE_NAME;
this._stateAfterAttributeName(cp);
break;
}
case unicode.CODE_POINTS.EQUALS_SIGN: {
this._leaveAttrName();
this.state = State.BEFORE_ATTRIBUTE_VALUE;
break;
}
case unicode.CODE_POINTS.QUOTATION_MARK:
case unicode.CODE_POINTS.APOSTROPHE:
case unicode.CODE_POINTS.LESS_THAN_SIGN: {
this._err(errorCodes.ERR.unexpectedCharacterInAttributeName);
this.currentAttr.name += String.fromCodePoint(cp);
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
this.currentAttr.name += unicode.REPLACEMENT_CHARACTER;
break;
}
default: {
this.currentAttr.name += String.fromCodePoint(isAsciiUpper(cp) ? toAsciiLower(cp) : cp);
}
}
}
// After attribute name state
//------------------------------------------------------------------
_stateAfterAttributeName(cp) {
switch (cp) {
case unicode.CODE_POINTS.SPACE:
case unicode.CODE_POINTS.LINE_FEED:
case unicode.CODE_POINTS.TABULATION:
case unicode.CODE_POINTS.FORM_FEED: {
// Ignore whitespace
break;
}
case unicode.CODE_POINTS.SOLIDUS: {
this.state = State.SELF_CLOSING_START_TAG;
break;
}
case unicode.CODE_POINTS.EQUALS_SIGN: {
this.state = State.BEFORE_ATTRIBUTE_VALUE;
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
this.emitCurrentTagToken();
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInTag);
this._emitEOFToken();
break;
}
default: {
this._createAttr('');
this.state = State.ATTRIBUTE_NAME;
this._stateAttributeName(cp);
}
}
}
// Before attribute value state
//------------------------------------------------------------------
_stateBeforeAttributeValue(cp) {
switch (cp) {
case unicode.CODE_POINTS.SPACE:
case unicode.CODE_POINTS.LINE_FEED:
case unicode.CODE_POINTS.TABULATION:
case unicode.CODE_POINTS.FORM_FEED: {
// Ignore whitespace
break;
}
case unicode.CODE_POINTS.QUOTATION_MARK: {
this.state = State.ATTRIBUTE_VALUE_DOUBLE_QUOTED;
break;
}
case unicode.CODE_POINTS.APOSTROPHE: {
this.state = State.ATTRIBUTE_VALUE_SINGLE_QUOTED;
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes.ERR.missingAttributeValue);
this.state = State.DATA;
this.emitCurrentTagToken();
break;
}
default: {
this.state = State.ATTRIBUTE_VALUE_UNQUOTED;
this._stateAttributeValueUnquoted(cp);
}
}
}
// Attribute value (double-quoted) state
//------------------------------------------------------------------
_stateAttributeValueDoubleQuoted(cp) {
switch (cp) {
case unicode.CODE_POINTS.QUOTATION_MARK: {
this.state = State.AFTER_ATTRIBUTE_VALUE_QUOTED;
break;
}
case unicode.CODE_POINTS.AMPERSAND: {
this.returnState = State.ATTRIBUTE_VALUE_DOUBLE_QUOTED;
this.state = State.CHARACTER_REFERENCE;
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
this.currentAttr.value += unicode.REPLACEMENT_CHARACTER;
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInTag);
this._emitEOFToken();
break;
}
default: {
this.currentAttr.value += String.fromCodePoint(cp);
}
}
}
// Attribute value (single-quoted) state
//------------------------------------------------------------------
_stateAttributeValueSingleQuoted(cp) {
switch (cp) {
case unicode.CODE_POINTS.APOSTROPHE: {
this.state = State.AFTER_ATTRIBUTE_VALUE_QUOTED;
break;
}
case unicode.CODE_POINTS.AMPERSAND: {
this.returnState = State.ATTRIBUTE_VALUE_SINGLE_QUOTED;
this.state = State.CHARACTER_REFERENCE;
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
this.currentAttr.value += unicode.REPLACEMENT_CHARACTER;
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInTag);
this._emitEOFToken();
break;
}
default: {
this.currentAttr.value += String.fromCodePoint(cp);
}
}
}
// Attribute value (unquoted) state
//------------------------------------------------------------------
_stateAttributeValueUnquoted(cp) {
switch (cp) {
case unicode.CODE_POINTS.SPACE:
case unicode.CODE_POINTS.LINE_FEED:
case unicode.CODE_POINTS.TABULATION:
case unicode.CODE_POINTS.FORM_FEED: {
this._leaveAttrValue();
this.state = State.BEFORE_ATTRIBUTE_NAME;
break;
}
case unicode.CODE_POINTS.AMPERSAND: {
this.returnState = State.ATTRIBUTE_VALUE_UNQUOTED;
this.state = State.CHARACTER_REFERENCE;
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this._leaveAttrValue();
this.state = State.DATA;
this.emitCurrentTagToken();
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
this.currentAttr.value += unicode.REPLACEMENT_CHARACTER;
break;
}
case unicode.CODE_POINTS.QUOTATION_MARK:
case unicode.CODE_POINTS.APOSTROPHE:
case unicode.CODE_POINTS.LESS_THAN_SIGN:
case unicode.CODE_POINTS.EQUALS_SIGN:
case unicode.CODE_POINTS.GRAVE_ACCENT: {
this._err(errorCodes.ERR.unexpectedCharacterInUnquotedAttributeValue);
this.currentAttr.value += String.fromCodePoint(cp);
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInTag);
this._emitEOFToken();
break;
}
default: {
this.currentAttr.value += String.fromCodePoint(cp);
}
}
}
// After attribute value (quoted) state
//------------------------------------------------------------------
_stateAfterAttributeValueQuoted(cp) {
switch (cp) {
case unicode.CODE_POINTS.SPACE:
case unicode.CODE_POINTS.LINE_FEED:
case unicode.CODE_POINTS.TABULATION:
case unicode.CODE_POINTS.FORM_FEED: {
this._leaveAttrValue();
this.state = State.BEFORE_ATTRIBUTE_NAME;
break;
}
case unicode.CODE_POINTS.SOLIDUS: {
this._leaveAttrValue();
this.state = State.SELF_CLOSING_START_TAG;
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this._leaveAttrValue();
this.state = State.DATA;
this.emitCurrentTagToken();
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInTag);
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes.ERR.missingWhitespaceBetweenAttributes);
this.state = State.BEFORE_ATTRIBUTE_NAME;
this._stateBeforeAttributeName(cp);
}
}
}
// Self-closing start tag state
//------------------------------------------------------------------
_stateSelfClosingStartTag(cp) {
switch (cp) {
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
const token = this.currentToken;
token.selfClosing = true;
this.state = State.DATA;
this.emitCurrentTagToken();
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInTag);
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes.ERR.unexpectedSolidusInTag);
this.state = State.BEFORE_ATTRIBUTE_NAME;
this._stateBeforeAttributeName(cp);
}
}
}
// Bogus comment state
//------------------------------------------------------------------
_stateBogusComment(cp) {
const token = this.currentToken;
switch (cp) {
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
this.emitCurrentComment(token);
break;
}
case unicode.CODE_POINTS.EOF: {
this.emitCurrentComment(token);
this._emitEOFToken();
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
token.data += unicode.REPLACEMENT_CHARACTER;
break;
}
default: {
token.data += String.fromCodePoint(cp);
}
}
}
// Markup declaration open state
//------------------------------------------------------------------
_stateMarkupDeclarationOpen(cp) {
if (this._consumeSequenceIfMatch(unicode.SEQUENCES.DASH_DASH, true)) {
this._createCommentToken(unicode.SEQUENCES.DASH_DASH.length + 1);
this.state = State.COMMENT_START;
}
else if (this._consumeSequenceIfMatch(unicode.SEQUENCES.DOCTYPE, false)) {
// NOTE: Doctypes tokens are created without fixed offsets. We keep track of the moment a doctype *might* start here.
this.currentLocation = this.getCurrentLocation(unicode.SEQUENCES.DOCTYPE.length + 1);
this.state = State.DOCTYPE;
}
else if (this._consumeSequenceIfMatch(unicode.SEQUENCES.CDATA_START, true)) {
if (this.inForeignNode) {
this.state = State.CDATA_SECTION;
}
else {
this._err(errorCodes.ERR.cdataInHtmlContent);
this._createCommentToken(unicode.SEQUENCES.CDATA_START.length + 1);
this.currentToken.data = '[CDATA[';
this.state = State.BOGUS_COMMENT;
}
}
//NOTE: Sequence lookups can be abrupted by hibernation. In that case, lookup
//results are no longer valid and we will need to start over.
else if (!this._ensureHibernation()) {
this._err(errorCodes.ERR.incorrectlyOpenedComment);
this._createCommentToken(2);
this.state = State.BOGUS_COMMENT;
this._stateBogusComment(cp);
}
}
// Comment start state
//------------------------------------------------------------------
_stateCommentStart(cp) {
switch (cp) {
case unicode.CODE_POINTS.HYPHEN_MINUS: {
this.state = State.COMMENT_START_DASH;
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes.ERR.abruptClosingOfEmptyComment);
this.state = State.DATA;
const token = this.currentToken;
this.emitCurrentComment(token);
break;
}
default: {
this.state = State.COMMENT;
this._stateComment(cp);
}
}
}
// Comment start dash state
//------------------------------------------------------------------
_stateCommentStartDash(cp) {
const token = this.currentToken;
switch (cp) {
case unicode.CODE_POINTS.HYPHEN_MINUS: {
this.state = State.COMMENT_END;
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes.ERR.abruptClosingOfEmptyComment);
this.state = State.DATA;
this.emitCurrentComment(token);
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInComment);
this.emitCurrentComment(token);
this._emitEOFToken();
break;
}
default: {
token.data += '-';
this.state = State.COMMENT;
this._stateComment(cp);
}
}
}
// Comment state
//------------------------------------------------------------------
_stateComment(cp) {
const token = this.currentToken;
switch (cp) {
case unicode.CODE_POINTS.HYPHEN_MINUS: {
this.state = State.COMMENT_END_DASH;
break;
}
case unicode.CODE_POINTS.LESS_THAN_SIGN: {
token.data += '<';
this.state = State.COMMENT_LESS_THAN_SIGN;
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
token.data += unicode.REPLACEMENT_CHARACTER;
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInComment);
this.emitCurrentComment(token);
this._emitEOFToken();
break;
}
default: {
token.data += String.fromCodePoint(cp);
}
}
}
// Comment less-than sign state
//------------------------------------------------------------------
_stateCommentLessThanSign(cp) {
const token = this.currentToken;
switch (cp) {
case unicode.CODE_POINTS.EXCLAMATION_MARK: {
token.data += '!';
this.state = State.COMMENT_LESS_THAN_SIGN_BANG;
break;
}
case unicode.CODE_POINTS.LESS_THAN_SIGN: {
token.data += '<';
break;
}
default: {
this.state = State.COMMENT;
this._stateComment(cp);
}
}
}
// Comment less-than sign bang state
//------------------------------------------------------------------
_stateCommentLessThanSignBang(cp) {
if (cp === unicode.CODE_POINTS.HYPHEN_MINUS) {
this.state = State.COMMENT_LESS_THAN_SIGN_BANG_DASH;
}
else {
this.state = State.COMMENT;
this._stateComment(cp);
}
}
// Comment less-than sign bang dash state
//------------------------------------------------------------------
_stateCommentLessThanSignBangDash(cp) {
if (cp === unicode.CODE_POINTS.HYPHEN_MINUS) {
this.state = State.COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH;
}
else {
this.state = State.COMMENT_END_DASH;
this._stateCommentEndDash(cp);
}
}
// Comment less-than sign bang dash dash state
//------------------------------------------------------------------
_stateCommentLessThanSignBangDashDash(cp) {
if (cp !== unicode.CODE_POINTS.GREATER_THAN_SIGN && cp !== unicode.CODE_POINTS.EOF) {
this._err(errorCodes.ERR.nestedComment);
}
this.state = State.COMMENT_END;
this._stateCommentEnd(cp);
}
// Comment end dash state
//------------------------------------------------------------------
_stateCommentEndDash(cp) {
const token = this.currentToken;
switch (cp) {
case unicode.CODE_POINTS.HYPHEN_MINUS: {
this.state = State.COMMENT_END;
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInComment);
this.emitCurrentComment(token);
this._emitEOFToken();
break;
}
default: {
token.data += '-';
this.state = State.COMMENT;
this._stateComment(cp);
}
}
}
// Comment end state
//------------------------------------------------------------------
_stateCommentEnd(cp) {
const token = this.currentToken;
switch (cp) {
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
this.emitCurrentComment(token);
break;
}
case unicode.CODE_POINTS.EXCLAMATION_MARK: {
this.state = State.COMMENT_END_BANG;
break;
}
case unicode.CODE_POINTS.HYPHEN_MINUS: {
token.data += '-';
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInComment);
this.emitCurrentComment(token);
this._emitEOFToken();
break;
}
default: {
token.data += '--';
this.state = State.COMMENT;
this._stateComment(cp);
}
}
}
// Comment end bang state
//------------------------------------------------------------------
_stateCommentEndBang(cp) {
const token = this.currentToken;
switch (cp) {
case unicode.CODE_POINTS.HYPHEN_MINUS: {
token.data += '--!';
this.state = State.COMMENT_END_DASH;
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes.ERR.incorrectlyClosedComment);
this.state = State.DATA;
this.emitCurrentComment(token);
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInComment);
this.emitCurrentComment(token);
this._emitEOFToken();
break;
}
default: {
token.data += '--!';
this.state = State.COMMENT;
this._stateComment(cp);
}
}
}
// DOCTYPE state
//------------------------------------------------------------------
_stateDoctype(cp) {
switch (cp) {
case unicode.CODE_POINTS.SPACE:
case unicode.CODE_POINTS.LINE_FEED:
case unicode.CODE_POINTS.TABULATION:
case unicode.CODE_POINTS.FORM_FEED: {
this.state = State.BEFORE_DOCTYPE_NAME;
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.BEFORE_DOCTYPE_NAME;
this._stateBeforeDoctypeName(cp);
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInDoctype);
this._createDoctypeToken(null);
const token = this.currentToken;
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes.ERR.missingWhitespaceBeforeDoctypeName);
this.state = State.BEFORE_DOCTYPE_NAME;
this._stateBeforeDoctypeName(cp);
}
}
}
// Before DOCTYPE name state
//------------------------------------------------------------------
_stateBeforeDoctypeName(cp) {
if (isAsciiUpper(cp)) {
this._createDoctypeToken(String.fromCharCode(toAsciiLower(cp)));
this.state = State.DOCTYPE_NAME;
}
else
switch (cp) {
case unicode.CODE_POINTS.SPACE:
case unicode.CODE_POINTS.LINE_FEED:
case unicode.CODE_POINTS.TABULATION:
case unicode.CODE_POINTS.FORM_FEED: {
// Ignore whitespace
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
this._createDoctypeToken(unicode.REPLACEMENT_CHARACTER);
this.state = State.DOCTYPE_NAME;
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes.ERR.missingDoctypeName);
this._createDoctypeToken(null);
const token = this.currentToken;
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInDoctype);
this._createDoctypeToken(null);
const token = this.currentToken;
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._createDoctypeToken(String.fromCodePoint(cp));
this.state = State.DOCTYPE_NAME;
}
}
}
// DOCTYPE name state
//------------------------------------------------------------------
_stateDoctypeName(cp) {
const token = this.currentToken;
switch (cp) {
case unicode.CODE_POINTS.SPACE:
case unicode.CODE_POINTS.LINE_FEED:
case unicode.CODE_POINTS.TABULATION:
case unicode.CODE_POINTS.FORM_FEED: {
this.state = State.AFTER_DOCTYPE_NAME;
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
this.emitCurrentDoctype(token);
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
token.name += unicode.REPLACEMENT_CHARACTER;
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
token.name += String.fromCodePoint(isAsciiUpper(cp) ? toAsciiLower(cp) : cp);
}
}
}
// After DOCTYPE name state
//------------------------------------------------------------------
_stateAfterDoctypeName(cp) {
const token = this.currentToken;
switch (cp) {
case unicode.CODE_POINTS.SPACE:
case unicode.CODE_POINTS.LINE_FEED:
case unicode.CODE_POINTS.TABULATION:
case unicode.CODE_POINTS.FORM_FEED: {
// Ignore whitespace
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
this.emitCurrentDoctype(token);
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
if (this._consumeSequenceIfMatch(unicode.SEQUENCES.PUBLIC, false)) {
this.state = State.AFTER_DOCTYPE_PUBLIC_KEYWORD;
}
else if (this._consumeSequenceIfMatch(unicode.SEQUENCES.SYSTEM, false)) {
this.state = State.AFTER_DOCTYPE_SYSTEM_KEYWORD;
}
//NOTE: sequence lookup can be abrupted by hibernation. In that case lookup
//results are no longer valid and we will need to start over.
else if (!this._ensureHibernation()) {
this._err(errorCodes.ERR.invalidCharacterSequenceAfterDoctypeName);
token.forceQuirks = true;
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
}
// After DOCTYPE public keyword state
//------------------------------------------------------------------
_stateAfterDoctypePublicKeyword(cp) {
const token = this.currentToken;
switch (cp) {
case unicode.CODE_POINTS.SPACE:
case unicode.CODE_POINTS.LINE_FEED:
case unicode.CODE_POINTS.TABULATION:
case unicode.CODE_POINTS.FORM_FEED: {
this.state = State.BEFORE_DOCTYPE_PUBLIC_IDENTIFIER;
break;
}
case unicode.CODE_POINTS.QUOTATION_MARK: {
this._err(errorCodes.ERR.missingWhitespaceAfterDoctypePublicKeyword);
token.publicId = '';
this.state = State.DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED;
break;
}
case unicode.CODE_POINTS.APOSTROPHE: {
this._err(errorCodes.ERR.missingWhitespaceAfterDoctypePublicKeyword);
token.publicId = '';
this.state = State.DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED;
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes.ERR.missingDoctypePublicIdentifier);
token.forceQuirks = true;
this.state = State.DATA;
this.emitCurrentDoctype(token);
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes.ERR.missingQuoteBeforeDoctypePublicIdentifier);
token.forceQuirks = true;
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
// Before DOCTYPE public identifier state
//------------------------------------------------------------------
_stateBeforeDoctypePublicIdentifier(cp) {
const token = this.currentToken;
switch (cp) {
case unicode.CODE_POINTS.SPACE:
case unicode.CODE_POINTS.LINE_FEED:
case unicode.CODE_POINTS.TABULATION:
case unicode.CODE_POINTS.FORM_FEED: {
// Ignore whitespace
break;
}
case unicode.CODE_POINTS.QUOTATION_MARK: {
token.publicId = '';
this.state = State.DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED;
break;
}
case unicode.CODE_POINTS.APOSTROPHE: {
token.publicId = '';
this.state = State.DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED;
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes.ERR.missingDoctypePublicIdentifier);
token.forceQuirks = true;
this.state = State.DATA;
this.emitCurrentDoctype(token);
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes.ERR.missingQuoteBeforeDoctypePublicIdentifier);
token.forceQuirks = true;
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
// DOCTYPE public identifier (double-quoted) state
//------------------------------------------------------------------
_stateDoctypePublicIdentifierDoubleQuoted(cp) {
const token = this.currentToken;
switch (cp) {
case unicode.CODE_POINTS.QUOTATION_MARK: {
this.state = State.AFTER_DOCTYPE_PUBLIC_IDENTIFIER;
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
token.publicId += unicode.REPLACEMENT_CHARACTER;
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes.ERR.abruptDoctypePublicIdentifier);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
token.publicId += String.fromCodePoint(cp);
}
}
}
// DOCTYPE public identifier (single-quoted) state
//------------------------------------------------------------------
_stateDoctypePublicIdentifierSingleQuoted(cp) {
const token = this.currentToken;
switch (cp) {
case unicode.CODE_POINTS.APOSTROPHE: {
this.state = State.AFTER_DOCTYPE_PUBLIC_IDENTIFIER;
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
token.publicId += unicode.REPLACEMENT_CHARACTER;
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes.ERR.abruptDoctypePublicIdentifier);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
token.publicId += String.fromCodePoint(cp);
}
}
}
// After DOCTYPE public identifier state
//------------------------------------------------------------------
_stateAfterDoctypePublicIdentifier(cp) {
const token = this.currentToken;
switch (cp) {
case unicode.CODE_POINTS.SPACE:
case unicode.CODE_POINTS.LINE_FEED:
case unicode.CODE_POINTS.TABULATION:
case unicode.CODE_POINTS.FORM_FEED: {
this.state = State.BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS;
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
this.emitCurrentDoctype(token);
break;
}
case unicode.CODE_POINTS.QUOTATION_MARK: {
this._err(errorCodes.ERR.missingWhitespaceBetweenDoctypePublicAndSystemIdentifiers);
token.systemId = '';
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED;
break;
}
case unicode.CODE_POINTS.APOSTROPHE: {
this._err(errorCodes.ERR.missingWhitespaceBetweenDoctypePublicAndSystemIdentifiers);
token.systemId = '';
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED;
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes.ERR.missingQuoteBeforeDoctypeSystemIdentifier);
token.forceQuirks = true;
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
// Between DOCTYPE public and system identifiers state
//------------------------------------------------------------------
_stateBetweenDoctypePublicAndSystemIdentifiers(cp) {
const token = this.currentToken;
switch (cp) {
case unicode.CODE_POINTS.SPACE:
case unicode.CODE_POINTS.LINE_FEED:
case unicode.CODE_POINTS.TABULATION:
case unicode.CODE_POINTS.FORM_FEED: {
// Ignore whitespace
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case unicode.CODE_POINTS.QUOTATION_MARK: {
token.systemId = '';
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED;
break;
}
case unicode.CODE_POINTS.APOSTROPHE: {
token.systemId = '';
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED;
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes.ERR.missingQuoteBeforeDoctypeSystemIdentifier);
token.forceQuirks = true;
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
// After DOCTYPE system keyword state
//------------------------------------------------------------------
_stateAfterDoctypeSystemKeyword(cp) {
const token = this.currentToken;
switch (cp) {
case unicode.CODE_POINTS.SPACE:
case unicode.CODE_POINTS.LINE_FEED:
case unicode.CODE_POINTS.TABULATION:
case unicode.CODE_POINTS.FORM_FEED: {
this.state = State.BEFORE_DOCTYPE_SYSTEM_IDENTIFIER;
break;
}
case unicode.CODE_POINTS.QUOTATION_MARK: {
this._err(errorCodes.ERR.missingWhitespaceAfterDoctypeSystemKeyword);
token.systemId = '';
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED;
break;
}
case unicode.CODE_POINTS.APOSTROPHE: {
this._err(errorCodes.ERR.missingWhitespaceAfterDoctypeSystemKeyword);
token.systemId = '';
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED;
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes.ERR.missingDoctypeSystemIdentifier);
token.forceQuirks = true;
this.state = State.DATA;
this.emitCurrentDoctype(token);
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes.ERR.missingQuoteBeforeDoctypeSystemIdentifier);
token.forceQuirks = true;
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
// Before DOCTYPE system identifier state
//------------------------------------------------------------------
_stateBeforeDoctypeSystemIdentifier(cp) {
const token = this.currentToken;
switch (cp) {
case unicode.CODE_POINTS.SPACE:
case unicode.CODE_POINTS.LINE_FEED:
case unicode.CODE_POINTS.TABULATION:
case unicode.CODE_POINTS.FORM_FEED: {
// Ignore whitespace
break;
}
case unicode.CODE_POINTS.QUOTATION_MARK: {
token.systemId = '';
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED;
break;
}
case unicode.CODE_POINTS.APOSTROPHE: {
token.systemId = '';
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED;
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes.ERR.missingDoctypeSystemIdentifier);
token.forceQuirks = true;
this.state = State.DATA;
this.emitCurrentDoctype(token);
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes.ERR.missingQuoteBeforeDoctypeSystemIdentifier);
token.forceQuirks = true;
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
// DOCTYPE system identifier (double-quoted) state
//------------------------------------------------------------------
_stateDoctypeSystemIdentifierDoubleQuoted(cp) {
const token = this.currentToken;
switch (cp) {
case unicode.CODE_POINTS.QUOTATION_MARK: {
this.state = State.AFTER_DOCTYPE_SYSTEM_IDENTIFIER;
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
token.systemId += unicode.REPLACEMENT_CHARACTER;
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes.ERR.abruptDoctypeSystemIdentifier);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
token.systemId += String.fromCodePoint(cp);
}
}
}
// DOCTYPE system identifier (single-quoted) state
//------------------------------------------------------------------
_stateDoctypeSystemIdentifierSingleQuoted(cp) {
const token = this.currentToken;
switch (cp) {
case unicode.CODE_POINTS.APOSTROPHE: {
this.state = State.AFTER_DOCTYPE_SYSTEM_IDENTIFIER;
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
token.systemId += unicode.REPLACEMENT_CHARACTER;
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this._err(errorCodes.ERR.abruptDoctypeSystemIdentifier);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
token.systemId += String.fromCodePoint(cp);
}
}
}
// After DOCTYPE system identifier state
//------------------------------------------------------------------
_stateAfterDoctypeSystemIdentifier(cp) {
const token = this.currentToken;
switch (cp) {
case unicode.CODE_POINTS.SPACE:
case unicode.CODE_POINTS.LINE_FEED:
case unicode.CODE_POINTS.TABULATION:
case unicode.CODE_POINTS.FORM_FEED: {
// Ignore whitespace
break;
}
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(errorCodes.ERR.unexpectedCharacterAfterDoctypeSystemIdentifier);
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
// Bogus DOCTYPE state
//------------------------------------------------------------------
_stateBogusDoctype(cp) {
const token = this.currentToken;
switch (cp) {
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case unicode.CODE_POINTS.NULL: {
this._err(errorCodes.ERR.unexpectedNullCharacter);
break;
}
case unicode.CODE_POINTS.EOF: {
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
// Do nothing
}
}
// CDATA section state
//------------------------------------------------------------------
_stateCdataSection(cp) {
switch (cp) {
case unicode.CODE_POINTS.RIGHT_SQUARE_BRACKET: {
this.state = State.CDATA_SECTION_BRACKET;
break;
}
case unicode.CODE_POINTS.EOF: {
this._err(errorCodes.ERR.eofInCdata);
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// CDATA section bracket state
//------------------------------------------------------------------
_stateCdataSectionBracket(cp) {
if (cp === unicode.CODE_POINTS.RIGHT_SQUARE_BRACKET) {
this.state = State.CDATA_SECTION_END;
}
else {
this._emitChars(']');
this.state = State.CDATA_SECTION;
this._stateCdataSection(cp);
}
}
// CDATA section end state
//------------------------------------------------------------------
_stateCdataSectionEnd(cp) {
switch (cp) {
case unicode.CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
break;
}
case unicode.CODE_POINTS.RIGHT_SQUARE_BRACKET: {
this._emitChars(']');
break;
}
default: {
this._emitChars(']]');
this.state = State.CDATA_SECTION;
this._stateCdataSection(cp);
}
}
}
// Character reference state
//------------------------------------------------------------------
_stateCharacterReference(cp) {
if (cp === unicode.CODE_POINTS.NUMBER_SIGN) {
this.state = State.NUMERIC_CHARACTER_REFERENCE;
}
else if (isAsciiAlphaNumeric(cp)) {
this.state = State.NAMED_CHARACTER_REFERENCE;
this._stateNamedCharacterReference(cp);
}
else {
this._flushCodePointConsumedAsCharacterReference(unicode.CODE_POINTS.AMPERSAND);
this._reconsumeInState(this.returnState, cp);
}
}
// Named character reference state
//------------------------------------------------------------------
_stateNamedCharacterReference(cp) {
const matchResult = this._matchNamedCharacterReference(cp);
//NOTE: Matching can be abrupted by hibernation. In that case, match
//results are no longer valid and we will need to start over.
if (this._ensureHibernation()) ;
else if (matchResult) {
for (let i = 0; i < matchResult.length; i++) {
this._flushCodePointConsumedAsCharacterReference(matchResult[i]);
}
this.state = this.returnState;
}
else {
this._flushCodePointConsumedAsCharacterReference(unicode.CODE_POINTS.AMPERSAND);
this.state = State.AMBIGUOUS_AMPERSAND;
}
}
// Ambiguos ampersand state
//------------------------------------------------------------------
_stateAmbiguousAmpersand(cp) {
if (isAsciiAlphaNumeric(cp)) {
this._flushCodePointConsumedAsCharacterReference(cp);
}
else {
if (cp === unicode.CODE_POINTS.SEMICOLON) {
this._err(errorCodes.ERR.unknownNamedCharacterReference);
}
this._reconsumeInState(this.returnState, cp);
}
}
// Numeric character reference state
//------------------------------------------------------------------
_stateNumericCharacterReference(cp) {
this.charRefCode = 0;
if (cp === unicode.CODE_POINTS.LATIN_SMALL_X || cp === unicode.CODE_POINTS.LATIN_CAPITAL_X) {
this.state = State.HEXADEMICAL_CHARACTER_REFERENCE_START;
}
// Inlined decimal character reference start state
else if (isAsciiDigit(cp)) {
this.state = State.DECIMAL_CHARACTER_REFERENCE;
this._stateDecimalCharacterReference(cp);
}
else {
this._err(errorCodes.ERR.absenceOfDigitsInNumericCharacterReference);
this._flushCodePointConsumedAsCharacterReference(unicode.CODE_POINTS.AMPERSAND);
this._flushCodePointConsumedAsCharacterReference(unicode.CODE_POINTS.NUMBER_SIGN);
this._reconsumeInState(this.returnState, cp);
}
}
// Hexademical character reference start state
//------------------------------------------------------------------
_stateHexademicalCharacterReferenceStart(cp) {
if (isAsciiHexDigit(cp)) {
this.state = State.HEXADEMICAL_CHARACTER_REFERENCE;
this._stateHexademicalCharacterReference(cp);
}
else {
this._err(errorCodes.ERR.absenceOfDigitsInNumericCharacterReference);
this._flushCodePointConsumedAsCharacterReference(unicode.CODE_POINTS.AMPERSAND);
this._flushCodePointConsumedAsCharacterReference(unicode.CODE_POINTS.NUMBER_SIGN);
this._unconsume(2);
this.state = this.returnState;
}
}
// Hexademical character reference state
//------------------------------------------------------------------
_stateHexademicalCharacterReference(cp) {
if (isAsciiUpperHexDigit(cp)) {
this.charRefCode = this.charRefCode * 16 + cp - 0x37;
}
else if (isAsciiLowerHexDigit(cp)) {
this.charRefCode = this.charRefCode * 16 + cp - 0x57;
}
else if (isAsciiDigit(cp)) {
this.charRefCode = this.charRefCode * 16 + cp - 0x30;
}
else if (cp === unicode.CODE_POINTS.SEMICOLON) {
this.state = State.NUMERIC_CHARACTER_REFERENCE_END;
}
else {
this._err(errorCodes.ERR.missingSemicolonAfterCharacterReference);
this.state = State.NUMERIC_CHARACTER_REFERENCE_END;
this._stateNumericCharacterReferenceEnd(cp);
}
}
// Decimal character reference state
//------------------------------------------------------------------
_stateDecimalCharacterReference(cp) {
if (isAsciiDigit(cp)) {
this.charRefCode = this.charRefCode * 10 + cp - 0x30;
}
else if (cp === unicode.CODE_POINTS.SEMICOLON) {
this.state = State.NUMERIC_CHARACTER_REFERENCE_END;
}
else {
this._err(errorCodes.ERR.missingSemicolonAfterCharacterReference);
this.state = State.NUMERIC_CHARACTER_REFERENCE_END;
this._stateNumericCharacterReferenceEnd(cp);
}
}
// Numeric character reference end state
//------------------------------------------------------------------
_stateNumericCharacterReferenceEnd(cp) {
if (this.charRefCode === unicode.CODE_POINTS.NULL) {
this._err(errorCodes.ERR.nullCharacterReference);
this.charRefCode = unicode.CODE_POINTS.REPLACEMENT_CHARACTER;
}
else if (this.charRefCode > 1114111) {
this._err(errorCodes.ERR.characterReferenceOutsideUnicodeRange);
this.charRefCode = unicode.CODE_POINTS.REPLACEMENT_CHARACTER;
}
else if ((0, unicode.isSurrogate)(this.charRefCode)) {
this._err(errorCodes.ERR.surrogateCharacterReference);
this.charRefCode = unicode.CODE_POINTS.REPLACEMENT_CHARACTER;
}
else if ((0, unicode.isUndefinedCodePoint)(this.charRefCode)) {
this._err(errorCodes.ERR.noncharacterCharacterReference);
}
else if ((0, unicode.isControlCodePoint)(this.charRefCode) || this.charRefCode === unicode.CODE_POINTS.CARRIAGE_RETURN) {
this._err(errorCodes.ERR.controlCharacterReference);
const replacement = C1_CONTROLS_REFERENCE_REPLACEMENTS.get(this.charRefCode);
if (replacement !== undefined) {
this.charRefCode = replacement;
}
}
this._flushCodePointConsumedAsCharacterReference(this.charRefCode);
this._reconsumeInState(this.returnState, cp);
}
}
exports.Tokenizer = Tokenizer;
});
var openElementStack = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.OpenElementStack = void 0;
//Element utils
const IMPLICIT_END_TAG_REQUIRED = new Set([html.TAG_ID.DD, html.TAG_ID.DT, html.TAG_ID.LI, html.TAG_ID.OPTGROUP, html.TAG_ID.OPTION, html.TAG_ID.P, html.TAG_ID.RB, html.TAG_ID.RP, html.TAG_ID.RT, html.TAG_ID.RTC]);
const IMPLICIT_END_TAG_REQUIRED_THOROUGHLY = new Set([
...IMPLICIT_END_TAG_REQUIRED,
html.TAG_ID.CAPTION,
html.TAG_ID.COLGROUP,
html.TAG_ID.TBODY,
html.TAG_ID.TD,
html.TAG_ID.TFOOT,
html.TAG_ID.TH,
html.TAG_ID.THEAD,
html.TAG_ID.TR,
]);
const SCOPING_ELEMENT_NS = new Map([
[html.TAG_ID.APPLET, html.NS.HTML],
[html.TAG_ID.CAPTION, html.NS.HTML],
[html.TAG_ID.HTML, html.NS.HTML],
[html.TAG_ID.MARQUEE, html.NS.HTML],
[html.TAG_ID.OBJECT, html.NS.HTML],
[html.TAG_ID.TABLE, html.NS.HTML],
[html.TAG_ID.TD, html.NS.HTML],
[html.TAG_ID.TEMPLATE, html.NS.HTML],
[html.TAG_ID.TH, html.NS.HTML],
[html.TAG_ID.ANNOTATION_XML, html.NS.MATHML],
[html.TAG_ID.MI, html.NS.MATHML],
[html.TAG_ID.MN, html.NS.MATHML],
[html.TAG_ID.MO, html.NS.MATHML],
[html.TAG_ID.MS, html.NS.MATHML],
[html.TAG_ID.MTEXT, html.NS.MATHML],
[html.TAG_ID.DESC, html.NS.SVG],
[html.TAG_ID.FOREIGN_OBJECT, html.NS.SVG],
[html.TAG_ID.TITLE, html.NS.SVG],
]);
const NAMED_HEADERS = [html.TAG_ID.H1, html.TAG_ID.H2, html.TAG_ID.H3, html.TAG_ID.H4, html.TAG_ID.H5, html.TAG_ID.H6];
const TABLE_ROW_CONTEXT = [html.TAG_ID.TR, html.TAG_ID.TEMPLATE, html.TAG_ID.HTML];
const TABLE_BODY_CONTEXT = [html.TAG_ID.TBODY, html.TAG_ID.TFOOT, html.TAG_ID.THEAD, html.TAG_ID.TEMPLATE, html.TAG_ID.HTML];
const TABLE_CONTEXT = [html.TAG_ID.TABLE, html.TAG_ID.TEMPLATE, html.TAG_ID.HTML];
const TABLE_CELLS = [html.TAG_ID.TD, html.TAG_ID.TH];
//Stack of open elements
class OpenElementStack {
get currentTmplContentOrNode() {
return this._isInTemplate() ? this.treeAdapter.getTemplateContent(this.current) : this.current;
}
constructor(document, treeAdapter, handler) {
this.treeAdapter = treeAdapter;
this.handler = handler;
this.items = [];
this.tagIDs = [];
this.stackTop = -1;
this.tmplCount = 0;
this.currentTagId = html.TAG_ID.UNKNOWN;
this.current = document;
}
//Index of element
_indexOf(element) {
return this.items.lastIndexOf(element, this.stackTop);
}
//Update current element
_isInTemplate() {
return this.currentTagId === html.TAG_ID.TEMPLATE && this.treeAdapter.getNamespaceURI(this.current) === html.NS.HTML;
}
_updateCurrentElement() {
this.current = this.items[this.stackTop];
this.currentTagId = this.tagIDs[this.stackTop];
}
//Mutations
push(element, tagID) {
this.stackTop++;
this.items[this.stackTop] = element;
this.current = element;
this.tagIDs[this.stackTop] = tagID;
this.currentTagId = tagID;
if (this._isInTemplate()) {
this.tmplCount++;
}
this.handler.onItemPush(element, tagID, true);
}
pop() {
const popped = this.current;
if (this.tmplCount > 0 && this._isInTemplate()) {
this.tmplCount--;
}
this.stackTop--;
this._updateCurrentElement();
this.handler.onItemPop(popped, true);
}
replace(oldElement, newElement) {
const idx = this._indexOf(oldElement);
this.items[idx] = newElement;
if (idx === this.stackTop) {
this.current = newElement;
}
}
insertAfter(referenceElement, newElement, newElementID) {
const insertionIdx = this._indexOf(referenceElement) + 1;
this.items.splice(insertionIdx, 0, newElement);
this.tagIDs.splice(insertionIdx, 0, newElementID);
this.stackTop++;
if (insertionIdx === this.stackTop) {
this._updateCurrentElement();
}
this.handler.onItemPush(this.current, this.currentTagId, insertionIdx === this.stackTop);
}
popUntilTagNamePopped(tagName) {
let targetIdx = this.stackTop + 1;
do {
targetIdx = this.tagIDs.lastIndexOf(tagName, targetIdx - 1);
} while (targetIdx > 0 && this.treeAdapter.getNamespaceURI(this.items[targetIdx]) !== html.NS.HTML);
this.shortenToLength(targetIdx < 0 ? 0 : targetIdx);
}
shortenToLength(idx) {
while (this.stackTop >= idx) {
const popped = this.current;
if (this.tmplCount > 0 && this._isInTemplate()) {
this.tmplCount -= 1;
}
this.stackTop--;
this._updateCurrentElement();
this.handler.onItemPop(popped, this.stackTop < idx);
}
}
popUntilElementPopped(element) {
const idx = this._indexOf(element);
this.shortenToLength(idx < 0 ? 0 : idx);
}
popUntilPopped(tagNames, targetNS) {
const idx = this._indexOfTagNames(tagNames, targetNS);
this.shortenToLength(idx < 0 ? 0 : idx);
}
popUntilNumberedHeaderPopped() {
this.popUntilPopped(NAMED_HEADERS, html.NS.HTML);
}
popUntilTableCellPopped() {
this.popUntilPopped(TABLE_CELLS, html.NS.HTML);
}
popAllUpToHtmlElement() {
//NOTE: here we assume that the root <html> element is always first in the open element stack, so
//we perform this fast stack clean up.
this.tmplCount = 0;
this.shortenToLength(1);
}
_indexOfTagNames(tagNames, namespace) {
for (let i = this.stackTop; i >= 0; i--) {
if (tagNames.includes(this.tagIDs[i]) && this.treeAdapter.getNamespaceURI(this.items[i]) === namespace) {
return i;
}
}
return -1;
}
clearBackTo(tagNames, targetNS) {
const idx = this._indexOfTagNames(tagNames, targetNS);
this.shortenToLength(idx + 1);
}
clearBackToTableContext() {
this.clearBackTo(TABLE_CONTEXT, html.NS.HTML);
}
clearBackToTableBodyContext() {
this.clearBackTo(TABLE_BODY_CONTEXT, html.NS.HTML);
}
clearBackToTableRowContext() {
this.clearBackTo(TABLE_ROW_CONTEXT, html.NS.HTML);
}
remove(element) {
const idx = this._indexOf(element);
if (idx >= 0) {
if (idx === this.stackTop) {
this.pop();
}
else {
this.items.splice(idx, 1);
this.tagIDs.splice(idx, 1);
this.stackTop--;
this._updateCurrentElement();
this.handler.onItemPop(element, false);
}
}
}
//Search
tryPeekProperlyNestedBodyElement() {
//Properly nested <body> element (should be second element in stack).
return this.stackTop >= 1 && this.tagIDs[1] === html.TAG_ID.BODY ? this.items[1] : null;
}
contains(element) {
return this._indexOf(element) > -1;
}
getCommonAncestor(element) {
const elementIdx = this._indexOf(element) - 1;
return elementIdx >= 0 ? this.items[elementIdx] : null;
}
isRootHtmlElementCurrent() {
return this.stackTop === 0 && this.tagIDs[0] === html.TAG_ID.HTML;
}
//Element in scope
hasInScope(tagName) {
for (let i = this.stackTop; i >= 0; i--) {
const tn = this.tagIDs[i];
const ns = this.treeAdapter.getNamespaceURI(this.items[i]);
if (tn === tagName && ns === html.NS.HTML) {
return true;
}
if (SCOPING_ELEMENT_NS.get(tn) === ns) {
return false;
}
}
return true;
}
hasNumberedHeaderInScope() {
for (let i = this.stackTop; i >= 0; i--) {
const tn = this.tagIDs[i];
const ns = this.treeAdapter.getNamespaceURI(this.items[i]);
if ((0, html.isNumberedHeader)(tn) && ns === html.NS.HTML) {
return true;
}
if (SCOPING_ELEMENT_NS.get(tn) === ns) {
return false;
}
}
return true;
}
hasInListItemScope(tagName) {
for (let i = this.stackTop; i >= 0; i--) {
const tn = this.tagIDs[i];
const ns = this.treeAdapter.getNamespaceURI(this.items[i]);
if (tn === tagName && ns === html.NS.HTML) {
return true;
}
if (((tn === html.TAG_ID.UL || tn === html.TAG_ID.OL) && ns === html.NS.HTML) || SCOPING_ELEMENT_NS.get(tn) === ns) {
return false;
}
}
return true;
}
hasInButtonScope(tagName) {
for (let i = this.stackTop; i >= 0; i--) {
const tn = this.tagIDs[i];
const ns = this.treeAdapter.getNamespaceURI(this.items[i]);
if (tn === tagName && ns === html.NS.HTML) {
return true;
}
if ((tn === html.TAG_ID.BUTTON && ns === html.NS.HTML) || SCOPING_ELEMENT_NS.get(tn) === ns) {
return false;
}
}
return true;
}
hasInTableScope(tagName) {
for (let i = this.stackTop; i >= 0; i--) {
const tn = this.tagIDs[i];
const ns = this.treeAdapter.getNamespaceURI(this.items[i]);
if (ns !== html.NS.HTML) {
continue;
}
if (tn === tagName) {
return true;
}
if (tn === html.TAG_ID.TABLE || tn === html.TAG_ID.TEMPLATE || tn === html.TAG_ID.HTML) {
return false;
}
}
return true;
}
hasTableBodyContextInTableScope() {
for (let i = this.stackTop; i >= 0; i--) {
const tn = this.tagIDs[i];
const ns = this.treeAdapter.getNamespaceURI(this.items[i]);
if (ns !== html.NS.HTML) {
continue;
}
if (tn === html.TAG_ID.TBODY || tn === html.TAG_ID.THEAD || tn === html.TAG_ID.TFOOT) {
return true;
}
if (tn === html.TAG_ID.TABLE || tn === html.TAG_ID.HTML) {
return false;
}
}
return true;
}
hasInSelectScope(tagName) {
for (let i = this.stackTop; i >= 0; i--) {
const tn = this.tagIDs[i];
const ns = this.treeAdapter.getNamespaceURI(this.items[i]);
if (ns !== html.NS.HTML) {
continue;
}
if (tn === tagName) {
return true;
}
if (tn !== html.TAG_ID.OPTION && tn !== html.TAG_ID.OPTGROUP) {
return false;
}
}
return true;
}
//Implied end tags
generateImpliedEndTags() {
while (IMPLICIT_END_TAG_REQUIRED.has(this.currentTagId)) {
this.pop();
}
}
generateImpliedEndTagsThoroughly() {
while (IMPLICIT_END_TAG_REQUIRED_THOROUGHLY.has(this.currentTagId)) {
this.pop();
}
}
generateImpliedEndTagsWithExclusion(exclusionId) {
while (this.currentTagId !== exclusionId && IMPLICIT_END_TAG_REQUIRED_THOROUGHLY.has(this.currentTagId)) {
this.pop();
}
}
}
exports.OpenElementStack = OpenElementStack;
});
var formattingElementList = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.FormattingElementList = exports.EntryType = void 0;
//Const
const NOAH_ARK_CAPACITY = 3;
var EntryType;
(function (EntryType) {
EntryType[EntryType["Marker"] = 0] = "Marker";
EntryType[EntryType["Element"] = 1] = "Element";
})(EntryType = exports.EntryType || (exports.EntryType = {}));
const MARKER = { type: EntryType.Marker };
//List of formatting elements
class FormattingElementList {
constructor(treeAdapter) {
this.treeAdapter = treeAdapter;
this.entries = [];
this.bookmark = null;
}
//Noah Ark's condition
//OPTIMIZATION: at first we try to find possible candidates for exclusion using
//lightweight heuristics without thorough attributes check.
_getNoahArkConditionCandidates(newElement, neAttrs) {
const candidates = [];
const neAttrsLength = neAttrs.length;
const neTagName = this.treeAdapter.getTagName(newElement);
const neNamespaceURI = this.treeAdapter.getNamespaceURI(newElement);
for (let i = 0; i < this.entries.length; i++) {
const entry = this.entries[i];
if (entry.type === EntryType.Marker) {
break;
}
const { element } = entry;
if (this.treeAdapter.getTagName(element) === neTagName &&
this.treeAdapter.getNamespaceURI(element) === neNamespaceURI) {
const elementAttrs = this.treeAdapter.getAttrList(element);
if (elementAttrs.length === neAttrsLength) {
candidates.push({ idx: i, attrs: elementAttrs });
}
}
}
return candidates;
}
_ensureNoahArkCondition(newElement) {
if (this.entries.length < NOAH_ARK_CAPACITY)
return;
const neAttrs = this.treeAdapter.getAttrList(newElement);
const candidates = this._getNoahArkConditionCandidates(newElement, neAttrs);
if (candidates.length < NOAH_ARK_CAPACITY)
return;
//NOTE: build attrs map for the new element, so we can perform fast lookups
const neAttrsMap = new Map(neAttrs.map((neAttr) => [neAttr.name, neAttr.value]));
let validCandidates = 0;
//NOTE: remove bottommost candidates, until Noah's Ark condition will not be met
for (let i = 0; i < candidates.length; i++) {
const candidate = candidates[i];
// We know that `candidate.attrs.length === neAttrs.length`
if (candidate.attrs.every((cAttr) => neAttrsMap.get(cAttr.name) === cAttr.value)) {
validCandidates += 1;
if (validCandidates >= NOAH_ARK_CAPACITY) {
this.entries.splice(candidate.idx, 1);
}
}
}
}
//Mutations
insertMarker() {
this.entries.unshift(MARKER);
}
pushElement(element, token) {
this._ensureNoahArkCondition(element);
this.entries.unshift({
type: EntryType.Element,
element,
token,
});
}
insertElementAfterBookmark(element, token) {
const bookmarkIdx = this.entries.indexOf(this.bookmark);
this.entries.splice(bookmarkIdx, 0, {
type: EntryType.Element,
element,
token,
});
}
removeEntry(entry) {
const entryIndex = this.entries.indexOf(entry);
if (entryIndex >= 0) {
this.entries.splice(entryIndex, 1);
}
}
/**
* Clears the list of formatting elements up to the last marker.
*
* @see https://html.spec.whatwg.org/multipage/parsing.html#clear-the-list-of-active-formatting-elements-up-to-the-last-marker
*/
clearToLastMarker() {
const markerIdx = this.entries.indexOf(MARKER);
if (markerIdx >= 0) {
this.entries.splice(0, markerIdx + 1);
}
else {
this.entries.length = 0;
}
}
//Search
getElementEntryInScopeWithTagName(tagName) {
const entry = this.entries.find((entry) => entry.type === EntryType.Marker || this.treeAdapter.getTagName(entry.element) === tagName);
return entry && entry.type === EntryType.Element ? entry : null;
}
getElementEntry(element) {
return this.entries.find((entry) => entry.type === EntryType.Element && entry.element === element);
}
}
exports.FormattingElementList = FormattingElementList;
});
var _default$1 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.defaultTreeAdapter = void 0;
function createTextNode(value) {
return {
nodeName: '#text',
value,
parentNode: null,
};
}
exports.defaultTreeAdapter = {
//Node construction
createDocument() {
return {
nodeName: '#document',
mode: html.DOCUMENT_MODE.NO_QUIRKS,
childNodes: [],
};
},
createDocumentFragment() {
return {
nodeName: '#document-fragment',
childNodes: [],
};
},
createElement(tagName, namespaceURI, attrs) {
return {
nodeName: tagName,
tagName,
attrs,
namespaceURI,
childNodes: [],
parentNode: null,
};
},
createCommentNode(data) {
return {
nodeName: '#comment',
data,
parentNode: null,
};
},
//Tree mutation
appendChild(parentNode, newNode) {
parentNode.childNodes.push(newNode);
newNode.parentNode = parentNode;
},
insertBefore(parentNode, newNode, referenceNode) {
const insertionIdx = parentNode.childNodes.indexOf(referenceNode);
parentNode.childNodes.splice(insertionIdx, 0, newNode);
newNode.parentNode = parentNode;
},
setTemplateContent(templateElement, contentElement) {
templateElement.content = contentElement;
},
getTemplateContent(templateElement) {
return templateElement.content;
},
setDocumentType(document, name, publicId, systemId) {
const doctypeNode = document.childNodes.find((node) => node.nodeName === '#documentType');
if (doctypeNode) {
doctypeNode.name = name;
doctypeNode.publicId = publicId;
doctypeNode.systemId = systemId;
}
else {
const node = {
nodeName: '#documentType',
name,
publicId,
systemId,
parentNode: null,
};
exports.defaultTreeAdapter.appendChild(document, node);
}
},
setDocumentMode(document, mode) {
document.mode = mode;
},
getDocumentMode(document) {
return document.mode;
},
detachNode(node) {
if (node.parentNode) {
const idx = node.parentNode.childNodes.indexOf(node);
node.parentNode.childNodes.splice(idx, 1);
node.parentNode = null;
}
},
insertText(parentNode, text) {
if (parentNode.childNodes.length > 0) {
const prevNode = parentNode.childNodes[parentNode.childNodes.length - 1];
if (exports.defaultTreeAdapter.isTextNode(prevNode)) {
prevNode.value += text;
return;
}
}
exports.defaultTreeAdapter.appendChild(parentNode, createTextNode(text));
},
insertTextBefore(parentNode, text, referenceNode) {
const prevNode = parentNode.childNodes[parentNode.childNodes.indexOf(referenceNode) - 1];
if (prevNode && exports.defaultTreeAdapter.isTextNode(prevNode)) {
prevNode.value += text;
}
else {
exports.defaultTreeAdapter.insertBefore(parentNode, createTextNode(text), referenceNode);
}
},
adoptAttributes(recipient, attrs) {
const recipientAttrsMap = new Set(recipient.attrs.map((attr) => attr.name));
for (let j = 0; j < attrs.length; j++) {
if (!recipientAttrsMap.has(attrs[j].name)) {
recipient.attrs.push(attrs[j]);
}
}
},
//Tree traversing
getFirstChild(node) {
return node.childNodes[0];
},
getChildNodes(node) {
return node.childNodes;
},
getParentNode(node) {
return node.parentNode;
},
getAttrList(element) {
return element.attrs;
},
//Node data
getTagName(element) {
return element.tagName;
},
getNamespaceURI(element) {
return element.namespaceURI;
},
getTextNodeContent(textNode) {
return textNode.value;
},
getCommentNodeContent(commentNode) {
return commentNode.data;
},
getDocumentTypeNodeName(doctypeNode) {
return doctypeNode.name;
},
getDocumentTypeNodePublicId(doctypeNode) {
return doctypeNode.publicId;
},
getDocumentTypeNodeSystemId(doctypeNode) {
return doctypeNode.systemId;
},
//Node types
isTextNode(node) {
return node.nodeName === '#text';
},
isCommentNode(node) {
return node.nodeName === '#comment';
},
isDocumentTypeNode(node) {
return node.nodeName === '#documentType';
},
isElementNode(node) {
return Object.prototype.hasOwnProperty.call(node, 'tagName');
},
// Source code location
setNodeSourceCodeLocation(node, location) {
node.sourceCodeLocation = location;
},
getNodeSourceCodeLocation(node) {
return node.sourceCodeLocation;
},
updateNodeSourceCodeLocation(node, endLocation) {
node.sourceCodeLocation = Object.assign(Object.assign({}, node.sourceCodeLocation), endLocation);
},
};
});
var doctype = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.getDocumentMode = exports.isConforming = void 0;
//Const
const VALID_DOCTYPE_NAME = 'html';
const VALID_SYSTEM_ID = 'about:legacy-compat';
const QUIRKS_MODE_SYSTEM_ID = 'http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd';
const QUIRKS_MODE_PUBLIC_ID_PREFIXES = [
'+//silmaril//dtd html pro v0r11 19970101//',
'-//as//dtd html 3.0 aswedit + extensions//',
'-//advasoft ltd//dtd html 3.0 aswedit + extensions//',
'-//ietf//dtd html 2.0 level 1//',
'-//ietf//dtd html 2.0 level 2//',
'-//ietf//dtd html 2.0 strict level 1//',
'-//ietf//dtd html 2.0 strict level 2//',
'-//ietf//dtd html 2.0 strict//',
'-//ietf//dtd html 2.0//',
'-//ietf//dtd html 2.1e//',
'-//ietf//dtd html 3.0//',
'-//ietf//dtd html 3.2 final//',
'-//ietf//dtd html 3.2//',
'-//ietf//dtd html 3//',
'-//ietf//dtd html level 0//',
'-//ietf//dtd html level 1//',
'-//ietf//dtd html level 2//',
'-//ietf//dtd html level 3//',
'-//ietf//dtd html strict level 0//',
'-//ietf//dtd html strict level 1//',
'-//ietf//dtd html strict level 2//',
'-//ietf//dtd html strict level 3//',
'-//ietf//dtd html strict//',
'-//ietf//dtd html//',
'-//metrius//dtd metrius presentational//',
'-//microsoft//dtd internet explorer 2.0 html strict//',
'-//microsoft//dtd internet explorer 2.0 html//',
'-//microsoft//dtd internet explorer 2.0 tables//',
'-//microsoft//dtd internet explorer 3.0 html strict//',
'-//microsoft//dtd internet explorer 3.0 html//',
'-//microsoft//dtd internet explorer 3.0 tables//',
'-//netscape comm. corp.//dtd html//',
'-//netscape comm. corp.//dtd strict html//',
"-//o'reilly and associates//dtd html 2.0//",
"-//o'reilly and associates//dtd html extended 1.0//",
"-//o'reilly and associates//dtd html extended relaxed 1.0//",
'-//sq//dtd html 2.0 hotmetal + extensions//',
'-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//',
'-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//',
'-//spyglass//dtd html 2.0 extended//',
'-//sun microsystems corp.//dtd hotjava html//',
'-//sun microsystems corp.//dtd hotjava strict html//',
'-//w3c//dtd html 3 1995-03-24//',
'-//w3c//dtd html 3.2 draft//',
'-//w3c//dtd html 3.2 final//',
'-//w3c//dtd html 3.2//',
'-//w3c//dtd html 3.2s draft//',
'-//w3c//dtd html 4.0 frameset//',
'-//w3c//dtd html 4.0 transitional//',
'-//w3c//dtd html experimental 19960712//',
'-//w3c//dtd html experimental 970421//',
'-//w3c//dtd w3 html//',
'-//w3o//dtd w3 html 3.0//',
'-//webtechs//dtd mozilla html 2.0//',
'-//webtechs//dtd mozilla html//',
];
const QUIRKS_MODE_NO_SYSTEM_ID_PUBLIC_ID_PREFIXES = [
...QUIRKS_MODE_PUBLIC_ID_PREFIXES,
'-//w3c//dtd html 4.01 frameset//',
'-//w3c//dtd html 4.01 transitional//',
];
const QUIRKS_MODE_PUBLIC_IDS = new Set([
'-//w3o//dtd w3 html strict 3.0//en//',
'-/w3c/dtd html 4.0 transitional/en',
'html',
]);
const LIMITED_QUIRKS_PUBLIC_ID_PREFIXES = ['-//w3c//dtd xhtml 1.0 frameset//', '-//w3c//dtd xhtml 1.0 transitional//'];
const LIMITED_QUIRKS_WITH_SYSTEM_ID_PUBLIC_ID_PREFIXES = [
...LIMITED_QUIRKS_PUBLIC_ID_PREFIXES,
'-//w3c//dtd html 4.01 frameset//',
'-//w3c//dtd html 4.01 transitional//',
];
//Utils
function hasPrefix(publicId, prefixes) {
return prefixes.some((prefix) => publicId.startsWith(prefix));
}
//API
function isConforming(token) {
return (token.name === VALID_DOCTYPE_NAME &&
token.publicId === null &&
(token.systemId === null || token.systemId === VALID_SYSTEM_ID));
}
exports.isConforming = isConforming;
function getDocumentMode(token) {
if (token.name !== VALID_DOCTYPE_NAME) {
return html.DOCUMENT_MODE.QUIRKS;
}
const { systemId } = token;
if (systemId && systemId.toLowerCase() === QUIRKS_MODE_SYSTEM_ID) {
return html.DOCUMENT_MODE.QUIRKS;
}
let { publicId } = token;
if (publicId !== null) {
publicId = publicId.toLowerCase();
if (QUIRKS_MODE_PUBLIC_IDS.has(publicId)) {
return html.DOCUMENT_MODE.QUIRKS;
}
let prefixes = systemId === null ? QUIRKS_MODE_NO_SYSTEM_ID_PUBLIC_ID_PREFIXES : QUIRKS_MODE_PUBLIC_ID_PREFIXES;
if (hasPrefix(publicId, prefixes)) {
return html.DOCUMENT_MODE.QUIRKS;
}
prefixes =
systemId === null ? LIMITED_QUIRKS_PUBLIC_ID_PREFIXES : LIMITED_QUIRKS_WITH_SYSTEM_ID_PUBLIC_ID_PREFIXES;
if (hasPrefix(publicId, prefixes)) {
return html.DOCUMENT_MODE.LIMITED_QUIRKS;
}
}
return html.DOCUMENT_MODE.NO_QUIRKS;
}
exports.getDocumentMode = getDocumentMode;
});
var foreignContent = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.isIntegrationPoint = exports.adjustTokenSVGTagName = exports.adjustTokenXMLAttrs = exports.adjustTokenSVGAttrs = exports.adjustTokenMathMLAttrs = exports.causesExit = exports.SVG_TAG_NAMES_ADJUSTMENT_MAP = void 0;
//MIME types
const MIME_TYPES = {
TEXT_HTML: 'text/html',
APPLICATION_XML: 'application/xhtml+xml',
};
//Attributes
const DEFINITION_URL_ATTR = 'definitionurl';
const ADJUSTED_DEFINITION_URL_ATTR = 'definitionURL';
const SVG_ATTRS_ADJUSTMENT_MAP = new Map([
'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((attr) => [attr.toLowerCase(), attr]));
const XML_ATTRS_ADJUSTMENT_MAP = new Map([
['xlink:actuate', { prefix: 'xlink', name: 'actuate', namespace: html.NS.XLINK }],
['xlink:arcrole', { prefix: 'xlink', name: 'arcrole', namespace: html.NS.XLINK }],
['xlink:href', { prefix: 'xlink', name: 'href', namespace: html.NS.XLINK }],
['xlink:role', { prefix: 'xlink', name: 'role', namespace: html.NS.XLINK }],
['xlink:show', { prefix: 'xlink', name: 'show', namespace: html.NS.XLINK }],
['xlink:title', { prefix: 'xlink', name: 'title', namespace: html.NS.XLINK }],
['xlink:type', { prefix: 'xlink', name: 'type', namespace: html.NS.XLINK }],
['xml:base', { prefix: 'xml', name: 'base', namespace: html.NS.XML }],
['xml:lang', { prefix: 'xml', name: 'lang', namespace: html.NS.XML }],
['xml:space', { prefix: 'xml', name: 'space', namespace: html.NS.XML }],
['xmlns', { prefix: '', name: 'xmlns', namespace: html.NS.XMLNS }],
['xmlns:xlink', { prefix: 'xmlns', name: 'xlink', namespace: html.NS.XMLNS }],
]);
//SVG tag names adjustment map
exports.SVG_TAG_NAMES_ADJUSTMENT_MAP = new Map([
'altGlyph',
'altGlyphDef',
'altGlyphItem',
'animateColor',
'animateMotion',
'animateTransform',
'clipPath',
'feBlend',
'feColorMatrix',
'feComponentTransfer',
'feComposite',
'feConvolveMatrix',
'feDiffuseLighting',
'feDisplacementMap',
'feDistantLight',
'feFlood',
'feFuncA',
'feFuncB',
'feFuncG',
'feFuncR',
'feGaussianBlur',
'feImage',
'feMerge',
'feMergeNode',
'feMorphology',
'feOffset',
'fePointLight',
'feSpecularLighting',
'feSpotLight',
'feTile',
'feTurbulence',
'foreignObject',
'glyphRef',
'linearGradient',
'radialGradient',
'textPath',
].map((tn) => [tn.toLowerCase(), tn]));
//Tags that causes exit from foreign content
const EXITS_FOREIGN_CONTENT = new Set([
html.TAG_ID.B,
html.TAG_ID.BIG,
html.TAG_ID.BLOCKQUOTE,
html.TAG_ID.BODY,
html.TAG_ID.BR,
html.TAG_ID.CENTER,
html.TAG_ID.CODE,
html.TAG_ID.DD,
html.TAG_ID.DIV,
html.TAG_ID.DL,
html.TAG_ID.DT,
html.TAG_ID.EM,
html.TAG_ID.EMBED,
html.TAG_ID.H1,
html.TAG_ID.H2,
html.TAG_ID.H3,
html.TAG_ID.H4,
html.TAG_ID.H5,
html.TAG_ID.H6,
html.TAG_ID.HEAD,
html.TAG_ID.HR,
html.TAG_ID.I,
html.TAG_ID.IMG,
html.TAG_ID.LI,
html.TAG_ID.LISTING,
html.TAG_ID.MENU,
html.TAG_ID.META,
html.TAG_ID.NOBR,
html.TAG_ID.OL,
html.TAG_ID.P,
html.TAG_ID.PRE,
html.TAG_ID.RUBY,
html.TAG_ID.S,
html.TAG_ID.SMALL,
html.TAG_ID.SPAN,
html.TAG_ID.STRONG,
html.TAG_ID.STRIKE,
html.TAG_ID.SUB,
html.TAG_ID.SUP,
html.TAG_ID.TABLE,
html.TAG_ID.TT,
html.TAG_ID.U,
html.TAG_ID.UL,
html.TAG_ID.VAR,
]);
//Check exit from foreign content
function causesExit(startTagToken) {
const tn = startTagToken.tagID;
const isFontWithAttrs = tn === html.TAG_ID.FONT &&
startTagToken.attrs.some(({ name }) => name === html.ATTRS.COLOR || name === html.ATTRS.SIZE || name === html.ATTRS.FACE);
return isFontWithAttrs || EXITS_FOREIGN_CONTENT.has(tn);
}
exports.causesExit = causesExit;
//Token adjustments
function adjustTokenMathMLAttrs(token) {
for (let i = 0; i < token.attrs.length; i++) {
if (token.attrs[i].name === DEFINITION_URL_ATTR) {
token.attrs[i].name = ADJUSTED_DEFINITION_URL_ATTR;
break;
}
}
}
exports.adjustTokenMathMLAttrs = adjustTokenMathMLAttrs;
function adjustTokenSVGAttrs(token) {
for (let i = 0; i < token.attrs.length; i++) {
const adjustedAttrName = SVG_ATTRS_ADJUSTMENT_MAP.get(token.attrs[i].name);
if (adjustedAttrName != null) {
token.attrs[i].name = adjustedAttrName;
}
}
}
exports.adjustTokenSVGAttrs = adjustTokenSVGAttrs;
function adjustTokenXMLAttrs(token) {
for (let i = 0; i < token.attrs.length; i++) {
const adjustedAttrEntry = XML_ATTRS_ADJUSTMENT_MAP.get(token.attrs[i].name);
if (adjustedAttrEntry) {
token.attrs[i].prefix = adjustedAttrEntry.prefix;
token.attrs[i].name = adjustedAttrEntry.name;
token.attrs[i].namespace = adjustedAttrEntry.namespace;
}
}
}
exports.adjustTokenXMLAttrs = adjustTokenXMLAttrs;
function adjustTokenSVGTagName(token) {
const adjustedTagName = exports.SVG_TAG_NAMES_ADJUSTMENT_MAP.get(token.tagName);
if (adjustedTagName != null) {
token.tagName = adjustedTagName;
token.tagID = (0, html.getTagID)(token.tagName);
}
}
exports.adjustTokenSVGTagName = adjustTokenSVGTagName;
//Integration points
function isMathMLTextIntegrationPoint(tn, ns) {
return ns === html.NS.MATHML && (tn === html.TAG_ID.MI || tn === html.TAG_ID.MO || tn === html.TAG_ID.MN || tn === html.TAG_ID.MS || tn === html.TAG_ID.MTEXT);
}
function isHtmlIntegrationPoint(tn, ns, attrs) {
if (ns === html.NS.MATHML && tn === html.TAG_ID.ANNOTATION_XML) {
for (let i = 0; i < attrs.length; i++) {
if (attrs[i].name === html.ATTRS.ENCODING) {
const value = attrs[i].value.toLowerCase();
return value === MIME_TYPES.TEXT_HTML || value === MIME_TYPES.APPLICATION_XML;
}
}
}
return ns === html.NS.SVG && (tn === html.TAG_ID.FOREIGN_OBJECT || tn === html.TAG_ID.DESC || tn === html.TAG_ID.TITLE);
}
function isIntegrationPoint(tn, ns, attrs, foreignNS) {
return (((!foreignNS || foreignNS === html.NS.HTML) && isHtmlIntegrationPoint(tn, ns, attrs)) ||
((!foreignNS || foreignNS === html.NS.MATHML) && isMathMLTextIntegrationPoint(tn, ns)));
}
exports.isIntegrationPoint = isIntegrationPoint;
});
var parser = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.Parser = void 0;
//Misc constants
const HIDDEN_INPUT_TYPE = 'hidden';
//Adoption agency loops iteration count
const AA_OUTER_LOOP_ITER = 8;
const AA_INNER_LOOP_ITER = 3;
//Insertion modes
var InsertionMode;
(function (InsertionMode) {
InsertionMode[InsertionMode["INITIAL"] = 0] = "INITIAL";
InsertionMode[InsertionMode["BEFORE_HTML"] = 1] = "BEFORE_HTML";
InsertionMode[InsertionMode["BEFORE_HEAD"] = 2] = "BEFORE_HEAD";
InsertionMode[InsertionMode["IN_HEAD"] = 3] = "IN_HEAD";
InsertionMode[InsertionMode["IN_HEAD_NO_SCRIPT"] = 4] = "IN_HEAD_NO_SCRIPT";
InsertionMode[InsertionMode["AFTER_HEAD"] = 5] = "AFTER_HEAD";
InsertionMode[InsertionMode["IN_BODY"] = 6] = "IN_BODY";
InsertionMode[InsertionMode["TEXT"] = 7] = "TEXT";
InsertionMode[InsertionMode["IN_TABLE"] = 8] = "IN_TABLE";
InsertionMode[InsertionMode["IN_TABLE_TEXT"] = 9] = "IN_TABLE_TEXT";
InsertionMode[InsertionMode["IN_CAPTION"] = 10] = "IN_CAPTION";
InsertionMode[InsertionMode["IN_COLUMN_GROUP"] = 11] = "IN_COLUMN_GROUP";
InsertionMode[InsertionMode["IN_TABLE_BODY"] = 12] = "IN_TABLE_BODY";
InsertionMode[InsertionMode["IN_ROW"] = 13] = "IN_ROW";
InsertionMode[InsertionMode["IN_CELL"] = 14] = "IN_CELL";
InsertionMode[InsertionMode["IN_SELECT"] = 15] = "IN_SELECT";
InsertionMode[InsertionMode["IN_SELECT_IN_TABLE"] = 16] = "IN_SELECT_IN_TABLE";
InsertionMode[InsertionMode["IN_TEMPLATE"] = 17] = "IN_TEMPLATE";
InsertionMode[InsertionMode["AFTER_BODY"] = 18] = "AFTER_BODY";
InsertionMode[InsertionMode["IN_FRAMESET"] = 19] = "IN_FRAMESET";
InsertionMode[InsertionMode["AFTER_FRAMESET"] = 20] = "AFTER_FRAMESET";
InsertionMode[InsertionMode["AFTER_AFTER_BODY"] = 21] = "AFTER_AFTER_BODY";
InsertionMode[InsertionMode["AFTER_AFTER_FRAMESET"] = 22] = "AFTER_AFTER_FRAMESET";
})(InsertionMode || (InsertionMode = {}));
const BASE_LOC = {
startLine: -1,
startCol: -1,
startOffset: -1,
endLine: -1,
endCol: -1,
endOffset: -1,
};
const TABLE_STRUCTURE_TAGS = new Set([html.TAG_ID.TABLE, html.TAG_ID.TBODY, html.TAG_ID.TFOOT, html.TAG_ID.THEAD, html.TAG_ID.TR]);
const defaultParserOptions = {
scriptingEnabled: true,
sourceCodeLocationInfo: false,
treeAdapter: _default$1.defaultTreeAdapter,
onParseError: null,
};
//Parser
class Parser {
constructor(options, document, fragmentContext = null, scriptHandler = null) {
this.fragmentContext = fragmentContext;
this.scriptHandler = scriptHandler;
this.currentToken = null;
this.stopped = false;
this.insertionMode = InsertionMode.INITIAL;
this.originalInsertionMode = InsertionMode.INITIAL;
this.headElement = null;
this.formElement = null;
/** Indicates that the current node is not an element in the HTML namespace */
this.currentNotInHTML = false;
/**
* The template insertion mode stack is maintained from the left.
* Ie. the topmost element will always have index 0.
*/
this.tmplInsertionModeStack = [];
this.pendingCharacterTokens = [];
this.hasNonWhitespacePendingCharacterToken = false;
this.framesetOk = true;
this.skipNextNewLine = false;
this.fosterParentingEnabled = false;
this.options = Object.assign(Object.assign({}, defaultParserOptions), options);
this.treeAdapter = this.options.treeAdapter;
this.onParseError = this.options.onParseError;
// Always enable location info if we report parse errors.
if (this.onParseError) {
this.options.sourceCodeLocationInfo = true;
}
this.document = document !== null && document !== void 0 ? document : this.treeAdapter.createDocument();
this.tokenizer = new tokenizer.Tokenizer(this.options, this);
this.activeFormattingElements = new formattingElementList.FormattingElementList(this.treeAdapter);
this.fragmentContextID = fragmentContext ? (0, html.getTagID)(this.treeAdapter.getTagName(fragmentContext)) : html.TAG_ID.UNKNOWN;
this._setContextModes(fragmentContext !== null && fragmentContext !== void 0 ? fragmentContext : this.document, this.fragmentContextID);
this.openElements = new openElementStack.OpenElementStack(this.document, this.treeAdapter, this);
}
// API
static parse(html, options) {
const parser = new this(options);
parser.tokenizer.write(html, true);
return parser.document;
}
static getFragmentParser(fragmentContext, options) {
const opts = Object.assign(Object.assign({}, defaultParserOptions), options);
//NOTE: use a <template> element as the fragment context if no context element was provided,
//so we will parse in a "forgiving" manner
fragmentContext !== null && fragmentContext !== void 0 ? fragmentContext : (fragmentContext = opts.treeAdapter.createElement(html.TAG_NAMES.TEMPLATE, html.NS.HTML, []));
//NOTE: create a fake element which will be used as the `document` for fragment parsing.
//This is important for jsdom, where a new `document` cannot be created. This led to
//fragment parsing messing with the main `document`.
const documentMock = opts.treeAdapter.createElement('documentmock', html.NS.HTML, []);
const parser = new this(opts, documentMock, fragmentContext);
if (parser.fragmentContextID === html.TAG_ID.TEMPLATE) {
parser.tmplInsertionModeStack.unshift(InsertionMode.IN_TEMPLATE);
}
parser._initTokenizerForFragmentParsing();
parser._insertFakeRootElement();
parser._resetInsertionMode();
parser._findFormInFragmentContext();
return parser;
}
getFragment() {
const rootElement = this.treeAdapter.getFirstChild(this.document);
const fragment = this.treeAdapter.createDocumentFragment();
this._adoptNodes(rootElement, fragment);
return fragment;
}
//Errors
_err(token, code, beforeToken) {
var _a;
if (!this.onParseError)
return;
const loc = (_a = token.location) !== null && _a !== void 0 ? _a : BASE_LOC;
const err = {
code,
startLine: loc.startLine,
startCol: loc.startCol,
startOffset: loc.startOffset,
endLine: beforeToken ? loc.startLine : loc.endLine,
endCol: beforeToken ? loc.startCol : loc.endCol,
endOffset: beforeToken ? loc.startOffset : loc.endOffset,
};
this.onParseError(err);
}
//Stack events
onItemPush(node, tid, isTop) {
var _a, _b;
(_b = (_a = this.treeAdapter).onItemPush) === null || _b === void 0 ? void 0 : _b.call(_a, node);
if (isTop && this.openElements.stackTop > 0)
this._setContextModes(node, tid);
}
onItemPop(node, isTop) {
var _a, _b;
if (this.options.sourceCodeLocationInfo) {
this._setEndLocation(node, this.currentToken);
}
(_b = (_a = this.treeAdapter).onItemPop) === null || _b === void 0 ? void 0 : _b.call(_a, node, this.openElements.current);
if (isTop) {
let current;
let currentTagId;
if (this.openElements.stackTop === 0 && this.fragmentContext) {
current = this.fragmentContext;
currentTagId = this.fragmentContextID;
}
else {
({ current, currentTagId } = this.openElements);
}
this._setContextModes(current, currentTagId);
}
}
_setContextModes(current, tid) {
const isHTML = current === this.document || this.treeAdapter.getNamespaceURI(current) === html.NS.HTML;
this.currentNotInHTML = !isHTML;
this.tokenizer.inForeignNode = !isHTML && !this._isIntegrationPoint(tid, current);
}
_switchToTextParsing(currentToken, nextTokenizerState) {
this._insertElement(currentToken, html.NS.HTML);
this.tokenizer.state = nextTokenizerState;
this.originalInsertionMode = this.insertionMode;
this.insertionMode = InsertionMode.TEXT;
}
switchToPlaintextParsing() {
this.insertionMode = InsertionMode.TEXT;
this.originalInsertionMode = InsertionMode.IN_BODY;
this.tokenizer.state = tokenizer.TokenizerMode.PLAINTEXT;
}
//Fragment parsing
_getAdjustedCurrentElement() {
return this.openElements.stackTop === 0 && this.fragmentContext
? this.fragmentContext
: this.openElements.current;
}
_findFormInFragmentContext() {
let node = this.fragmentContext;
while (node) {
if (this.treeAdapter.getTagName(node) === html.TAG_NAMES.FORM) {
this.formElement = node;
break;
}
node = this.treeAdapter.getParentNode(node);
}
}
_initTokenizerForFragmentParsing() {
if (!this.fragmentContext || this.treeAdapter.getNamespaceURI(this.fragmentContext) !== html.NS.HTML) {
return;
}
switch (this.fragmentContextID) {
case html.TAG_ID.TITLE:
case html.TAG_ID.TEXTAREA: {
this.tokenizer.state = tokenizer.TokenizerMode.RCDATA;
break;
}
case html.TAG_ID.STYLE:
case html.TAG_ID.XMP:
case html.TAG_ID.IFRAME:
case html.TAG_ID.NOEMBED:
case html.TAG_ID.NOFRAMES:
case html.TAG_ID.NOSCRIPT: {
this.tokenizer.state = tokenizer.TokenizerMode.RAWTEXT;
break;
}
case html.TAG_ID.SCRIPT: {
this.tokenizer.state = tokenizer.TokenizerMode.SCRIPT_DATA;
break;
}
case html.TAG_ID.PLAINTEXT: {
this.tokenizer.state = tokenizer.TokenizerMode.PLAINTEXT;
break;
}
// Do nothing
}
}
//Tree mutation
_setDocumentType(token) {
const name = token.name || '';
const publicId = token.publicId || '';
const systemId = token.systemId || '';
this.treeAdapter.setDocumentType(this.document, name, publicId, systemId);
if (token.location) {
const documentChildren = this.treeAdapter.getChildNodes(this.document);
const docTypeNode = documentChildren.find((node) => this.treeAdapter.isDocumentTypeNode(node));
if (docTypeNode) {
this.treeAdapter.setNodeSourceCodeLocation(docTypeNode, token.location);
}
}
}
_attachElementToTree(element, location) {
if (this.options.sourceCodeLocationInfo) {
const loc = location && Object.assign(Object.assign({}, location), { startTag: location });
this.treeAdapter.setNodeSourceCodeLocation(element, loc);
}
if (this._shouldFosterParentOnInsertion()) {
this._fosterParentElement(element);
}
else {
const parent = this.openElements.currentTmplContentOrNode;
this.treeAdapter.appendChild(parent, element);
}
}
_appendElement(token, namespaceURI) {
const element = this.treeAdapter.createElement(token.tagName, namespaceURI, token.attrs);
this._attachElementToTree(element, token.location);
}
_insertElement(token, namespaceURI) {
const element = this.treeAdapter.createElement(token.tagName, namespaceURI, token.attrs);
this._attachElementToTree(element, token.location);
this.openElements.push(element, token.tagID);
}
_insertFakeElement(tagName, tagID) {
const element = this.treeAdapter.createElement(tagName, html.NS.HTML, []);
this._attachElementToTree(element, null);
this.openElements.push(element, tagID);
}
_insertTemplate(token) {
const tmpl = this.treeAdapter.createElement(token.tagName, html.NS.HTML, token.attrs);
const content = this.treeAdapter.createDocumentFragment();
this.treeAdapter.setTemplateContent(tmpl, content);
this._attachElementToTree(tmpl, token.location);
this.openElements.push(tmpl, token.tagID);
if (this.options.sourceCodeLocationInfo)
this.treeAdapter.setNodeSourceCodeLocation(content, null);
}
_insertFakeRootElement() {
const element = this.treeAdapter.createElement(html.TAG_NAMES.HTML, html.NS.HTML, []);
if (this.options.sourceCodeLocationInfo)
this.treeAdapter.setNodeSourceCodeLocation(element, null);
this.treeAdapter.appendChild(this.openElements.current, element);
this.openElements.push(element, html.TAG_ID.HTML);
}
_appendCommentNode(token, parent) {
const commentNode = this.treeAdapter.createCommentNode(token.data);
this.treeAdapter.appendChild(parent, commentNode);
if (this.options.sourceCodeLocationInfo) {
this.treeAdapter.setNodeSourceCodeLocation(commentNode, token.location);
}
}
_insertCharacters(token) {
let parent;
let beforeElement;
if (this._shouldFosterParentOnInsertion()) {
({ parent, beforeElement } = this._findFosterParentingLocation());
if (beforeElement) {
this.treeAdapter.insertTextBefore(parent, token.chars, beforeElement);
}
else {
this.treeAdapter.insertText(parent, token.chars);
}
}
else {
parent = this.openElements.currentTmplContentOrNode;
this.treeAdapter.insertText(parent, token.chars);
}
if (!token.location)
return;
const siblings = this.treeAdapter.getChildNodes(parent);
const textNodeIdx = beforeElement ? siblings.lastIndexOf(beforeElement) : siblings.length;
const textNode = siblings[textNodeIdx - 1];
//NOTE: if we have a location assigned by another token, then just update the end position
const tnLoc = this.treeAdapter.getNodeSourceCodeLocation(textNode);
if (tnLoc) {
const { endLine, endCol, endOffset } = token.location;
this.treeAdapter.updateNodeSourceCodeLocation(textNode, { endLine, endCol, endOffset });
}
else if (this.options.sourceCodeLocationInfo) {
this.treeAdapter.setNodeSourceCodeLocation(textNode, token.location);
}
}
_adoptNodes(donor, recipient) {
for (let child = this.treeAdapter.getFirstChild(donor); child; child = this.treeAdapter.getFirstChild(donor)) {
this.treeAdapter.detachNode(child);
this.treeAdapter.appendChild(recipient, child);
}
}
_setEndLocation(element, closingToken) {
if (this.treeAdapter.getNodeSourceCodeLocation(element) && closingToken.location) {
const ctLoc = closingToken.location;
const tn = this.treeAdapter.getTagName(element);
const endLoc =
// NOTE: For cases like <p> <p> </p> - First 'p' closes without a closing
// tag and for cases like <td> <p> </td> - 'p' closes without a closing tag.
closingToken.type === token.TokenType.END_TAG && tn === closingToken.tagName
? {
endTag: Object.assign({}, ctLoc),
endLine: ctLoc.endLine,
endCol: ctLoc.endCol,
endOffset: ctLoc.endOffset,
}
: {
endLine: ctLoc.startLine,
endCol: ctLoc.startCol,
endOffset: ctLoc.startOffset,
};
this.treeAdapter.updateNodeSourceCodeLocation(element, endLoc);
}
}
//Token processing
shouldProcessStartTagTokenInForeignContent(token) {
// Check that neither current === document, or ns === NS.HTML
if (!this.currentNotInHTML)
return false;
let current;
let currentTagId;
if (this.openElements.stackTop === 0 && this.fragmentContext) {
current = this.fragmentContext;
currentTagId = this.fragmentContextID;
}
else {
({ current, currentTagId } = this.openElements);
}
if (token.tagID === html.TAG_ID.SVG &&
this.treeAdapter.getTagName(current) === html.TAG_NAMES.ANNOTATION_XML &&
this.treeAdapter.getNamespaceURI(current) === html.NS.MATHML) {
return false;
}
return (
// Check that `current` is not an integration point for HTML or MathML elements.
this.tokenizer.inForeignNode ||
// If it _is_ an integration point, then we might have to check that it is not an HTML
// integration point.
((token.tagID === html.TAG_ID.MGLYPH || token.tagID === html.TAG_ID.MALIGNMARK) &&
!this._isIntegrationPoint(currentTagId, current, html.NS.HTML)));
}
_processToken(token$1) {
switch (token$1.type) {
case token.TokenType.CHARACTER: {
this.onCharacter(token$1);
break;
}
case token.TokenType.NULL_CHARACTER: {
this.onNullCharacter(token$1);
break;
}
case token.TokenType.COMMENT: {
this.onComment(token$1);
break;
}
case token.TokenType.DOCTYPE: {
this.onDoctype(token$1);
break;
}
case token.TokenType.START_TAG: {
this._processStartTag(token$1);
break;
}
case token.TokenType.END_TAG: {
this.onEndTag(token$1);
break;
}
case token.TokenType.EOF: {
this.onEof(token$1);
break;
}
case token.TokenType.WHITESPACE_CHARACTER: {
this.onWhitespaceCharacter(token$1);
break;
}
}
}
//Integration points
_isIntegrationPoint(tid, element, foreignNS) {
const ns = this.treeAdapter.getNamespaceURI(element);
const attrs = this.treeAdapter.getAttrList(element);
return foreignContent.isIntegrationPoint(tid, ns, attrs, foreignNS);
}
//Active formatting elements reconstruction
_reconstructActiveFormattingElements() {
const listLength = this.activeFormattingElements.entries.length;
if (listLength) {
const endIndex = this.activeFormattingElements.entries.findIndex((entry) => entry.type === formattingElementList.EntryType.Marker || this.openElements.contains(entry.element));
const unopenIdx = endIndex < 0 ? listLength - 1 : endIndex - 1;
for (let i = unopenIdx; i >= 0; i--) {
const entry = this.activeFormattingElements.entries[i];
this._insertElement(entry.token, this.treeAdapter.getNamespaceURI(entry.element));
entry.element = this.openElements.current;
}
}
}
//Close elements
_closeTableCell() {
this.openElements.generateImpliedEndTags();
this.openElements.popUntilTableCellPopped();
this.activeFormattingElements.clearToLastMarker();
this.insertionMode = InsertionMode.IN_ROW;
}
_closePElement() {
this.openElements.generateImpliedEndTagsWithExclusion(html.TAG_ID.P);
this.openElements.popUntilTagNamePopped(html.TAG_ID.P);
}
//Insertion modes
_resetInsertionMode() {
for (let i = this.openElements.stackTop; i >= 0; i--) {
//Insertion mode reset map
switch (i === 0 && this.fragmentContext ? this.fragmentContextID : this.openElements.tagIDs[i]) {
case html.TAG_ID.TR: {
this.insertionMode = InsertionMode.IN_ROW;
return;
}
case html.TAG_ID.TBODY:
case html.TAG_ID.THEAD:
case html.TAG_ID.TFOOT: {
this.insertionMode = InsertionMode.IN_TABLE_BODY;
return;
}
case html.TAG_ID.CAPTION: {
this.insertionMode = InsertionMode.IN_CAPTION;
return;
}
case html.TAG_ID.COLGROUP: {
this.insertionMode = InsertionMode.IN_COLUMN_GROUP;
return;
}
case html.TAG_ID.TABLE: {
this.insertionMode = InsertionMode.IN_TABLE;
return;
}
case html.TAG_ID.BODY: {
this.insertionMode = InsertionMode.IN_BODY;
return;
}
case html.TAG_ID.FRAMESET: {
this.insertionMode = InsertionMode.IN_FRAMESET;
return;
}
case html.TAG_ID.SELECT: {
this._resetInsertionModeForSelect(i);
return;
}
case html.TAG_ID.TEMPLATE: {
this.insertionMode = this.tmplInsertionModeStack[0];
return;
}
case html.TAG_ID.HTML: {
this.insertionMode = this.headElement ? InsertionMode.AFTER_HEAD : InsertionMode.BEFORE_HEAD;
return;
}
case html.TAG_ID.TD:
case html.TAG_ID.TH: {
if (i > 0) {
this.insertionMode = InsertionMode.IN_CELL;
return;
}
break;
}
case html.TAG_ID.HEAD: {
if (i > 0) {
this.insertionMode = InsertionMode.IN_HEAD;
return;
}
break;
}
}
}
this.insertionMode = InsertionMode.IN_BODY;
}
_resetInsertionModeForSelect(selectIdx) {
if (selectIdx > 0) {
for (let i = selectIdx - 1; i > 0; i--) {
const tn = this.openElements.tagIDs[i];
if (tn === html.TAG_ID.TEMPLATE) {
break;
}
else if (tn === html.TAG_ID.TABLE) {
this.insertionMode = InsertionMode.IN_SELECT_IN_TABLE;
return;
}
}
}
this.insertionMode = InsertionMode.IN_SELECT;
}
//Foster parenting
_isElementCausesFosterParenting(tn) {
return TABLE_STRUCTURE_TAGS.has(tn);
}
_shouldFosterParentOnInsertion() {
return this.fosterParentingEnabled && this._isElementCausesFosterParenting(this.openElements.currentTagId);
}
_findFosterParentingLocation() {
for (let i = this.openElements.stackTop; i >= 0; i--) {
const openElement = this.openElements.items[i];
switch (this.openElements.tagIDs[i]) {
case html.TAG_ID.TEMPLATE: {
if (this.treeAdapter.getNamespaceURI(openElement) === html.NS.HTML) {
return { parent: this.treeAdapter.getTemplateContent(openElement), beforeElement: null };
}
break;
}
case html.TAG_ID.TABLE: {
const parent = this.treeAdapter.getParentNode(openElement);
if (parent) {
return { parent, beforeElement: openElement };
}
return { parent: this.openElements.items[i - 1], beforeElement: null };
}
// Do nothing
}
}
return { parent: this.openElements.items[0], beforeElement: null };
}
_fosterParentElement(element) {
const location = this._findFosterParentingLocation();
if (location.beforeElement) {
this.treeAdapter.insertBefore(location.parent, element, location.beforeElement);
}
else {
this.treeAdapter.appendChild(location.parent, element);
}
}
//Special elements
_isSpecialElement(element, id) {
const ns = this.treeAdapter.getNamespaceURI(element);
return html.SPECIAL_ELEMENTS[ns].has(id);
}
onCharacter(token) {
this.skipNextNewLine = false;
if (this.tokenizer.inForeignNode) {
characterInForeignContent(this, token);
return;
}
switch (this.insertionMode) {
case InsertionMode.INITIAL: {
tokenInInitialMode(this, token);
break;
}
case InsertionMode.BEFORE_HTML: {
tokenBeforeHtml(this, token);
break;
}
case InsertionMode.BEFORE_HEAD: {
tokenBeforeHead(this, token);
break;
}
case InsertionMode.IN_HEAD: {
tokenInHead(this, token);
break;
}
case InsertionMode.IN_HEAD_NO_SCRIPT: {
tokenInHeadNoScript(this, token);
break;
}
case InsertionMode.AFTER_HEAD: {
tokenAfterHead(this, token);
break;
}
case InsertionMode.IN_BODY:
case InsertionMode.IN_CAPTION:
case InsertionMode.IN_CELL:
case InsertionMode.IN_TEMPLATE: {
characterInBody(this, token);
break;
}
case InsertionMode.TEXT:
case InsertionMode.IN_SELECT:
case InsertionMode.IN_SELECT_IN_TABLE: {
this._insertCharacters(token);
break;
}
case InsertionMode.IN_TABLE:
case InsertionMode.IN_TABLE_BODY:
case InsertionMode.IN_ROW: {
characterInTable(this, token);
break;
}
case InsertionMode.IN_TABLE_TEXT: {
characterInTableText(this, token);
break;
}
case InsertionMode.IN_COLUMN_GROUP: {
tokenInColumnGroup(this, token);
break;
}
case InsertionMode.AFTER_BODY: {
tokenAfterBody(this, token);
break;
}
case InsertionMode.AFTER_AFTER_BODY: {
tokenAfterAfterBody(this, token);
break;
}
// Do nothing
}
}
onNullCharacter(token) {
this.skipNextNewLine = false;
if (this.tokenizer.inForeignNode) {
nullCharacterInForeignContent(this, token);
return;
}
switch (this.insertionMode) {
case InsertionMode.INITIAL: {
tokenInInitialMode(this, token);
break;
}
case InsertionMode.BEFORE_HTML: {
tokenBeforeHtml(this, token);
break;
}
case InsertionMode.BEFORE_HEAD: {
tokenBeforeHead(this, token);
break;
}
case InsertionMode.IN_HEAD: {
tokenInHead(this, token);
break;
}
case InsertionMode.IN_HEAD_NO_SCRIPT: {
tokenInHeadNoScript(this, token);
break;
}
case InsertionMode.AFTER_HEAD: {
tokenAfterHead(this, token);
break;
}
case InsertionMode.TEXT: {
this._insertCharacters(token);
break;
}
case InsertionMode.IN_TABLE:
case InsertionMode.IN_TABLE_BODY:
case InsertionMode.IN_ROW: {
characterInTable(this, token);
break;
}
case InsertionMode.IN_COLUMN_GROUP: {
tokenInColumnGroup(this, token);
break;
}
case InsertionMode.AFTER_BODY: {
tokenAfterBody(this, token);
break;
}
case InsertionMode.AFTER_AFTER_BODY: {
tokenAfterAfterBody(this, token);
break;
}
// Do nothing
}
}
onComment(token) {
this.skipNextNewLine = false;
if (this.currentNotInHTML) {
appendComment(this, token);
return;
}
switch (this.insertionMode) {
case InsertionMode.INITIAL:
case InsertionMode.BEFORE_HTML:
case InsertionMode.BEFORE_HEAD:
case InsertionMode.IN_HEAD:
case InsertionMode.IN_HEAD_NO_SCRIPT:
case InsertionMode.AFTER_HEAD:
case InsertionMode.IN_BODY:
case InsertionMode.IN_TABLE:
case InsertionMode.IN_CAPTION:
case InsertionMode.IN_COLUMN_GROUP:
case InsertionMode.IN_TABLE_BODY:
case InsertionMode.IN_ROW:
case InsertionMode.IN_CELL:
case InsertionMode.IN_SELECT:
case InsertionMode.IN_SELECT_IN_TABLE:
case InsertionMode.IN_TEMPLATE:
case InsertionMode.IN_FRAMESET:
case InsertionMode.AFTER_FRAMESET: {
appendComment(this, token);
break;
}
case InsertionMode.IN_TABLE_TEXT: {
tokenInTableText(this, token);
break;
}
case InsertionMode.AFTER_BODY: {
appendCommentToRootHtmlElement(this, token);
break;
}
case InsertionMode.AFTER_AFTER_BODY:
case InsertionMode.AFTER_AFTER_FRAMESET: {
appendCommentToDocument(this, token);
break;
}
// Do nothing
}
}
onDoctype(token) {
this.skipNextNewLine = false;
switch (this.insertionMode) {
case InsertionMode.INITIAL: {
doctypeInInitialMode(this, token);
break;
}
case InsertionMode.BEFORE_HEAD:
case InsertionMode.IN_HEAD:
case InsertionMode.IN_HEAD_NO_SCRIPT:
case InsertionMode.AFTER_HEAD: {
this._err(token, errorCodes.ERR.misplacedDoctype);
break;
}
case InsertionMode.IN_TABLE_TEXT: {
tokenInTableText(this, token);
break;
}
// Do nothing
}
}
onStartTag(token) {
this.skipNextNewLine = false;
this.currentToken = token;
this._processStartTag(token);
if (token.selfClosing && !token.ackSelfClosing) {
this._err(token, errorCodes.ERR.nonVoidHtmlElementStartTagWithTrailingSolidus);
}
}
/**
* Processes a given start tag.
*
* `onStartTag` checks if a self-closing tag was recognized. When a token
* is moved inbetween multiple insertion modes, this check for self-closing
* could lead to false positives. To avoid this, `_processStartTag` is used
* for nested calls.
*
* @param token The token to process.
*/
_processStartTag(token) {
if (this.shouldProcessStartTagTokenInForeignContent(token)) {
startTagInForeignContent(this, token);
}
else {
this._startTagOutsideForeignContent(token);
}
}
_startTagOutsideForeignContent(token) {
switch (this.insertionMode) {
case InsertionMode.INITIAL: {
tokenInInitialMode(this, token);
break;
}
case InsertionMode.BEFORE_HTML: {
startTagBeforeHtml(this, token);
break;
}
case InsertionMode.BEFORE_HEAD: {
startTagBeforeHead(this, token);
break;
}
case InsertionMode.IN_HEAD: {
startTagInHead(this, token);
break;
}
case InsertionMode.IN_HEAD_NO_SCRIPT: {
startTagInHeadNoScript(this, token);
break;
}
case InsertionMode.AFTER_HEAD: {
startTagAfterHead(this, token);
break;
}
case InsertionMode.IN_BODY: {
startTagInBody(this, token);
break;
}
case InsertionMode.IN_TABLE: {
startTagInTable(this, token);
break;
}
case InsertionMode.IN_TABLE_TEXT: {
tokenInTableText(this, token);
break;
}
case InsertionMode.IN_CAPTION: {
startTagInCaption(this, token);
break;
}
case InsertionMode.IN_COLUMN_GROUP: {
startTagInColumnGroup(this, token);
break;
}
case InsertionMode.IN_TABLE_BODY: {
startTagInTableBody(this, token);
break;
}
case InsertionMode.IN_ROW: {
startTagInRow(this, token);
break;
}
case InsertionMode.IN_CELL: {
startTagInCell(this, token);
break;
}
case InsertionMode.IN_SELECT: {
startTagInSelect(this, token);
break;
}
case InsertionMode.IN_SELECT_IN_TABLE: {
startTagInSelectInTable(this, token);
break;
}
case InsertionMode.IN_TEMPLATE: {
startTagInTemplate(this, token);
break;
}
case InsertionMode.AFTER_BODY: {
startTagAfterBody(this, token);
break;
}
case InsertionMode.IN_FRAMESET: {
startTagInFrameset(this, token);
break;
}
case InsertionMode.AFTER_FRAMESET: {
startTagAfterFrameset(this, token);
break;
}
case InsertionMode.AFTER_AFTER_BODY: {
startTagAfterAfterBody(this, token);
break;
}
case InsertionMode.AFTER_AFTER_FRAMESET: {
startTagAfterAfterFrameset(this, token);
break;
}
// Do nothing
}
}
onEndTag(token) {
this.skipNextNewLine = false;
this.currentToken = token;
if (this.currentNotInHTML) {
endTagInForeignContent(this, token);
}
else {
this._endTagOutsideForeignContent(token);
}
}
_endTagOutsideForeignContent(token) {
switch (this.insertionMode) {
case InsertionMode.INITIAL: {
tokenInInitialMode(this, token);
break;
}
case InsertionMode.BEFORE_HTML: {
endTagBeforeHtml(this, token);
break;
}
case InsertionMode.BEFORE_HEAD: {
endTagBeforeHead(this, token);
break;
}
case InsertionMode.IN_HEAD: {
endTagInHead(this, token);
break;
}
case InsertionMode.IN_HEAD_NO_SCRIPT: {
endTagInHeadNoScript(this, token);
break;
}
case InsertionMode.AFTER_HEAD: {
endTagAfterHead(this, token);
break;
}
case InsertionMode.IN_BODY: {
endTagInBody(this, token);
break;
}
case InsertionMode.TEXT: {
endTagInText(this, token);
break;
}
case InsertionMode.IN_TABLE: {
endTagInTable(this, token);
break;
}
case InsertionMode.IN_TABLE_TEXT: {
tokenInTableText(this, token);
break;
}
case InsertionMode.IN_CAPTION: {
endTagInCaption(this, token);
break;
}
case InsertionMode.IN_COLUMN_GROUP: {
endTagInColumnGroup(this, token);
break;
}
case InsertionMode.IN_TABLE_BODY: {
endTagInTableBody(this, token);
break;
}
case InsertionMode.IN_ROW: {
endTagInRow(this, token);
break;
}
case InsertionMode.IN_CELL: {
endTagInCell(this, token);
break;
}
case InsertionMode.IN_SELECT: {
endTagInSelect(this, token);
break;
}
case InsertionMode.IN_SELECT_IN_TABLE: {
endTagInSelectInTable(this, token);
break;
}
case InsertionMode.IN_TEMPLATE: {
endTagInTemplate(this, token);
break;
}
case InsertionMode.AFTER_BODY: {
endTagAfterBody(this, token);
break;
}
case InsertionMode.IN_FRAMESET: {
endTagInFrameset(this, token);
break;
}
case InsertionMode.AFTER_FRAMESET: {
endTagAfterFrameset(this, token);
break;
}
case InsertionMode.AFTER_AFTER_BODY: {
tokenAfterAfterBody(this, token);
break;
}
// Do nothing
}
}
onEof(token) {
switch (this.insertionMode) {
case InsertionMode.INITIAL: {
tokenInInitialMode(this, token);
break;
}
case InsertionMode.BEFORE_HTML: {
tokenBeforeHtml(this, token);
break;
}
case InsertionMode.BEFORE_HEAD: {
tokenBeforeHead(this, token);
break;
}
case InsertionMode.IN_HEAD: {
tokenInHead(this, token);
break;
}
case InsertionMode.IN_HEAD_NO_SCRIPT: {
tokenInHeadNoScript(this, token);
break;
}
case InsertionMode.AFTER_HEAD: {
tokenAfterHead(this, token);
break;
}
case InsertionMode.IN_BODY:
case InsertionMode.IN_TABLE:
case InsertionMode.IN_CAPTION:
case InsertionMode.IN_COLUMN_GROUP:
case InsertionMode.IN_TABLE_BODY:
case InsertionMode.IN_ROW:
case InsertionMode.IN_CELL:
case InsertionMode.IN_SELECT:
case InsertionMode.IN_SELECT_IN_TABLE: {
eofInBody(this, token);
break;
}
case InsertionMode.TEXT: {
eofInText(this, token);
break;
}
case InsertionMode.IN_TABLE_TEXT: {
tokenInTableText(this, token);
break;
}
case InsertionMode.IN_TEMPLATE: {
eofInTemplate(this, token);
break;
}
case InsertionMode.AFTER_BODY:
case InsertionMode.IN_FRAMESET:
case InsertionMode.AFTER_FRAMESET:
case InsertionMode.AFTER_AFTER_BODY:
case InsertionMode.AFTER_AFTER_FRAMESET: {
stopParsing(this, token);
break;
}
// Do nothing
}
}
onWhitespaceCharacter(token) {
if (this.skipNextNewLine) {
this.skipNextNewLine = false;
if (token.chars.charCodeAt(0) === unicode.CODE_POINTS.LINE_FEED) {
if (token.chars.length === 1) {
return;
}
token.chars = token.chars.substr(1);
}
}
if (this.tokenizer.inForeignNode) {
this._insertCharacters(token);
return;
}
switch (this.insertionMode) {
case InsertionMode.IN_HEAD:
case InsertionMode.IN_HEAD_NO_SCRIPT:
case InsertionMode.AFTER_HEAD:
case InsertionMode.TEXT:
case InsertionMode.IN_COLUMN_GROUP:
case InsertionMode.IN_SELECT:
case InsertionMode.IN_SELECT_IN_TABLE:
case InsertionMode.IN_FRAMESET:
case InsertionMode.AFTER_FRAMESET: {
this._insertCharacters(token);
break;
}
case InsertionMode.IN_BODY:
case InsertionMode.IN_CAPTION:
case InsertionMode.IN_CELL:
case InsertionMode.IN_TEMPLATE:
case InsertionMode.AFTER_BODY:
case InsertionMode.AFTER_AFTER_BODY:
case InsertionMode.AFTER_AFTER_FRAMESET: {
whitespaceCharacterInBody(this, token);
break;
}
case InsertionMode.IN_TABLE:
case InsertionMode.IN_TABLE_BODY:
case InsertionMode.IN_ROW: {
characterInTable(this, token);
break;
}
case InsertionMode.IN_TABLE_TEXT: {
whitespaceCharacterInTableText(this, token);
break;
}
// Do nothing
}
}
}
exports.Parser = Parser;
//Adoption agency algorithm
//(see: http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#adoptionAgency)
//------------------------------------------------------------------
//Steps 5-8 of the algorithm
function aaObtainFormattingElementEntry(p, token) {
let formattingElementEntry = p.activeFormattingElements.getElementEntryInScopeWithTagName(token.tagName);
if (formattingElementEntry) {
if (!p.openElements.contains(formattingElementEntry.element)) {
p.activeFormattingElements.removeEntry(formattingElementEntry);
formattingElementEntry = null;
}
else if (!p.openElements.hasInScope(token.tagID)) {
formattingElementEntry = null;
}
}
else {
genericEndTagInBody(p, token);
}
return formattingElementEntry;
}
//Steps 9 and 10 of the algorithm
function aaObtainFurthestBlock(p, formattingElementEntry) {
let furthestBlock = null;
let idx = p.openElements.stackTop;
for (; idx >= 0; idx--) {
const element = p.openElements.items[idx];
if (element === formattingElementEntry.element) {
break;
}
if (p._isSpecialElement(element, p.openElements.tagIDs[idx])) {
furthestBlock = element;
}
}
if (!furthestBlock) {
p.openElements.shortenToLength(idx < 0 ? 0 : idx);
p.activeFormattingElements.removeEntry(formattingElementEntry);
}
return furthestBlock;
}
//Step 13 of the algorithm
function aaInnerLoop(p, furthestBlock, formattingElement) {
let lastElement = furthestBlock;
let nextElement = p.openElements.getCommonAncestor(furthestBlock);
for (let i = 0, element = nextElement; element !== formattingElement; i++, element = nextElement) {
//NOTE: store the next element for the next loop iteration (it may be deleted from the stack by step 9.5)
nextElement = p.openElements.getCommonAncestor(element);
const elementEntry = p.activeFormattingElements.getElementEntry(element);
const counterOverflow = elementEntry && i >= AA_INNER_LOOP_ITER;
const shouldRemoveFromOpenElements = !elementEntry || counterOverflow;
if (shouldRemoveFromOpenElements) {
if (counterOverflow) {
p.activeFormattingElements.removeEntry(elementEntry);
}
p.openElements.remove(element);
}
else {
element = aaRecreateElementFromEntry(p, elementEntry);
if (lastElement === furthestBlock) {
p.activeFormattingElements.bookmark = elementEntry;
}
p.treeAdapter.detachNode(lastElement);
p.treeAdapter.appendChild(element, lastElement);
lastElement = element;
}
}
return lastElement;
}
//Step 13.7 of the algorithm
function aaRecreateElementFromEntry(p, elementEntry) {
const ns = p.treeAdapter.getNamespaceURI(elementEntry.element);
const newElement = p.treeAdapter.createElement(elementEntry.token.tagName, ns, elementEntry.token.attrs);
p.openElements.replace(elementEntry.element, newElement);
elementEntry.element = newElement;
return newElement;
}
//Step 14 of the algorithm
function aaInsertLastNodeInCommonAncestor(p, commonAncestor, lastElement) {
const tn = p.treeAdapter.getTagName(commonAncestor);
const tid = (0, html.getTagID)(tn);
if (p._isElementCausesFosterParenting(tid)) {
p._fosterParentElement(lastElement);
}
else {
const ns = p.treeAdapter.getNamespaceURI(commonAncestor);
if (tid === html.TAG_ID.TEMPLATE && ns === html.NS.HTML) {
commonAncestor = p.treeAdapter.getTemplateContent(commonAncestor);
}
p.treeAdapter.appendChild(commonAncestor, lastElement);
}
}
//Steps 15-19 of the algorithm
function aaReplaceFormattingElement(p, furthestBlock, formattingElementEntry) {
const ns = p.treeAdapter.getNamespaceURI(formattingElementEntry.element);
const { token } = formattingElementEntry;
const newElement = p.treeAdapter.createElement(token.tagName, ns, token.attrs);
p._adoptNodes(furthestBlock, newElement);
p.treeAdapter.appendChild(furthestBlock, newElement);
p.activeFormattingElements.insertElementAfterBookmark(newElement, token);
p.activeFormattingElements.removeEntry(formattingElementEntry);
p.openElements.remove(formattingElementEntry.element);
p.openElements.insertAfter(furthestBlock, newElement, token.tagID);
}
//Algorithm entry point
function callAdoptionAgency(p, token) {
for (let i = 0; i < AA_OUTER_LOOP_ITER; i++) {
const formattingElementEntry = aaObtainFormattingElementEntry(p, token);
if (!formattingElementEntry) {
break;
}
const furthestBlock = aaObtainFurthestBlock(p, formattingElementEntry);
if (!furthestBlock) {
break;
}
p.activeFormattingElements.bookmark = formattingElementEntry;
const lastElement = aaInnerLoop(p, furthestBlock, formattingElementEntry.element);
const commonAncestor = p.openElements.getCommonAncestor(formattingElementEntry.element);
p.treeAdapter.detachNode(lastElement);
if (commonAncestor)
aaInsertLastNodeInCommonAncestor(p, commonAncestor, lastElement);
aaReplaceFormattingElement(p, furthestBlock, formattingElementEntry);
}
}
//Generic token handlers
//------------------------------------------------------------------
function appendComment(p, token) {
p._appendCommentNode(token, p.openElements.currentTmplContentOrNode);
}
function appendCommentToRootHtmlElement(p, token) {
p._appendCommentNode(token, p.openElements.items[0]);
}
function appendCommentToDocument(p, token) {
p._appendCommentNode(token, p.document);
}
function stopParsing(p, token) {
p.stopped = true;
// NOTE: Set end locations for elements that remain on the open element stack.
if (token.location) {
// NOTE: If we are not in a fragment, `html` and `body` will stay on the stack.
// This is a problem, as we might overwrite their end position here.
const target = p.fragmentContext ? 0 : 2;
for (let i = p.openElements.stackTop; i >= target; i--) {
p._setEndLocation(p.openElements.items[i], token);
}
// Handle `html` and `body`
if (!p.fragmentContext && p.openElements.stackTop >= 0) {
const htmlElement = p.openElements.items[0];
const htmlLocation = p.treeAdapter.getNodeSourceCodeLocation(htmlElement);
if (htmlLocation && !htmlLocation.endTag) {
p._setEndLocation(htmlElement, token);
if (p.openElements.stackTop >= 1) {
const bodyElement = p.openElements.items[1];
const bodyLocation = p.treeAdapter.getNodeSourceCodeLocation(bodyElement);
if (bodyLocation && !bodyLocation.endTag) {
p._setEndLocation(bodyElement, token);
}
}
}
}
}
}
// The "initial" insertion mode
//------------------------------------------------------------------
function doctypeInInitialMode(p, token) {
p._setDocumentType(token);
const mode = token.forceQuirks ? html.DOCUMENT_MODE.QUIRKS : doctype.getDocumentMode(token);
if (!doctype.isConforming(token)) {
p._err(token, errorCodes.ERR.nonConformingDoctype);
}
p.treeAdapter.setDocumentMode(p.document, mode);
p.insertionMode = InsertionMode.BEFORE_HTML;
}
function tokenInInitialMode(p, token) {
p._err(token, errorCodes.ERR.missingDoctype, true);
p.treeAdapter.setDocumentMode(p.document, html.DOCUMENT_MODE.QUIRKS);
p.insertionMode = InsertionMode.BEFORE_HTML;
p._processToken(token);
}
// The "before html" insertion mode
//------------------------------------------------------------------
function startTagBeforeHtml(p, token) {
if (token.tagID === html.TAG_ID.HTML) {
p._insertElement(token, html.NS.HTML);
p.insertionMode = InsertionMode.BEFORE_HEAD;
}
else {
tokenBeforeHtml(p, token);
}
}
function endTagBeforeHtml(p, token) {
const tn = token.tagID;
if (tn === html.TAG_ID.HTML || tn === html.TAG_ID.HEAD || tn === html.TAG_ID.BODY || tn === html.TAG_ID.BR) {
tokenBeforeHtml(p, token);
}
}
function tokenBeforeHtml(p, token) {
p._insertFakeRootElement();
p.insertionMode = InsertionMode.BEFORE_HEAD;
p._processToken(token);
}
// The "before head" insertion mode
//------------------------------------------------------------------
function startTagBeforeHead(p, token) {
switch (token.tagID) {
case html.TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case html.TAG_ID.HEAD: {
p._insertElement(token, html.NS.HTML);
p.headElement = p.openElements.current;
p.insertionMode = InsertionMode.IN_HEAD;
break;
}
default: {
tokenBeforeHead(p, token);
}
}
}
function endTagBeforeHead(p, token) {
const tn = token.tagID;
if (tn === html.TAG_ID.HEAD || tn === html.TAG_ID.BODY || tn === html.TAG_ID.HTML || tn === html.TAG_ID.BR) {
tokenBeforeHead(p, token);
}
else {
p._err(token, errorCodes.ERR.endTagWithoutMatchingOpenElement);
}
}
function tokenBeforeHead(p, token) {
p._insertFakeElement(html.TAG_NAMES.HEAD, html.TAG_ID.HEAD);
p.headElement = p.openElements.current;
p.insertionMode = InsertionMode.IN_HEAD;
p._processToken(token);
}
// The "in head" insertion mode
//------------------------------------------------------------------
function startTagInHead(p, token) {
switch (token.tagID) {
case html.TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case html.TAG_ID.BASE:
case html.TAG_ID.BASEFONT:
case html.TAG_ID.BGSOUND:
case html.TAG_ID.LINK:
case html.TAG_ID.META: {
p._appendElement(token, html.NS.HTML);
token.ackSelfClosing = true;
break;
}
case html.TAG_ID.TITLE: {
p._switchToTextParsing(token, tokenizer.TokenizerMode.RCDATA);
break;
}
case html.TAG_ID.NOSCRIPT: {
if (p.options.scriptingEnabled) {
p._switchToTextParsing(token, tokenizer.TokenizerMode.RAWTEXT);
}
else {
p._insertElement(token, html.NS.HTML);
p.insertionMode = InsertionMode.IN_HEAD_NO_SCRIPT;
}
break;
}
case html.TAG_ID.NOFRAMES:
case html.TAG_ID.STYLE: {
p._switchToTextParsing(token, tokenizer.TokenizerMode.RAWTEXT);
break;
}
case html.TAG_ID.SCRIPT: {
p._switchToTextParsing(token, tokenizer.TokenizerMode.SCRIPT_DATA);
break;
}
case html.TAG_ID.TEMPLATE: {
p._insertTemplate(token);
p.activeFormattingElements.insertMarker();
p.framesetOk = false;
p.insertionMode = InsertionMode.IN_TEMPLATE;
p.tmplInsertionModeStack.unshift(InsertionMode.IN_TEMPLATE);
break;
}
case html.TAG_ID.HEAD: {
p._err(token, errorCodes.ERR.misplacedStartTagForHeadElement);
break;
}
default: {
tokenInHead(p, token);
}
}
}
function endTagInHead(p, token) {
switch (token.tagID) {
case html.TAG_ID.HEAD: {
p.openElements.pop();
p.insertionMode = InsertionMode.AFTER_HEAD;
break;
}
case html.TAG_ID.BODY:
case html.TAG_ID.BR:
case html.TAG_ID.HTML: {
tokenInHead(p, token);
break;
}
case html.TAG_ID.TEMPLATE: {
templateEndTagInHead(p, token);
break;
}
default: {
p._err(token, errorCodes.ERR.endTagWithoutMatchingOpenElement);
}
}
}
function templateEndTagInHead(p, token) {
if (p.openElements.tmplCount > 0) {
p.openElements.generateImpliedEndTagsThoroughly();
if (p.openElements.currentTagId !== html.TAG_ID.TEMPLATE) {
p._err(token, errorCodes.ERR.closingOfElementWithOpenChildElements);
}
p.openElements.popUntilTagNamePopped(html.TAG_ID.TEMPLATE);
p.activeFormattingElements.clearToLastMarker();
p.tmplInsertionModeStack.shift();
p._resetInsertionMode();
}
else {
p._err(token, errorCodes.ERR.endTagWithoutMatchingOpenElement);
}
}
function tokenInHead(p, token) {
p.openElements.pop();
p.insertionMode = InsertionMode.AFTER_HEAD;
p._processToken(token);
}
// The "in head no script" insertion mode
//------------------------------------------------------------------
function startTagInHeadNoScript(p, token) {
switch (token.tagID) {
case html.TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case html.TAG_ID.BASEFONT:
case html.TAG_ID.BGSOUND:
case html.TAG_ID.HEAD:
case html.TAG_ID.LINK:
case html.TAG_ID.META:
case html.TAG_ID.NOFRAMES:
case html.TAG_ID.STYLE: {
startTagInHead(p, token);
break;
}
case html.TAG_ID.NOSCRIPT: {
p._err(token, errorCodes.ERR.nestedNoscriptInHead);
break;
}
default: {
tokenInHeadNoScript(p, token);
}
}
}
function endTagInHeadNoScript(p, token) {
switch (token.tagID) {
case html.TAG_ID.NOSCRIPT: {
p.openElements.pop();
p.insertionMode = InsertionMode.IN_HEAD;
break;
}
case html.TAG_ID.BR: {
tokenInHeadNoScript(p, token);
break;
}
default: {
p._err(token, errorCodes.ERR.endTagWithoutMatchingOpenElement);
}
}
}
function tokenInHeadNoScript(p, token$1) {
const errCode = token$1.type === token.TokenType.EOF ? errorCodes.ERR.openElementsLeftAfterEof : errorCodes.ERR.disallowedContentInNoscriptInHead;
p._err(token$1, errCode);
p.openElements.pop();
p.insertionMode = InsertionMode.IN_HEAD;
p._processToken(token$1);
}
// The "after head" insertion mode
//------------------------------------------------------------------
function startTagAfterHead(p, token) {
switch (token.tagID) {
case html.TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case html.TAG_ID.BODY: {
p._insertElement(token, html.NS.HTML);
p.framesetOk = false;
p.insertionMode = InsertionMode.IN_BODY;
break;
}
case html.TAG_ID.FRAMESET: {
p._insertElement(token, html.NS.HTML);
p.insertionMode = InsertionMode.IN_FRAMESET;
break;
}
case html.TAG_ID.BASE:
case html.TAG_ID.BASEFONT:
case html.TAG_ID.BGSOUND:
case html.TAG_ID.LINK:
case html.TAG_ID.META:
case html.TAG_ID.NOFRAMES:
case html.TAG_ID.SCRIPT:
case html.TAG_ID.STYLE:
case html.TAG_ID.TEMPLATE:
case html.TAG_ID.TITLE: {
p._err(token, errorCodes.ERR.abandonedHeadElementChild);
p.openElements.push(p.headElement, html.TAG_ID.HEAD);
startTagInHead(p, token);
p.openElements.remove(p.headElement);
break;
}
case html.TAG_ID.HEAD: {
p._err(token, errorCodes.ERR.misplacedStartTagForHeadElement);
break;
}
default: {
tokenAfterHead(p, token);
}
}
}
function endTagAfterHead(p, token) {
switch (token.tagID) {
case html.TAG_ID.BODY:
case html.TAG_ID.HTML:
case html.TAG_ID.BR: {
tokenAfterHead(p, token);
break;
}
case html.TAG_ID.TEMPLATE: {
templateEndTagInHead(p, token);
break;
}
default: {
p._err(token, errorCodes.ERR.endTagWithoutMatchingOpenElement);
}
}
}
function tokenAfterHead(p, token) {
p._insertFakeElement(html.TAG_NAMES.BODY, html.TAG_ID.BODY);
p.insertionMode = InsertionMode.IN_BODY;
modeInBody(p, token);
}
// The "in body" insertion mode
//------------------------------------------------------------------
function modeInBody(p, token$1) {
switch (token$1.type) {
case token.TokenType.CHARACTER: {
characterInBody(p, token$1);
break;
}
case token.TokenType.WHITESPACE_CHARACTER: {
whitespaceCharacterInBody(p, token$1);
break;
}
case token.TokenType.COMMENT: {
appendComment(p, token$1);
break;
}
case token.TokenType.START_TAG: {
startTagInBody(p, token$1);
break;
}
case token.TokenType.END_TAG: {
endTagInBody(p, token$1);
break;
}
case token.TokenType.EOF: {
eofInBody(p, token$1);
break;
}
// Do nothing
}
}
function whitespaceCharacterInBody(p, token) {
p._reconstructActiveFormattingElements();
p._insertCharacters(token);
}
function characterInBody(p, token) {
p._reconstructActiveFormattingElements();
p._insertCharacters(token);
p.framesetOk = false;
}
function htmlStartTagInBody(p, token) {
if (p.openElements.tmplCount === 0) {
p.treeAdapter.adoptAttributes(p.openElements.items[0], token.attrs);
}
}
function bodyStartTagInBody(p, token) {
const bodyElement = p.openElements.tryPeekProperlyNestedBodyElement();
if (bodyElement && p.openElements.tmplCount === 0) {
p.framesetOk = false;
p.treeAdapter.adoptAttributes(bodyElement, token.attrs);
}
}
function framesetStartTagInBody(p, token) {
const bodyElement = p.openElements.tryPeekProperlyNestedBodyElement();
if (p.framesetOk && bodyElement) {
p.treeAdapter.detachNode(bodyElement);
p.openElements.popAllUpToHtmlElement();
p._insertElement(token, html.NS.HTML);
p.insertionMode = InsertionMode.IN_FRAMESET;
}
}
function addressStartTagInBody(p, token) {
if (p.openElements.hasInButtonScope(html.TAG_ID.P)) {
p._closePElement();
}
p._insertElement(token, html.NS.HTML);
}
function numberedHeaderStartTagInBody(p, token) {
if (p.openElements.hasInButtonScope(html.TAG_ID.P)) {
p._closePElement();
}
if ((0, html.isNumberedHeader)(p.openElements.currentTagId)) {
p.openElements.pop();
}
p._insertElement(token, html.NS.HTML);
}
function preStartTagInBody(p, token) {
if (p.openElements.hasInButtonScope(html.TAG_ID.P)) {
p._closePElement();
}
p._insertElement(token, html.NS.HTML);
//NOTE: If the next token is a U+000A LINE FEED (LF) character token, then ignore that token and move
//on to the next one. (Newlines at the start of pre blocks are ignored as an authoring convenience.)
p.skipNextNewLine = true;
p.framesetOk = false;
}
function formStartTagInBody(p, token) {
const inTemplate = p.openElements.tmplCount > 0;
if (!p.formElement || inTemplate) {
if (p.openElements.hasInButtonScope(html.TAG_ID.P)) {
p._closePElement();
}
p._insertElement(token, html.NS.HTML);
if (!inTemplate) {
p.formElement = p.openElements.current;
}
}
}
function listItemStartTagInBody(p, token) {
p.framesetOk = false;
const tn = token.tagID;
for (let i = p.openElements.stackTop; i >= 0; i--) {
const elementId = p.openElements.tagIDs[i];
if ((tn === html.TAG_ID.LI && elementId === html.TAG_ID.LI) ||
((tn === html.TAG_ID.DD || tn === html.TAG_ID.DT) && (elementId === html.TAG_ID.DD || elementId === html.TAG_ID.DT))) {
p.openElements.generateImpliedEndTagsWithExclusion(elementId);
p.openElements.popUntilTagNamePopped(elementId);
break;
}
if (elementId !== html.TAG_ID.ADDRESS &&
elementId !== html.TAG_ID.DIV &&
elementId !== html.TAG_ID.P &&
p._isSpecialElement(p.openElements.items[i], elementId)) {
break;
}
}
if (p.openElements.hasInButtonScope(html.TAG_ID.P)) {
p._closePElement();
}
p._insertElement(token, html.NS.HTML);
}
function plaintextStartTagInBody(p, token) {
if (p.openElements.hasInButtonScope(html.TAG_ID.P)) {
p._closePElement();
}
p._insertElement(token, html.NS.HTML);
p.tokenizer.state = tokenizer.TokenizerMode.PLAINTEXT;
}
function buttonStartTagInBody(p, token) {
if (p.openElements.hasInScope(html.TAG_ID.BUTTON)) {
p.openElements.generateImpliedEndTags();
p.openElements.popUntilTagNamePopped(html.TAG_ID.BUTTON);
}
p._reconstructActiveFormattingElements();
p._insertElement(token, html.NS.HTML);
p.framesetOk = false;
}
function aStartTagInBody(p, token) {
const activeElementEntry = p.activeFormattingElements.getElementEntryInScopeWithTagName(html.TAG_NAMES.A);
if (activeElementEntry) {
callAdoptionAgency(p, token);
p.openElements.remove(activeElementEntry.element);
p.activeFormattingElements.removeEntry(activeElementEntry);
}
p._reconstructActiveFormattingElements();
p._insertElement(token, html.NS.HTML);
p.activeFormattingElements.pushElement(p.openElements.current, token);
}
function bStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
p._insertElement(token, html.NS.HTML);
p.activeFormattingElements.pushElement(p.openElements.current, token);
}
function nobrStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
if (p.openElements.hasInScope(html.TAG_ID.NOBR)) {
callAdoptionAgency(p, token);
p._reconstructActiveFormattingElements();
}
p._insertElement(token, html.NS.HTML);
p.activeFormattingElements.pushElement(p.openElements.current, token);
}
function appletStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
p._insertElement(token, html.NS.HTML);
p.activeFormattingElements.insertMarker();
p.framesetOk = false;
}
function tableStartTagInBody(p, token) {
if (p.treeAdapter.getDocumentMode(p.document) !== html.DOCUMENT_MODE.QUIRKS && p.openElements.hasInButtonScope(html.TAG_ID.P)) {
p._closePElement();
}
p._insertElement(token, html.NS.HTML);
p.framesetOk = false;
p.insertionMode = InsertionMode.IN_TABLE;
}
function areaStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
p._appendElement(token, html.NS.HTML);
p.framesetOk = false;
token.ackSelfClosing = true;
}
function isHiddenInput(token$1) {
const inputType = (0, token.getTokenAttr)(token$1, html.ATTRS.TYPE);
return inputType != null && inputType.toLowerCase() === HIDDEN_INPUT_TYPE;
}
function inputStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
p._appendElement(token, html.NS.HTML);
if (!isHiddenInput(token)) {
p.framesetOk = false;
}
token.ackSelfClosing = true;
}
function paramStartTagInBody(p, token) {
p._appendElement(token, html.NS.HTML);
token.ackSelfClosing = true;
}
function hrStartTagInBody(p, token) {
if (p.openElements.hasInButtonScope(html.TAG_ID.P)) {
p._closePElement();
}
p._appendElement(token, html.NS.HTML);
p.framesetOk = false;
token.ackSelfClosing = true;
}
function imageStartTagInBody(p, token) {
token.tagName = html.TAG_NAMES.IMG;
token.tagID = html.TAG_ID.IMG;
areaStartTagInBody(p, token);
}
function textareaStartTagInBody(p, token) {
p._insertElement(token, html.NS.HTML);
//NOTE: If the next token is a U+000A LINE FEED (LF) character token, then ignore that token and move
//on to the next one. (Newlines at the start of textarea elements are ignored as an authoring convenience.)
p.skipNextNewLine = true;
p.tokenizer.state = tokenizer.TokenizerMode.RCDATA;
p.originalInsertionMode = p.insertionMode;
p.framesetOk = false;
p.insertionMode = InsertionMode.TEXT;
}
function xmpStartTagInBody(p, token) {
if (p.openElements.hasInButtonScope(html.TAG_ID.P)) {
p._closePElement();
}
p._reconstructActiveFormattingElements();
p.framesetOk = false;
p._switchToTextParsing(token, tokenizer.TokenizerMode.RAWTEXT);
}
function iframeStartTagInBody(p, token) {
p.framesetOk = false;
p._switchToTextParsing(token, tokenizer.TokenizerMode.RAWTEXT);
}
//NOTE: here we assume that we always act as an user agent with enabled plugins, so we parse
//<noembed> as rawtext.
function noembedStartTagInBody(p, token) {
p._switchToTextParsing(token, tokenizer.TokenizerMode.RAWTEXT);
}
function selectStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
p._insertElement(token, html.NS.HTML);
p.framesetOk = false;
p.insertionMode =
p.insertionMode === InsertionMode.IN_TABLE ||
p.insertionMode === InsertionMode.IN_CAPTION ||
p.insertionMode === InsertionMode.IN_TABLE_BODY ||
p.insertionMode === InsertionMode.IN_ROW ||
p.insertionMode === InsertionMode.IN_CELL
? InsertionMode.IN_SELECT_IN_TABLE
: InsertionMode.IN_SELECT;
}
function optgroupStartTagInBody(p, token) {
if (p.openElements.currentTagId === html.TAG_ID.OPTION) {
p.openElements.pop();
}
p._reconstructActiveFormattingElements();
p._insertElement(token, html.NS.HTML);
}
function rbStartTagInBody(p, token) {
if (p.openElements.hasInScope(html.TAG_ID.RUBY)) {
p.openElements.generateImpliedEndTags();
}
p._insertElement(token, html.NS.HTML);
}
function rtStartTagInBody(p, token) {
if (p.openElements.hasInScope(html.TAG_ID.RUBY)) {
p.openElements.generateImpliedEndTagsWithExclusion(html.TAG_ID.RTC);
}
p._insertElement(token, html.NS.HTML);
}
function mathStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
foreignContent.adjustTokenMathMLAttrs(token);
foreignContent.adjustTokenXMLAttrs(token);
if (token.selfClosing) {
p._appendElement(token, html.NS.MATHML);
}
else {
p._insertElement(token, html.NS.MATHML);
}
token.ackSelfClosing = true;
}
function svgStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
foreignContent.adjustTokenSVGAttrs(token);
foreignContent.adjustTokenXMLAttrs(token);
if (token.selfClosing) {
p._appendElement(token, html.NS.SVG);
}
else {
p._insertElement(token, html.NS.SVG);
}
token.ackSelfClosing = true;
}
function genericStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
p._insertElement(token, html.NS.HTML);
}
function startTagInBody(p, token) {
switch (token.tagID) {
case html.TAG_ID.I:
case html.TAG_ID.S:
case html.TAG_ID.B:
case html.TAG_ID.U:
case html.TAG_ID.EM:
case html.TAG_ID.TT:
case html.TAG_ID.BIG:
case html.TAG_ID.CODE:
case html.TAG_ID.FONT:
case html.TAG_ID.SMALL:
case html.TAG_ID.STRIKE:
case html.TAG_ID.STRONG: {
bStartTagInBody(p, token);
break;
}
case html.TAG_ID.A: {
aStartTagInBody(p, token);
break;
}
case html.TAG_ID.H1:
case html.TAG_ID.H2:
case html.TAG_ID.H3:
case html.TAG_ID.H4:
case html.TAG_ID.H5:
case html.TAG_ID.H6: {
numberedHeaderStartTagInBody(p, token);
break;
}
case html.TAG_ID.P:
case html.TAG_ID.DL:
case html.TAG_ID.OL:
case html.TAG_ID.UL:
case html.TAG_ID.DIV:
case html.TAG_ID.DIR:
case html.TAG_ID.NAV:
case html.TAG_ID.MAIN:
case html.TAG_ID.MENU:
case html.TAG_ID.ASIDE:
case html.TAG_ID.CENTER:
case html.TAG_ID.FIGURE:
case html.TAG_ID.FOOTER:
case html.TAG_ID.HEADER:
case html.TAG_ID.HGROUP:
case html.TAG_ID.DIALOG:
case html.TAG_ID.DETAILS:
case html.TAG_ID.ADDRESS:
case html.TAG_ID.ARTICLE:
case html.TAG_ID.SECTION:
case html.TAG_ID.SUMMARY:
case html.TAG_ID.FIELDSET:
case html.TAG_ID.BLOCKQUOTE:
case html.TAG_ID.FIGCAPTION: {
addressStartTagInBody(p, token);
break;
}
case html.TAG_ID.LI:
case html.TAG_ID.DD:
case html.TAG_ID.DT: {
listItemStartTagInBody(p, token);
break;
}
case html.TAG_ID.BR:
case html.TAG_ID.IMG:
case html.TAG_ID.WBR:
case html.TAG_ID.AREA:
case html.TAG_ID.EMBED:
case html.TAG_ID.KEYGEN: {
areaStartTagInBody(p, token);
break;
}
case html.TAG_ID.HR: {
hrStartTagInBody(p, token);
break;
}
case html.TAG_ID.RB:
case html.TAG_ID.RTC: {
rbStartTagInBody(p, token);
break;
}
case html.TAG_ID.RT:
case html.TAG_ID.RP: {
rtStartTagInBody(p, token);
break;
}
case html.TAG_ID.PRE:
case html.TAG_ID.LISTING: {
preStartTagInBody(p, token);
break;
}
case html.TAG_ID.XMP: {
xmpStartTagInBody(p, token);
break;
}
case html.TAG_ID.SVG: {
svgStartTagInBody(p, token);
break;
}
case html.TAG_ID.HTML: {
htmlStartTagInBody(p, token);
break;
}
case html.TAG_ID.BASE:
case html.TAG_ID.LINK:
case html.TAG_ID.META:
case html.TAG_ID.STYLE:
case html.TAG_ID.TITLE:
case html.TAG_ID.SCRIPT:
case html.TAG_ID.BGSOUND:
case html.TAG_ID.BASEFONT:
case html.TAG_ID.TEMPLATE: {
startTagInHead(p, token);
break;
}
case html.TAG_ID.BODY: {
bodyStartTagInBody(p, token);
break;
}
case html.TAG_ID.FORM: {
formStartTagInBody(p, token);
break;
}
case html.TAG_ID.NOBR: {
nobrStartTagInBody(p, token);
break;
}
case html.TAG_ID.MATH: {
mathStartTagInBody(p, token);
break;
}
case html.TAG_ID.TABLE: {
tableStartTagInBody(p, token);
break;
}
case html.TAG_ID.INPUT: {
inputStartTagInBody(p, token);
break;
}
case html.TAG_ID.PARAM:
case html.TAG_ID.TRACK:
case html.TAG_ID.SOURCE: {
paramStartTagInBody(p, token);
break;
}
case html.TAG_ID.IMAGE: {
imageStartTagInBody(p, token);
break;
}
case html.TAG_ID.BUTTON: {
buttonStartTagInBody(p, token);
break;
}
case html.TAG_ID.APPLET:
case html.TAG_ID.OBJECT:
case html.TAG_ID.MARQUEE: {
appletStartTagInBody(p, token);
break;
}
case html.TAG_ID.IFRAME: {
iframeStartTagInBody(p, token);
break;
}
case html.TAG_ID.SELECT: {
selectStartTagInBody(p, token);
break;
}
case html.TAG_ID.OPTION:
case html.TAG_ID.OPTGROUP: {
optgroupStartTagInBody(p, token);
break;
}
case html.TAG_ID.NOEMBED: {
noembedStartTagInBody(p, token);
break;
}
case html.TAG_ID.FRAMESET: {
framesetStartTagInBody(p, token);
break;
}
case html.TAG_ID.TEXTAREA: {
textareaStartTagInBody(p, token);
break;
}
case html.TAG_ID.NOSCRIPT: {
if (p.options.scriptingEnabled) {
noembedStartTagInBody(p, token);
}
else {
genericStartTagInBody(p, token);
}
break;
}
case html.TAG_ID.PLAINTEXT: {
plaintextStartTagInBody(p, token);
break;
}
case html.TAG_ID.COL:
case html.TAG_ID.TH:
case html.TAG_ID.TD:
case html.TAG_ID.TR:
case html.TAG_ID.HEAD:
case html.TAG_ID.FRAME:
case html.TAG_ID.TBODY:
case html.TAG_ID.TFOOT:
case html.TAG_ID.THEAD:
case html.TAG_ID.CAPTION:
case html.TAG_ID.COLGROUP: {
// Ignore token
break;
}
default: {
genericStartTagInBody(p, token);
}
}
}
function bodyEndTagInBody(p, token) {
if (p.openElements.hasInScope(html.TAG_ID.BODY)) {
p.insertionMode = InsertionMode.AFTER_BODY;
//NOTE: <body> is never popped from the stack, so we need to updated
//the end location explicitly.
if (p.options.sourceCodeLocationInfo) {
const bodyElement = p.openElements.tryPeekProperlyNestedBodyElement();
if (bodyElement) {
p._setEndLocation(bodyElement, token);
}
}
}
}
function htmlEndTagInBody(p, token) {
if (p.openElements.hasInScope(html.TAG_ID.BODY)) {
p.insertionMode = InsertionMode.AFTER_BODY;
endTagAfterBody(p, token);
}
}
function addressEndTagInBody(p, token) {
const tn = token.tagID;
if (p.openElements.hasInScope(tn)) {
p.openElements.generateImpliedEndTags();
p.openElements.popUntilTagNamePopped(tn);
}
}
function formEndTagInBody(p) {
const inTemplate = p.openElements.tmplCount > 0;
const { formElement } = p;
if (!inTemplate) {
p.formElement = null;
}
if ((formElement || inTemplate) && p.openElements.hasInScope(html.TAG_ID.FORM)) {
p.openElements.generateImpliedEndTags();
if (inTemplate) {
p.openElements.popUntilTagNamePopped(html.TAG_ID.FORM);
}
else if (formElement) {
p.openElements.remove(formElement);
}
}
}
function pEndTagInBody(p) {
if (!p.openElements.hasInButtonScope(html.TAG_ID.P)) {
p._insertFakeElement(html.TAG_NAMES.P, html.TAG_ID.P);
}
p._closePElement();
}
function liEndTagInBody(p) {
if (p.openElements.hasInListItemScope(html.TAG_ID.LI)) {
p.openElements.generateImpliedEndTagsWithExclusion(html.TAG_ID.LI);
p.openElements.popUntilTagNamePopped(html.TAG_ID.LI);
}
}
function ddEndTagInBody(p, token) {
const tn = token.tagID;
if (p.openElements.hasInScope(tn)) {
p.openElements.generateImpliedEndTagsWithExclusion(tn);
p.openElements.popUntilTagNamePopped(tn);
}
}
function numberedHeaderEndTagInBody(p) {
if (p.openElements.hasNumberedHeaderInScope()) {
p.openElements.generateImpliedEndTags();
p.openElements.popUntilNumberedHeaderPopped();
}
}
function appletEndTagInBody(p, token) {
const tn = token.tagID;
if (p.openElements.hasInScope(tn)) {
p.openElements.generateImpliedEndTags();
p.openElements.popUntilTagNamePopped(tn);
p.activeFormattingElements.clearToLastMarker();
}
}
function brEndTagInBody(p) {
p._reconstructActiveFormattingElements();
p._insertFakeElement(html.TAG_NAMES.BR, html.TAG_ID.BR);
p.openElements.pop();
p.framesetOk = false;
}
function genericEndTagInBody(p, token) {
const tn = token.tagName;
const tid = token.tagID;
for (let i = p.openElements.stackTop; i > 0; i--) {
const element = p.openElements.items[i];
const elementId = p.openElements.tagIDs[i];
// Compare the tag name here, as the tag might not be a known tag with an ID.
if (tid === elementId && (tid !== html.TAG_ID.UNKNOWN || p.treeAdapter.getTagName(element) === tn)) {
p.openElements.generateImpliedEndTagsWithExclusion(tid);
if (p.openElements.stackTop >= i)
p.openElements.shortenToLength(i);
break;
}
if (p._isSpecialElement(element, elementId)) {
break;
}
}
}
function endTagInBody(p, token) {
switch (token.tagID) {
case html.TAG_ID.A:
case html.TAG_ID.B:
case html.TAG_ID.I:
case html.TAG_ID.S:
case html.TAG_ID.U:
case html.TAG_ID.EM:
case html.TAG_ID.TT:
case html.TAG_ID.BIG:
case html.TAG_ID.CODE:
case html.TAG_ID.FONT:
case html.TAG_ID.NOBR:
case html.TAG_ID.SMALL:
case html.TAG_ID.STRIKE:
case html.TAG_ID.STRONG: {
callAdoptionAgency(p, token);
break;
}
case html.TAG_ID.P: {
pEndTagInBody(p);
break;
}
case html.TAG_ID.DL:
case html.TAG_ID.UL:
case html.TAG_ID.OL:
case html.TAG_ID.DIR:
case html.TAG_ID.DIV:
case html.TAG_ID.NAV:
case html.TAG_ID.PRE:
case html.TAG_ID.MAIN:
case html.TAG_ID.MENU:
case html.TAG_ID.ASIDE:
case html.TAG_ID.BUTTON:
case html.TAG_ID.CENTER:
case html.TAG_ID.FIGURE:
case html.TAG_ID.FOOTER:
case html.TAG_ID.HEADER:
case html.TAG_ID.HGROUP:
case html.TAG_ID.DIALOG:
case html.TAG_ID.ADDRESS:
case html.TAG_ID.ARTICLE:
case html.TAG_ID.DETAILS:
case html.TAG_ID.SECTION:
case html.TAG_ID.SUMMARY:
case html.TAG_ID.LISTING:
case html.TAG_ID.FIELDSET:
case html.TAG_ID.BLOCKQUOTE:
case html.TAG_ID.FIGCAPTION: {
addressEndTagInBody(p, token);
break;
}
case html.TAG_ID.LI: {
liEndTagInBody(p);
break;
}
case html.TAG_ID.DD:
case html.TAG_ID.DT: {
ddEndTagInBody(p, token);
break;
}
case html.TAG_ID.H1:
case html.TAG_ID.H2:
case html.TAG_ID.H3:
case html.TAG_ID.H4:
case html.TAG_ID.H5:
case html.TAG_ID.H6: {
numberedHeaderEndTagInBody(p);
break;
}
case html.TAG_ID.BR: {
brEndTagInBody(p);
break;
}
case html.TAG_ID.BODY: {
bodyEndTagInBody(p, token);
break;
}
case html.TAG_ID.HTML: {
htmlEndTagInBody(p, token);
break;
}
case html.TAG_ID.FORM: {
formEndTagInBody(p);
break;
}
case html.TAG_ID.APPLET:
case html.TAG_ID.OBJECT:
case html.TAG_ID.MARQUEE: {
appletEndTagInBody(p, token);
break;
}
case html.TAG_ID.TEMPLATE: {
templateEndTagInHead(p, token);
break;
}
default: {
genericEndTagInBody(p, token);
}
}
}
function eofInBody(p, token) {
if (p.tmplInsertionModeStack.length > 0) {
eofInTemplate(p, token);
}
else {
stopParsing(p, token);
}
}
// The "text" insertion mode
//------------------------------------------------------------------
function endTagInText(p, token) {
var _a;
if (token.tagID === html.TAG_ID.SCRIPT) {
(_a = p.scriptHandler) === null || _a === void 0 ? void 0 : _a.call(p, p.openElements.current);
}
p.openElements.pop();
p.insertionMode = p.originalInsertionMode;
}
function eofInText(p, token) {
p._err(token, errorCodes.ERR.eofInElementThatCanContainOnlyText);
p.openElements.pop();
p.insertionMode = p.originalInsertionMode;
p.onEof(token);
}
// The "in table" insertion mode
//------------------------------------------------------------------
function characterInTable(p, token$1) {
if (TABLE_STRUCTURE_TAGS.has(p.openElements.currentTagId)) {
p.pendingCharacterTokens.length = 0;
p.hasNonWhitespacePendingCharacterToken = false;
p.originalInsertionMode = p.insertionMode;
p.insertionMode = InsertionMode.IN_TABLE_TEXT;
switch (token$1.type) {
case token.TokenType.CHARACTER: {
characterInTableText(p, token$1);
break;
}
case token.TokenType.WHITESPACE_CHARACTER: {
whitespaceCharacterInTableText(p, token$1);
break;
}
// Ignore null
}
}
else {
tokenInTable(p, token$1);
}
}
function captionStartTagInTable(p, token) {
p.openElements.clearBackToTableContext();
p.activeFormattingElements.insertMarker();
p._insertElement(token, html.NS.HTML);
p.insertionMode = InsertionMode.IN_CAPTION;
}
function colgroupStartTagInTable(p, token) {
p.openElements.clearBackToTableContext();
p._insertElement(token, html.NS.HTML);
p.insertionMode = InsertionMode.IN_COLUMN_GROUP;
}
function colStartTagInTable(p, token) {
p.openElements.clearBackToTableContext();
p._insertFakeElement(html.TAG_NAMES.COLGROUP, html.TAG_ID.COLGROUP);
p.insertionMode = InsertionMode.IN_COLUMN_GROUP;
startTagInColumnGroup(p, token);
}
function tbodyStartTagInTable(p, token) {
p.openElements.clearBackToTableContext();
p._insertElement(token, html.NS.HTML);
p.insertionMode = InsertionMode.IN_TABLE_BODY;
}
function tdStartTagInTable(p, token) {
p.openElements.clearBackToTableContext();
p._insertFakeElement(html.TAG_NAMES.TBODY, html.TAG_ID.TBODY);
p.insertionMode = InsertionMode.IN_TABLE_BODY;
startTagInTableBody(p, token);
}
function tableStartTagInTable(p, token) {
if (p.openElements.hasInTableScope(html.TAG_ID.TABLE)) {
p.openElements.popUntilTagNamePopped(html.TAG_ID.TABLE);
p._resetInsertionMode();
p._processStartTag(token);
}
}
function inputStartTagInTable(p, token) {
if (isHiddenInput(token)) {
p._appendElement(token, html.NS.HTML);
}
else {
tokenInTable(p, token);
}
token.ackSelfClosing = true;
}
function formStartTagInTable(p, token) {
if (!p.formElement && p.openElements.tmplCount === 0) {
p._insertElement(token, html.NS.HTML);
p.formElement = p.openElements.current;
p.openElements.pop();
}
}
function startTagInTable(p, token) {
switch (token.tagID) {
case html.TAG_ID.TD:
case html.TAG_ID.TH:
case html.TAG_ID.TR: {
tdStartTagInTable(p, token);
break;
}
case html.TAG_ID.STYLE:
case html.TAG_ID.SCRIPT:
case html.TAG_ID.TEMPLATE: {
startTagInHead(p, token);
break;
}
case html.TAG_ID.COL: {
colStartTagInTable(p, token);
break;
}
case html.TAG_ID.FORM: {
formStartTagInTable(p, token);
break;
}
case html.TAG_ID.TABLE: {
tableStartTagInTable(p, token);
break;
}
case html.TAG_ID.TBODY:
case html.TAG_ID.TFOOT:
case html.TAG_ID.THEAD: {
tbodyStartTagInTable(p, token);
break;
}
case html.TAG_ID.INPUT: {
inputStartTagInTable(p, token);
break;
}
case html.TAG_ID.CAPTION: {
captionStartTagInTable(p, token);
break;
}
case html.TAG_ID.COLGROUP: {
colgroupStartTagInTable(p, token);
break;
}
default: {
tokenInTable(p, token);
}
}
}
function endTagInTable(p, token) {
switch (token.tagID) {
case html.TAG_ID.TABLE: {
if (p.openElements.hasInTableScope(html.TAG_ID.TABLE)) {
p.openElements.popUntilTagNamePopped(html.TAG_ID.TABLE);
p._resetInsertionMode();
}
break;
}
case html.TAG_ID.TEMPLATE: {
templateEndTagInHead(p, token);
break;
}
case html.TAG_ID.BODY:
case html.TAG_ID.CAPTION:
case html.TAG_ID.COL:
case html.TAG_ID.COLGROUP:
case html.TAG_ID.HTML:
case html.TAG_ID.TBODY:
case html.TAG_ID.TD:
case html.TAG_ID.TFOOT:
case html.TAG_ID.TH:
case html.TAG_ID.THEAD:
case html.TAG_ID.TR: {
// Ignore token
break;
}
default: {
tokenInTable(p, token);
}
}
}
function tokenInTable(p, token) {
const savedFosterParentingState = p.fosterParentingEnabled;
p.fosterParentingEnabled = true;
// Process token in `In Body` mode
modeInBody(p, token);
p.fosterParentingEnabled = savedFosterParentingState;
}
// The "in table text" insertion mode
//------------------------------------------------------------------
function whitespaceCharacterInTableText(p, token) {
p.pendingCharacterTokens.push(token);
}
function characterInTableText(p, token) {
p.pendingCharacterTokens.push(token);
p.hasNonWhitespacePendingCharacterToken = true;
}
function tokenInTableText(p, token) {
let i = 0;
if (p.hasNonWhitespacePendingCharacterToken) {
for (; i < p.pendingCharacterTokens.length; i++) {
tokenInTable(p, p.pendingCharacterTokens[i]);
}
}
else {
for (; i < p.pendingCharacterTokens.length; i++) {
p._insertCharacters(p.pendingCharacterTokens[i]);
}
}
p.insertionMode = p.originalInsertionMode;
p._processToken(token);
}
// The "in caption" insertion mode
//------------------------------------------------------------------
const TABLE_VOID_ELEMENTS = new Set([html.TAG_ID.CAPTION, html.TAG_ID.COL, html.TAG_ID.COLGROUP, html.TAG_ID.TBODY, html.TAG_ID.TD, html.TAG_ID.TFOOT, html.TAG_ID.TH, html.TAG_ID.THEAD, html.TAG_ID.TR]);
function startTagInCaption(p, token) {
const tn = token.tagID;
if (TABLE_VOID_ELEMENTS.has(tn)) {
if (p.openElements.hasInTableScope(html.TAG_ID.CAPTION)) {
p.openElements.generateImpliedEndTags();
p.openElements.popUntilTagNamePopped(html.TAG_ID.CAPTION);
p.activeFormattingElements.clearToLastMarker();
p.insertionMode = InsertionMode.IN_TABLE;
startTagInTable(p, token);
}
}
else {
startTagInBody(p, token);
}
}
function endTagInCaption(p, token) {
const tn = token.tagID;
switch (tn) {
case html.TAG_ID.CAPTION:
case html.TAG_ID.TABLE: {
if (p.openElements.hasInTableScope(html.TAG_ID.CAPTION)) {
p.openElements.generateImpliedEndTags();
p.openElements.popUntilTagNamePopped(html.TAG_ID.CAPTION);
p.activeFormattingElements.clearToLastMarker();
p.insertionMode = InsertionMode.IN_TABLE;
if (tn === html.TAG_ID.TABLE) {
endTagInTable(p, token);
}
}
break;
}
case html.TAG_ID.BODY:
case html.TAG_ID.COL:
case html.TAG_ID.COLGROUP:
case html.TAG_ID.HTML:
case html.TAG_ID.TBODY:
case html.TAG_ID.TD:
case html.TAG_ID.TFOOT:
case html.TAG_ID.TH:
case html.TAG_ID.THEAD:
case html.TAG_ID.TR: {
// Ignore token
break;
}
default: {
endTagInBody(p, token);
}
}
}
// The "in column group" insertion mode
//------------------------------------------------------------------
function startTagInColumnGroup(p, token) {
switch (token.tagID) {
case html.TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case html.TAG_ID.COL: {
p._appendElement(token, html.NS.HTML);
token.ackSelfClosing = true;
break;
}
case html.TAG_ID.TEMPLATE: {
startTagInHead(p, token);
break;
}
default: {
tokenInColumnGroup(p, token);
}
}
}
function endTagInColumnGroup(p, token) {
switch (token.tagID) {
case html.TAG_ID.COLGROUP: {
if (p.openElements.currentTagId === html.TAG_ID.COLGROUP) {
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE;
}
break;
}
case html.TAG_ID.TEMPLATE: {
templateEndTagInHead(p, token);
break;
}
case html.TAG_ID.COL: {
// Ignore token
break;
}
default: {
tokenInColumnGroup(p, token);
}
}
}
function tokenInColumnGroup(p, token) {
if (p.openElements.currentTagId === html.TAG_ID.COLGROUP) {
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE;
p._processToken(token);
}
}
// The "in table body" insertion mode
//------------------------------------------------------------------
function startTagInTableBody(p, token) {
switch (token.tagID) {
case html.TAG_ID.TR: {
p.openElements.clearBackToTableBodyContext();
p._insertElement(token, html.NS.HTML);
p.insertionMode = InsertionMode.IN_ROW;
break;
}
case html.TAG_ID.TH:
case html.TAG_ID.TD: {
p.openElements.clearBackToTableBodyContext();
p._insertFakeElement(html.TAG_NAMES.TR, html.TAG_ID.TR);
p.insertionMode = InsertionMode.IN_ROW;
startTagInRow(p, token);
break;
}
case html.TAG_ID.CAPTION:
case html.TAG_ID.COL:
case html.TAG_ID.COLGROUP:
case html.TAG_ID.TBODY:
case html.TAG_ID.TFOOT:
case html.TAG_ID.THEAD: {
if (p.openElements.hasTableBodyContextInTableScope()) {
p.openElements.clearBackToTableBodyContext();
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE;
startTagInTable(p, token);
}
break;
}
default: {
startTagInTable(p, token);
}
}
}
function endTagInTableBody(p, token) {
const tn = token.tagID;
switch (token.tagID) {
case html.TAG_ID.TBODY:
case html.TAG_ID.TFOOT:
case html.TAG_ID.THEAD: {
if (p.openElements.hasInTableScope(tn)) {
p.openElements.clearBackToTableBodyContext();
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE;
}
break;
}
case html.TAG_ID.TABLE: {
if (p.openElements.hasTableBodyContextInTableScope()) {
p.openElements.clearBackToTableBodyContext();
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE;
endTagInTable(p, token);
}
break;
}
case html.TAG_ID.BODY:
case html.TAG_ID.CAPTION:
case html.TAG_ID.COL:
case html.TAG_ID.COLGROUP:
case html.TAG_ID.HTML:
case html.TAG_ID.TD:
case html.TAG_ID.TH:
case html.TAG_ID.TR: {
// Ignore token
break;
}
default: {
endTagInTable(p, token);
}
}
}
// The "in row" insertion mode
//------------------------------------------------------------------
function startTagInRow(p, token) {
switch (token.tagID) {
case html.TAG_ID.TH:
case html.TAG_ID.TD: {
p.openElements.clearBackToTableRowContext();
p._insertElement(token, html.NS.HTML);
p.insertionMode = InsertionMode.IN_CELL;
p.activeFormattingElements.insertMarker();
break;
}
case html.TAG_ID.CAPTION:
case html.TAG_ID.COL:
case html.TAG_ID.COLGROUP:
case html.TAG_ID.TBODY:
case html.TAG_ID.TFOOT:
case html.TAG_ID.THEAD:
case html.TAG_ID.TR: {
if (p.openElements.hasInTableScope(html.TAG_ID.TR)) {
p.openElements.clearBackToTableRowContext();
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE_BODY;
startTagInTableBody(p, token);
}
break;
}
default: {
startTagInTable(p, token);
}
}
}
function endTagInRow(p, token) {
switch (token.tagID) {
case html.TAG_ID.TR: {
if (p.openElements.hasInTableScope(html.TAG_ID.TR)) {
p.openElements.clearBackToTableRowContext();
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE_BODY;
}
break;
}
case html.TAG_ID.TABLE: {
if (p.openElements.hasInTableScope(html.TAG_ID.TR)) {
p.openElements.clearBackToTableRowContext();
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE_BODY;
endTagInTableBody(p, token);
}
break;
}
case html.TAG_ID.TBODY:
case html.TAG_ID.TFOOT:
case html.TAG_ID.THEAD: {
if (p.openElements.hasInTableScope(token.tagID) || p.openElements.hasInTableScope(html.TAG_ID.TR)) {
p.openElements.clearBackToTableRowContext();
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE_BODY;
endTagInTableBody(p, token);
}
break;
}
case html.TAG_ID.BODY:
case html.TAG_ID.CAPTION:
case html.TAG_ID.COL:
case html.TAG_ID.COLGROUP:
case html.TAG_ID.HTML:
case html.TAG_ID.TD:
case html.TAG_ID.TH: {
// Ignore end tag
break;
}
default: {
endTagInTable(p, token);
}
}
}
// The "in cell" insertion mode
//------------------------------------------------------------------
function startTagInCell(p, token) {
const tn = token.tagID;
if (TABLE_VOID_ELEMENTS.has(tn)) {
if (p.openElements.hasInTableScope(html.TAG_ID.TD) || p.openElements.hasInTableScope(html.TAG_ID.TH)) {
p._closeTableCell();
startTagInRow(p, token);
}
}
else {
startTagInBody(p, token);
}
}
function endTagInCell(p, token) {
const tn = token.tagID;
switch (tn) {
case html.TAG_ID.TD:
case html.TAG_ID.TH: {
if (p.openElements.hasInTableScope(tn)) {
p.openElements.generateImpliedEndTags();
p.openElements.popUntilTagNamePopped(tn);
p.activeFormattingElements.clearToLastMarker();
p.insertionMode = InsertionMode.IN_ROW;
}
break;
}
case html.TAG_ID.TABLE:
case html.TAG_ID.TBODY:
case html.TAG_ID.TFOOT:
case html.TAG_ID.THEAD:
case html.TAG_ID.TR: {
if (p.openElements.hasInTableScope(tn)) {
p._closeTableCell();
endTagInRow(p, token);
}
break;
}
case html.TAG_ID.BODY:
case html.TAG_ID.CAPTION:
case html.TAG_ID.COL:
case html.TAG_ID.COLGROUP:
case html.TAG_ID.HTML: {
// Ignore token
break;
}
default: {
endTagInBody(p, token);
}
}
}
// The "in select" insertion mode
//------------------------------------------------------------------
function startTagInSelect(p, token) {
switch (token.tagID) {
case html.TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case html.TAG_ID.OPTION: {
if (p.openElements.currentTagId === html.TAG_ID.OPTION) {
p.openElements.pop();
}
p._insertElement(token, html.NS.HTML);
break;
}
case html.TAG_ID.OPTGROUP: {
if (p.openElements.currentTagId === html.TAG_ID.OPTION) {
p.openElements.pop();
}
if (p.openElements.currentTagId === html.TAG_ID.OPTGROUP) {
p.openElements.pop();
}
p._insertElement(token, html.NS.HTML);
break;
}
case html.TAG_ID.INPUT:
case html.TAG_ID.KEYGEN:
case html.TAG_ID.TEXTAREA:
case html.TAG_ID.SELECT: {
if (p.openElements.hasInSelectScope(html.TAG_ID.SELECT)) {
p.openElements.popUntilTagNamePopped(html.TAG_ID.SELECT);
p._resetInsertionMode();
if (token.tagID !== html.TAG_ID.SELECT) {
p._processStartTag(token);
}
}
break;
}
case html.TAG_ID.SCRIPT:
case html.TAG_ID.TEMPLATE: {
startTagInHead(p, token);
break;
}
// Do nothing
}
}
function endTagInSelect(p, token) {
switch (token.tagID) {
case html.TAG_ID.OPTGROUP: {
if (p.openElements.stackTop > 0 &&
p.openElements.currentTagId === html.TAG_ID.OPTION &&
p.openElements.tagIDs[p.openElements.stackTop - 1] === html.TAG_ID.OPTGROUP) {
p.openElements.pop();
}
if (p.openElements.currentTagId === html.TAG_ID.OPTGROUP) {
p.openElements.pop();
}
break;
}
case html.TAG_ID.OPTION: {
if (p.openElements.currentTagId === html.TAG_ID.OPTION) {
p.openElements.pop();
}
break;
}
case html.TAG_ID.SELECT: {
if (p.openElements.hasInSelectScope(html.TAG_ID.SELECT)) {
p.openElements.popUntilTagNamePopped(html.TAG_ID.SELECT);
p._resetInsertionMode();
}
break;
}
case html.TAG_ID.TEMPLATE: {
templateEndTagInHead(p, token);
break;
}
// Do nothing
}
}
// The "in select in table" insertion mode
//------------------------------------------------------------------
function startTagInSelectInTable(p, token) {
const tn = token.tagID;
if (tn === html.TAG_ID.CAPTION ||
tn === html.TAG_ID.TABLE ||
tn === html.TAG_ID.TBODY ||
tn === html.TAG_ID.TFOOT ||
tn === html.TAG_ID.THEAD ||
tn === html.TAG_ID.TR ||
tn === html.TAG_ID.TD ||
tn === html.TAG_ID.TH) {
p.openElements.popUntilTagNamePopped(html.TAG_ID.SELECT);
p._resetInsertionMode();
p._processStartTag(token);
}
else {
startTagInSelect(p, token);
}
}
function endTagInSelectInTable(p, token) {
const tn = token.tagID;
if (tn === html.TAG_ID.CAPTION ||
tn === html.TAG_ID.TABLE ||
tn === html.TAG_ID.TBODY ||
tn === html.TAG_ID.TFOOT ||
tn === html.TAG_ID.THEAD ||
tn === html.TAG_ID.TR ||
tn === html.TAG_ID.TD ||
tn === html.TAG_ID.TH) {
if (p.openElements.hasInTableScope(tn)) {
p.openElements.popUntilTagNamePopped(html.TAG_ID.SELECT);
p._resetInsertionMode();
p.onEndTag(token);
}
}
else {
endTagInSelect(p, token);
}
}
// The "in template" insertion mode
//------------------------------------------------------------------
function startTagInTemplate(p, token) {
switch (token.tagID) {
// First, handle tags that can start without a mode change
case html.TAG_ID.BASE:
case html.TAG_ID.BASEFONT:
case html.TAG_ID.BGSOUND:
case html.TAG_ID.LINK:
case html.TAG_ID.META:
case html.TAG_ID.NOFRAMES:
case html.TAG_ID.SCRIPT:
case html.TAG_ID.STYLE:
case html.TAG_ID.TEMPLATE:
case html.TAG_ID.TITLE: {
startTagInHead(p, token);
break;
}
// Re-process the token in the appropriate mode
case html.TAG_ID.CAPTION:
case html.TAG_ID.COLGROUP:
case html.TAG_ID.TBODY:
case html.TAG_ID.TFOOT:
case html.TAG_ID.THEAD: {
p.tmplInsertionModeStack[0] = InsertionMode.IN_TABLE;
p.insertionMode = InsertionMode.IN_TABLE;
startTagInTable(p, token);
break;
}
case html.TAG_ID.COL: {
p.tmplInsertionModeStack[0] = InsertionMode.IN_COLUMN_GROUP;
p.insertionMode = InsertionMode.IN_COLUMN_GROUP;
startTagInColumnGroup(p, token);
break;
}
case html.TAG_ID.TR: {
p.tmplInsertionModeStack[0] = InsertionMode.IN_TABLE_BODY;
p.insertionMode = InsertionMode.IN_TABLE_BODY;
startTagInTableBody(p, token);
break;
}
case html.TAG_ID.TD:
case html.TAG_ID.TH: {
p.tmplInsertionModeStack[0] = InsertionMode.IN_ROW;
p.insertionMode = InsertionMode.IN_ROW;
startTagInRow(p, token);
break;
}
default: {
p.tmplInsertionModeStack[0] = InsertionMode.IN_BODY;
p.insertionMode = InsertionMode.IN_BODY;
startTagInBody(p, token);
}
}
}
function endTagInTemplate(p, token) {
if (token.tagID === html.TAG_ID.TEMPLATE) {
templateEndTagInHead(p, token);
}
}
function eofInTemplate(p, token) {
if (p.openElements.tmplCount > 0) {
p.openElements.popUntilTagNamePopped(html.TAG_ID.TEMPLATE);
p.activeFormattingElements.clearToLastMarker();
p.tmplInsertionModeStack.shift();
p._resetInsertionMode();
p.onEof(token);
}
else {
stopParsing(p, token);
}
}
// The "after body" insertion mode
//------------------------------------------------------------------
function startTagAfterBody(p, token) {
if (token.tagID === html.TAG_ID.HTML) {
startTagInBody(p, token);
}
else {
tokenAfterBody(p, token);
}
}
function endTagAfterBody(p, token) {
var _a;
if (token.tagID === html.TAG_ID.HTML) {
if (!p.fragmentContext) {
p.insertionMode = InsertionMode.AFTER_AFTER_BODY;
}
//NOTE: <html> is never popped from the stack, so we need to updated
//the end location explicitly.
if (p.options.sourceCodeLocationInfo && p.openElements.tagIDs[0] === html.TAG_ID.HTML) {
p._setEndLocation(p.openElements.items[0], token);
// Update the body element, if it doesn't have an end tag
const bodyElement = p.openElements.items[1];
if (bodyElement && !((_a = p.treeAdapter.getNodeSourceCodeLocation(bodyElement)) === null || _a === void 0 ? void 0 : _a.endTag)) {
p._setEndLocation(bodyElement, token);
}
}
}
else {
tokenAfterBody(p, token);
}
}
function tokenAfterBody(p, token) {
p.insertionMode = InsertionMode.IN_BODY;
modeInBody(p, token);
}
// The "in frameset" insertion mode
//------------------------------------------------------------------
function startTagInFrameset(p, token) {
switch (token.tagID) {
case html.TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case html.TAG_ID.FRAMESET: {
p._insertElement(token, html.NS.HTML);
break;
}
case html.TAG_ID.FRAME: {
p._appendElement(token, html.NS.HTML);
token.ackSelfClosing = true;
break;
}
case html.TAG_ID.NOFRAMES: {
startTagInHead(p, token);
break;
}
// Do nothing
}
}
function endTagInFrameset(p, token) {
if (token.tagID === html.TAG_ID.FRAMESET && !p.openElements.isRootHtmlElementCurrent()) {
p.openElements.pop();
if (!p.fragmentContext && p.openElements.currentTagId !== html.TAG_ID.FRAMESET) {
p.insertionMode = InsertionMode.AFTER_FRAMESET;
}
}
}
// The "after frameset" insertion mode
//------------------------------------------------------------------
function startTagAfterFrameset(p, token) {
switch (token.tagID) {
case html.TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case html.TAG_ID.NOFRAMES: {
startTagInHead(p, token);
break;
}
// Do nothing
}
}
function endTagAfterFrameset(p, token) {
if (token.tagID === html.TAG_ID.HTML) {
p.insertionMode = InsertionMode.AFTER_AFTER_FRAMESET;
}
}
// The "after after body" insertion mode
//------------------------------------------------------------------
function startTagAfterAfterBody(p, token) {
if (token.tagID === html.TAG_ID.HTML) {
startTagInBody(p, token);
}
else {
tokenAfterAfterBody(p, token);
}
}
function tokenAfterAfterBody(p, token) {
p.insertionMode = InsertionMode.IN_BODY;
modeInBody(p, token);
}
// The "after after frameset" insertion mode
//------------------------------------------------------------------
function startTagAfterAfterFrameset(p, token) {
switch (token.tagID) {
case html.TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case html.TAG_ID.NOFRAMES: {
startTagInHead(p, token);
break;
}
// Do nothing
}
}
// The rules for parsing tokens in foreign content
//------------------------------------------------------------------
function nullCharacterInForeignContent(p, token) {
token.chars = unicode.REPLACEMENT_CHARACTER;
p._insertCharacters(token);
}
function characterInForeignContent(p, token) {
p._insertCharacters(token);
p.framesetOk = false;
}
function popUntilHtmlOrIntegrationPoint(p) {
while (p.treeAdapter.getNamespaceURI(p.openElements.current) !== html.NS.HTML &&
!p._isIntegrationPoint(p.openElements.currentTagId, p.openElements.current)) {
p.openElements.pop();
}
}
function startTagInForeignContent(p, token) {
if (foreignContent.causesExit(token)) {
popUntilHtmlOrIntegrationPoint(p);
p._startTagOutsideForeignContent(token);
}
else {
const current = p._getAdjustedCurrentElement();
const currentNs = p.treeAdapter.getNamespaceURI(current);
if (currentNs === html.NS.MATHML) {
foreignContent.adjustTokenMathMLAttrs(token);
}
else if (currentNs === html.NS.SVG) {
foreignContent.adjustTokenSVGTagName(token);
foreignContent.adjustTokenSVGAttrs(token);
}
foreignContent.adjustTokenXMLAttrs(token);
if (token.selfClosing) {
p._appendElement(token, currentNs);
}
else {
p._insertElement(token, currentNs);
}
token.ackSelfClosing = true;
}
}
function endTagInForeignContent(p, token) {
if (token.tagID === html.TAG_ID.P || token.tagID === html.TAG_ID.BR) {
popUntilHtmlOrIntegrationPoint(p);
p._endTagOutsideForeignContent(token);
return;
}
for (let i = p.openElements.stackTop; i > 0; i--) {
const element = p.openElements.items[i];
if (p.treeAdapter.getNamespaceURI(element) === html.NS.HTML) {
p._endTagOutsideForeignContent(token);
break;
}
const tagName = p.treeAdapter.getTagName(element);
if (tagName.toLowerCase() === token.tagName) {
//NOTE: update the token tag name for `_setEndLocation`.
token.tagName = tagName;
p.openElements.shortenToLength(i);
break;
}
}
}
});
var serializer = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.serializeOuter = exports.serialize = void 0;
// Sets
const VOID_ELEMENTS = new Set([
html.TAG_NAMES.AREA,
html.TAG_NAMES.BASE,
html.TAG_NAMES.BASEFONT,
html.TAG_NAMES.BGSOUND,
html.TAG_NAMES.BR,
html.TAG_NAMES.COL,
html.TAG_NAMES.EMBED,
html.TAG_NAMES.FRAME,
html.TAG_NAMES.HR,
html.TAG_NAMES.IMG,
html.TAG_NAMES.INPUT,
html.TAG_NAMES.KEYGEN,
html.TAG_NAMES.LINK,
html.TAG_NAMES.META,
html.TAG_NAMES.PARAM,
html.TAG_NAMES.SOURCE,
html.TAG_NAMES.TRACK,
html.TAG_NAMES.WBR,
]);
function isVoidElement(node, options) {
return (options.treeAdapter.isElementNode(node) &&
options.treeAdapter.getNamespaceURI(node) === html.NS.HTML &&
VOID_ELEMENTS.has(options.treeAdapter.getTagName(node)));
}
const defaultOpts = { treeAdapter: _default$1.defaultTreeAdapter, scriptingEnabled: true };
/**
* Serializes an AST node to an HTML string.
*
* @example
*
* ```js
* const parse5 = require('parse5');
*
* const document = parse5.parse('<!DOCTYPE html><html><head></head><body>Hi there!</body></html>');
*
* // Serializes a document.
* const html = parse5.serialize(document);
*
* // Serializes the <html> element content.
* const str = parse5.serialize(document.childNodes[1]);
*
* console.log(str); //> '<head></head><body>Hi there!</body>'
* ```
*
* @param node Node to serialize.
* @param options Serialization options.
*/
function serialize(node, options) {
const opts = Object.assign(Object.assign({}, defaultOpts), options);
if (isVoidElement(node, opts)) {
return '';
}
return serializeChildNodes(node, opts);
}
exports.serialize = serialize;
/**
* Serializes an AST element node to an HTML string, including the element node.
*
* @example
*
* ```js
* const parse5 = require('parse5');
*
* const document = parse5.parseFragment('<div>Hello, <b>world</b>!</div>');
*
* // Serializes the <div> element.
* const html = parse5.serializeOuter(document.childNodes[0]);
*
* console.log(str); //> '<div>Hello, <b>world</b>!</div>'
* ```
*
* @param node Node to serialize.
* @param options Serialization options.
*/
function serializeOuter(node, options) {
const opts = Object.assign(Object.assign({}, defaultOpts), options);
return serializeNode(node, opts);
}
exports.serializeOuter = serializeOuter;
function serializeChildNodes(parentNode, options) {
let html$1 = '';
// Get container of the child nodes
const container = options.treeAdapter.isElementNode(parentNode) &&
options.treeAdapter.getTagName(parentNode) === html.TAG_NAMES.TEMPLATE &&
options.treeAdapter.getNamespaceURI(parentNode) === html.NS.HTML
? options.treeAdapter.getTemplateContent(parentNode)
: parentNode;
const childNodes = options.treeAdapter.getChildNodes(container);
if (childNodes) {
for (const currentNode of childNodes) {
html$1 += serializeNode(currentNode, options);
}
}
return html$1;
}
function serializeNode(node, options) {
if (options.treeAdapter.isElementNode(node)) {
return serializeElement(node, options);
}
if (options.treeAdapter.isTextNode(node)) {
return serializeTextNode(node, options);
}
if (options.treeAdapter.isCommentNode(node)) {
return serializeCommentNode(node, options);
}
if (options.treeAdapter.isDocumentTypeNode(node)) {
return serializeDocumentTypeNode(node, options);
}
// Return an empty string for unknown nodes
return '';
}
function serializeElement(node, options) {
const tn = options.treeAdapter.getTagName(node);
return `<${tn}${serializeAttributes(node, options)}>${isVoidElement(node, options) ? '' : `${serializeChildNodes(node, options)}</${tn}>`}`;
}
function serializeAttributes(node, { treeAdapter }) {
let html$1 = '';
for (const attr of treeAdapter.getAttrList(node)) {
html$1 += ' ';
if (!attr.namespace) {
html$1 += attr.name;
}
else
switch (attr.namespace) {
case html.NS.XML: {
html$1 += `xml:${attr.name}`;
break;
}
case html.NS.XMLNS: {
if (attr.name !== 'xmlns') {
html$1 += 'xmlns:';
}
html$1 += attr.name;
break;
}
case html.NS.XLINK: {
html$1 += `xlink:${attr.name}`;
break;
}
default: {
html$1 += `${attr.prefix}:${attr.name}`;
}
}
html$1 += `="${(0, escape_js_1.escapeAttribute)(attr.value)}"`;
}
return html$1;
}
function serializeTextNode(node, options) {
const { treeAdapter } = options;
const content = treeAdapter.getTextNodeContent(node);
const parent = treeAdapter.getParentNode(node);
const parentTn = parent && treeAdapter.isElementNode(parent) && treeAdapter.getTagName(parent);
return parentTn &&
treeAdapter.getNamespaceURI(parent) === html.NS.HTML &&
(0, html.hasUnescapedText)(parentTn, options.scriptingEnabled)
? content
: (0, escape_js_1.escapeText)(content);
}
function serializeCommentNode(node, { treeAdapter }) {
return `<!--${treeAdapter.getCommentNodeContent(node)}-->`;
}
function serializeDocumentTypeNode(node, { treeAdapter }) {
return `<!DOCTYPE ${treeAdapter.getDocumentTypeNodeName(node)}>`;
}
});
var cjs$1 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseFragment = exports.parse = exports.TokenizerMode = exports.Tokenizer = exports.Token = exports.html = exports.foreignContent = exports.ErrorCodes = exports.serializeOuter = exports.serialize = exports.Parser = exports.defaultTreeAdapter = void 0;
Object.defineProperty(exports, "defaultTreeAdapter", { enumerable: true, get: function () { return _default$1.defaultTreeAdapter; } });
var index_js_2 = parser;
Object.defineProperty(exports, "Parser", { enumerable: true, get: function () { return index_js_2.Parser; } });
Object.defineProperty(exports, "serialize", { enumerable: true, get: function () { return serializer.serialize; } });
Object.defineProperty(exports, "serializeOuter", { enumerable: true, get: function () { return serializer.serializeOuter; } });
Object.defineProperty(exports, "ErrorCodes", { enumerable: true, get: function () { return errorCodes.ERR; } });
/** @internal */
exports.foreignContent = foreignContent;
/** @internal */
exports.html = html;
/** @internal */
exports.Token = token;
/** @internal */
Object.defineProperty(exports, "Tokenizer", { enumerable: true, get: function () { return tokenizer.Tokenizer; } });
Object.defineProperty(exports, "TokenizerMode", { enumerable: true, get: function () { return tokenizer.TokenizerMode; } });
// Shorthands
/**
* Parses an HTML string.
*
* @param html Input HTML string.
* @param options Parsing options.
* @returns Document
*
* @example
*
* ```js
* const parse5 = require('parse5');
*
* const document = parse5.parse('<!DOCTYPE html><html><head></head><body>Hi there!</body></html>');
*
* console.log(document.childNodes[1].tagName); //> 'html'
*```
*/
function parse(html, options) {
return parser.Parser.parse(html, options);
}
exports.parse = parse;
function parseFragment(fragmentContext, html, options) {
if (typeof fragmentContext === 'string') {
options = html;
html = fragmentContext;
fragmentContext = null;
}
const parser$1 = parser.Parser.getFragmentParser(fragmentContext, options);
parser$1.tokenizer.write(html, true);
return parser$1.getFragment();
}
exports.parseFragment = parseFragment;
});
var cjs = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.adapter = exports.serializeDoctypeContent = void 0;
function createTextNode(value) {
return new domhandler_1.Text(value);
}
function enquoteDoctypeId(id) {
const quote = id.includes('"') ? "'" : '"';
return quote + id + quote;
}
/** @internal */
function serializeDoctypeContent(name, publicId, systemId) {
let str = '!DOCTYPE ';
if (name) {
str += name;
}
if (publicId) {
str += ` PUBLIC ${enquoteDoctypeId(publicId)}`;
}
else if (systemId) {
str += ' SYSTEM';
}
if (systemId) {
str += ` ${enquoteDoctypeId(systemId)}`;
}
return str;
}
exports.serializeDoctypeContent = serializeDoctypeContent;
exports.adapter = {
// Re-exports from domhandler
isCommentNode: domhandler_1.isComment,
isElementNode: domhandler_1.isTag,
isTextNode: domhandler_1.isText,
//Node construction
createDocument() {
const node = new domhandler_1.Document([]);
node['x-mode'] = cjs$1.html.DOCUMENT_MODE.NO_QUIRKS;
return node;
},
createDocumentFragment() {
return new domhandler_1.Document([]);
},
createElement(tagName, namespaceURI, attrs) {
const attribs = Object.create(null);
const attribsNamespace = Object.create(null);
const attribsPrefix = Object.create(null);
for (let i = 0; i < attrs.length; i++) {
const attrName = attrs[i].name;
attribs[attrName] = attrs[i].value;
attribsNamespace[attrName] = attrs[i].namespace;
attribsPrefix[attrName] = attrs[i].prefix;
}
const node = new domhandler_1.Element(tagName, attribs, []);
node.namespace = namespaceURI;
node['x-attribsNamespace'] = attribsNamespace;
node['x-attribsPrefix'] = attribsPrefix;
return node;
},
createCommentNode(data) {
return new domhandler_1.Comment(data);
},
//Tree mutation
appendChild(parentNode, newNode) {
const prev = parentNode.children[parentNode.children.length - 1];
if (prev) {
prev.next = newNode;
newNode.prev = prev;
}
parentNode.children.push(newNode);
newNode.parent = parentNode;
},
insertBefore(parentNode, newNode, referenceNode) {
const insertionIdx = parentNode.children.indexOf(referenceNode);
const { prev } = referenceNode;
if (prev) {
prev.next = newNode;
newNode.prev = prev;
}
referenceNode.prev = newNode;
newNode.next = referenceNode;
parentNode.children.splice(insertionIdx, 0, newNode);
newNode.parent = parentNode;
},
setTemplateContent(templateElement, contentElement) {
exports.adapter.appendChild(templateElement, contentElement);
},
getTemplateContent(templateElement) {
return templateElement.children[0];
},
setDocumentType(document, name, publicId, systemId) {
const data = serializeDoctypeContent(name, publicId, systemId);
let doctypeNode = document.children.find((node) => (0, domhandler_1.isDirective)(node) && node.name === '!doctype');
if (doctypeNode) {
doctypeNode.data = data !== null && data !== void 0 ? data : null;
}
else {
doctypeNode = new domhandler_1.ProcessingInstruction('!doctype', data);
exports.adapter.appendChild(document, doctypeNode);
}
doctypeNode['x-name'] = name !== null && name !== void 0 ? name : undefined;
doctypeNode['x-publicId'] = publicId !== null && publicId !== void 0 ? publicId : undefined;
doctypeNode['x-systemId'] = systemId !== null && systemId !== void 0 ? systemId : undefined;
},
setDocumentMode(document, mode) {
document['x-mode'] = mode;
},
getDocumentMode(document) {
return document['x-mode'];
},
detachNode(node) {
if (node.parent) {
const idx = node.parent.children.indexOf(node);
const { prev, next } = node;
node.prev = null;
node.next = null;
if (prev) {
prev.next = next;
}
if (next) {
next.prev = prev;
}
node.parent.children.splice(idx, 1);
node.parent = null;
}
},
insertText(parentNode, text) {
const lastChild = parentNode.children[parentNode.children.length - 1];
if (lastChild && (0, domhandler_1.isText)(lastChild)) {
lastChild.data += text;
}
else {
exports.adapter.appendChild(parentNode, createTextNode(text));
}
},
insertTextBefore(parentNode, text, referenceNode) {
const prevNode = parentNode.children[parentNode.children.indexOf(referenceNode) - 1];
if (prevNode && (0, domhandler_1.isText)(prevNode)) {
prevNode.data += text;
}
else {
exports.adapter.insertBefore(parentNode, createTextNode(text), referenceNode);
}
},
adoptAttributes(recipient, attrs) {
for (let i = 0; i < attrs.length; i++) {
const attrName = attrs[i].name;
if (typeof recipient.attribs[attrName] === 'undefined') {
recipient.attribs[attrName] = attrs[i].value;
recipient['x-attribsNamespace'][attrName] = attrs[i].namespace;
recipient['x-attribsPrefix'][attrName] = attrs[i].prefix;
}
}
},
//Tree traversing
getFirstChild(node) {
return node.children[0];
},
getChildNodes(node) {
return node.children;
},
getParentNode(node) {
return node.parent;
},
getAttrList(element) {
return element.attributes;
},
//Node data
getTagName(element) {
return element.name;
},
getNamespaceURI(element) {
return element.namespace;
},
getTextNodeContent(textNode) {
return textNode.data;
},
getCommentNodeContent(commentNode) {
return commentNode.data;
},
getDocumentTypeNodeName(doctypeNode) {
var _a;
return (_a = doctypeNode['x-name']) !== null && _a !== void 0 ? _a : '';
},
getDocumentTypeNodePublicId(doctypeNode) {
var _a;
return (_a = doctypeNode['x-publicId']) !== null && _a !== void 0 ? _a : '';
},
getDocumentTypeNodeSystemId(doctypeNode) {
var _a;
return (_a = doctypeNode['x-systemId']) !== null && _a !== void 0 ? _a : '';
},
//Node types
isDocumentTypeNode(node) {
return (0, domhandler_1.isDirective)(node) && node.name === '!doctype';
},
// Source code location
setNodeSourceCodeLocation(node, location) {
if (location) {
node.startIndex = location.startOffset;
node.endIndex = location.endOffset;
}
node.sourceCodeLocation = location;
},
getNodeSourceCodeLocation(node) {
return node.sourceCodeLocation;
},
updateNodeSourceCodeLocation(node, endLocation) {
if (endLocation.endOffset != null)
node.endIndex = endLocation.endOffset;
node.sourceCodeLocation = Object.assign(Object.assign({}, node.sourceCodeLocation), endLocation);
},
};
});
var parse5Adapter = createCommonjsModule(function (module, exports) {
var __spreadArray = (commonjsGlobal && commonjsGlobal.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.renderWithParse5 = exports.parseWithParse5 = void 0;
/**
* Parse the content with `parse5` in the context of the given `ParentNode`.
*
* @param content - The content to parse.
* @param options - A set of options to use to parse.
* @param isDocument - Whether to parse the content as a full HTML document.
* @param context - The context in which to parse the content.
* @returns The parsed content.
*/
function parseWithParse5(content, options, isDocument, context) {
var opts = {
scriptingEnabled: typeof options.scriptingEnabled === 'boolean'
? options.scriptingEnabled
: true,
treeAdapter: cjs.adapter,
sourceCodeLocationInfo: options.sourceCodeLocationInfo,
};
return isDocument
? (0, cjs$2.parse)(content, opts)
: (0, cjs$2.parseFragment)(context, content, opts);
}
exports.parseWithParse5 = parseWithParse5;
var renderOpts = { treeAdapter: cjs.adapter };
/**
* Renders the given DOM tree with `parse5` and returns the result as a string.
*
* @param dom - The DOM tree to render.
* @returns The rendered document.
*/
function renderWithParse5(dom) {
var _a;
/*
* `dom-serializer` passes over the special "root" node and renders the
* node's children in its place. To mimic this behavior with `parse5`, an
* equivalent operation must be applied to the input array.
*/
var nodes = 'length' in dom ? dom : [dom];
for (var index = 0; index < nodes.length; index += 1) {
var node = nodes[index];
if ((0, domhandler_1.isDocument)(node)) {
(_a = Array.prototype.splice).call.apply(_a, __spreadArray([nodes, index, 1], node.children, false));
}
}
var result = '';
for (var index = 0; index < nodes.length; index += 1) {
var node = nodes[index];
result += (0, cjs$2.serializeOuter)(node, renderOpts);
}
return result;
}
exports.renderWithParse5 = renderWithParse5;
});
var Tokenizer_1 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.QuoteType = void 0;
var CharCodes;
(function (CharCodes) {
CharCodes[CharCodes["Tab"] = 9] = "Tab";
CharCodes[CharCodes["NewLine"] = 10] = "NewLine";
CharCodes[CharCodes["FormFeed"] = 12] = "FormFeed";
CharCodes[CharCodes["CarriageReturn"] = 13] = "CarriageReturn";
CharCodes[CharCodes["Space"] = 32] = "Space";
CharCodes[CharCodes["ExclamationMark"] = 33] = "ExclamationMark";
CharCodes[CharCodes["Num"] = 35] = "Num";
CharCodes[CharCodes["Amp"] = 38] = "Amp";
CharCodes[CharCodes["SingleQuote"] = 39] = "SingleQuote";
CharCodes[CharCodes["DoubleQuote"] = 34] = "DoubleQuote";
CharCodes[CharCodes["Dash"] = 45] = "Dash";
CharCodes[CharCodes["Slash"] = 47] = "Slash";
CharCodes[CharCodes["Zero"] = 48] = "Zero";
CharCodes[CharCodes["Nine"] = 57] = "Nine";
CharCodes[CharCodes["Semi"] = 59] = "Semi";
CharCodes[CharCodes["Lt"] = 60] = "Lt";
CharCodes[CharCodes["Eq"] = 61] = "Eq";
CharCodes[CharCodes["Gt"] = 62] = "Gt";
CharCodes[CharCodes["Questionmark"] = 63] = "Questionmark";
CharCodes[CharCodes["UpperA"] = 65] = "UpperA";
CharCodes[CharCodes["LowerA"] = 97] = "LowerA";
CharCodes[CharCodes["UpperF"] = 70] = "UpperF";
CharCodes[CharCodes["LowerF"] = 102] = "LowerF";
CharCodes[CharCodes["UpperZ"] = 90] = "UpperZ";
CharCodes[CharCodes["LowerZ"] = 122] = "LowerZ";
CharCodes[CharCodes["LowerX"] = 120] = "LowerX";
CharCodes[CharCodes["OpeningSquareBracket"] = 91] = "OpeningSquareBracket";
})(CharCodes || (CharCodes = {}));
/** All the states the tokenizer can be in. */
var State;
(function (State) {
State[State["Text"] = 1] = "Text";
State[State["BeforeTagName"] = 2] = "BeforeTagName";
State[State["InTagName"] = 3] = "InTagName";
State[State["InSelfClosingTag"] = 4] = "InSelfClosingTag";
State[State["BeforeClosingTagName"] = 5] = "BeforeClosingTagName";
State[State["InClosingTagName"] = 6] = "InClosingTagName";
State[State["AfterClosingTagName"] = 7] = "AfterClosingTagName";
// Attributes
State[State["BeforeAttributeName"] = 8] = "BeforeAttributeName";
State[State["InAttributeName"] = 9] = "InAttributeName";
State[State["AfterAttributeName"] = 10] = "AfterAttributeName";
State[State["BeforeAttributeValue"] = 11] = "BeforeAttributeValue";
State[State["InAttributeValueDq"] = 12] = "InAttributeValueDq";
State[State["InAttributeValueSq"] = 13] = "InAttributeValueSq";
State[State["InAttributeValueNq"] = 14] = "InAttributeValueNq";
// Declarations
State[State["BeforeDeclaration"] = 15] = "BeforeDeclaration";
State[State["InDeclaration"] = 16] = "InDeclaration";
// Processing instructions
State[State["InProcessingInstruction"] = 17] = "InProcessingInstruction";
// Comments & CDATA
State[State["BeforeComment"] = 18] = "BeforeComment";
State[State["CDATASequence"] = 19] = "CDATASequence";
State[State["InSpecialComment"] = 20] = "InSpecialComment";
State[State["InCommentLike"] = 21] = "InCommentLike";
// Special tags
State[State["BeforeSpecialS"] = 22] = "BeforeSpecialS";
State[State["SpecialStartSequence"] = 23] = "SpecialStartSequence";
State[State["InSpecialTag"] = 24] = "InSpecialTag";
State[State["BeforeEntity"] = 25] = "BeforeEntity";
State[State["BeforeNumericEntity"] = 26] = "BeforeNumericEntity";
State[State["InNamedEntity"] = 27] = "InNamedEntity";
State[State["InNumericEntity"] = 28] = "InNumericEntity";
State[State["InHexEntity"] = 29] = "InHexEntity";
})(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 isNumber(c) {
return c >= CharCodes.Zero && c <= CharCodes.Nine;
}
function isASCIIAlpha(c) {
return ((c >= CharCodes.LowerA && c <= CharCodes.LowerZ) ||
(c >= CharCodes.UpperA && c <= CharCodes.UpperZ));
}
function isHexDigit(c) {
return ((c >= CharCodes.UpperA && c <= CharCodes.UpperF) ||
(c >= CharCodes.LowerA && c <= CharCodes.LowerF));
}
var QuoteType;
(function (QuoteType) {
QuoteType[QuoteType["NoValue"] = 0] = "NoValue";
QuoteType[QuoteType["Unquoted"] = 1] = "Unquoted";
QuoteType[QuoteType["Single"] = 2] = "Single";
QuoteType[QuoteType["Double"] = 3] = "Double";
})(QuoteType = exports.QuoteType || (exports.QuoteType = {}));
/**
* Sequences used to match longer strings.
*
* We don't have `Script`, `Style`, or `Title` here. Instead, we re-use the *End
* sequences with an increased offset.
*/
var Sequences = {
Cdata: new Uint8Array([0x43, 0x44, 0x41, 0x54, 0x41, 0x5b]),
CdataEnd: new Uint8Array([0x5d, 0x5d, 0x3e]),
CommentEnd: new Uint8Array([0x2d, 0x2d, 0x3e]),
ScriptEnd: new Uint8Array([0x3c, 0x2f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74]),
StyleEnd: new Uint8Array([0x3c, 0x2f, 0x73, 0x74, 0x79, 0x6c, 0x65]),
TitleEnd: new Uint8Array([0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65]), // `</title`
};
var Tokenizer = /** @class */ (function () {
function Tokenizer(_a, cbs) {
var _b = _a.xmlMode, xmlMode = _b === void 0 ? false : _b, _c = _a.decodeEntities, decodeEntities = _c === void 0 ? true : _c;
this.cbs = cbs;
/** The current state the tokenizer is in. */
this.state = State.Text;
/** The read buffer. */
this.buffer = "";
/** The beginning of the section that is currently being read. */
this.sectionStart = 0;
/** The index within the buffer that we are currently looking at. */
this.index = 0;
/** Some behavior, eg. when decoding entities, is done while we are in another state. This keeps track of the other state type. */
this.baseState = State.Text;
/** For special parsing behavior inside of script and style tags. */
this.isSpecial = false;
/** Indicates whether the tokenizer has been paused. */
this.running = true;
/** The offset of the current buffer. */
this.offset = 0;
this.sequenceIndex = 0;
this.trieIndex = 0;
this.trieCurrent = 0;
/** For named entities, the index of the value. For numeric entities, the code point. */
this.entityResult = 0;
this.entityExcess = 0;
this.xmlMode = xmlMode;
this.decodeEntities = decodeEntities;
this.entityTrie = xmlMode ? decode_js_1.xmlDecodeTree : decode_js_1.htmlDecodeTree;
}
Tokenizer.prototype.reset = function () {
this.state = State.Text;
this.buffer = "";
this.sectionStart = 0;
this.index = 0;
this.baseState = State.Text;
this.currentSequence = undefined;
this.running = true;
this.offset = 0;
};
Tokenizer.prototype.write = function (chunk) {
this.offset += this.buffer.length;
this.buffer = chunk;
this.parse();
};
Tokenizer.prototype.end = function () {
if (this.running)
this.finish();
};
Tokenizer.prototype.pause = function () {
this.running = false;
};
Tokenizer.prototype.resume = function () {
this.running = true;
if (this.index < this.buffer.length + this.offset) {
this.parse();
}
};
/**
* The current index within all of the written data.
*/
Tokenizer.prototype.getIndex = function () {
return this.index;
};
/**
* The start of the current section.
*/
Tokenizer.prototype.getSectionStart = function () {
return this.sectionStart;
};
Tokenizer.prototype.stateText = function (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.state = State.BeforeEntity;
}
};
Tokenizer.prototype.stateSpecialStartSequence = function (c) {
var isEnd = this.sequenceIndex === this.currentSequence.length;
var 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 | 0x20) === 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. */
Tokenizer.prototype.stateInSpecialTag = function (c) {
if (this.sequenceIndex === this.currentSequence.length) {
if (c === CharCodes.Gt || isWhitespace(c)) {
var endOfText = this.index - this.currentSequence.length;
if (this.sectionStart < endOfText) {
// Spoof the index so that reported locations match up.
var actualIndex = this.index;
this.index = endOfText;
this.cbs.ontext(this.sectionStart, endOfText);
this.index = actualIndex;
}
this.isSpecial = false;
this.sectionStart = endOfText + 2; // Skip over the `</`
this.stateInClosingTagName(c);
return; // We are done; skip the rest of the function.
}
this.sequenceIndex = 0;
}
if ((c | 0x20) === this.currentSequence[this.sequenceIndex]) {
this.sequenceIndex += 1;
}
else if (this.sequenceIndex === 0) {
if (this.currentSequence === Sequences.TitleEnd) {
// We have to parse entities in <title> tags.
if (this.decodeEntities && c === CharCodes.Amp) {
this.state = State.BeforeEntity;
}
}
else if (this.fastForwardTo(CharCodes.Lt)) {
// Outside of <title> tags, we can fast-forward.
this.sequenceIndex = 1;
}
}
else {
// If we see a `<`, set the sequence index to 1; useful for eg. `<</script>`.
this.sequenceIndex = Number(c === CharCodes.Lt);
}
};
Tokenizer.prototype.stateCDATASequence = function (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); // Reconsume the character
}
};
/**
* 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.
*/
Tokenizer.prototype.fastForwardTo = function (c) {
while (++this.index < this.buffer.length + this.offset) {
if (this.buffer.charCodeAt(this.index - this.offset) === c) {
return true;
}
}
/*
* We increment the index at the end of the `parse` loop,
* so set it to `buffer.length - 1` here.
*
* TODO: Refactor `parse` to increment index before calling states.
*/
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.
*/
Tokenizer.prototype.stateInCommentLike = function (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) {
// Fast-forward to the first character of the sequence
if (this.fastForwardTo(this.currentSequence[0])) {
this.sequenceIndex = 1;
}
}
else if (c !== this.currentSequence[this.sequenceIndex - 1]) {
// Allow long sequences, eg. --->, ]]]>
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.
*/
Tokenizer.prototype.isTagStartChar = function (c) {
return this.xmlMode ? !isEndOfTagSection(c) : isASCIIAlpha(c);
};
Tokenizer.prototype.startSpecial = function (sequence, offset) {
this.isSpecial = true;
this.currentSequence = sequence;
this.sequenceIndex = offset;
this.state = State.SpecialStartSequence;
};
Tokenizer.prototype.stateBeforeTagName = function (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)) {
var lower = c | 0x20;
this.sectionStart = this.index;
if (!this.xmlMode && lower === Sequences.TitleEnd[2]) {
this.startSpecial(Sequences.TitleEnd, 3);
}
else {
this.state =
!this.xmlMode && lower === Sequences.ScriptEnd[2]
? State.BeforeSpecialS
: State.InTagName;
}
}
else if (c === CharCodes.Slash) {
this.state = State.BeforeClosingTagName;
}
else {
this.state = State.Text;
this.stateText(c);
}
};
Tokenizer.prototype.stateInTagName = function (c) {
if (isEndOfTagSection(c)) {
this.cbs.onopentagname(this.sectionStart, this.index);
this.sectionStart = -1;
this.state = State.BeforeAttributeName;
this.stateBeforeAttributeName(c);
}
};
Tokenizer.prototype.stateBeforeClosingTagName = function (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;
}
};
Tokenizer.prototype.stateInClosingTagName = function (c) {
if (c === CharCodes.Gt || isWhitespace(c)) {
this.cbs.onclosetag(this.sectionStart, this.index);
this.sectionStart = -1;
this.state = State.AfterClosingTagName;
this.stateAfterClosingTagName(c);
}
};
Tokenizer.prototype.stateAfterClosingTagName = function (c) {
// Skip everything until ">"
if (c === CharCodes.Gt || this.fastForwardTo(CharCodes.Gt)) {
this.state = State.Text;
this.sectionStart = this.index + 1;
}
};
Tokenizer.prototype.stateBeforeAttributeName = function (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.baseState = this.state;
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;
}
};
Tokenizer.prototype.stateInSelfClosingTag = function (c) {
if (c === CharCodes.Gt) {
this.cbs.onselfclosingtag(this.index);
this.state = State.Text;
this.baseState = State.Text;
this.sectionStart = this.index + 1;
this.isSpecial = false; // Reset special state, in case of self-closing special tags
}
else if (!isWhitespace(c)) {
this.state = State.BeforeAttributeName;
this.stateBeforeAttributeName(c);
}
};
Tokenizer.prototype.stateInAttributeName = function (c) {
if (c === CharCodes.Eq || isEndOfTagSection(c)) {
this.cbs.onattribname(this.sectionStart, this.index);
this.sectionStart = -1;
this.state = State.AfterAttributeName;
this.stateAfterAttributeName(c);
}
};
Tokenizer.prototype.stateAfterAttributeName = function (c) {
if (c === CharCodes.Eq) {
this.state = State.BeforeAttributeValue;
}
else if (c === CharCodes.Slash || c === CharCodes.Gt) {
this.cbs.onattribend(QuoteType.NoValue, this.index);
this.state = State.BeforeAttributeName;
this.stateBeforeAttributeName(c);
}
else if (!isWhitespace(c)) {
this.cbs.onattribend(QuoteType.NoValue, this.index);
this.state = State.InAttributeName;
this.sectionStart = this.index;
}
};
Tokenizer.prototype.stateBeforeAttributeValue = function (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); // Reconsume token
}
};
Tokenizer.prototype.handleInAttributeValue = function (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);
this.state = State.BeforeAttributeName;
}
else if (this.decodeEntities && c === CharCodes.Amp) {
this.baseState = this.state;
this.state = State.BeforeEntity;
}
};
Tokenizer.prototype.stateInAttributeValueDoubleQuotes = function (c) {
this.handleInAttributeValue(c, CharCodes.DoubleQuote);
};
Tokenizer.prototype.stateInAttributeValueSingleQuotes = function (c) {
this.handleInAttributeValue(c, CharCodes.SingleQuote);
};
Tokenizer.prototype.stateInAttributeValueNoQuotes = function (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.baseState = this.state;
this.state = State.BeforeEntity;
}
};
Tokenizer.prototype.stateBeforeDeclaration = function (c) {
if (c === CharCodes.OpeningSquareBracket) {
this.state = State.CDATASequence;
this.sequenceIndex = 0;
}
else {
this.state =
c === CharCodes.Dash
? State.BeforeComment
: State.InDeclaration;
}
};
Tokenizer.prototype.stateInDeclaration = function (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;
}
};
Tokenizer.prototype.stateInProcessingInstruction = function (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;
}
};
Tokenizer.prototype.stateBeforeComment = function (c) {
if (c === CharCodes.Dash) {
this.state = State.InCommentLike;
this.currentSequence = Sequences.CommentEnd;
// Allow short comments (eg. <!-->)
this.sequenceIndex = 2;
this.sectionStart = this.index + 1;
}
else {
this.state = State.InDeclaration;
}
};
Tokenizer.prototype.stateInSpecialComment = function (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;
}
};
Tokenizer.prototype.stateBeforeSpecialS = function (c) {
var lower = c | 0x20;
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); // Consume the token again
}
};
Tokenizer.prototype.stateBeforeEntity = function (c) {
// Start excess with 1 to include the '&'
this.entityExcess = 1;
this.entityResult = 0;
if (c === CharCodes.Num) {
this.state = State.BeforeNumericEntity;
}
else if (c === CharCodes.Amp) ;
else {
this.trieIndex = 0;
this.trieCurrent = this.entityTrie[0];
this.state = State.InNamedEntity;
this.stateInNamedEntity(c);
}
};
Tokenizer.prototype.stateInNamedEntity = function (c) {
this.entityExcess += 1;
this.trieIndex = (0, decode_js_1.determineBranch)(this.entityTrie, this.trieCurrent, this.trieIndex + 1, c);
if (this.trieIndex < 0) {
this.emitNamedEntity();
this.index--;
return;
}
this.trieCurrent = this.entityTrie[this.trieIndex];
var masked = this.trieCurrent & decode_js_1.BinTrieFlags.VALUE_LENGTH;
// If the branch is a value, store it and continue
if (masked) {
// The mask is the number of bytes of the value, including the current byte.
var valueLength = (masked >> 14) - 1;
// If we have a legacy entity while parsing strictly, just skip the number of bytes
if (!this.allowLegacyEntity() && c !== CharCodes.Semi) {
this.trieIndex += valueLength;
}
else {
// Add 1 as we have already incremented the excess
var entityStart = this.index - this.entityExcess + 1;
if (entityStart > this.sectionStart) {
this.emitPartial(this.sectionStart, entityStart);
}
// If this is a surrogate pair, consume the next two bytes
this.entityResult = this.trieIndex;
this.trieIndex += valueLength;
this.entityExcess = 0;
this.sectionStart = this.index + 1;
if (valueLength === 0) {
this.emitNamedEntity();
}
}
}
};
Tokenizer.prototype.emitNamedEntity = function () {
this.state = this.baseState;
if (this.entityResult === 0) {
return;
}
var valueLength = (this.entityTrie[this.entityResult] & decode_js_1.BinTrieFlags.VALUE_LENGTH) >>
14;
switch (valueLength) {
case 1:
this.emitCodePoint(this.entityTrie[this.entityResult] &
~decode_js_1.BinTrieFlags.VALUE_LENGTH);
break;
case 2:
this.emitCodePoint(this.entityTrie[this.entityResult + 1]);
break;
case 3: {
this.emitCodePoint(this.entityTrie[this.entityResult + 1]);
this.emitCodePoint(this.entityTrie[this.entityResult + 2]);
}
}
};
Tokenizer.prototype.stateBeforeNumericEntity = function (c) {
if ((c | 0x20) === CharCodes.LowerX) {
this.entityExcess++;
this.state = State.InHexEntity;
}
else {
this.state = State.InNumericEntity;
this.stateInNumericEntity(c);
}
};
Tokenizer.prototype.emitNumericEntity = function (strict) {
var entityStart = this.index - this.entityExcess - 1;
var numberStart = entityStart + 2 + Number(this.state === State.InHexEntity);
if (numberStart !== this.index) {
// Emit leading data if any
if (entityStart > this.sectionStart) {
this.emitPartial(this.sectionStart, entityStart);
}
this.sectionStart = this.index + Number(strict);
this.emitCodePoint((0, decode_js_1.replaceCodePoint)(this.entityResult));
}
this.state = this.baseState;
};
Tokenizer.prototype.stateInNumericEntity = function (c) {
if (c === CharCodes.Semi) {
this.emitNumericEntity(true);
}
else if (isNumber(c)) {
this.entityResult = this.entityResult * 10 + (c - CharCodes.Zero);
this.entityExcess++;
}
else {
if (this.allowLegacyEntity()) {
this.emitNumericEntity(false);
}
else {
this.state = this.baseState;
}
this.index--;
}
};
Tokenizer.prototype.stateInHexEntity = function (c) {
if (c === CharCodes.Semi) {
this.emitNumericEntity(true);
}
else if (isNumber(c)) {
this.entityResult = this.entityResult * 16 + (c - CharCodes.Zero);
this.entityExcess++;
}
else if (isHexDigit(c)) {
this.entityResult =
this.entityResult * 16 + ((c | 0x20) - CharCodes.LowerA + 10);
this.entityExcess++;
}
else {
if (this.allowLegacyEntity()) {
this.emitNumericEntity(false);
}
else {
this.state = this.baseState;
}
this.index--;
}
};
Tokenizer.prototype.allowLegacyEntity = function () {
return (!this.xmlMode &&
(this.baseState === State.Text ||
this.baseState === State.InSpecialTag));
};
/**
* Remove data that has already been consumed from the buffer.
*/
Tokenizer.prototype.cleanup = function () {
// If we are inside of text or attributes, emit what we already have.
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;
}
}
};
Tokenizer.prototype.shouldContinue = function () {
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.
*/
Tokenizer.prototype.parse = function () {
while (this.shouldContinue()) {
var c = this.buffer.charCodeAt(this.index - this.offset);
if (this.state === State.Text) {
this.stateText(c);
}
else if (this.state === State.SpecialStartSequence) {
this.stateSpecialStartSequence(c);
}
else if (this.state === State.InSpecialTag) {
this.stateInSpecialTag(c);
}
else if (this.state === State.CDATASequence) {
this.stateCDATASequence(c);
}
else if (this.state === State.InAttributeValueDq) {
this.stateInAttributeValueDoubleQuotes(c);
}
else if (this.state === State.InAttributeName) {
this.stateInAttributeName(c);
}
else if (this.state === State.InCommentLike) {
this.stateInCommentLike(c);
}
else if (this.state === State.InSpecialComment) {
this.stateInSpecialComment(c);
}
else if (this.state === State.BeforeAttributeName) {
this.stateBeforeAttributeName(c);
}
else if (this.state === State.InTagName) {
this.stateInTagName(c);
}
else if (this.state === State.InClosingTagName) {
this.stateInClosingTagName(c);
}
else if (this.state === State.BeforeTagName) {
this.stateBeforeTagName(c);
}
else if (this.state === State.AfterAttributeName) {
this.stateAfterAttributeName(c);
}
else if (this.state === State.InAttributeValueSq) {
this.stateInAttributeValueSingleQuotes(c);
}
else if (this.state === State.BeforeAttributeValue) {
this.stateBeforeAttributeValue(c);
}
else if (this.state === State.BeforeClosingTagName) {
this.stateBeforeClosingTagName(c);
}
else if (this.state === State.AfterClosingTagName) {
this.stateAfterClosingTagName(c);
}
else if (this.state === State.BeforeSpecialS) {
this.stateBeforeSpecialS(c);
}
else if (this.state === State.InAttributeValueNq) {
this.stateInAttributeValueNoQuotes(c);
}
else if (this.state === State.InSelfClosingTag) {
this.stateInSelfClosingTag(c);
}
else if (this.state === State.InDeclaration) {
this.stateInDeclaration(c);
}
else if (this.state === State.BeforeDeclaration) {
this.stateBeforeDeclaration(c);
}
else if (this.state === State.BeforeComment) {
this.stateBeforeComment(c);
}
else if (this.state === State.InProcessingInstruction) {
this.stateInProcessingInstruction(c);
}
else if (this.state === State.InNamedEntity) {
this.stateInNamedEntity(c);
}
else if (this.state === State.BeforeEntity) {
this.stateBeforeEntity(c);
}
else if (this.state === State.InHexEntity) {
this.stateInHexEntity(c);
}
else if (this.state === State.InNumericEntity) {
this.stateInNumericEntity(c);
}
else {
// `this._state === State.BeforeNumericEntity`
this.stateBeforeNumericEntity(c);
}
this.index++;
}
this.cleanup();
};
Tokenizer.prototype.finish = function () {
if (this.state === State.InNamedEntity) {
this.emitNamedEntity();
}
// If there is remaining data, emit it in a reasonable way
if (this.sectionStart < this.index) {
this.handleTrailingData();
}
this.cbs.onend();
};
/** Handle any trailing data. */
Tokenizer.prototype.handleTrailingData = function () {
var endIndex = this.buffer.length + this.offset;
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.InNumericEntity &&
this.allowLegacyEntity()) {
this.emitNumericEntity(false);
// All trailing data will have been consumed
}
else if (this.state === State.InHexEntity &&
this.allowLegacyEntity()) {
this.emitNumericEntity(false);
// All trailing data will have been consumed
}
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);
}
};
Tokenizer.prototype.emitPartial = function (start, endIndex) {
if (this.baseState !== State.Text &&
this.baseState !== State.InSpecialTag) {
this.cbs.onattribdata(start, endIndex);
}
else {
this.cbs.ontext(start, endIndex);
}
};
Tokenizer.prototype.emitCodePoint = function (cp) {
if (this.baseState !== State.Text &&
this.baseState !== State.InSpecialTag) {
this.cbs.onattribentity(cp);
}
else {
this.cbs.ontextentity(cp);
}
};
return Tokenizer;
}());
exports.default = Tokenizer;
});
var Tokenizer_js_1 = Tokenizer_1;
var Parser_1 = createCommonjsModule(function (module, exports) {
var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (commonjsGlobal && commonjsGlobal.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (commonjsGlobal && commonjsGlobal.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Parser = void 0;
var Tokenizer_js_1$1 = __importStar(Tokenizer_js_1);
var formTags = new Set([
"input",
"option",
"optgroup",
"select",
"button",
"datalist",
"textarea",
]);
var pTag = new Set(["p"]);
var tableSectionTags = new Set(["thead", "tbody"]);
var ddtTags = new Set(["dd", "dt"]);
var rtpTags = new Set(["rt", "rp"]);
var openImpliesClose = new Map([
["tr", new Set(["tr", "th", "td"])],
["th", new Set(["th"])],
["td", new Set(["thead", "th", "td"])],
["body", new Set(["head", "link", "script"])],
["li", 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", new Set(["option"])],
["optgroup", 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],
]);
var voidElements = new Set([
"area",
"base",
"basefont",
"br",
"col",
"command",
"embed",
"frame",
"hr",
"img",
"input",
"isindex",
"keygen",
"link",
"meta",
"param",
"source",
"track",
"wbr",
]);
var foreignContextElements = new Set(["math", "svg"]);
var htmlIntegrationElements = new Set([
"mi",
"mo",
"mn",
"ms",
"mtext",
"annotation-xml",
"foreignobject",
"desc",
"title",
]);
var reNameEnd = /\s|\//;
var Parser = /** @class */ (function () {
function Parser(cbs, options) {
if (options === void 0) { options = {}; }
var _a, _b, _c, _d, _e;
this.options = options;
/** The start index of the last event. */
this.startIndex = 0;
/** The end index of the last event. */
this.endIndex = 0;
/**
* Store the start index of the current open tag,
* so we can update the start index for attributes.
*/
this.openTagStart = 0;
this.tagname = "";
this.attribname = "";
this.attribvalue = "";
this.attribs = null;
this.stack = [];
this.foreignContext = [];
this.buffers = [];
this.bufferOffset = 0;
/** The index of the last written buffer. Used when resuming after a `pause()`. */
this.writeIndex = 0;
/** Indicates whether the parser has finished running / `.end` has been called. */
this.ended = false;
this.cbs = cbs !== null && cbs !== void 0 ? cbs : {};
this.lowerCaseTagNames = (_a = options.lowerCaseTags) !== null && _a !== void 0 ? _a : !options.xmlMode;
this.lowerCaseAttributeNames =
(_b = options.lowerCaseAttributeNames) !== null && _b !== void 0 ? _b : !options.xmlMode;
this.tokenizer = new ((_c = options.Tokenizer) !== null && _c !== void 0 ? _c : Tokenizer_js_1$1.default)(this.options, this);
(_e = (_d = this.cbs).onparserinit) === null || _e === void 0 ? void 0 : _e.call(_d, this);
}
// Tokenizer event handlers
/** @internal */
Parser.prototype.ontext = function (start, endIndex) {
var _a, _b;
var data = this.getSlice(start, endIndex);
this.endIndex = endIndex - 1;
(_b = (_a = this.cbs).ontext) === null || _b === void 0 ? void 0 : _b.call(_a, data);
this.startIndex = endIndex;
};
/** @internal */
Parser.prototype.ontextentity = function (cp) {
var _a, _b;
/*
* Entities can be emitted on the character, or directly after.
* We use the section start here to get accurate indices.
*/
var idx = this.tokenizer.getSectionStart();
this.endIndex = idx - 1;
(_b = (_a = this.cbs).ontext) === null || _b === void 0 ? void 0 : _b.call(_a, (0, decode_js_1.fromCodePoint)(cp));
this.startIndex = idx;
};
Parser.prototype.isVoidElement = function (name) {
return !this.options.xmlMode && voidElements.has(name);
};
/** @internal */
Parser.prototype.onopentagname = function (start, endIndex) {
this.endIndex = endIndex;
var name = this.getSlice(start, endIndex);
if (this.lowerCaseTagNames) {
name = name.toLowerCase();
}
this.emitOpenTag(name);
};
Parser.prototype.emitOpenTag = function (name) {
var _a, _b, _c, _d;
this.openTagStart = this.startIndex;
this.tagname = name;
var impliesClose = !this.options.xmlMode && openImpliesClose.get(name);
if (impliesClose) {
while (this.stack.length > 0 &&
impliesClose.has(this.stack[this.stack.length - 1])) {
var el = this.stack.pop();
(_b = (_a = this.cbs).onclosetag) === null || _b === void 0 ? void 0 : _b.call(_a, el, true);
}
}
if (!this.isVoidElement(name)) {
this.stack.push(name);
if (foreignContextElements.has(name)) {
this.foreignContext.push(true);
}
else if (htmlIntegrationElements.has(name)) {
this.foreignContext.push(false);
}
}
(_d = (_c = this.cbs).onopentagname) === null || _d === void 0 ? void 0 : _d.call(_c, name);
if (this.cbs.onopentag)
this.attribs = {};
};
Parser.prototype.endOpenTag = function (isImplied) {
var _a, _b;
this.startIndex = this.openTagStart;
if (this.attribs) {
(_b = (_a = this.cbs).onopentag) === null || _b === void 0 ? void 0 : _b.call(_a, 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 */
Parser.prototype.onopentagend = function (endIndex) {
this.endIndex = endIndex;
this.endOpenTag(false);
// Set `startIndex` for next node
this.startIndex = endIndex + 1;
};
/** @internal */
Parser.prototype.onclosetag = function (start, endIndex) {
var _a, _b, _c, _d, _e, _f;
this.endIndex = endIndex;
var name = this.getSlice(start, endIndex);
if (this.lowerCaseTagNames) {
name = name.toLowerCase();
}
if (foreignContextElements.has(name) ||
htmlIntegrationElements.has(name)) {
this.foreignContext.pop();
}
if (!this.isVoidElement(name)) {
var pos = this.stack.lastIndexOf(name);
if (pos !== -1) {
if (this.cbs.onclosetag) {
var count = this.stack.length - pos;
while (count--) {
// We know the stack has sufficient elements.
this.cbs.onclosetag(this.stack.pop(), count !== 0);
}
}
else
this.stack.length = pos;
}
else if (!this.options.xmlMode && name === "p") {
// Implicit open before close
this.emitOpenTag("p");
this.closeCurrentTag(true);
}
}
else if (!this.options.xmlMode && name === "br") {
// We can't use `emitOpenTag` for implicit open, as `br` would be implicitly closed.
(_b = (_a = this.cbs).onopentagname) === null || _b === void 0 ? void 0 : _b.call(_a, "br");
(_d = (_c = this.cbs).onopentag) === null || _d === void 0 ? void 0 : _d.call(_c, "br", {}, true);
(_f = (_e = this.cbs).onclosetag) === null || _f === void 0 ? void 0 : _f.call(_e, "br", false);
}
// Set `startIndex` for next node
this.startIndex = endIndex + 1;
};
/** @internal */
Parser.prototype.onselfclosingtag = function (endIndex) {
this.endIndex = endIndex;
if (this.options.xmlMode ||
this.options.recognizeSelfClosing ||
this.foreignContext[this.foreignContext.length - 1]) {
this.closeCurrentTag(false);
// Set `startIndex` for next node
this.startIndex = endIndex + 1;
}
else {
// Ignore the fact that the tag is self-closing.
this.onopentagend(endIndex);
}
};
Parser.prototype.closeCurrentTag = function (isOpenImplied) {
var _a, _b;
var name = this.tagname;
this.endOpenTag(isOpenImplied);
// Self-closing tags will be on the top of the stack
if (this.stack[this.stack.length - 1] === name) {
// If the opening tag isn't implied, the closing tag has to be implied.
(_b = (_a = this.cbs).onclosetag) === null || _b === void 0 ? void 0 : _b.call(_a, name, !isOpenImplied);
this.stack.pop();
}
};
/** @internal */
Parser.prototype.onattribname = function (start, endIndex) {
this.startIndex = start;
var name = this.getSlice(start, endIndex);
this.attribname = this.lowerCaseAttributeNames
? name.toLowerCase()
: name;
};
/** @internal */
Parser.prototype.onattribdata = function (start, endIndex) {
this.attribvalue += this.getSlice(start, endIndex);
};
/** @internal */
Parser.prototype.onattribentity = function (cp) {
this.attribvalue += (0, decode_js_1.fromCodePoint)(cp);
};
/** @internal */
Parser.prototype.onattribend = function (quote, endIndex) {
var _a, _b;
this.endIndex = endIndex;
(_b = (_a = this.cbs).onattribute) === null || _b === void 0 ? void 0 : _b.call(_a, this.attribname, this.attribvalue, quote === Tokenizer_js_1$1.QuoteType.Double
? '"'
: quote === Tokenizer_js_1$1.QuoteType.Single
? "'"
: quote === Tokenizer_js_1$1.QuoteType.NoValue
? undefined
: null);
if (this.attribs &&
!Object.prototype.hasOwnProperty.call(this.attribs, this.attribname)) {
this.attribs[this.attribname] = this.attribvalue;
}
this.attribvalue = "";
};
Parser.prototype.getInstructionName = function (value) {
var idx = value.search(reNameEnd);
var name = idx < 0 ? value : value.substr(0, idx);
if (this.lowerCaseTagNames) {
name = name.toLowerCase();
}
return name;
};
/** @internal */
Parser.prototype.ondeclaration = function (start, endIndex) {
this.endIndex = endIndex;
var value = this.getSlice(start, endIndex);
if (this.cbs.onprocessinginstruction) {
var name = this.getInstructionName(value);
this.cbs.onprocessinginstruction("!".concat(name), "!".concat(value));
}
// Set `startIndex` for next node
this.startIndex = endIndex + 1;
};
/** @internal */
Parser.prototype.onprocessinginstruction = function (start, endIndex) {
this.endIndex = endIndex;
var value = this.getSlice(start, endIndex);
if (this.cbs.onprocessinginstruction) {
var name = this.getInstructionName(value);
this.cbs.onprocessinginstruction("?".concat(name), "?".concat(value));
}
// Set `startIndex` for next node
this.startIndex = endIndex + 1;
};
/** @internal */
Parser.prototype.oncomment = function (start, endIndex, offset) {
var _a, _b, _c, _d;
this.endIndex = endIndex;
(_b = (_a = this.cbs).oncomment) === null || _b === void 0 ? void 0 : _b.call(_a, this.getSlice(start, endIndex - offset));
(_d = (_c = this.cbs).oncommentend) === null || _d === void 0 ? void 0 : _d.call(_c);
// Set `startIndex` for next node
this.startIndex = endIndex + 1;
};
/** @internal */
Parser.prototype.oncdata = function (start, endIndex, offset) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
this.endIndex = endIndex;
var value = this.getSlice(start, endIndex - offset);
if (this.options.xmlMode || this.options.recognizeCDATA) {
(_b = (_a = this.cbs).oncdatastart) === null || _b === void 0 ? void 0 : _b.call(_a);
(_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[".concat(value, "]]"));
(_k = (_j = this.cbs).oncommentend) === null || _k === void 0 ? void 0 : _k.call(_j);
}
// Set `startIndex` for next node
this.startIndex = endIndex + 1;
};
/** @internal */
Parser.prototype.onend = function () {
var _a, _b;
if (this.cbs.onclosetag) {
// Set the end index for all remaining tags
this.endIndex = this.startIndex;
for (var i = this.stack.length; i > 0; this.cbs.onclosetag(this.stack[--i], true))
;
}
(_b = (_a = this.cbs).onend) === null || _b === void 0 ? void 0 : _b.call(_a);
};
/**
* Resets the parser to a blank state, ready to parse a new HTML document
*/
Parser.prototype.reset = function () {
var _a, _b, _c, _d;
(_b = (_a = this.cbs).onreset) === null || _b === void 0 ? void 0 : _b.call(_a);
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.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.
*/
Parser.prototype.parseComplete = function (data) {
this.reset();
this.end(data);
};
Parser.prototype.getSlice = function (start, end) {
while (start - this.bufferOffset >= this.buffers[0].length) {
this.shiftBuffer();
}
var str = this.buffers[0].slice(start - this.bufferOffset, end - this.bufferOffset);
while (end - this.bufferOffset > this.buffers[0].length) {
this.shiftBuffer();
str += this.buffers[0].slice(0, end - this.bufferOffset);
}
return str;
};
Parser.prototype.shiftBuffer = function () {
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.
*/
Parser.prototype.write = function (chunk) {
var _a, _b;
if (this.ended) {
(_b = (_a = this.cbs).onerror) === null || _b === void 0 ? void 0 : _b.call(_a, 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.
*/
Parser.prototype.end = function (chunk) {
var _a, _b;
if (this.ended) {
(_b = (_a = this.cbs).onerror) === null || _b === void 0 ? void 0 : _b.call(_a, 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.
*/
Parser.prototype.pause = function () {
this.tokenizer.pause();
};
/**
* Resumes parsing after `pause` was called.
*/
Parser.prototype.resume = function () {
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
*/
Parser.prototype.parseChunk = function (chunk) {
this.write(chunk);
};
/**
* Alias of `end`, for backwards compatibility.
*
* @param chunk Optional final chunk to parse.
* @deprecated
*/
Parser.prototype.done = function (chunk) {
this.end(chunk);
};
return Parser;
}());
exports.Parser = Parser;
});
var Parser_js_1 = Parser_1;
var lib$1 = createCommonjsModule(function (module, exports) {
var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (commonjsGlobal && commonjsGlobal.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (commonjsGlobal && commonjsGlobal.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DefaultHandler = exports.DomUtils = exports.parseFeed = exports.getFeed = exports.ElementType = exports.Tokenizer = exports.createDomStream = exports.parseDOM = exports.parseDocument = exports.DomHandler = exports.Parser = void 0;
Object.defineProperty(exports, "Parser", { enumerable: true, get: function () { return Parser_js_1.Parser; } });
Object.defineProperty(exports, "DomHandler", { enumerable: true, get: function () { return domhandler_1.DomHandler; } });
Object.defineProperty(exports, "DefaultHandler", { enumerable: true, get: function () { return domhandler_1.DomHandler; } });
// Helper methods
/**
* Parses the data, returns the resulting document.
*
* @param data The data that should be parsed.
* @param options Optional options for the parser and DOM builder.
*/
function parseDocument(data, options) {
var handler = new domhandler_1.DomHandler(undefined, options);
new Parser_js_1.Parser(handler, options).end(data);
return handler.root;
}
exports.parseDocument = parseDocument;
/**
* Parses data, returns an array of the root nodes.
*
* Note that the root nodes still have a `Document` node as their parent.
* Use `parseDocument` to get the `Document` node instead.
*
* @param data The data that should be parsed.
* @param options Optional options for the parser and DOM builder.
* @deprecated Use `parseDocument` instead.
*/
function parseDOM(data, options) {
return parseDocument(data, options).children;
}
exports.parseDOM = parseDOM;
/**
* Creates a parser instance, with an attached DOM handler.
*
* @param cb A callback that will be called once parsing has been completed.
* @param options Optional options for the parser and DOM builder.
* @param elementCb An optional callback that will be called every time a tag has been completed inside of the DOM.
*/
function createDomStream(cb, options, elementCb) {
var handler = new domhandler_1.DomHandler(cb, options, elementCb);
return new Parser_js_1.Parser(handler, options);
}
exports.createDomStream = createDomStream;
Object.defineProperty(exports, "Tokenizer", { enumerable: true, get: function () { return __importDefault(Tokenizer_js_1).default; } });
/*
* All of the following exports exist for backwards-compatibility.
* They should probably be removed eventually.
*/
var ElementType = __importStar(require$$0$5);
exports.ElementType = ElementType;
Object.defineProperty(exports, "getFeed", { enumerable: true, get: function () { return domutils_1.getFeed; } });
/**
* Parse a feed.
*
* @param feed The feed that should be parsed, as a string.
* @param options Optionally, options for parsing. When using this, you should set `xmlMode` to `true`.
*/
function parseFeed(feed, options) {
if (options === void 0) { options = { xmlMode: true }; }
return (0, domutils_1.getFeed)(parseDOM(feed, options));
}
exports.parseFeed = parseFeed;
exports.DomUtils = __importStar(domutils_1);
});
var htmlparser2_1 = lib$1;
var lib = createCommonjsModule(function (module, exports) {
var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (commonjsGlobal && commonjsGlobal.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __exportStar = (commonjsGlobal && commonjsGlobal.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __importStar = (commonjsGlobal && commonjsGlobal.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.root = exports.parseHTML = exports.merge = exports.contains = exports.text = exports.xml = exports.html = exports.load = void 0;
/**
* Types used in signatures of Cheerio methods.
*
* @category Cheerio
*/
__exportStar(types, exports);
var dom_serializer_1 = __importDefault(require$$1$1);
var parse$1 = (0, parse.getParse)(function (content, options, isDocument, context) {
return options.xmlMode || options._useHtmlParser2
? (0, htmlparser2_1.parseDocument)(content, options)
: (0, parse5Adapter.parseWithParse5)(content, options, isDocument, context);
});
// Duplicate docs due to https://github.com/TypeStrong/typedoc/issues/1616
/**
* Create a querying function, bound to a document created from the provided markup.
*
* Note that similar to web browser contexts, this operation may introduce
* `<html>`, `<head>`, and `<body>` elements; set `isDocument` to `false` to
* switch to fragment mode and disable this.
*
* @param content - Markup to be loaded.
* @param options - Options for the created instance.
* @param isDocument - Allows parser to be switched to fragment mode.
* @returns The loaded document.
* @see {@link https://cheerio.js.org#loading} for additional usage information.
*/
exports.load = (0, load.getLoad)(parse$1, function (dom, options) {
return options.xmlMode || options._useHtmlParser2
? (0, dom_serializer_1.default)(dom, options)
: (0, parse5Adapter.renderWithParse5)(dom);
});
/**
* The default cheerio instance.
*
* @deprecated Use the function returned by `load` instead.
*/
exports.default = (0, exports.load)([]);
Object.defineProperty(exports, "html", { enumerable: true, get: function () { return _static.html; } });
Object.defineProperty(exports, "xml", { enumerable: true, get: function () { return _static.xml; } });
Object.defineProperty(exports, "text", { enumerable: true, get: function () { return _static.text; } });
var staticMethods = __importStar(_static);
/**
* In order to promote consistency with the jQuery library, users are encouraged
* to instead use the static method of the same name.
*
* @deprecated
* @example
*
* ```js
* const $ = cheerio.load('<div><p></p></div>');
*
* $.contains($('div').get(0), $('p').get(0));
* //=> true
*
* $.contains($('p').get(0), $('div').get(0));
* //=> false
* ```
*
* @returns {boolean}
*/
exports.contains = staticMethods.contains;
/**
* In order to promote consistency with the jQuery library, users are encouraged
* to instead use the static method of the same name.
*
* @deprecated
* @example
*
* ```js
* const $ = cheerio.load('');
*
* $.merge([1, 2], [3, 4]);
* //=> [1, 2, 3, 4]
* ```
*/
exports.merge = staticMethods.merge;
/**
* In order to promote consistency with the jQuery library, users are encouraged
* to instead use the static method of the same name as it is defined on the
* "loaded" Cheerio factory function.
*
* @deprecated See {@link static/parseHTML}.
* @example
*
* ```js
* const $ = cheerio.load('');
* $.parseHTML('<b>markup</b>');
* ```
*/
exports.parseHTML = staticMethods.parseHTML;
/**
* Users seeking to access the top-level element of a parsed document should
* instead use the `root` static method of a "loaded" Cheerio function.
*
* @deprecated
* @example
*
* ```js
* const $ = cheerio.load('');
* $.root();
* ```
*/
exports.root = staticMethods.root;
});
var browserPonyfill = createCommonjsModule(function (module, exports) {
var global = typeof self !== 'undefined' ? self : commonjsGlobal;
var __self__ = (function () {
function F() {
this.fetch = false;
this.DOMException = global.DOMException;
}
F.prototype = global;
return new F();
})();
(function(self) {
((function (exports) {
var support = {
searchParams: 'URLSearchParams' in self,
iterable: 'Symbol' in self && 'iterator' in Symbol,
blob:
'FileReader' in self &&
'Blob' in self &&
(function() {
try {
new Blob();
return true
} catch (e) {
return false
}
})(),
formData: 'FormData' in self,
arrayBuffer: 'ArrayBuffer' in self
};
function isDataView(obj) {
return obj && DataView.prototype.isPrototypeOf(obj)
}
if (support.arrayBuffer) {
var viewClasses = [
'[object Int8Array]',
'[object Uint8Array]',
'[object Uint8ClampedArray]',
'[object Int16Array]',
'[object Uint16Array]',
'[object Int32Array]',
'[object Uint32Array]',
'[object Float32Array]',
'[object Float64Array]'
];
var isArrayBufferView =
ArrayBuffer.isView ||
function(obj) {
return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1
};
}
function normalizeName(name) {
if (typeof name !== 'string') {
name = String(name);
}
if (/[^a-z0-9\-#$%&'*+.^_`|~]/i.test(name)) {
throw new TypeError('Invalid character in header field name')
}
return name.toLowerCase()
}
function normalizeValue(value) {
if (typeof value !== 'string') {
value = String(value);
}
return value
}
// Build a destructive iterator for the value list
function iteratorFor(items) {
var iterator = {
next: function() {
var value = items.shift();
return {done: value === undefined, value: value}
}
};
if (support.iterable) {
iterator[Symbol.iterator] = function() {
return iterator
};
}
return iterator
}
function Headers(headers) {
this.map = {};
if (headers instanceof Headers) {
headers.forEach(function(value, name) {
this.append(name, value);
}, this);
} else if (Array.isArray(headers)) {
headers.forEach(function(header) {
this.append(header[0], header[1]);
}, this);
} else if (headers) {
Object.getOwnPropertyNames(headers).forEach(function(name) {
this.append(name, headers[name]);
}, this);
}
}
Headers.prototype.append = function(name, value) {
name = normalizeName(name);
value = normalizeValue(value);
var oldValue = this.map[name];
this.map[name] = oldValue ? oldValue + ', ' + value : value;
};
Headers.prototype['delete'] = function(name) {
delete this.map[normalizeName(name)];
};
Headers.prototype.get = function(name) {
name = normalizeName(name);
return this.has(name) ? this.map[name] : null
};
Headers.prototype.has = function(name) {
return this.map.hasOwnProperty(normalizeName(name))
};
Headers.prototype.set = function(name, value) {
this.map[normalizeName(name)] = normalizeValue(value);
};
Headers.prototype.forEach = function(callback, thisArg) {
for (var name in this.map) {
if (this.map.hasOwnProperty(name)) {
callback.call(thisArg, this.map[name], name, this);
}
}
};
Headers.prototype.keys = function() {
var items = [];
this.forEach(function(value, name) {
items.push(name);
});
return iteratorFor(items)
};
Headers.prototype.values = function() {
var items = [];
this.forEach(function(value) {
items.push(value);
});
return iteratorFor(items)
};
Headers.prototype.entries = function() {
var items = [];
this.forEach(function(value, name) {
items.push([name, value]);
});
return iteratorFor(items)
};
if (support.iterable) {
Headers.prototype[Symbol.iterator] = Headers.prototype.entries;
}
function consumed(body) {
if (body.bodyUsed) {
return Promise.reject(new TypeError('Already read'))
}
body.bodyUsed = true;
}
function fileReaderReady(reader) {
return new Promise(function(resolve, reject) {
reader.onload = function() {
resolve(reader.result);
};
reader.onerror = function() {
reject(reader.error);
};
})
}
function readBlobAsArrayBuffer(blob) {
var reader = new FileReader();
var promise = fileReaderReady(reader);
reader.readAsArrayBuffer(blob);
return promise
}
function readBlobAsText(blob) {
var reader = new FileReader();
var promise = fileReaderReady(reader);
reader.readAsText(blob);
return promise
}
function readArrayBufferAsText(buf) {
var view = new Uint8Array(buf);
var chars = new Array(view.length);
for (var i = 0; i < view.length; i++) {
chars[i] = String.fromCharCode(view[i]);
}
return chars.join('')
}
function bufferClone(buf) {
if (buf.slice) {
return buf.slice(0)
} else {
var view = new Uint8Array(buf.byteLength);
view.set(new Uint8Array(buf));
return view.buffer
}
}
function Body() {
this.bodyUsed = false;
this._initBody = function(body) {
this._bodyInit = body;
if (!body) {
this._bodyText = '';
} else if (typeof body === 'string') {
this._bodyText = body;
} else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
this._bodyBlob = body;
} else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
this._bodyFormData = body;
} else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
this._bodyText = body.toString();
} else if (support.arrayBuffer && support.blob && isDataView(body)) {
this._bodyArrayBuffer = bufferClone(body.buffer);
// IE 10-11 can't handle a DataView body.
this._bodyInit = new Blob([this._bodyArrayBuffer]);
} else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {
this._bodyArrayBuffer = bufferClone(body);
} else {
this._bodyText = body = Object.prototype.toString.call(body);
}
if (!this.headers.get('content-type')) {
if (typeof body === 'string') {
this.headers.set('content-type', 'text/plain;charset=UTF-8');
} else if (this._bodyBlob && this._bodyBlob.type) {
this.headers.set('content-type', this._bodyBlob.type);
} else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
}
}
};
if (support.blob) {
this.blob = function() {
var rejected = consumed(this);
if (rejected) {
return rejected
}
if (this._bodyBlob) {
return Promise.resolve(this._bodyBlob)
} else if (this._bodyArrayBuffer) {
return Promise.resolve(new Blob([this._bodyArrayBuffer]))
} else if (this._bodyFormData) {
throw new Error('could not read FormData body as blob')
} else {
return Promise.resolve(new Blob([this._bodyText]))
}
};
this.arrayBuffer = function() {
if (this._bodyArrayBuffer) {
return consumed(this) || Promise.resolve(this._bodyArrayBuffer)
} else {
return this.blob().then(readBlobAsArrayBuffer)
}
};
}
this.text = function() {
var rejected = consumed(this);
if (rejected) {
return rejected
}
if (this._bodyBlob) {
return readBlobAsText(this._bodyBlob)
} else if (this._bodyArrayBuffer) {
return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer))
} else if (this._bodyFormData) {
throw new Error('could not read FormData body as text')
} else {
return Promise.resolve(this._bodyText)
}
};
if (support.formData) {
this.formData = function() {
return this.text().then(decode)
};
}
this.json = function() {
return this.text().then(JSON.parse)
};
return this
}
// HTTP methods whose capitalization should be normalized
var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'];
function normalizeMethod(method) {
var upcased = method.toUpperCase();
return methods.indexOf(upcased) > -1 ? upcased : method
}
function Request(input, options) {
options = options || {};
var body = options.body;
if (input instanceof Request) {
if (input.bodyUsed) {
throw new TypeError('Already read')
}
this.url = input.url;
this.credentials = input.credentials;
if (!options.headers) {
this.headers = new Headers(input.headers);
}
this.method = input.method;
this.mode = input.mode;
this.signal = input.signal;
if (!body && input._bodyInit != null) {
body = input._bodyInit;
input.bodyUsed = true;
}
} else {
this.url = String(input);
}
this.credentials = options.credentials || this.credentials || 'same-origin';
if (options.headers || !this.headers) {
this.headers = new Headers(options.headers);
}
this.method = normalizeMethod(options.method || this.method || 'GET');
this.mode = options.mode || this.mode || null;
this.signal = options.signal || this.signal;
this.referrer = null;
if ((this.method === 'GET' || this.method === 'HEAD') && body) {
throw new TypeError('Body not allowed for GET or HEAD requests')
}
this._initBody(body);
}
Request.prototype.clone = function() {
return new Request(this, {body: this._bodyInit})
};
function decode(body) {
var form = new FormData();
body
.trim()
.split('&')
.forEach(function(bytes) {
if (bytes) {
var split = bytes.split('=');
var name = split.shift().replace(/\+/g, ' ');
var value = split.join('=').replace(/\+/g, ' ');
form.append(decodeURIComponent(name), decodeURIComponent(value));
}
});
return form
}
function parseHeaders(rawHeaders) {
var headers = new Headers();
// Replace instances of \r\n and \n followed by at least one space or horizontal tab with a space
// https://tools.ietf.org/html/rfc7230#section-3.2
var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, ' ');
preProcessedHeaders.split(/\r?\n/).forEach(function(line) {
var parts = line.split(':');
var key = parts.shift().trim();
if (key) {
var value = parts.join(':').trim();
headers.append(key, value);
}
});
return headers
}
Body.call(Request.prototype);
function Response(bodyInit, options) {
if (!options) {
options = {};
}
this.type = 'default';
this.status = options.status === undefined ? 200 : options.status;
this.ok = this.status >= 200 && this.status < 300;
this.statusText = 'statusText' in options ? options.statusText : 'OK';
this.headers = new Headers(options.headers);
this.url = options.url || '';
this._initBody(bodyInit);
}
Body.call(Response.prototype);
Response.prototype.clone = function() {
return new Response(this._bodyInit, {
status: this.status,
statusText: this.statusText,
headers: new Headers(this.headers),
url: this.url
})
};
Response.error = function() {
var response = new Response(null, {status: 0, statusText: ''});
response.type = 'error';
return response
};
var redirectStatuses = [301, 302, 303, 307, 308];
Response.redirect = function(url, status) {
if (redirectStatuses.indexOf(status) === -1) {
throw new RangeError('Invalid status code')
}
return new Response(null, {status: status, headers: {location: url}})
};
exports.DOMException = self.DOMException;
try {
new exports.DOMException();
} catch (err) {
exports.DOMException = function(message, name) {
this.message = message;
this.name = name;
var error = Error(message);
this.stack = error.stack;
};
exports.DOMException.prototype = Object.create(Error.prototype);
exports.DOMException.prototype.constructor = exports.DOMException;
}
function fetch(input, init) {
return new Promise(function(resolve, reject) {
var request = new Request(input, init);
if (request.signal && request.signal.aborted) {
return reject(new exports.DOMException('Aborted', 'AbortError'))
}
var xhr = new XMLHttpRequest();
function abortXhr() {
xhr.abort();
}
xhr.onload = function() {
var options = {
status: xhr.status,
statusText: xhr.statusText,
headers: parseHeaders(xhr.getAllResponseHeaders() || '')
};
options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL');
var body = 'response' in xhr ? xhr.response : xhr.responseText;
resolve(new Response(body, options));
};
xhr.onerror = function() {
reject(new TypeError('Network request failed'));
};
xhr.ontimeout = function() {
reject(new TypeError('Network request failed'));
};
xhr.onabort = function() {
reject(new exports.DOMException('Aborted', 'AbortError'));
};
xhr.open(request.method, request.url, true);
if (request.credentials === 'include') {
xhr.withCredentials = true;
} else if (request.credentials === 'omit') {
xhr.withCredentials = false;
}
if ('responseType' in xhr && support.blob) {
xhr.responseType = 'blob';
}
request.headers.forEach(function(value, name) {
xhr.setRequestHeader(name, value);
});
if (request.signal) {
request.signal.addEventListener('abort', abortXhr);
xhr.onreadystatechange = function() {
// DONE (success or failure)
if (xhr.readyState === 4) {
request.signal.removeEventListener('abort', abortXhr);
}
};
}
xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit);
})
}
fetch.polyfill = true;
if (!self.fetch) {
self.fetch = fetch;
self.Headers = Headers;
self.Request = Request;
self.Response = Response;
}
exports.Headers = Headers;
exports.Request = Request;
exports.Response = Response;
exports.fetch = fetch;
Object.defineProperty(exports, '__esModule', { value: true });
return exports;
}))({});
})(__self__);
__self__.fetch.ponyfill = true;
// Remove "polyfill" property added by whatwg-fetch
delete __self__.fetch.polyfill;
// Choose between native implementation (global) or custom implementation (__self__)
// var ctx = global.fetch ? global : __self__;
var ctx = __self__; // this line disable service worker support temporarily
exports = ctx.fetch; // To enable: import fetch from 'cross-fetch'
exports.default = ctx.fetch; // For TypeScript consumers without esModuleInterop.
exports.fetch = ctx.fetch; // To enable: import {fetch} from 'cross-fetch'
exports.Headers = ctx.Headers;
exports.Request = ctx.Request;
exports.Response = ctx.Response;
module.exports = exports;
});
/*globals self, window */
/*eslint-disable @mysticatea/prettier */
const { AbortController, AbortSignal } =
typeof self !== "undefined" ? self :
typeof window !== "undefined" ? window :
/* otherwise */ undefined;
/*eslint-enable @mysticatea/prettier */
var browser = AbortController;
var AbortSignal_1 = AbortSignal;
var _default = AbortController;
browser.AbortSignal = AbortSignal_1;
browser.default = _default;
var constants = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.CONSTANTS = void 0;
exports.CONSTANTS = {
REGEX_VALID_URL: new RegExp("^" +
// protocol identifier
"(?:(?:https?|ftp)://)" +
// user:pass authentication
"(?:\\S+(?::\\S*)?@)?" +
"(?:" +
// IP address exclusion
// private & local networks
"(?!(?:10|127)(?:\\.\\d{1,3}){3})" +
"(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})" +
"(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})" +
// IP address dotted notation octets
// excludes loopback network 0.0.0.0
// excludes reserved space >= 224.0.0.0
// excludes network & broacast addresses
// (first & last IP address of each class)
"(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" +
"(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" +
"(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" +
"|" +
// host name
"(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)" +
// domain name
"(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*" +
// TLD identifier
"(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))" +
// TLD may end with dot
"\\.?" +
")" +
// port number
"(?::\\d{2,5})?" +
// resource path
"(?:[/?#]\\S*)?" +
"$", "i"),
REGEX_LOOPBACK: new RegExp("^" +
"(?:(?:10|127)(?:\\.\\d{1,3}){3})" +
"|" +
"(?:(?:169\\.254|192\\.168|192\\.0)(?:\\.\\d{1,3}){2})" +
"|" +
"(?:172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})" +
"$", "i"),
REGEX_CONTENT_TYPE_IMAGE: new RegExp("image/.*", "i"),
REGEX_CONTENT_TYPE_AUDIO: new RegExp("audio/.*", "i"),
REGEX_CONTENT_TYPE_VIDEO: new RegExp("video/.*", "i"),
REGEX_CONTENT_TYPE_TEXT: new RegExp("text/.*", "i"),
REGEX_CONTENT_TYPE_APPLICATION: new RegExp("application/.*", "i"),
};
});
var build = createCommonjsModule(function (module, exports) {
var __awaiter = (commonjsGlobal && commonjsGlobal.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (commonjsGlobal && commonjsGlobal.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getPreviewFromContent = exports.getLinkPreview = void 0;
var cheerio_1 = __importDefault(lib);
var abort_controller_1 = __importDefault(browser);
var url_1 = __importDefault(require$$2__default["default"]);
function throwOnLoopback(address) {
if (constants.CONSTANTS.REGEX_LOOPBACK.test(address)) {
throw new Error("SSRF request detected, trying to query host");
}
}
function metaTag(doc, type, attr) {
var nodes = doc("meta[".concat(attr, "='").concat(type, "']"));
return nodes.length ? nodes : null;
}
function metaTagContent(doc, type, attr) {
return doc("meta[".concat(attr, "='").concat(type, "']")).attr("content");
}
function getTitle(doc) {
var title = metaTagContent(doc, "og:title", "property") ||
metaTagContent(doc, "og:title", "name");
if (!title) {
title = doc("title").text();
}
return title;
}
function getSiteName(doc) {
var siteName = metaTagContent(doc, "og:site_name", "property") ||
metaTagContent(doc, "og:site_name", "name");
return siteName;
}
function getDescription(doc) {
var description = metaTagContent(doc, "description", "name") ||
metaTagContent(doc, "Description", "name") ||
metaTagContent(doc, "og:description", "property");
return description;
}
function getMediaType(doc) {
var node = metaTag(doc, "medium", "name");
if (node) {
var content = node.attr("content");
return content === "image" ? "photo" : content;
}
return (metaTagContent(doc, "og:type", "property") ||
metaTagContent(doc, "og:type", "name"));
}
function getImages(doc, rootUrl, imagesPropertyType) {
var images = [];
var nodes;
var src;
var dic = {};
var imagePropertyType = imagesPropertyType !== null && imagesPropertyType !== void 0 ? imagesPropertyType : "og";
nodes =
metaTag(doc, "".concat(imagePropertyType, ":image"), "property") ||
metaTag(doc, "".concat(imagePropertyType, ":image"), "name");
if (nodes) {
nodes.each(function (_, node) {
if (node.type === "tag") {
src = node.attribs.content;
if (src) {
src = url_1.default.resolve(rootUrl, src);
images.push(src);
}
}
});
}
if (images.length <= 0 && !imagesPropertyType) {
src = doc("link[rel=image_src]").attr("href");
if (src) {
src = url_1.default.resolve(rootUrl, src);
images = [src];
}
else {
nodes = doc("img");
if (nodes === null || nodes === void 0 ? void 0 : nodes.length) {
dic = {};
images = [];
nodes.each(function (_, node) {
if (node.type === "tag")
src = node.attribs.src;
if (src && !dic[src]) {
dic[src] = true;
// width = node.attribs.width;
// height = node.attribs.height;
images.push(url_1.default.resolve(rootUrl, src));
}
});
}
}
}
return images;
}
function getVideos(doc) {
var videos = [];
var nodeTypes;
var nodeSecureUrls;
var nodeType;
var nodeSecureUrl;
var video;
var videoType;
var videoSecureUrl;
var width;
var height;
var videoObj;
var index;
var nodes = metaTag(doc, "og:video", "property") || metaTag(doc, "og:video", "name");
if (nodes === null || nodes === void 0 ? void 0 : nodes.length) {
nodeTypes =
metaTag(doc, "og:video:type", "property") ||
metaTag(doc, "og:video:type", "name");
nodeSecureUrls =
metaTag(doc, "og:video:secure_url", "property") ||
metaTag(doc, "og:video:secure_url", "name");
width =
metaTagContent(doc, "og:video:width", "property") ||
metaTagContent(doc, "og:video:width", "name");
height =
metaTagContent(doc, "og:video:height", "property") ||
metaTagContent(doc, "og:video:height", "name");
for (index = 0; index < nodes.length; index += 1) {
var node = nodes[index];
if (node.type === "tag")
video = node.attribs.content;
nodeType = nodeTypes === null || nodeTypes === void 0 ? void 0 : nodeTypes[index];
if ((nodeType === null || nodeType === void 0 ? void 0 : nodeType.type) === "tag") {
videoType = nodeType ? nodeType.attribs.content : null;
}
nodeSecureUrl = nodeSecureUrls === null || nodeSecureUrls === void 0 ? void 0 : nodeSecureUrls[index];
if ((nodeSecureUrl === null || nodeSecureUrl === void 0 ? void 0 : nodeSecureUrl.type) === "tag") {
videoSecureUrl = nodeSecureUrl ? nodeSecureUrl.attribs.content : null;
}
videoObj = {
url: video,
secureUrl: videoSecureUrl,
type: videoType,
width: width,
height: height,
};
if (videoType && videoType.indexOf("video/") === 0) {
videos.splice(0, 0, videoObj);
}
else {
videos.push(videoObj);
}
}
}
return videos;
}
// returns default favicon (//hostname/favicon.ico) for a url
function getDefaultFavicon(rootUrl) {
return url_1.default.resolve(rootUrl, "/favicon.ico");
}
// returns an array of URLs to favicon images
function getFavicons(doc, rootUrl) {
var images = [];
var nodes = [];
var src;
var relSelectors = [
"rel=icon",
"rel=\"shortcut icon\"",
"rel=apple-touch-icon",
];
relSelectors.forEach(function (relSelector) {
// look for all icon tags
nodes = doc("link[".concat(relSelector, "]"));
// collect all images from icon tags
if (nodes.length) {
nodes.each(function (_, node) {
if (node.type === "tag")
src = node.attribs.href;
if (src) {
src = url_1.default.resolve(rootUrl, src);
images.push(src);
}
});
}
});
// if no icon images, use default favicon location
if (images.length <= 0) {
images.push(getDefaultFavicon(rootUrl));
}
return images;
}
function parseImageResponse(url, contentType) {
return {
url: url,
mediaType: "image",
contentType: contentType,
favicons: [getDefaultFavicon(url)],
};
}
function parseAudioResponse(url, contentType) {
return {
url: url,
mediaType: "audio",
contentType: contentType,
favicons: [getDefaultFavicon(url)],
};
}
function parseVideoResponse(url, contentType) {
return {
url: url,
mediaType: "video",
contentType: contentType,
favicons: [getDefaultFavicon(url)],
};
}
function parseApplicationResponse(url, contentType) {
return {
url: url,
mediaType: "application",
contentType: contentType,
favicons: [getDefaultFavicon(url)],
};
}
function parseTextResponse(body, url, options, contentType) {
if (options === void 0) { options = {}; }
var doc = cheerio_1.default.load(body);
return {
url: url,
title: getTitle(doc),
siteName: getSiteName(doc),
description: getDescription(doc),
mediaType: getMediaType(doc) || "website",
contentType: contentType,
images: getImages(doc, url, options.imagesPropertyType),
videos: getVideos(doc),
favicons: getFavicons(doc, url),
};
}
function parseUnknownResponse(body, url, options, contentType) {
if (options === void 0) { options = {}; }
return parseTextResponse(body, url, options, contentType);
}
function parseResponse(response, options) {
try {
var contentType = response.headers["content-type"];
// console.warn(`original content type`, contentType);
if (contentType === null || contentType === void 0 ? void 0 : contentType.indexOf(";")) {
// eslint-disable-next-line prefer-destructuring
contentType = contentType.split(";")[0];
// console.warn(`splitting content type`, contentType);
}
if (!contentType) {
return parseUnknownResponse(response.data, response.url, options);
}
if (contentType instanceof Array) {
// eslint-disable-next-line no-param-reassign, prefer-destructuring
contentType = contentType[0];
}
// parse response depending on content type
if (constants.CONSTANTS.REGEX_CONTENT_TYPE_IMAGE.test(contentType)) {
return parseImageResponse(response.url, contentType);
}
if (constants.CONSTANTS.REGEX_CONTENT_TYPE_AUDIO.test(contentType)) {
return parseAudioResponse(response.url, contentType);
}
if (constants.CONSTANTS.REGEX_CONTENT_TYPE_VIDEO.test(contentType)) {
return parseVideoResponse(response.url, contentType);
}
if (constants.CONSTANTS.REGEX_CONTENT_TYPE_TEXT.test(contentType)) {
var htmlString_1 = response.data;
return parseTextResponse(htmlString_1, response.url, options, contentType);
}
if (constants.CONSTANTS.REGEX_CONTENT_TYPE_APPLICATION.test(contentType)) {
return parseApplicationResponse(response.url, contentType);
}
var htmlString = response.data;
return parseUnknownResponse(htmlString, response.url, options);
}
catch (e) {
throw new Error("link-preview-js could not fetch link information ".concat(e.toString()));
}
}
/**
* Parses the text, extracts the first link it finds and does a HTTP request
* to fetch the website content, afterwards it tries to parse the internal HTML
* and extract the information via meta tags
* @param text string, text to be parsed
* @param options ILinkPreviewOptions
*/
function getLinkPreview(text, options) {
var _a, _b, _c;
return __awaiter(this, void 0, void 0, function () {
var detectedUrl, resolvedUrl, timeout, controller, timeoutCounter, fetchOptions, fetchUrl, response, forwardedUrl, resolvedUrl, headers, normalizedResponse;
var _d;
return __generator(this, function (_e) {
switch (_e.label) {
case 0:
if (!text || typeof text !== "string") {
throw new Error("link-preview-js did not receive a valid url or text");
}
detectedUrl = text
.replace(/\n/g, " ")
.split(" ")
.find(function (token) { return constants.CONSTANTS.REGEX_VALID_URL.test(token); });
if (!detectedUrl) {
throw new Error("link-preview-js did not receive a valid a url or text");
}
if ((options === null || options === void 0 ? void 0 : options.followRedirects) === "manual" && !(options === null || options === void 0 ? void 0 : options.handleRedirects)) {
throw new Error("link-preview-js followRedirects is set to manual, but no handleRedirects function was provided");
}
if (!!!(options === null || options === void 0 ? void 0 : options.resolveDNSHost)) return [3 /*break*/, 2];
return [4 /*yield*/, options.resolveDNSHost(detectedUrl)];
case 1:
resolvedUrl = _e.sent();
throwOnLoopback(resolvedUrl);
_e.label = 2;
case 2:
timeout = (_a = options === null || options === void 0 ? void 0 : options.timeout) !== null && _a !== void 0 ? _a : 3000;
controller = new abort_controller_1.default();
timeoutCounter = setTimeout(function () { return controller.abort(); }, timeout);
fetchOptions = {
headers: (_b = options === null || options === void 0 ? void 0 : options.headers) !== null && _b !== void 0 ? _b : {},
redirect: (_c = options === null || options === void 0 ? void 0 : options.followRedirects) !== null && _c !== void 0 ? _c : "error",
signal: controller.signal,
};
fetchUrl = (options === null || options === void 0 ? void 0 : options.proxyUrl)
? options.proxyUrl.concat(detectedUrl)
: detectedUrl;
return [4 /*yield*/, (0, browserPonyfill.fetch)(fetchUrl, fetchOptions).catch(function (e) {
if (e.name === "AbortError") {
throw new Error("Request timeout");
}
clearTimeout(timeoutCounter);
throw e;
})];
case 3:
response = _e.sent();
if (!(response.status > 300 &&
response.status < 309 &&
fetchOptions.redirect === "manual" &&
(options === null || options === void 0 ? void 0 : options.handleRedirects))) return [3 /*break*/, 7];
forwardedUrl = response.headers.get("location") || "";
if (!options.handleRedirects(fetchUrl, forwardedUrl)) {
throw new Error("link-preview-js could not handle redirect");
}
if (!!!(options === null || options === void 0 ? void 0 : options.resolveDNSHost)) return [3 /*break*/, 5];
return [4 /*yield*/, options.resolveDNSHost(forwardedUrl)];
case 4:
resolvedUrl = _e.sent();
throwOnLoopback(resolvedUrl);
_e.label = 5;
case 5: return [4 /*yield*/, (0, browserPonyfill.fetch)(forwardedUrl, fetchOptions)];
case 6:
response = _e.sent();
_e.label = 7;
case 7:
clearTimeout(timeoutCounter);
headers = {};
response.headers.forEach(function (header, key) {
headers[key] = header;
});
_d = {
url: (options === null || options === void 0 ? void 0 : options.proxyUrl)
? response.url.replace(options.proxyUrl, "")
: response.url,
headers: headers
};
return [4 /*yield*/, response.text()];
case 8:
normalizedResponse = (_d.data = _e.sent(),
_d);
return [2 /*return*/, parseResponse(normalizedResponse, options)];
}
});
});
}
exports.getLinkPreview = getLinkPreview;
/**
* Skip the library fetching the website for you, instead pass a response object
* from whatever source you get and use the internal parsing of the HTML to return
* the necessary information
* @param response Preview Response
* @param options IPreviewLinkOptions
*/
function getPreviewFromContent(response, options) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
if (!response || typeof response !== "object") {
throw new Error("link-preview-js did not receive a valid response object");
}
if (!response.url) {
throw new Error("link-preview-js did not receive a valid response object");
}
return [2 /*return*/, parseResponse(response, options)];
});
});
}
exports.getPreviewFromContent = getPreviewFromContent;
});
class GenericPreviewEmbed {
constructor() {
this.name = "Generic Preview";
this.enabledKey = "replaceGenericLinks";
// unmatchable regex
// this source is used as a fallback when other sources fail to match
this.regex = new RegExp("(?!)");
}
createEmbed(link, container, settings, currentTheme, plugin) {
const preview = document.createElement("a");
preview.setAttr("href", link);
preview.classList.add("preview");
preview.textContent = "Loading preview...";
const loadPreview = () => __awaiter(this, void 0, void 0, function* () {
let metadata;
// await cache file load if not available yet
if (!plugin.genericPreviewCache)
yield plugin.cacheFileLoadPromise;
if (settings.useCacheForGenericLinks && link in plugin.genericPreviewCache) {
metadata = plugin.genericPreviewCache[link];
}
else {
const res = yield obsidian.requestUrl({ url: link });
metadata = yield build.getPreviewFromContent({
headers: res.headers,
data: res.text,
url: link
});
if (settings.useCacheForGenericLinks && "title" in metadata) {
plugin.saveGenericPreviewCache(link, metadata);
}
}
if (!("title" in metadata))
return;
preview.innerHTML =
String.raw `
<div class="image-container">
${metadata.images.length ? String.raw `<img src="${metadata.images[0]}" />` : ""}
</div>
<div class="content">
<div class="title">${metadata.title}</div>
<div class="description">${metadata.description ? metadata.description : ""}</div>
</div>
`;
});
try {
loadPreview();
}
catch (_a) {
preview.textContent = "Could not load preview";
}
container.appendChild(preview);
container.classList.add("generic-preview");
return container;
}
}
const DEFAULT_SETTINGS = {
replaceAppleMusicLinks: true,
replaceApplePodcastsLinks: true,
replaceAppleTVLinks: true,
replaceBandcampLinks: true,
replaceCodepenLinks: true,
replaceFlatIOLinks: true,
replaceGitHubGistLinks: true,
replaceInstagramLinks: true,
replaceNoteflightLinks: true,
replaceRedditLinks: true,
replaceTwitterLinks: true,
replaceVimeoLinks: true,
replaceWhimsicalLinks: true,
replaceYouTubeLinks: true,
replaceGenericLinks: false,
useCacheForGenericLinks: true,
twitterTheme: "auto",
codepenTheme: "auto",
codepenDefaultTab: "html",
codepenShowResult: true,
codepenClickToLoad: false,
codepenEditable: false,
redditTheme: "auto",
enableInLivePreview: false,
centerEmbeds: false,
keepLinksInPreview: false,
embedPlacement: "above",
disableAutomaticEmbeds: false,
};
class SimpleEmbedPluginSettingTab extends obsidian.PluginSettingTab {
constructor(app, plugin) {
super(app, plugin);
this.embedSettings = {};
this.plugin = plugin;
}
display() {
let { containerEl } = this;
containerEl.empty();
containerEl.classList.add("simple-embeds-settings");
containerEl.createEl("h3", { text: "Available Embed Sources" });
containerEl.createEl("p", {
cls: "setting-item-description",
}, (el) => {
el.innerHTML =
"Disable to prevent <em>all</em> links from source ever being turned into embeds. To disable an individual link, add <code>|noembed</code> to the link text. For example, <code>[Some description|noembed](https://twitter.com/user/status/123)</code>";
});
// Toggles to enabled/disabled embed sources.
this.plugin.embedSources.forEach((embedSource) => {
new obsidian.Setting(containerEl).setName(embedSource.name).addToggle((toggle) => {
toggle
.setValue(this.plugin.settings[embedSource.enabledKey])
.onChange((enabled) => __awaiter(this, void 0, void 0, function* () {
yield this.saveSettings({ [embedSource.enabledKey]: enabled });
this.toggleAdditionalSettings(embedSource, enabled);
}));
});
});
// Settings for generic link previews
containerEl.createEl("h3", { text: "Generic Link Previews" });
containerEl.createEl("p", {
cls: "setting-item-description",
}, (el) => {
el.innerHTML =
"Desktop only";
});
new obsidian.Setting(containerEl)
.setName("Show generic previews for links")
.addToggle((toggle) => {
toggle
.setValue(this.plugin.settings.replaceGenericLinks)
.onChange((enabled) => __awaiter(this, void 0, void 0, function* () {
yield this.saveSettings({ replaceGenericLinks: enabled });
}));
})
.setDisabled(obsidian.Platform.isMobile);
new obsidian.Setting(containerEl)
.setName("Use a cache for link preview metadata")
.addToggle((toggle) => {
toggle
.setValue(this.plugin.settings.useCacheForGenericLinks)
.onChange((enabled) => __awaiter(this, void 0, void 0, function* () {
yield this.saveSettings({ useCacheForGenericLinks: enabled });
}));
})
.setDisabled(obsidian.Platform.isMobile);
new obsidian.Setting(containerEl)
.setName("Clear link preview metadata cache")
.addButton((button) => {
button
.setButtonText("Clear")
.onClick(() => __awaiter(this, void 0, void 0, function* () {
yield this.app.vault.adapter.write(this.plugin.genericPreviewCacheFile, "{}");
this.plugin.genericPreviewCache = {};
yield this.plugin.saveSettings({});
}));
})
.setDisabled(obsidian.Platform.isMobile);
// Any additional settings for embed sources.
containerEl.createEl("h3", { text: "Appearance" });
this.plugin.embedSources.forEach((embedSource) => {
if (embedSource.createAdditionalSettings) {
containerEl.createEl("details", {}, (el) => {
const fragment = new DocumentFragment();
const summary = fragment.createEl("summary");
const title = fragment.createEl("h4", {
text: embedSource.name,
});
summary.appendChild(title);
el.appendChild(summary);
const settings = embedSource.createAdditionalSettings(el, this.plugin.settings, this.saveSettings.bind(this));
this.embedSettings[embedSource.constructor.name] = settings;
const enabled = this.plugin.settings[embedSource.enabledKey];
this.toggleAdditionalSettings(embedSource, enabled);
});
}
});
containerEl.createEl("h3", { text: "Advanced Settings" });
new obsidian.Setting(containerEl)
.setName("Show Embeds in Live Preview (beta)")
.addToggle((toggle) => {
toggle
.setValue(this.plugin.settings.enableInLivePreview)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
yield this.saveSettings({ enableInLivePreview: value });
}));
});
new obsidian.Setting(containerEl).setName("Center embeds").addToggle((toggle) => {
toggle
.setValue(this.plugin.settings.centerEmbeds)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
yield this.saveSettings({ centerEmbeds: value });
}));
});
new obsidian.Setting(containerEl)
.setName("Keep links in preview")
.setDesc("Insert embeds above the link, instead of replacing the link in the preview.")
.addToggle((toggle) => {
toggle
.setValue(this.plugin.settings.keepLinksInPreview)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
yield this.saveSettings({ keepLinksInPreview: value });
placement.setDisabled(!this.plugin.settings.keepLinksInPreview);
}));
});
const placement = new obsidian.Setting(containerEl)
.setName("Place embeds")
.setDesc('When "Keep links in preview" is enabled, choose whether to place the embed above or below the link.')
.addDropdown((dropdown) => {
dropdown
.addOptions({ above: "Above link", below: "Below link" })
.setValue(this.plugin.settings.embedPlacement)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
yield this.saveSettings({ embedPlacement: value });
}));
})
.setDisabled(!this.plugin.settings.keepLinksInPreview);
const fragment = new DocumentFragment();
const div = fragment.createEl("div");
const span = fragment.createEl("span");
span.innerHTML =
"Instead of automatically embedding all matching links, you must add <code>|embed</code> to the link text of each link you would like to turn into an embed. For example, <code>[Some description|embed](https://twitter.com/user/status/123)</code>";
div.appendChild(span);
fragment.appendChild(div);
new obsidian.Setting(containerEl)
.setName("Disable automatic embeds")
.setDesc(fragment)
.addToggle((toggle) => {
toggle
.setValue(this.plugin.settings.disableAutomaticEmbeds)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
yield this.saveSettings({ disableAutomaticEmbeds: value });
}));
});
}
saveSettings(updates) {
return __awaiter(this, void 0, void 0, function* () {
return this.plugin.saveSettings(updates);
});
}
// Disable/enable all additional settings when embed is disabled/enabled.
toggleAdditionalSettings(embedSource, enabled) {
const additionalSettings = this.embedSettings[embedSource.constructor.name];
if (additionalSettings) {
additionalSettings.forEach((setting) => {
setting.setDisabled(!enabled);
});
}
}
}
function buildSimpleEmbedsViewPlugin(plugin) {
class EmbedWidget extends view.WidgetType {
constructor(link, fullWidth, centered, keepLinks, embedSource, plugin) {
super();
this.link = link;
this.fullWidth = fullWidth;
this.centered = centered;
this.keepLinks = keepLinks;
this.embedSource = embedSource;
this.plugin = plugin;
}
eq(other) {
return (other.link === this.link &&
other.fullWidth === this.fullWidth &&
other.centered === this.centered &&
other.keepLinks === this.keepLinks);
}
toDOM() {
const embed = this.plugin.createEmbed(this.embedSource, this.link, this.fullWidth, this.centered, this.keepLinks);
return embed;
}
}
const viewPlugin = view.ViewPlugin.fromClass(class {
constructor(view) {
this.decorations = this.buildDecorations(view);
}
update(update) {
if (update.docChanged ||
update.viewportChanged ||
update.selectionSet) {
this.decorations = this.buildDecorations(update.view);
}
}
destroy() { }
buildDecorations(view) {
var _a;
let builder = new state.RangeSetBuilder();
let definitions = [];
if (!plugin.isLivePreviewSupported) {
return builder.finish();
}
let lines = [];
if (view.state.doc.length > 0) {
lines = Array.from({ length: view.state.doc.lines }, (_, i) => i + 1);
}
const currentSelections = [...view.state.selection.ranges];
for (let n of lines) {
const line = view.state.doc.line(n);
const startOfLine = line.from;
const endOfLine = line.to;
let currentLine = false;
currentSelections.forEach((r) => {
if (r.from >= startOfLine && r.to <= endOfLine) {
currentLine = true;
return;
}
});
const text = line.text;
const mdLink = (_a = text
.match(/\[([^\[]+)\](\(.*\))/)) === null || _a === void 0 ? void 0 : _a.first().trim();
if (!currentLine && mdLink) {
const start = line.text.indexOf(mdLink) + startOfLine;
const end = start + mdLink.length;
let embedSource = plugin.embedSources.find((source) => {
return (plugin.settings[source.enabledKey] &&
source.regex.test(line.text));
});
if (!embedSource && obsidian.Platform.isDesktopApp && plugin.settings.replaceGenericLinks) {
embedSource = plugin.genericPreviewEmbed;
}
const isWithinText = this.isWithinText(text);
const replaceWithEmbed = plugin.shouldReplaceWithEmbed(mdLink, isWithinText);
const fullWidth = mdLink.includes("|fullwidth");
definitions.push(...this.hideOptions(mdLink, start));
if (embedSource && replaceWithEmbed) {
let link;
if (embedSource == plugin.genericPreviewEmbed) {
const mdLinkRegex = /^\[([\w\s\d]+)\]\((https?:\/\/[\w\d./?=#]+)\)$/;
const [_full, _text, url] = line.text.match(mdLinkRegex);
if (!url)
continue;
link = url;
}
else {
link = line.text.match(embedSource.regex).first();
}
definitions.push(this.createWidget(link, fullWidth, embedSource, start, end));
}
}
}
definitions.sort((a, b) => {
return a.from - b.from;
});
definitions.forEach(({ from, to, deco }) => builder.add(from, to, deco));
return builder.finish();
}
hideOptions(text, startOfLink) {
const definitions = [];
for (let option of ["|noembed", "|embed", "|fullwidth"]) {
if (text.includes(option)) {
const from = text.indexOf(option) + startOfLink;
const to = from + option.length;
const deco = view.Decoration.replace({});
definitions.push({
from,
to,
deco,
});
}
}
return definitions;
}
createWidget(link, fullWidth, embedSource, start, end) {
const deco = view.Decoration.widget({
widget: new EmbedWidget(link, fullWidth, plugin.settings.centerEmbeds, plugin.settings.keepLinksInPreview, embedSource, plugin),
});
if (plugin.settings.keepLinksInPreview) {
if (plugin.settings.embedPlacement === "above") {
return {
from: start,
to: start,
deco,
};
}
else if (plugin.settings.embedPlacement === "below") {
return {
from: end,
to: end,
deco,
};
}
}
else {
return {
from: start,
to: end,
deco,
};
}
}
isWithinText(text) {
const mdLink = text
.match(/\[([^\[]+)\](\(.*\))/)[0].trim();
const lineWithoutLink = text.replace(mdLink, "");
const lineWithoutListMarkup = lineWithoutLink.replace(/-|\s\[|(\w|\s)\]/g, "")
.trim();
return (lineWithoutListMarkup === null || lineWithoutListMarkup === void 0 ? void 0 : lineWithoutListMarkup.length) > 0;
}
}, {
decorations: (v) => v.decorations,
});
return viewPlugin;
}
class SimpleEmbedsPlugin extends obsidian.Plugin {
constructor() {
super(...arguments);
this.embedSources = [
new TwitterEmbed(),
new YouTubeEmbed(),
new InstagramEmbed(),
new FlatIOEmbed(),
new NoteflightEmbed(),
new CodepenEmbed(),
new GitHubGistEmbed(),
new AppleMusicEmbed(),
new ApplePodcastsEmbed(),
new AppleTVEmbed(),
new BandcampEmbed(),
new VimeoEmbed(),
new RedditEmbed(),
new WhimsicalEmbed(),
];
this.genericPreviewEmbed = new GenericPreviewEmbed();
this.genericPreviewCache = null;
this.genericPreviewCacheFile = this.app.vault.configDir +
"/plugins/simple-embeds/genericPreviewCache.json";
this.cacheFileLoadPromise = null;
}
onload() {
return __awaiter(this, void 0, void 0, function* () {
console.log(`Loading ${this.manifest.name} v${this.manifest.version}`);
yield this.loadSettings();
this.addSettingTab(new SimpleEmbedPluginSettingTab(this.app, this));
this.currentTheme = this._getCurrentTheme();
const ext = buildSimpleEmbedsViewPlugin(this);
this.registerEditorExtension(ext);
this.processedMarkdown = obsidian.debounce(() => {
this.embedSources.forEach((source) => {
var _a;
(_a = source.afterAllEmbeds) === null || _a === void 0 ? void 0 : _a.call(source);
});
}, 100);
this.registerMarkdownPostProcessor((el, ctx) => {
const anchors = el.querySelectorAll("a.external-link");
anchors.forEach((anchor) => {
this._handleAnchor(anchor);
});
this.processedMarkdown();
});
this.registerEvent(this.app.workspace.on("css-change", () => {
// Theme has potentially changed.
const previousTheme = this.currentTheme;
this.currentTheme = this._getCurrentTheme();
if (previousTheme !== this.currentTheme) {
setTimeout(() => {
this.embedSources.forEach((embedSource) => {
var _a;
(_a = embedSource.updateTheme) === null || _a === void 0 ? void 0 : _a.call(embedSource, this.currentTheme, this.settings);
});
});
}
}));
// Load file for generic preview cache
const loadCacheFile = () => __awaiter(this, void 0, void 0, function* () {
if (!(yield this.app.vault.adapter.exists(this.genericPreviewCacheFile))) {
yield this.app.vault.create(this.genericPreviewCacheFile, "{}");
}
try {
const contents = JSON.parse(yield this.app.vault.adapter.read(this.genericPreviewCacheFile));
this.genericPreviewCache = contents;
}
catch (e) {
console.error("Error reading generic preview cache file");
console.error(e);
}
});
this.cacheFileLoadPromise = loadCacheFile();
});
}
onunload() {
console.log(`Unloading ${this.manifest.name}`);
this.processedMarkdown = null;
}
loadSettings() {
return __awaiter(this, void 0, void 0, function* () {
this.settings = Object.assign({}, DEFAULT_SETTINGS, yield this.loadData());
});
}
saveSettings(updates) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
this.settings = Object.assign(Object.assign({}, this.settings), updates);
yield this.saveData(this.settings);
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
(_a = view === null || view === void 0 ? void 0 : view.previewMode) === null || _a === void 0 ? void 0 : _a.rerender(true);
(_b = view === null || view === void 0 ? void 0 : view.editor) === null || _b === void 0 ? void 0 : _b.transaction({
selection: { from: { line: 0, ch: 0 }, to: { line: 0, ch: 0 } },
});
});
}
saveGenericPreviewCache(link, metadata) {
return __awaiter(this, void 0, void 0, function* () {
if (this.genericPreviewCacheFile) {
this.genericPreviewCache[link] = metadata;
yield this.app.vault.adapter.write(this.genericPreviewCacheFile, JSON.stringify(this.genericPreviewCache));
}
});
}
_getCurrentTheme() {
return document.body.classList.contains("theme-dark") ? "dark" : "light";
}
_handleAnchor(a) {
const isWithinText = Array.from(a.parentElement.childNodes)
.filter((node) => {
return node instanceof Text;
})
.some((text) => {
const nbsp = new RegExp(String.fromCharCode(160), "g");
const data = text.data.replace(nbsp, "").trim();
return !!data;
});
const replaceWithEmbed = this.shouldReplaceWithEmbed(a.innerText, isWithinText);
const fullWidth = a.innerText.includes("|fullwidth");
// Remove any allowed properties:
// |embed, |noembed, |fullwidth
a.innerHTML = a.innerHTML.replace(/\|(?:embed|noembed|fullwidth)/g, "");
if (!replaceWithEmbed) {
return;
}
const href = a.getAttribute("href");
// Try and find an enabled embed source that can handle the link.
let embedSource = this.embedSources.find((source) => {
return this.settings[source.enabledKey] && source.regex.test(href);
});
// Fall back to creating a generic embed if no source found
if (!embedSource && obsidian.Platform.isDesktopApp && this.settings.replaceGenericLinks) {
embedSource = this.genericPreviewEmbed;
}
if (embedSource) {
const embed = this.createEmbed(embedSource, href, fullWidth, this.settings.centerEmbeds, this.settings.keepLinksInPreview);
this._insertEmbed(a, embed);
}
}
shouldReplaceWithEmbed(text, isWithinText) {
const disableAutomaticEmbeds = this.settings.disableAutomaticEmbeds;
if (isWithinText && !disableAutomaticEmbeds) {
return false;
}
return disableAutomaticEmbeds
? text.includes("|embed")
: !text.includes("|noembed");
}
createEmbed(embedSource, link, fullWidth, centered, keepLinks) {
const container = document.createElement("div");
container.classList.add("embed-container");
const embed = embedSource.createEmbed(link, container, this.settings, this.currentTheme, this);
if (fullWidth) {
embed.classList.add("full-width");
}
if (centered) {
embed.classList.add("center");
}
if (!keepLinks) {
embed.classList.add("hide-link");
}
return embed;
}
_insertEmbed(a, container) {
const parent = a.parentElement;
const keepLinksInPreview = this.settings.keepLinksInPreview;
const placement = this.settings.embedPlacement;
if (keepLinksInPreview && placement === "above") {
parent.insertBefore(container, a);
}
else if (keepLinksInPreview && placement === "below") {
a.after(container);
}
else {
parent.replaceChild(container, a);
}
}
get isLivePreviewSupported() {
return (!!document.querySelector(".is-live-preview") &&
this.settings.enableInLivePreview);
}
}
module.exports = SimpleEmbedsPlugin;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZXMiOlsibm9kZV9tb2R1bGVzL3RzbGliL3RzbGliLmVzNi5qcyIsImVtYmVkcy9hcHBsZS1tdXNpYy50cyIsImVtYmVkcy9hcHBsZS1wb2RjYXN0cy50cyIsImVtYmVkcy9hcHBsZS10di50cyIsImVtYmVkcy9iYW5kY2FtcC50cyIsImVtYmVkcy9jb2RlcGVuLnRzIiwiZW1iZWRzL2ZsYXRfaW8udHMiLCJlbWJlZHMvZ2l0aHViX2dpc3QudHMiLCJlbWJlZHMvaW5zdGFncmFtLnRzIiwiZW1iZWRzL25vdGVmbGlnaHQudHMiLCJlbWJlZHMvcmVkZGl0LnRzIiwiZW1iZWRzL3R3aXR0ZXIudHMiLCJlbWJlZHMvdmltZW8udHMiLCJlbWJlZHMvd2hpbXNpY2FsLnRzIiwiZW1iZWRzL2xpdGUteXQtZW1iZWQuanMiLCJlbWJlZHMveW91dHViZS50cyIsIm5vZGVfbW9kdWxlcy9jaGVlcmlvL2xpYi9vcHRpb25zLmpzIiwibm9kZV9tb2R1bGVzL2RvbWVsZW1lbnR0eXBlL2xpYi9pbmRleC5qcyIsIm5vZGVfbW9kdWxlcy9kb21oYW5kbGVyL2xpYi9ub2RlLmpzIiwibm9kZV9tb2R1bGVzL2RvbWhhbmRsZXIvbGliL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2VudGl0aWVzL2xpYi9nZW5lcmF0ZWQvZGVjb2RlLWRhdGEtaHRtbC5qcyIsIm5vZGVfbW9kdWxlcy9lbnRpdGllcy9saWIvZ2VuZXJhdGVkL2RlY29kZS1kYXRhLXhtbC5qcyIsIm5vZGVfbW9kdWxlcy9lbnRpdGllcy9saWIvZGVjb2RlX2NvZGVwb2ludC5qcyIsIm5vZGVfbW9kdWxlcy9lbnRpdGllcy9saWIvZGVjb2RlLmpzIiwibm9kZV9tb2R1bGVzL2VudGl0aWVzL2xpYi9nZW5lcmF0ZWQvZW5jb2RlLWh0bWwuanMiLCJub2RlX21vZHVsZXMvZW50aXRpZXMvbGliL2VzY2FwZS5qcyIsIm5vZGVfbW9kdWxlcy9lbnRpdGllcy9saWIvZW5jb2RlLmpzIiwibm9kZV9tb2R1bGVzL2VudGl0aWVzL2xpYi9pbmRleC5qcyIsIm5vZGVfbW9kdWxlcy9kb20tc2VyaWFsaXplci9saWIvZm9yZWlnbk5hbWVzLmpzIiwibm9kZV9tb2R1bGVzL2RvbS1zZXJpYWxpemVyL2xpYi9pbmRleC5qcyIsIm5vZGVfbW9kdWxlcy9kb211dGlscy9saWIvc3RyaW5naWZ5LmpzIiwibm9kZV9tb2R1bGVzL2RvbXV0aWxzL2xpYi90cmF2ZXJzYWwuanMiLCJub2RlX21vZHVsZXMvZG9tdXRpbHMvbGliL21hbmlwdWxhdGlvbi5qcyIsIm5vZGVfbW9kdWxlcy9kb211dGlscy9saWIvcXVlcnlpbmcuanMiLCJub2RlX21vZHVsZXMvZG9tdXRpbHMvbGliL2xlZ2FjeS5qcyIsIm5vZGVfbW9kdWxlcy9kb211dGlscy9saWIvaGVscGVycy5qcyIsIm5vZGVfbW9kdWxlcy9kb211dGlscy9saWIvZmVlZHMuanMiLCJub2RlX21vZHVsZXMvZG9tdXRpbHMvbGliL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2NoZWVyaW8vbGliL3N0YXRpYy5qcyIsIm5vZGVfbW9kdWxlcy9jaGVlcmlvL2xpYi91dGlscy5qcyIsIm5vZGVfbW9kdWxlcy9jaGVlcmlvL2xpYi9hcGkvYXR0cmlidXRlcy5qcyIsIm5vZGVfbW9kdWxlcy9jc3Mtd2hhdC9saWIvZXMvdHlwZXMuanMiLCJub2RlX21vZHVsZXMvY3NzLXdoYXQvbGliL2VzL3BhcnNlLmpzIiwibm9kZV9tb2R1bGVzL2Nzcy13aGF0L2xpYi9lcy9zdHJpbmdpZnkuanMiLCJub2RlX21vZHVsZXMvYm9vbGJhc2UvaW5kZXguanMiLCJub2RlX21vZHVsZXMvY3NzLXNlbGVjdC9saWIvc29ydC5qcyIsIm5vZGVfbW9kdWxlcy9jc3Mtc2VsZWN0L2xpYi9hdHRyaWJ1dGVzLmpzIiwibm9kZV9tb2R1bGVzL250aC1jaGVjay9saWIvcGFyc2UuanMiLCJub2RlX21vZHVsZXMvbnRoLWNoZWNrL2xpYi9jb21waWxlLmpzIiwibm9kZV9tb2R1bGVzL250aC1jaGVjay9saWIvaW5kZXguanMiLCJub2RlX21vZHVsZXMvY3NzLXNlbGVjdC9saWIvcHNldWRvLXNlbGVjdG9ycy9maWx0ZXJzLmpzIiwibm9kZV9tb2R1bGVzL2Nzcy1zZWxlY3QvbGliL3BzZXVkby1zZWxlY3RvcnMvcHNldWRvcy5qcyIsIm5vZGVfbW9kdWxlcy9jc3Mtc2VsZWN0L2xpYi9wc2V1ZG8tc2VsZWN0b3JzL2FsaWFzZXMuanMiLCJub2RlX21vZHVsZXMvY3NzLXNlbGVjdC9saWIvcHNldWRvLXNlbGVjdG9ycy9zdWJzZWxlY3RzLmpzIiwibm9kZV9tb2R1bGVzL2Nzcy1zZWxlY3QvbGliL3BzZXVkby1zZWxlY3RvcnMvaW5kZXguanMiLCJub2RlX21vZHVsZXMvY3NzLXNlbGVjdC9saWIvZ2VuZXJhbC5qcyIsIm5vZGVfbW9kdWxlcy9jc3Mtc2VsZWN0L2xpYi9jb21waWxlLmpzIiwibm9kZV9tb2R1bGVzL2Nzcy1zZWxlY3QvbGliL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2NoZWVyaW8tc2VsZWN0L2xpYi9wb3NpdGlvbmFscy5qcyIsIm5vZGVfbW9kdWxlcy9jaGVlcmlvLXNlbGVjdC9saWIvaGVscGVycy5qcyIsIm5vZGVfbW9kdWxlcy9jaGVlcmlvLXNlbGVjdC9saWIvaW5kZXguanMiLCJub2RlX21vZHVsZXMvY2hlZXJpby9saWIvYXBpL3RyYXZlcnNpbmcuanMiLCJub2RlX21vZHVsZXMvY2hlZXJpby9saWIvcGFyc2UuanMiLCJub2RlX21vZHVsZXMvY2hlZXJpby9saWIvYXBpL21hbmlwdWxhdGlvbi5qcyIsIm5vZGVfbW9kdWxlcy9jaGVlcmlvL2xpYi9hcGkvY3NzLmpzIiwibm9kZV9tb2R1bGVzL2NoZWVyaW8vbGliL2FwaS9mb3Jtcy5qcyIsIm5vZGVfbW9kdWxlcy9jaGVlcmlvL2xpYi9jaGVlcmlvLmpzIiwibm9kZV9tb2R1bGVzL2NoZWVyaW8vbGliL2xvYWQuanMiLCJub2RlX21vZHVsZXMvY2hlZXJpby9ub2RlX21vZHVsZXMvcGFyc2U1L2Rpc3QvY2pzL2NvbW1vbi91bmljb2RlLmpzIiwibm9kZV9tb2R1bGVzL2NoZWVyaW8vbm9kZV9tb2R1bGVzL3BhcnNlNS9kaXN0L2Nqcy9jb21tb24vZXJyb3ItY29kZXMuanMiLCJub2RlX21vZHVsZXMvY2hlZXJpby9ub2RlX21vZHVsZXMvcGFyc2U1L2Rpc3QvY2pzL3Rva2VuaXplci9wcmVwcm9jZXNzb3IuanMiLCJub2RlX21vZHVsZXMvY2hlZXJpby9ub2RlX21vZHVsZXMvcGFyc2U1L2Rpc3QvY2pzL2NvbW1vbi90b2tlbi5qcyIsIm5vZGVfbW9kdWxlcy9jaGVlcmlvL25vZGVfbW9kdWxlcy9wYXJzZTUvZGlzdC9janMvY29tbW9uL2h0bWwuanMiLCJub2RlX21vZHVsZXMvY2hlZXJpby9ub2RlX21