您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
monkeygpt
当前为
// ==UserScript== // @name monkey-gpt // @namespace monkeygpt // @version 0.0.2 // @author monkey // @icon https://jisuai.cn/logo.png // @match *://*/* // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.global.prod.js // @grant GM_addStyle // @description monkeygpt // ==/UserScript== (e => { if (typeof GM_addStyle == "function") { GM_addStyle(e); return } const t = document.createElement("style"); t.textContent = e, document.head.append(t) })(" :root{font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-text-size-adjust:100%}#monkeygpt{position:fixed;top:0;right:0;z-index:10000;font-size:14px;line-height:2rem}#monkeygpt xmp,#monkeygpt pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}#monkeygpt .loader{border:8px solid #f3f3f3;border-top:8px solid #3498db;border-radius:50%;width:60px;height:60px;animation:spin 1s linear infinite}.monkeygpt-card{position:absolute;top:30vh;right:0;border-radius:.5rem}.monkeygpt-card button{border:none;background:#3b5998;text-decoration:none;font-weight:700;color:#fff;cursor:pointer;width:auto;overflow:visible;padding:6px;font-size:14px;line-height:1.5rem;font-family:Lucida Grande,Tahoma,Arial,Verdana,sans-serif;border-radius:.1rem}.monkeygpt-warp{background-color:#fffc;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);width:30vw;height:100vh;margin:0 auto;box-shadow:-4px 4px 6px #0000001a;overflow:auto}.monkeygpt-warp .monkeygpt-card{top:0;padding:1.5rem;width:100%;box-sizing:border-box}.monkeygpt-warp .monkeygpt-card button{padding:4px 15px;margin-right:8px;border-radius:2px;box-shadow:0 2px #0000000b}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@media screen and (max-width: 1560px){.monkeygpt-warp{width:50vw}}@media screen and (max-width: 720px){.monkeygpt-warp{width:100vw}}@media (prefers-color-scheme: light){:root{color:#213547;background-color:#fff}}.monkeygpt-body[data-v-b0fd14ee]{margin-top:1rem}h3[data-v-b0fd14ee]{display:flex;align-content:center;margin-bottom:1rem}h3 img[data-v-b0fd14ee]{margin-left:1rem}.close[data-v-b0fd14ee]{width:1.5rem;cursor:pointer}.nav[data-v-b0fd14ee]{display:flex;justify-content:space-between}.loading[data-v-b0fd14ee]{width:3rem} "); (function (vue) { 'use strict'; var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); var Readability$1 = { exports: {} }; (function (module) { function Readability2(doc, options) { if (options && options.documentElement) { doc = options; options = arguments[2]; } else if (!doc || !doc.documentElement) { throw new Error("First argument to Readability constructor should be a document object."); } options = options || {}; this._doc = doc; this._docJSDOMParser = this._doc.firstChild.__JSDOMParser__; this._articleTitle = null; this._articleByline = null; this._articleDir = null; this._articleSiteName = null; this._attempts = []; this._debug = !!options.debug; this._maxElemsToParse = options.maxElemsToParse || this.DEFAULT_MAX_ELEMS_TO_PARSE; this._nbTopCandidates = options.nbTopCandidates || this.DEFAULT_N_TOP_CANDIDATES; this._charThreshold = options.charThreshold || this.DEFAULT_CHAR_THRESHOLD; this._classesToPreserve = this.CLASSES_TO_PRESERVE.concat(options.classesToPreserve || []); this._keepClasses = !!options.keepClasses; this._serializer = options.serializer || function (el) { return el.innerHTML; }; this._disableJSONLD = !!options.disableJSONLD; this._allowedVideoRegex = options.allowedVideoRegex || this.REGEXPS.videos; this._flags = this.FLAG_STRIP_UNLIKELYS | this.FLAG_WEIGHT_CLASSES | this.FLAG_CLEAN_CONDITIONALLY; if (this._debug) { let logNode = function (node) { if (node.nodeType == node.TEXT_NODE) { return `${node.nodeName} ("${node.textContent}")`; } let attrPairs = Array.from(node.attributes || [], function (attr) { return `${attr.name}="${attr.value}"`; }).join(" "); return `<${node.localName} ${attrPairs}>`; }; this.log = function () { if (typeof console !== "undefined") { let args = Array.from(arguments, (arg) => { if (arg && arg.nodeType == this.ELEMENT_NODE) { return logNode(arg); } return arg; }); args.unshift("Reader: (Readability)"); console.log.apply(console, args); } else if (typeof dump !== "undefined") { var msg = Array.prototype.map.call(arguments, function (x) { return x && x.nodeName ? logNode(x) : x; }).join(" "); dump("Reader: (Readability) " + msg + "\n"); } }; } else { this.log = function () {}; } } Readability2.prototype = { FLAG_STRIP_UNLIKELYS: 1, FLAG_WEIGHT_CLASSES: 2, FLAG_CLEAN_CONDITIONALLY: 4, // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType ELEMENT_NODE: 1, TEXT_NODE: 3, // Max number of nodes supported by this parser. Default: 0 (no limit) DEFAULT_MAX_ELEMS_TO_PARSE: 0, // The number of top candidates to consider when analysing how // tight the competition is among candidates. DEFAULT_N_TOP_CANDIDATES: 5, // Element tags to score by default. DEFAULT_TAGS_TO_SCORE: "section,h2,h3,h4,h5,h6,p,td,pre".toUpperCase().split(","), // The default number of chars an article must have in order to return a result DEFAULT_CHAR_THRESHOLD: 500, // All of the regular expressions in use within readability. // Defined up here so we don't instantiate them repeatedly in loops. REGEXPS: { // NOTE: These two regular expressions are duplicated in // Readability-readerable.js. Please keep both copies in sync. unlikelyCandidates: /-ad-|ai2html|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|footer|gdpr|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i, okMaybeItsACandidate: /and|article|body|column|content|main|shadow/i, positive: /article|body|content|entry|hentry|h-entry|main|page|pagination|post|text|blog|story/i, negative: /-ad-|hidden|^hid$| hid$| hid |^hid |banner|combx|comment|com-|contact|foot|footer|footnote|gdpr|masthead|media|meta|outbrain|promo|related|scroll|share|shoutbox|sidebar|skyscraper|sponsor|shopping|tags|tool|widget/i, extraneous: /print|archive|comment|discuss|e[\-]?mail|share|reply|all|login|sign|single|utility/i, byline: /byline|author|dateline|writtenby|p-author/i, replaceFonts: /<(\/?)font[^>]*>/gi, normalize: /\s{2,}/g, videos: /\/\/(www\.)?((dailymotion|youtube|youtube-nocookie|player\.vimeo|v\.qq)\.com|(archive|upload\.wikimedia)\.org|player\.twitch\.tv)/i, shareElements: /(\b|_)(share|sharedaddy)(\b|_)/i, nextLink: /(next|weiter|continue|>([^\|]|$)|»([^\|]|$))/i, prevLink: /(prev|earl|old|new|<|«)/i, tokenize: /\W+/g, whitespace: /^\s*$/, hasContent: /\S$/, hashUrl: /^#.+/, srcsetUrl: /(\S+)(\s+[\d.]+[xw])?(\s*(?:,|$))/g, b64DataUrl: /^data:\s*([^\s;,]+)\s*;\s*base64\s*,/i, // Commas as used in Latin, Sindhi, Chinese and various other scripts. // see: https://en.wikipedia.org/wiki/Comma#Comma_variants commas: /\u002C|\u060C|\uFE50|\uFE10|\uFE11|\u2E41|\u2E34|\u2E32|\uFF0C/g, // See: https://schema.org/Article jsonLdArticleTypes: /^Article|AdvertiserContentArticle|NewsArticle|AnalysisNewsArticle|AskPublicNewsArticle|BackgroundNewsArticle|OpinionNewsArticle|ReportageNewsArticle|ReviewNewsArticle|Report|SatiricalArticle|ScholarlyArticle|MedicalScholarlyArticle|SocialMediaPosting|BlogPosting|LiveBlogPosting|DiscussionForumPosting|TechArticle|APIReference$/ }, UNLIKELY_ROLES: ["menu", "menubar", "complementary", "navigation", "alert", "alertdialog", "dialog"], DIV_TO_P_ELEMS: /* @__PURE__ */ new Set(["BLOCKQUOTE", "DL", "DIV", "IMG", "OL", "P", "PRE", "TABLE", "UL"]), ALTER_TO_DIV_EXCEPTIONS: ["DIV", "ARTICLE", "SECTION", "P"], PRESENTATIONAL_ATTRIBUTES: ["align", "background", "bgcolor", "border", "cellpadding", "cellspacing", "frame", "hspace", "rules", "style", "valign", "vspace"], DEPRECATED_SIZE_ATTRIBUTE_ELEMS: ["TABLE", "TH", "TD", "HR", "PRE"], // The commented out elements qualify as phrasing content but tend to be // removed by readability when put into paragraphs, so we ignore them here. PHRASING_ELEMS: [ // "CANVAS", "IFRAME", "SVG", "VIDEO", "ABBR", "AUDIO", "B", "BDO", "BR", "BUTTON", "CITE", "CODE", "DATA", "DATALIST", "DFN", "EM", "EMBED", "I", "IMG", "INPUT", "KBD", "LABEL", "MARK", "MATH", "METER", "NOSCRIPT", "OBJECT", "OUTPUT", "PROGRESS", "Q", "RUBY", "SAMP", "SCRIPT", "SELECT", "SMALL", "SPAN", "STRONG", "SUB", "SUP", "TEXTAREA", "TIME", "VAR", "WBR" ], // These are the classes that readability sets itself. CLASSES_TO_PRESERVE: ["page"], // These are the list of HTML entities that need to be escaped. HTML_ESCAPE_MAP: { "lt": "<", "gt": ">", "amp": "&", "quot": '"', "apos": "'" }, /** * Run any post-process modifications to article content as necessary. * * @param Element * @return void **/ _postProcessContent: function (articleContent) { this._fixRelativeUris(articleContent); this._simplifyNestedElements(articleContent); if (!this._keepClasses) { this._cleanClasses(articleContent); } }, /** * Iterates over a NodeList, calls `filterFn` for each node and removes node * if function returned `true`. * * If function is not passed, removes all the nodes in node list. * * @param NodeList nodeList The nodes to operate on * @param Function filterFn the function to use as a filter * @return void */ _removeNodes: function (nodeList, filterFn) { if (this._docJSDOMParser && nodeList._isLiveNodeList) { throw new Error("Do not pass live node lists to _removeNodes"); } for (var i = nodeList.length - 1; i >= 0; i--) { var node = nodeList[i]; var parentNode = node.parentNode; if (parentNode) { if (!filterFn || filterFn.call(this, node, i, nodeList)) { parentNode.removeChild(node); } } } }, /** * Iterates over a NodeList, and calls _setNodeTag for each node. * * @param NodeList nodeList The nodes to operate on * @param String newTagName the new tag name to use * @return void */ _replaceNodeTags: function (nodeList, newTagName) { if (this._docJSDOMParser && nodeList._isLiveNodeList) { throw new Error("Do not pass live node lists to _replaceNodeTags"); } for (const node of nodeList) { this._setNodeTag(node, newTagName); } }, /** * Iterate over a NodeList, which doesn't natively fully implement the Array * interface. * * For convenience, the current object context is applied to the provided * iterate function. * * @param NodeList nodeList The NodeList. * @param Function fn The iterate function. * @return void */ _forEachNode: function (nodeList, fn) { Array.prototype.forEach.call(nodeList, fn, this); }, /** * Iterate over a NodeList, and return the first node that passes * the supplied test function * * For convenience, the current object context is applied to the provided * test function. * * @param NodeList nodeList The NodeList. * @param Function fn The test function. * @return void */ _findNode: function (nodeList, fn) { return Array.prototype.find.call(nodeList, fn, this); }, /** * Iterate over a NodeList, return true if any of the provided iterate * function calls returns true, false otherwise. * * For convenience, the current object context is applied to the * provided iterate function. * * @param NodeList nodeList The NodeList. * @param Function fn The iterate function. * @return Boolean */ _someNode: function (nodeList, fn) { return Array.prototype.some.call(nodeList, fn, this); }, /** * Iterate over a NodeList, return true if all of the provided iterate * function calls return true, false otherwise. * * For convenience, the current object context is applied to the * provided iterate function. * * @param NodeList nodeList The NodeList. * @param Function fn The iterate function. * @return Boolean */ _everyNode: function (nodeList, fn) { return Array.prototype.every.call(nodeList, fn, this); }, /** * Concat all nodelists passed as arguments. * * @return ...NodeList * @return Array */ _concatNodeLists: function () { var slice = Array.prototype.slice; var args = slice.call(arguments); var nodeLists = args.map(function (list2) { return slice.call(list2); }); return Array.prototype.concat.apply([], nodeLists); }, _getAllNodesWithTag: function (node, tagNames) { if (node.querySelectorAll) { return node.querySelectorAll(tagNames.join(",")); } return [].concat.apply([], tagNames.map(function (tag2) { var collection = node.getElementsByTagName(tag2); return Array.isArray(collection) ? collection : Array.from(collection); })); }, /** * Removes the class="" attribute from every element in the given * subtree, except those that match CLASSES_TO_PRESERVE and * the classesToPreserve array from the options object. * * @param Element * @return void */ _cleanClasses: function (node) { var classesToPreserve = this._classesToPreserve; var className = (node.getAttribute("class") || "").split(/\s+/).filter(function (cls) { return classesToPreserve.indexOf(cls) != -1; }).join(" "); if (className) { node.setAttribute("class", className); } else { node.removeAttribute("class"); } for (node = node.firstElementChild; node; node = node.nextElementSibling) { this._cleanClasses(node); } }, /** * Converts each <a> and <img> uri in the given element to an absolute URI, * ignoring #ref URIs. * * @param Element * @return void */ _fixRelativeUris: function (articleContent) { var baseURI = this._doc.baseURI; var documentURI = this._doc.documentURI; function toAbsoluteURI(uri) { if (baseURI == documentURI && uri.charAt(0) == "#") { return uri; } try { return new URL(uri, baseURI).href; } catch (ex) {} return uri; } var links = this._getAllNodesWithTag(articleContent, ["a"]); this._forEachNode(links, function (link2) { var href = link2.getAttribute("href"); if (href) { if (href.indexOf("javascript:") === 0) { if (link2.childNodes.length === 1 && link2.childNodes[0].nodeType === this.TEXT_NODE) { var text = this._doc.createTextNode(link2.textContent); link2.parentNode.replaceChild(text, link2); } else { var container = this._doc.createElement("span"); while (link2.firstChild) { container.appendChild(link2.firstChild); } link2.parentNode.replaceChild(container, link2); } } else { link2.setAttribute("href", toAbsoluteURI(href)); } } }); var medias = this._getAllNodesWithTag(articleContent, [ "img", "picture", "figure", "video", "audio", "source" ]); this._forEachNode(medias, function (media) { var src = media.getAttribute("src"); var poster = media.getAttribute("poster"); var srcset = media.getAttribute("srcset"); if (src) { media.setAttribute("src", toAbsoluteURI(src)); } if (poster) { media.setAttribute("poster", toAbsoluteURI(poster)); } if (srcset) { var newSrcset = srcset.replace(this.REGEXPS.srcsetUrl, function (_, p1, p2, p3) { return toAbsoluteURI(p1) + (p2 || "") + p3; }); media.setAttribute("srcset", newSrcset); } }); }, _simplifyNestedElements: function (articleContent) { var node = articleContent; while (node) { if (node.parentNode && ["DIV", "SECTION"].includes(node.tagName) && !(node.id && node.id.startsWith("readability"))) { if (this._isElementWithoutContent(node)) { node = this._removeAndGetNext(node); continue; } else if (this._hasSingleTagInsideElement(node, "DIV") || this._hasSingleTagInsideElement(node, "SECTION")) { var child = node.children[0]; for (var i = 0; i < node.attributes.length; i++) { child.setAttribute(node.attributes[i].name, node.attributes[i].value); } node.parentNode.replaceChild(child, node); node = child; continue; } } node = this._getNextNode(node); } }, /** * Get the article title as an H1. * * @return string **/ _getArticleTitle: function () { var doc = this._doc; var curTitle = ""; var origTitle = ""; try { curTitle = origTitle = doc.title.trim(); if (typeof curTitle !== "string") curTitle = origTitle = this._getInnerText(doc.getElementsByTagName("title")[0]); } catch (e) {} var titleHadHierarchicalSeparators = false; function wordCount(str) { return str.split(/\s+/).length; } if (/ [\|\-\\\/>»] /.test(curTitle)) { titleHadHierarchicalSeparators = / [\\\/>»] /.test(curTitle); curTitle = origTitle.replace(/(.*)[\|\-\\\/>»] .*/gi, "$1"); if (wordCount(curTitle) < 3) curTitle = origTitle.replace(/[^\|\-\\\/>»]*[\|\-\\\/>»](.*)/gi, "$1"); } else if (curTitle.indexOf(": ") !== -1) { var headings = this._concatNodeLists( doc.getElementsByTagName("h1"), doc.getElementsByTagName("h2") ); var trimmedTitle = curTitle.trim(); var match = this._someNode(headings, function (heading2) { return heading2.textContent.trim() === trimmedTitle; }); if (!match) { curTitle = origTitle.substring(origTitle.lastIndexOf(":") + 1); if (wordCount(curTitle) < 3) { curTitle = origTitle.substring(origTitle.indexOf(":") + 1); } else if (wordCount(origTitle.substr(0, origTitle.indexOf(":"))) > 5) { curTitle = origTitle; } } } else if (curTitle.length > 150 || curTitle.length < 15) { var hOnes = doc.getElementsByTagName("h1"); if (hOnes.length === 1) curTitle = this._getInnerText(hOnes[0]); } curTitle = curTitle.trim().replace(this.REGEXPS.normalize, " "); var curTitleWordCount = wordCount(curTitle); if (curTitleWordCount <= 4 && (!titleHadHierarchicalSeparators || curTitleWordCount != wordCount(origTitle.replace(/[\|\-\\\/>»]+/g, "")) - 1)) { curTitle = origTitle; } return curTitle; }, /** * Prepare the HTML document for readability to scrape it. * This includes things like stripping javascript, CSS, and handling terrible markup. * * @return void **/ _prepDocument: function () { var doc = this._doc; this._removeNodes(this._getAllNodesWithTag(doc, ["style"])); if (doc.body) { this._replaceBrs(doc.body); } this._replaceNodeTags(this._getAllNodesWithTag(doc, ["font"]), "SPAN"); }, /** * Finds the next node, starting from the given node, and ignoring * whitespace in between. If the given node is an element, the same node is * returned. */ _nextNode: function (node) { var next = node; while (next && next.nodeType != this.ELEMENT_NODE && this.REGEXPS.whitespace.test(next.textContent)) { next = next.nextSibling; } return next; }, /** * Replaces 2 or more successive <br> elements with a single <p>. * Whitespace between <br> elements are ignored. For example: * <div>foo<br>bar<br> <br><br>abc</div> * will become: * <div>foo<br>bar<p>abc</p></div> */ _replaceBrs: function (elem) { this._forEachNode(this._getAllNodesWithTag(elem, ["br"]), function (br2) { var next = br2.nextSibling; var replaced = false; while ((next = this._nextNode(next)) && next.tagName == "BR") { replaced = true; var brSibling = next.nextSibling; next.parentNode.removeChild(next); next = brSibling; } if (replaced) { var p = this._doc.createElement("p"); br2.parentNode.replaceChild(p, br2); next = p.nextSibling; while (next) { if (next.tagName == "BR") { var nextElem = this._nextNode(next.nextSibling); if (nextElem && nextElem.tagName == "BR") break; } if (!this._isPhrasingContent(next)) break; var sibling = next.nextSibling; p.appendChild(next); next = sibling; } while (p.lastChild && this._isWhitespace(p.lastChild)) { p.removeChild(p.lastChild); } if (p.parentNode.tagName === "P") this._setNodeTag(p.parentNode, "DIV"); } }); }, _setNodeTag: function (node, tag2) { this.log("_setNodeTag", node, tag2); if (this._docJSDOMParser) { node.localName = tag2.toLowerCase(); node.tagName = tag2.toUpperCase(); return node; } var replacement = node.ownerDocument.createElement(tag2); while (node.firstChild) { replacement.appendChild(node.firstChild); } node.parentNode.replaceChild(replacement, node); if (node.readability) replacement.readability = node.readability; for (var i = 0; i < node.attributes.length; i++) { try { replacement.setAttribute(node.attributes[i].name, node.attributes[i].value); } catch (ex) {} } return replacement; }, /** * Prepare the article node for display. Clean out any inline styles, * iframes, forms, strip extraneous <p> tags, etc. * * @param Element * @return void **/ _prepArticle: function (articleContent) { this._cleanStyles(articleContent); this._markDataTables(articleContent); this._fixLazyImages(articleContent); this._cleanConditionally(articleContent, "form"); this._cleanConditionally(articleContent, "fieldset"); this._clean(articleContent, "object"); this._clean(articleContent, "embed"); this._clean(articleContent, "footer"); this._clean(articleContent, "link"); this._clean(articleContent, "aside"); var shareElementThreshold = this.DEFAULT_CHAR_THRESHOLD; this._forEachNode(articleContent.children, function (topCandidate) { this._cleanMatchedNodes(topCandidate, function (node, matchString) { return this.REGEXPS.shareElements.test(matchString) && node.textContent.length < shareElementThreshold; }); }); this._clean(articleContent, "iframe"); this._clean(articleContent, "input"); this._clean(articleContent, "textarea"); this._clean(articleContent, "select"); this._clean(articleContent, "button"); this._cleanHeaders(articleContent); this._cleanConditionally(articleContent, "table"); this._cleanConditionally(articleContent, "ul"); this._cleanConditionally(articleContent, "div"); this._replaceNodeTags(this._getAllNodesWithTag(articleContent, ["h1"]), "h2"); this._removeNodes(this._getAllNodesWithTag(articleContent, ["p"]), function (paragraph2) { var imgCount = paragraph2.getElementsByTagName("img").length; var embedCount = paragraph2.getElementsByTagName("embed").length; var objectCount = paragraph2.getElementsByTagName("object").length; var iframeCount = paragraph2.getElementsByTagName("iframe").length; var totalCount = imgCount + embedCount + objectCount + iframeCount; return totalCount === 0 && !this._getInnerText(paragraph2, false); }); this._forEachNode(this._getAllNodesWithTag(articleContent, ["br"]), function (br2) { var next = this._nextNode(br2.nextSibling); if (next && next.tagName == "P") br2.parentNode.removeChild(br2); }); this._forEachNode(this._getAllNodesWithTag(articleContent, ["table"]), function (table) { var tbody = this._hasSingleTagInsideElement(table, "TBODY") ? table.firstElementChild : table; if (this._hasSingleTagInsideElement(tbody, "TR")) { var row = tbody.firstElementChild; if (this._hasSingleTagInsideElement(row, "TD")) { var cell = row.firstElementChild; cell = this._setNodeTag(cell, this._everyNode(cell.childNodes, this._isPhrasingContent) ? "P" : "DIV"); table.parentNode.replaceChild(cell, table); } } }); }, /** * Initialize a node with the readability object. Also checks the * className/id for special names to add to its score. * * @param Element * @return void **/ _initializeNode: function (node) { node.readability = { "contentScore": 0 }; switch (node.tagName) { case "DIV": node.readability.contentScore += 5; break; case "PRE": case "TD": case "BLOCKQUOTE": node.readability.contentScore += 3; break; case "ADDRESS": case "OL": case "UL": case "DL": case "DD": case "DT": case "LI": case "FORM": node.readability.contentScore -= 3; break; case "H1": case "H2": case "H3": case "H4": case "H5": case "H6": case "TH": node.readability.contentScore -= 5; break; } node.readability.contentScore += this._getClassWeight(node); }, _removeAndGetNext: function (node) { var nextNode = this._getNextNode(node, true); node.parentNode.removeChild(node); return nextNode; }, /** * Traverse the DOM from node to node, starting at the node passed in. * Pass true for the second parameter to indicate this node itself * (and its kids) are going away, and we want the next node over. * * Calling this in a loop will traverse the DOM depth-first. */ _getNextNode: function (node, ignoreSelfAndKids) { if (!ignoreSelfAndKids && node.firstElementChild) { return node.firstElementChild; } if (node.nextElementSibling) { return node.nextElementSibling; } do { node = node.parentNode; } while (node && !node.nextElementSibling); return node && node.nextElementSibling; }, // compares second text to first one // 1 = same text, 0 = completely different text // works the way that it splits both texts into words and then finds words that are unique in second text // the result is given by the lower length of unique parts _textSimilarity: function (textA, textB) { var tokensA = textA.toLowerCase().split(this.REGEXPS.tokenize).filter(Boolean); var tokensB = textB.toLowerCase().split(this.REGEXPS.tokenize).filter(Boolean); if (!tokensA.length || !tokensB.length) { return 0; } var uniqTokensB = tokensB.filter((token) => !tokensA.includes(token)); var distanceB = uniqTokensB.join(" ").length / tokensB.join(" ").length; return 1 - distanceB; }, _checkByline: function (node, matchString) { if (this._articleByline) { return false; } if (node.getAttribute !== void 0) { var rel = node.getAttribute("rel"); var itemprop = node.getAttribute("itemprop"); } if ((rel === "author" || itemprop && itemprop.indexOf("author") !== -1 || this.REGEXPS.byline.test(matchString)) && this._isValidByline(node.textContent)) { this._articleByline = node.textContent.trim(); return true; } return false; }, _getNodeAncestors: function (node, maxDepth) { maxDepth = maxDepth || 0; var i = 0, ancestors = []; while (node.parentNode) { ancestors.push(node.parentNode); if (maxDepth && ++i === maxDepth) break; node = node.parentNode; } return ancestors; }, /*** * grabArticle - Using a variety of metrics (content score, classname, element types), find the content that is * most likely to be the stuff a user wants to read. Then return it wrapped up in a div. * * @param page a document to run upon. Needs to be a full document, complete with body. * @return Element **/ _grabArticle: function (page) { this.log("**** grabArticle ****"); var doc = this._doc; var isPaging = page !== null; page = page ? page : this._doc.body; if (!page) { this.log("No body found in document. Abort."); return null; } var pageCacheHtml = page.innerHTML; while (true) { this.log("Starting grabArticle loop"); var stripUnlikelyCandidates = this._flagIsActive(this.FLAG_STRIP_UNLIKELYS); var elementsToScore = []; var node = this._doc.documentElement; let shouldRemoveTitleHeader = true; while (node) { if (node.tagName === "HTML") { this._articleLang = node.getAttribute("lang"); } var matchString = node.className + " " + node.id; if (!this._isProbablyVisible(node)) { this.log("Removing hidden node - " + matchString); node = this._removeAndGetNext(node); continue; } if (node.getAttribute("aria-modal") == "true" && node.getAttribute("role") == "dialog") { node = this._removeAndGetNext(node); continue; } if (this._checkByline(node, matchString)) { node = this._removeAndGetNext(node); continue; } if (shouldRemoveTitleHeader && this._headerDuplicatesTitle(node)) { this.log("Removing header: ", node.textContent.trim(), this._articleTitle.trim()); shouldRemoveTitleHeader = false; node = this._removeAndGetNext(node); continue; } if (stripUnlikelyCandidates) { if (this.REGEXPS.unlikelyCandidates.test(matchString) && !this.REGEXPS.okMaybeItsACandidate.test(matchString) && !this._hasAncestorTag(node, "table") && !this._hasAncestorTag(node, "code") && node.tagName !== "BODY" && node.tagName !== "A") { this.log("Removing unlikely candidate - " + matchString); node = this._removeAndGetNext(node); continue; } if (this.UNLIKELY_ROLES.includes(node.getAttribute("role"))) { this.log("Removing content with role " + node.getAttribute("role") + " - " + matchString); node = this._removeAndGetNext(node); continue; } } if ((node.tagName === "DIV" || node.tagName === "SECTION" || node.tagName === "HEADER" || node.tagName === "H1" || node.tagName === "H2" || node.tagName === "H3" || node.tagName === "H4" || node.tagName === "H5" || node.tagName === "H6") && this._isElementWithoutContent(node)) { node = this._removeAndGetNext(node); continue; } if (this.DEFAULT_TAGS_TO_SCORE.indexOf(node.tagName) !== -1) { elementsToScore.push(node); } if (node.tagName === "DIV") { var p = null; var childNode = node.firstChild; while (childNode) { var nextSibling = childNode.nextSibling; if (this._isPhrasingContent(childNode)) { if (p !== null) { p.appendChild(childNode); } else if (!this._isWhitespace(childNode)) { p = doc.createElement("p"); node.replaceChild(p, childNode); p.appendChild(childNode); } } else if (p !== null) { while (p.lastChild && this._isWhitespace(p.lastChild)) { p.removeChild(p.lastChild); } p = null; } childNode = nextSibling; } if (this._hasSingleTagInsideElement(node, "P") && this._getLinkDensity(node) < 0.25) { var newNode = node.children[0]; node.parentNode.replaceChild(newNode, node); node = newNode; elementsToScore.push(node); } else if (!this._hasChildBlockElement(node)) { node = this._setNodeTag(node, "P"); elementsToScore.push(node); } } node = this._getNextNode(node); } var candidates = []; this._forEachNode(elementsToScore, function (elementToScore) { if (!elementToScore.parentNode || typeof elementToScore.parentNode.tagName === "undefined") return; var innerText = this._getInnerText(elementToScore); if (innerText.length < 25) return; var ancestors2 = this._getNodeAncestors(elementToScore, 5); if (ancestors2.length === 0) return; var contentScore = 0; contentScore += 1; contentScore += innerText.split(this.REGEXPS.commas).length; contentScore += Math.min(Math.floor(innerText.length / 100), 3); this._forEachNode(ancestors2, function (ancestor, level) { if (!ancestor.tagName || !ancestor.parentNode || typeof ancestor.parentNode.tagName === "undefined") return; if (typeof ancestor.readability === "undefined") { this._initializeNode(ancestor); candidates.push(ancestor); } if (level === 0) var scoreDivider = 1; else if (level === 1) scoreDivider = 2; else scoreDivider = level * 3; ancestor.readability.contentScore += contentScore / scoreDivider; }); }); var topCandidates = []; for (var c = 0, cl = candidates.length; c < cl; c += 1) { var candidate = candidates[c]; var candidateScore = candidate.readability.contentScore * (1 - this._getLinkDensity(candidate)); candidate.readability.contentScore = candidateScore; this.log("Candidate:", candidate, "with score " + candidateScore); for (var t = 0; t < this._nbTopCandidates; t++) { var aTopCandidate = topCandidates[t]; if (!aTopCandidate || candidateScore > aTopCandidate.readability.contentScore) { topCandidates.splice(t, 0, candidate); if (topCandidates.length > this._nbTopCandidates) topCandidates.pop(); break; } } } var topCandidate = topCandidates[0] || null; var neededToCreateTopCandidate = false; var parentOfTopCandidate; if (topCandidate === null || topCandidate.tagName === "BODY") { topCandidate = doc.createElement("DIV"); neededToCreateTopCandidate = true; while (page.firstChild) { this.log("Moving child out:", page.firstChild); topCandidate.appendChild(page.firstChild); } page.appendChild(topCandidate); this._initializeNode(topCandidate); } else if (topCandidate) { var alternativeCandidateAncestors = []; for (var i = 1; i < topCandidates.length; i++) { if (topCandidates[i].readability.contentScore / topCandidate.readability.contentScore >= 0.75) { alternativeCandidateAncestors.push(this._getNodeAncestors(topCandidates[i])); } } var MINIMUM_TOPCANDIDATES = 3; if (alternativeCandidateAncestors.length >= MINIMUM_TOPCANDIDATES) { parentOfTopCandidate = topCandidate.parentNode; while (parentOfTopCandidate.tagName !== "BODY") { var listsContainingThisAncestor = 0; for (var ancestorIndex = 0; ancestorIndex < alternativeCandidateAncestors.length && listsContainingThisAncestor < MINIMUM_TOPCANDIDATES; ancestorIndex++) { listsContainingThisAncestor += Number(alternativeCandidateAncestors[ancestorIndex].includes(parentOfTopCandidate)); } if (listsContainingThisAncestor >= MINIMUM_TOPCANDIDATES) { topCandidate = parentOfTopCandidate; break; } parentOfTopCandidate = parentOfTopCandidate.parentNode; } } if (!topCandidate.readability) { this._initializeNode(topCandidate); } parentOfTopCandidate = topCandidate.parentNode; var lastScore = topCandidate.readability.contentScore; var scoreThreshold = lastScore / 3; while (parentOfTopCandidate.tagName !== "BODY") { if (!parentOfTopCandidate.readability) { parentOfTopCandidate = parentOfTopCandidate.parentNode; continue; } var parentScore = parentOfTopCandidate.readability.contentScore; if (parentScore < scoreThreshold) break; if (parentScore > lastScore) { topCandidate = parentOfTopCandidate; break; } lastScore = parentOfTopCandidate.readability.contentScore; parentOfTopCandidate = parentOfTopCandidate.parentNode; } parentOfTopCandidate = topCandidate.parentNode; while (parentOfTopCandidate.tagName != "BODY" && parentOfTopCandidate.children.length == 1) { topCandidate = parentOfTopCandidate; parentOfTopCandidate = topCandidate.parentNode; } if (!topCandidate.readability) { this._initializeNode(topCandidate); } } var articleContent = doc.createElement("DIV"); if (isPaging) articleContent.id = "readability-content"; var siblingScoreThreshold = Math.max(10, topCandidate.readability.contentScore * 0.2); parentOfTopCandidate = topCandidate.parentNode; var siblings = parentOfTopCandidate.children; for (var s = 0, sl = siblings.length; s < sl; s++) { var sibling = siblings[s]; var append = false; this.log("Looking at sibling node:", sibling, sibling.readability ? "with score " + sibling.readability.contentScore : ""); this.log("Sibling has score", sibling.readability ? sibling.readability.contentScore : "Unknown"); if (sibling === topCandidate) { append = true; } else { var contentBonus = 0; if (sibling.className === topCandidate.className && topCandidate.className !== "") contentBonus += topCandidate.readability.contentScore * 0.2; if (sibling.readability && sibling.readability.contentScore + contentBonus >= siblingScoreThreshold) { append = true; } else if (sibling.nodeName === "P") { var linkDensity = this._getLinkDensity(sibling); var nodeContent = this._getInnerText(sibling); var nodeLength = nodeContent.length; if (nodeLength > 80 && linkDensity < 0.25) { append = true; } else if (nodeLength < 80 && nodeLength > 0 && linkDensity === 0 && nodeContent.search(/\.( |$)/) !== -1) { append = true; } } } if (append) { this.log("Appending node:", sibling); if (this.ALTER_TO_DIV_EXCEPTIONS.indexOf(sibling.nodeName) === -1) { this.log("Altering sibling:", sibling, "to div."); sibling = this._setNodeTag(sibling, "DIV"); } articleContent.appendChild(sibling); siblings = parentOfTopCandidate.children; s -= 1; sl -= 1; } } if (this._debug) this.log("Article content pre-prep: " + articleContent.innerHTML); this._prepArticle(articleContent); if (this._debug) this.log("Article content post-prep: " + articleContent.innerHTML); if (neededToCreateTopCandidate) { topCandidate.id = "readability-page-1"; topCandidate.className = "page"; } else { var div = doc.createElement("DIV"); div.id = "readability-page-1"; div.className = "page"; while (articleContent.firstChild) { div.appendChild(articleContent.firstChild); } articleContent.appendChild(div); } if (this._debug) this.log("Article content after paging: " + articleContent.innerHTML); var parseSuccessful = true; var textLength = this._getInnerText(articleContent, true).length; if (textLength < this._charThreshold) { parseSuccessful = false; page.innerHTML = pageCacheHtml; if (this._flagIsActive(this.FLAG_STRIP_UNLIKELYS)) { this._removeFlag(this.FLAG_STRIP_UNLIKELYS); this._attempts.push({ articleContent, textLength }); } else if (this._flagIsActive(this.FLAG_WEIGHT_CLASSES)) { this._removeFlag(this.FLAG_WEIGHT_CLASSES); this._attempts.push({ articleContent, textLength }); } else if (this._flagIsActive(this.FLAG_CLEAN_CONDITIONALLY)) { this._removeFlag(this.FLAG_CLEAN_CONDITIONALLY); this._attempts.push({ articleContent, textLength }); } else { this._attempts.push({ articleContent, textLength }); this._attempts.sort(function (a, b) { return b.textLength - a.textLength; }); if (!this._attempts[0].textLength) { return null; } articleContent = this._attempts[0].articleContent; parseSuccessful = true; } } if (parseSuccessful) { var ancestors = [parentOfTopCandidate, topCandidate].concat(this._getNodeAncestors(parentOfTopCandidate)); this._someNode(ancestors, function (ancestor) { if (!ancestor.tagName) return false; var articleDir = ancestor.getAttribute("dir"); if (articleDir) { this._articleDir = articleDir; return true; } return false; }); return articleContent; } } }, /** * Check whether the input string could be a byline. * This verifies that the input is a string, and that the length * is less than 100 chars. * * @param possibleByline {string} - a string to check whether its a byline. * @return Boolean - whether the input string is a byline. */ _isValidByline: function (byline) { if (typeof byline == "string" || byline instanceof String) { byline = byline.trim(); return byline.length > 0 && byline.length < 100; } return false; }, /** * Converts some of the common HTML entities in string to their corresponding characters. * * @param str {string} - a string to unescape. * @return string without HTML entity. */ _unescapeHtmlEntities: function (str) { if (!str) { return str; } var htmlEscapeMap = this.HTML_ESCAPE_MAP; return str.replace(/&(quot|amp|apos|lt|gt);/g, function (_, tag2) { return htmlEscapeMap[tag2]; }).replace(/&#(?:x([0-9a-z]{1,4})|([0-9]{1,4}));/gi, function (_, hex, numStr) { var num = parseInt(hex || numStr, hex ? 16 : 10); return String.fromCharCode(num); }); }, /** * Try to extract metadata from JSON-LD object. * For now, only Schema.org objects of type Article or its subtypes are supported. * @return Object with any metadata that could be extracted (possibly none) */ _getJSONLD: function (doc) { var scripts = this._getAllNodesWithTag(doc, ["script"]); var metadata; this._forEachNode(scripts, function (jsonLdElement) { if (!metadata && jsonLdElement.getAttribute("type") === "application/ld+json") { try { var content = jsonLdElement.textContent.replace(/^\s*<!\[CDATA\[|\]\]>\s*$/g, ""); var parsed = JSON.parse(content); if (!parsed["@context"] || !parsed["@context"].match(/^https?\:\/\/schema\.org$/)) { return; } if (!parsed["@type"] && Array.isArray(parsed["@graph"])) { parsed = parsed["@graph"].find(function (it) { return (it["@type"] || "").match( this.REGEXPS.jsonLdArticleTypes ); }); } if (!parsed || !parsed["@type"] || !parsed["@type"].match(this.REGEXPS.jsonLdArticleTypes)) { return; } metadata = {}; if (typeof parsed.name === "string" && typeof parsed.headline === "string" && parsed.name !== parsed.headline) { var title = this._getArticleTitle(); var nameMatches = this._textSimilarity(parsed.name, title) > 0.75; var headlineMatches = this._textSimilarity(parsed.headline, title) > 0.75; if (headlineMatches && !nameMatches) { metadata.title = parsed.headline; } else { metadata.title = parsed.name; } } else if (typeof parsed.name === "string") { metadata.title = parsed.name.trim(); } else if (typeof parsed.headline === "string") { metadata.title = parsed.headline.trim(); } if (parsed.author) { if (typeof parsed.author.name === "string") { metadata.byline = parsed.author.name.trim(); } else if (Array.isArray(parsed.author) && parsed.author[0] && typeof parsed.author[0].name === "string") { metadata.byline = parsed.author.filter(function (author) { return author && typeof author.name === "string"; }).map(function (author) { return author.name.trim(); }).join(", "); } } if (typeof parsed.description === "string") { metadata.excerpt = parsed.description.trim(); } if (parsed.publisher && typeof parsed.publisher.name === "string") { metadata.siteName = parsed.publisher.name.trim(); } if (typeof parsed.datePublished === "string") { metadata.datePublished = parsed.datePublished.trim(); } return; } catch (err) { this.log(err.message); } } }); return metadata ? metadata : {}; }, /** * Attempts to get excerpt and byline metadata for the article. * * @param {Object} jsonld — object containing any metadata that * could be extracted from JSON-LD object. * * @return Object with optional "excerpt" and "byline" properties */ _getArticleMetadata: function (jsonld) { var metadata = {}; var values = {}; var metaElements = this._doc.getElementsByTagName("meta"); var propertyPattern = /\s*(article|dc|dcterm|og|twitter)\s*:\s*(author|creator|description|published_time|title|site_name)\s*/gi; var namePattern = /^\s*(?:(dc|dcterm|og|twitter|weibo:(article|webpage))\s*[\.:]\s*)?(author|creator|description|title|site_name)\s*$/i; this._forEachNode(metaElements, function (element) { var elementName = element.getAttribute("name"); var elementProperty = element.getAttribute("property"); var content = element.getAttribute("content"); if (!content) { return; } var matches = null; var name = null; if (elementProperty) { matches = elementProperty.match(propertyPattern); if (matches) { name = matches[0].toLowerCase().replace(/\s/g, ""); values[name] = content.trim(); } } if (!matches && elementName && namePattern.test(elementName)) { name = elementName; if (content) { name = name.toLowerCase().replace(/\s/g, "").replace(/\./g, ":"); values[name] = content.trim(); } } }); metadata.title = jsonld.title || values["dc:title"] || values["dcterm:title"] || values["og:title"] || values["weibo:article:title"] || values["weibo:webpage:title"] || values["title"] || values["twitter:title"]; if (!metadata.title) { metadata.title = this._getArticleTitle(); } metadata.byline = jsonld.byline || values["dc:creator"] || values["dcterm:creator"] || values["author"]; metadata.excerpt = jsonld.excerpt || values["dc:description"] || values["dcterm:description"] || values["og:description"] || values["weibo:article:description"] || values["weibo:webpage:description"] || values["description"] || values["twitter:description"]; metadata.siteName = jsonld.siteName || values["og:site_name"]; metadata.publishedTime = jsonld.datePublished || values["article:published_time"] || null; metadata.title = this._unescapeHtmlEntities(metadata.title); metadata.byline = this._unescapeHtmlEntities(metadata.byline); metadata.excerpt = this._unescapeHtmlEntities(metadata.excerpt); metadata.siteName = this._unescapeHtmlEntities(metadata.siteName); metadata.publishedTime = this._unescapeHtmlEntities(metadata.publishedTime); return metadata; }, /** * Check if node is image, or if node contains exactly only one image * whether as a direct child or as its descendants. * * @param Element **/ _isSingleImage: function (node) { if (node.tagName === "IMG") { return true; } if (node.children.length !== 1 || node.textContent.trim() !== "") { return false; } return this._isSingleImage(node.children[0]); }, /** * Find all <noscript> that are located after <img> nodes, and which contain only one * <img> element. Replace the first image with the image from inside the <noscript> tag, * and remove the <noscript> tag. This improves the quality of the images we use on * some sites (e.g. Medium). * * @param Element **/ _unwrapNoscriptImages: function (doc) { var imgs = Array.from(doc.getElementsByTagName("img")); this._forEachNode(imgs, function (img) { for (var i = 0; i < img.attributes.length; i++) { var attr = img.attributes[i]; switch (attr.name) { case "src": case "srcset": case "data-src": case "data-srcset": return; } if (/\.(jpg|jpeg|png|webp)/i.test(attr.value)) { return; } } img.parentNode.removeChild(img); }); var noscripts = Array.from(doc.getElementsByTagName("noscript")); this._forEachNode(noscripts, function (noscript) { var tmp = doc.createElement("div"); tmp.innerHTML = noscript.innerHTML; if (!this._isSingleImage(tmp)) { return; } var prevElement = noscript.previousElementSibling; if (prevElement && this._isSingleImage(prevElement)) { var prevImg = prevElement; if (prevImg.tagName !== "IMG") { prevImg = prevElement.getElementsByTagName("img")[0]; } var newImg = tmp.getElementsByTagName("img")[0]; for (var i = 0; i < prevImg.attributes.length; i++) { var attr = prevImg.attributes[i]; if (attr.value === "") { continue; } if (attr.name === "src" || attr.name === "srcset" || /\.(jpg|jpeg|png|webp)/i.test(attr.value)) { if (newImg.getAttribute(attr.name) === attr.value) { continue; } var attrName = attr.name; if (newImg.hasAttribute(attrName)) { attrName = "data-old-" + attrName; } newImg.setAttribute(attrName, attr.value); } } noscript.parentNode.replaceChild(tmp.firstElementChild, prevElement); } }); }, /** * Removes script tags from the document. * * @param Element **/ _removeScripts: function (doc) { this._removeNodes(this._getAllNodesWithTag(doc, ["script", "noscript"])); }, /** * Check if this node has only whitespace and a single element with given tag * Returns false if the DIV node contains non-empty text nodes * or if it contains no element with given tag or more than 1 element. * * @param Element * @param string tag of child element **/ _hasSingleTagInsideElement: function (element, tag2) { if (element.children.length != 1 || element.children[0].tagName !== tag2) { return false; } return !this._someNode(element.childNodes, function (node) { return node.nodeType === this.TEXT_NODE && this.REGEXPS.hasContent.test(node.textContent); }); }, _isElementWithoutContent: function (node) { return node.nodeType === this.ELEMENT_NODE && node.textContent.trim().length == 0 && (node.children.length == 0 || node.children.length == node.getElementsByTagName("br").length + node.getElementsByTagName("hr").length); }, /** * Determine whether element has any children block level elements. * * @param Element */ _hasChildBlockElement: function (element) { return this._someNode(element.childNodes, function (node) { return this.DIV_TO_P_ELEMS.has(node.tagName) || this._hasChildBlockElement(node); }); }, /*** * Determine if a node qualifies as phrasing content. * https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_categories#Phrasing_content **/ _isPhrasingContent: function (node) { return node.nodeType === this.TEXT_NODE || this.PHRASING_ELEMS.indexOf(node.tagName) !== -1 || (node.tagName === "A" || node.tagName === "DEL" || node.tagName === "INS") && this._everyNode(node.childNodes, this._isPhrasingContent); }, _isWhitespace: function (node) { return node.nodeType === this.TEXT_NODE && node.textContent.trim().length === 0 || node.nodeType === this.ELEMENT_NODE && node.tagName === "BR"; }, /** * Get the inner text of a node - cross browser compatibly. * This also strips out any excess whitespace to be found. * * @param Element * @param Boolean normalizeSpaces (default: true) * @return string **/ _getInnerText: function (e, normalizeSpaces) { normalizeSpaces = typeof normalizeSpaces === "undefined" ? true : normalizeSpaces; var textContent = e.textContent.trim(); if (normalizeSpaces) { return textContent.replace(this.REGEXPS.normalize, " "); } return textContent; }, /** * Get the number of times a string s appears in the node e. * * @param Element * @param string - what to split on. Default is "," * @return number (integer) **/ _getCharCount: function (e, s) { s = s || ","; return this._getInnerText(e).split(s).length - 1; }, /** * Remove the style attribute on every e and under. * TODO: Test if getElementsByTagName(*) is faster. * * @param Element * @return void **/ _cleanStyles: function (e) { if (!e || e.tagName.toLowerCase() === "svg") return; for (var i = 0; i < this.PRESENTATIONAL_ATTRIBUTES.length; i++) { e.removeAttribute(this.PRESENTATIONAL_ATTRIBUTES[i]); } if (this.DEPRECATED_SIZE_ATTRIBUTE_ELEMS.indexOf(e.tagName) !== -1) { e.removeAttribute("width"); e.removeAttribute("height"); } var cur = e.firstElementChild; while (cur !== null) { this._cleanStyles(cur); cur = cur.nextElementSibling; } }, /** * Get the density of links as a percentage of the content * This is the amount of text that is inside a link divided by the total text in the node. * * @param Element * @return number (float) **/ _getLinkDensity: function (element) { var textLength = this._getInnerText(element).length; if (textLength === 0) return 0; var linkLength = 0; this._forEachNode(element.getElementsByTagName("a"), function (linkNode) { var href = linkNode.getAttribute("href"); var coefficient = href && this.REGEXPS.hashUrl.test(href) ? 0.3 : 1; linkLength += this._getInnerText(linkNode).length * coefficient; }); return linkLength / textLength; }, /** * Get an elements class/id weight. Uses regular expressions to tell if this * element looks good or bad. * * @param Element * @return number (Integer) **/ _getClassWeight: function (e) { if (!this._flagIsActive(this.FLAG_WEIGHT_CLASSES)) return 0; var weight = 0; if (typeof e.className === "string" && e.className !== "") { if (this.REGEXPS.negative.test(e.className)) weight -= 25; if (this.REGEXPS.positive.test(e.className)) weight += 25; } if (typeof e.id === "string" && e.id !== "") { if (this.REGEXPS.negative.test(e.id)) weight -= 25; if (this.REGEXPS.positive.test(e.id)) weight += 25; } return weight; }, /** * Clean a node of all elements of type "tag". * (Unless it's a youtube/vimeo video. People love movies.) * * @param Element * @param string tag to clean * @return void **/ _clean: function (e, tag2) { var isEmbed = ["object", "embed", "iframe"].indexOf(tag2) !== -1; this._removeNodes(this._getAllNodesWithTag(e, [tag2]), function (element) { if (isEmbed) { for (var i = 0; i < element.attributes.length; i++) { if (this._allowedVideoRegex.test(element.attributes[i].value)) { return false; } } if (element.tagName === "object" && this._allowedVideoRegex.test(element.innerHTML)) { return false; } } return true; }); }, /** * Check if a given node has one of its ancestor tag name matching the * provided one. * @param HTMLElement node * @param String tagName * @param Number maxDepth * @param Function filterFn a filter to invoke to determine whether this node 'counts' * @return Boolean */ _hasAncestorTag: function (node, tagName, maxDepth, filterFn) { maxDepth = maxDepth || 3; tagName = tagName.toUpperCase(); var depth = 0; while (node.parentNode) { if (maxDepth > 0 && depth > maxDepth) return false; if (node.parentNode.tagName === tagName && (!filterFn || filterFn(node.parentNode))) return true; node = node.parentNode; depth++; } return false; }, /** * Return an object indicating how many rows and columns this table has. */ _getRowAndColumnCount: function (table) { var rows = 0; var columns = 0; var trs = table.getElementsByTagName("tr"); for (var i = 0; i < trs.length; i++) { var rowspan = trs[i].getAttribute("rowspan") || 0; if (rowspan) { rowspan = parseInt(rowspan, 10); } rows += rowspan || 1; var columnsInThisRow = 0; var cells = trs[i].getElementsByTagName("td"); for (var j = 0; j < cells.length; j++) { var colspan = cells[j].getAttribute("colspan") || 0; if (colspan) { colspan = parseInt(colspan, 10); } columnsInThisRow += colspan || 1; } columns = Math.max(columns, columnsInThisRow); } return { rows, columns }; }, /** * Look for 'data' (as opposed to 'layout') tables, for which we use * similar checks as * https://searchfox.org/mozilla-central/rev/f82d5c549f046cb64ce5602bfd894b7ae807c8f8/accessible/generic/TableAccessible.cpp#19 */ _markDataTables: function (root) { var tables = root.getElementsByTagName("table"); for (var i = 0; i < tables.length; i++) { var table = tables[i]; var role = table.getAttribute("role"); if (role == "presentation") { table._readabilityDataTable = false; continue; } var datatable = table.getAttribute("datatable"); if (datatable == "0") { table._readabilityDataTable = false; continue; } var summary = table.getAttribute("summary"); if (summary) { table._readabilityDataTable = true; continue; } var caption = table.getElementsByTagName("caption")[0]; if (caption && caption.childNodes.length > 0) { table._readabilityDataTable = true; continue; } var dataTableDescendants = ["col", "colgroup", "tfoot", "thead", "th"]; var descendantExists = function (tag2) { return !!table.getElementsByTagName(tag2)[0]; }; if (dataTableDescendants.some(descendantExists)) { this.log("Data table because found data-y descendant"); table._readabilityDataTable = true; continue; } if (table.getElementsByTagName("table")[0]) { table._readabilityDataTable = false; continue; } var sizeInfo = this._getRowAndColumnCount(table); if (sizeInfo.rows >= 10 || sizeInfo.columns > 4) { table._readabilityDataTable = true; continue; } table._readabilityDataTable = sizeInfo.rows * sizeInfo.columns > 10; } }, /* convert images and figures that have properties like data-src into images that can be loaded without JS */ _fixLazyImages: function (root) { this._forEachNode(this._getAllNodesWithTag(root, ["img", "picture", "figure"]), function (elem) { if (elem.src && this.REGEXPS.b64DataUrl.test(elem.src)) { var parts = this.REGEXPS.b64DataUrl.exec(elem.src); if (parts[1] === "image/svg+xml") { return; } var srcCouldBeRemoved = false; for (var i = 0; i < elem.attributes.length; i++) { var attr = elem.attributes[i]; if (attr.name === "src") { continue; } if (/\.(jpg|jpeg|png|webp)/i.test(attr.value)) { srcCouldBeRemoved = true; break; } } if (srcCouldBeRemoved) { var b64starts = elem.src.search(/base64\s*/i) + 7; var b64length = elem.src.length - b64starts; if (b64length < 133) { elem.removeAttribute("src"); } } } if ((elem.src || elem.srcset && elem.srcset != "null") && elem.className.toLowerCase().indexOf("lazy") === -1) { return; } for (var j = 0; j < elem.attributes.length; j++) { attr = elem.attributes[j]; if (attr.name === "src" || attr.name === "srcset" || attr.name === "alt") { continue; } var copyTo = null; if (/\.(jpg|jpeg|png|webp)\s+\d/.test(attr.value)) { copyTo = "srcset"; } else if (/^\s*\S+\.(jpg|jpeg|png|webp)\S*\s*$/.test(attr.value)) { copyTo = "src"; } if (copyTo) { if (elem.tagName === "IMG" || elem.tagName === "PICTURE") { elem.setAttribute(copyTo, attr.value); } else if (elem.tagName === "FIGURE" && !this._getAllNodesWithTag(elem, ["img", "picture"]).length) { var img = this._doc.createElement("img"); img.setAttribute(copyTo, attr.value); elem.appendChild(img); } } } }); }, _getTextDensity: function (e, tags) { var textLength = this._getInnerText(e, true).length; if (textLength === 0) { return 0; } var childrenLength = 0; var children = this._getAllNodesWithTag(e, tags); this._forEachNode(children, (child) => childrenLength += this._getInnerText(child, true).length); return childrenLength / textLength; }, /** * Clean an element of all tags of type "tag" if they look fishy. * "Fishy" is an algorithm based on content length, classnames, link density, number of images & embeds, etc. * * @return void **/ _cleanConditionally: function (e, tag2) { if (!this._flagIsActive(this.FLAG_CLEAN_CONDITIONALLY)) return; this._removeNodes(this._getAllNodesWithTag(e, [tag2]), function (node) { var isDataTable = function (t) { return t._readabilityDataTable; }; var isList = tag2 === "ul" || tag2 === "ol"; if (!isList) { var listLength = 0; var listNodes = this._getAllNodesWithTag(node, ["ul", "ol"]); this._forEachNode(listNodes, (list2) => listLength += this._getInnerText(list2).length); isList = listLength / this._getInnerText(node).length > 0.9; } if (tag2 === "table" && isDataTable(node)) { return false; } if (this._hasAncestorTag(node, "table", -1, isDataTable)) { return false; } if (this._hasAncestorTag(node, "code")) { return false; } var weight = this._getClassWeight(node); this.log("Cleaning Conditionally", node); var contentScore = 0; if (weight + contentScore < 0) { return true; } if (this._getCharCount(node, ",") < 10) { var p = node.getElementsByTagName("p").length; var img = node.getElementsByTagName("img").length; var li = node.getElementsByTagName("li").length - 100; var input = node.getElementsByTagName("input").length; var headingDensity = this._getTextDensity(node, ["h1", "h2", "h3", "h4", "h5", "h6"]); var embedCount = 0; var embeds = this._getAllNodesWithTag(node, ["object", "embed", "iframe"]); for (var i = 0; i < embeds.length; i++) { for (var j = 0; j < embeds[i].attributes.length; j++) { if (this._allowedVideoRegex.test(embeds[i].attributes[j].value)) { return false; } } if (embeds[i].tagName === "object" && this._allowedVideoRegex.test(embeds[i].innerHTML)) { return false; } embedCount++; } var linkDensity = this._getLinkDensity(node); var contentLength = this._getInnerText(node).length; var haveToRemove = img > 1 && p / img < 0.5 && !this._hasAncestorTag(node, "figure") || !isList && li > p || input > Math.floor(p / 3) || !isList && headingDensity < 0.9 && contentLength < 25 && (img === 0 || img > 2) && !this._hasAncestorTag(node, "figure") || !isList && weight < 25 && linkDensity > 0.2 || weight >= 25 && linkDensity > 0.5 || (embedCount === 1 && contentLength < 75 || embedCount > 1); if (isList && haveToRemove) { for (var x = 0; x < node.children.length; x++) { let child = node.children[x]; if (child.children.length > 1) { return haveToRemove; } } let li_count = node.getElementsByTagName("li").length; if (img == li_count) { return false; } } return haveToRemove; } return false; }); }, /** * Clean out elements that match the specified conditions * * @param Element * @param Function determines whether a node should be removed * @return void **/ _cleanMatchedNodes: function (e, filter) { var endOfSearchMarkerNode = this._getNextNode(e, true); var next = this._getNextNode(e); while (next && next != endOfSearchMarkerNode) { if (filter.call(this, next, next.className + " " + next.id)) { next = this._removeAndGetNext(next); } else { next = this._getNextNode(next); } } }, /** * Clean out spurious headers from an Element. * * @param Element * @return void **/ _cleanHeaders: function (e) { let headingNodes = this._getAllNodesWithTag(e, ["h1", "h2"]); this._removeNodes(headingNodes, function (node) { let shouldRemove = this._getClassWeight(node) < 0; if (shouldRemove) { this.log("Removing header with low class weight:", node); } return shouldRemove; }); }, /** * Check if this node is an H1 or H2 element whose content is mostly * the same as the article title. * * @param Element the node to check. * @return boolean indicating whether this is a title-like header. */ _headerDuplicatesTitle: function (node) { if (node.tagName != "H1" && node.tagName != "H2") { return false; } var heading2 = this._getInnerText(node, false); this.log("Evaluating similarity of header:", heading2, this._articleTitle); return this._textSimilarity(this._articleTitle, heading2) > 0.75; }, _flagIsActive: function (flag) { return (this._flags & flag) > 0; }, _removeFlag: function (flag) { this._flags = this._flags & ~flag; }, _isProbablyVisible: function (node) { return (!node.style || node.style.display != "none") && (!node.style || node.style.visibility != "hidden") && !node.hasAttribute("hidden") && (!node.hasAttribute("aria-hidden") || node.getAttribute("aria-hidden") != "true" || node.className && node.className.indexOf && node.className.indexOf("fallback-image") !== -1); }, /** * Runs readability. * * Workflow: * 1. Prep the document by removing script tags, css, etc. * 2. Build readability's DOM tree. * 3. Grab the article content from the current dom tree. * 4. Replace the current DOM tree with the new one. * 5. Read peacefully. * * @return void **/ parse: function () { if (this._maxElemsToParse > 0) { var numTags = this._doc.getElementsByTagName("*").length; if (numTags > this._maxElemsToParse) { throw new Error("Aborting parsing document; " + numTags + " elements found"); } } this._unwrapNoscriptImages(this._doc); var jsonLd = this._disableJSONLD ? {} : this._getJSONLD(this._doc); this._removeScripts(this._doc); this._prepDocument(); var metadata = this._getArticleMetadata(jsonLd); this._articleTitle = metadata.title; var articleContent = this._grabArticle(); if (!articleContent) return null; this.log("Grabbed: " + articleContent.innerHTML); this._postProcessContent(articleContent); if (!metadata.excerpt) { var paragraphs = articleContent.getElementsByTagName("p"); if (paragraphs.length > 0) { metadata.excerpt = paragraphs[0].textContent.trim(); } } var textContent = articleContent.textContent; return { title: this._articleTitle, byline: metadata.byline || this._articleByline, dir: this._articleDir, lang: this._articleLang, content: this._serializer(articleContent), textContent, length: textContent.length, excerpt: metadata.excerpt, siteName: metadata.siteName || this._articleSiteName, publishedTime: metadata.publishedTime }; } }; { module.exports = Readability2; } })(Readability$1); var ReadabilityExports = Readability$1.exports; var ReadabilityReaderable = { exports: {} }; (function (module) { var REGEXPS = { // NOTE: These two regular expressions are duplicated in // Readability.js. Please keep both copies in sync. unlikelyCandidates: /-ad-|ai2html|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|footer|gdpr|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i, okMaybeItsACandidate: /and|article|body|column|content|main|shadow/i }; function isNodeVisible(node) { return (!node.style || node.style.display != "none") && !node.hasAttribute("hidden") && (!node.hasAttribute("aria-hidden") || node.getAttribute("aria-hidden") != "true" || node.className && node.className.indexOf && node.className.indexOf("fallback-image") !== -1); } function isProbablyReaderable2(doc, options = {}) { if (typeof options == "function") { options = { visibilityChecker: options }; } var defaultOptions = { minScore: 20, minContentLength: 140, visibilityChecker: isNodeVisible }; options = Object.assign(defaultOptions, options); var nodes = doc.querySelectorAll("p, pre, article"); var brNodes = doc.querySelectorAll("div > br"); if (brNodes.length) { var set = new Set(nodes); [].forEach.call(brNodes, function (node) { set.add(node.parentNode); }); nodes = Array.from(set); } var score = 0; return [].some.call(nodes, function (node) { if (!options.visibilityChecker(node)) { return false; } var matchString = node.className + " " + node.id; if (REGEXPS.unlikelyCandidates.test(matchString) && !REGEXPS.okMaybeItsACandidate.test(matchString)) { return false; } if (node.matches("li p")) { return false; } var textContentLength = node.textContent.trim().length; if (textContentLength < options.minContentLength) { return false; } score += Math.sqrt(textContentLength - options.minContentLength); if (score > options.minScore) { return true; } return false; }); } { module.exports = isProbablyReaderable2; } })(ReadabilityReaderable); var ReadabilityReaderableExports = ReadabilityReaderable.exports; var Readability = ReadabilityExports; var isProbablyReaderable = ReadabilityReaderableExports; var readability = { Readability, isProbablyReaderable }; function getSimpleText(doc) { doc = doc ? doc : document; doc = doc.cloneNode(true); const app = doc.querySelector("#monkeygpt"); app.remove(); let article = new readability.Readability(doc).parse(); let str = replaceEmpty(article.textContent); return str; } function replaceEmpty(str) { while (str.includes(" ")) { str = str.replaceAll(" ", " "); } while (str.includes("\n\n")) { str = str.replaceAll("\n\n", "\n"); } while (str.includes(" ")) { str = str.replaceAll(" ", " "); } return str; } async function chat$1(messages, model = "gpt-4o-mini", apiKey, apiEndpoint = "https://api.openai.com/v1/chat/completions") { const headers = { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}` }; const requestBody = { model, // 使用的模型名称 messages }; return fetch(apiEndpoint, { method: "POST", headers, body: JSON.stringify(requestBody) }).then((response) => response.json()).then(async (data) => { const reply = data.choices[0].message.content; return reply; }); } const defaultConfig = { model: "gpt-4o-mini", apiKey: "", apiEndpoint: "https://ai.01234.fun/v1/chat/completions" }; async function chat(content, config = defaultConfig) { return await chat$1([{ role: "user", content }], config.model, config.apiKey, config.apiEndpoint); } async function summarize(text, config = defaultConfig) { return chat(`请帮忙总结一下 :"${text}"`, config); } async function ask(text, config = defaultConfig) { return chat(`请帮忙回复一下 :"${text}"`, config); } function _getDefaults() { return { async: false, breaks: false, extensions: null, gfm: true, hooks: null, pedantic: false, renderer: null, silent: false, tokenizer: null, walkTokens: null }; } let _defaults = _getDefaults(); function changeDefaults(newDefaults) { _defaults = newDefaults; } const escapeTest = /[&<>"']/; const escapeReplace = new RegExp(escapeTest.source, "g"); const escapeTestNoEncode = /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/; const escapeReplaceNoEncode = new RegExp(escapeTestNoEncode.source, "g"); const escapeReplacements = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }; const getEscapeReplacement = (ch) => escapeReplacements[ch]; function escape$1(html2, encode) { if (encode) { if (escapeTest.test(html2)) { return html2.replace(escapeReplace, getEscapeReplacement); } } else { if (escapeTestNoEncode.test(html2)) { return html2.replace(escapeReplaceNoEncode, getEscapeReplacement); } } return html2; } const caret = /(^|[^\[])\^/g; function edit(regex, opt) { let source = typeof regex === "string" ? regex : regex.source; opt = opt || ""; const obj = { replace: (name, val) => { let valSource = typeof val === "string" ? val : val.source; valSource = valSource.replace(caret, "$1"); source = source.replace(name, valSource); return obj; }, getRegex: () => { return new RegExp(source, opt); } }; return obj; } function cleanUrl(href) { try { href = encodeURI(href).replace(/%25/g, "%"); } catch { return null; } return href; } const noopTest = { exec: () => null }; function splitCells(tableRow, count) { const row = tableRow.replace(/\|/g, (match, offset, str) => { let escaped = false; let curr = offset; while (--curr >= 0 && str[curr] === "\\") escaped = !escaped; if (escaped) { return "|"; } else { return " |"; } }), cells = row.split(/ \|/); let i = 0; if (!cells[0].trim()) { cells.shift(); } if (cells.length > 0 && !cells[cells.length - 1].trim()) { cells.pop(); } if (count) { if (cells.length > count) { cells.splice(count); } else { while (cells.length < count) cells.push(""); } } for (; i < cells.length; i++) { cells[i] = cells[i].trim().replace(/\\\|/g, "|"); } return cells; } function rtrim(str, c, invert) { const l = str.length; if (l === 0) { return ""; } let suffLen = 0; while (suffLen < l) { const currChar = str.charAt(l - suffLen - 1); if (currChar === c && !invert) { suffLen++; } else if (currChar !== c && invert) { suffLen++; } else { break; } } return str.slice(0, l - suffLen); } function findClosingBracket(str, b) { if (str.indexOf(b[1]) === -1) { return -1; } let level = 0; for (let i = 0; i < str.length; i++) { if (str[i] === "\\") { i++; } else if (str[i] === b[0]) { level++; } else if (str[i] === b[1]) { level--; if (level < 0) { return i; } } } return -1; } function outputLink(cap, link2, raw, lexer) { const href = link2.href; const title = link2.title ? escape$1(link2.title) : null; const text = cap[1].replace(/\\([\[\]])/g, "$1"); if (cap[0].charAt(0) !== "!") { lexer.state.inLink = true; const token = { type: "link", raw, href, title, text, tokens: lexer.inlineTokens(text) }; lexer.state.inLink = false; return token; } return { type: "image", raw, href, title, text: escape$1(text) }; } function indentCodeCompensation(raw, text) { const matchIndentToCode = raw.match(/^(\s+)(?:```)/); if (matchIndentToCode === null) { return text; } const indentToCode = matchIndentToCode[1]; return text.split("\n").map((node) => { const matchIndentInNode = node.match(/^\s+/); if (matchIndentInNode === null) { return node; } const [indentInNode] = matchIndentInNode; if (indentInNode.length >= indentToCode.length) { return node.slice(indentToCode.length); } return node; }).join("\n"); } class _Tokenizer { // set by the lexer constructor(options) { __publicField(this, "options"); __publicField(this, "rules"); // set by the lexer __publicField(this, "lexer"); this.options = options || _defaults; } space(src) { const cap = this.rules.block.newline.exec(src); if (cap && cap[0].length > 0) { return { type: "space", raw: cap[0] }; } } code(src) { const cap = this.rules.block.code.exec(src); if (cap) { const text = cap[0].replace(/^ {1,4}/gm, ""); return { type: "code", raw: cap[0], codeBlockStyle: "indented", text: !this.options.pedantic ? rtrim(text, "\n") : text }; } } fences(src) { const cap = this.rules.block.fences.exec(src); if (cap) { const raw = cap[0]; const text = indentCodeCompensation(raw, cap[3] || ""); return { type: "code", raw, lang: cap[2] ? cap[2].trim().replace(this.rules.inline.anyPunctuation, "$1") : cap[2], text }; } } heading(src) { const cap = this.rules.block.heading.exec(src); if (cap) { let text = cap[2].trim(); if (/#$/.test(text)) { const trimmed = rtrim(text, "#"); if (this.options.pedantic) { text = trimmed.trim(); } else if (!trimmed || / $/.test(trimmed)) { text = trimmed.trim(); } } return { type: "heading", raw: cap[0], depth: cap[1].length, text, tokens: this.lexer.inline(text) }; } } hr(src) { const cap = this.rules.block.hr.exec(src); if (cap) { return { type: "hr", raw: rtrim(cap[0], "\n") }; } } blockquote(src) { const cap = this.rules.block.blockquote.exec(src); if (cap) { let lines = rtrim(cap[0], "\n").split("\n"); let raw = ""; let text = ""; const tokens = []; while (lines.length > 0) { let inBlockquote = false; const currentLines = []; let i; for (i = 0; i < lines.length; i++) { if (/^ {0,3}>/.test(lines[i])) { currentLines.push(lines[i]); inBlockquote = true; } else if (!inBlockquote) { currentLines.push(lines[i]); } else { break; } } lines = lines.slice(i); const currentRaw = currentLines.join("\n"); const currentText = currentRaw.replace(/\n {0,3}((?:=+|-+) *)(?=\n|$)/g, "\n $1").replace(/^ {0,3}>[ \t]?/gm, ""); raw = raw ? `${raw} ${currentRaw}` : currentRaw; text = text ? `${text} ${currentText}` : currentText; const top = this.lexer.state.top; this.lexer.state.top = true; this.lexer.blockTokens(currentText, tokens, true); this.lexer.state.top = top; if (lines.length === 0) { break; } const lastToken = tokens[tokens.length - 1]; if ((lastToken == null ? void 0 : lastToken.type) === "code") { break; } else if ((lastToken == null ? void 0 : lastToken.type) === "blockquote") { const oldToken = lastToken; const newText = oldToken.raw + "\n" + lines.join("\n"); const newToken = this.blockquote(newText); tokens[tokens.length - 1] = newToken; raw = raw.substring(0, raw.length - oldToken.raw.length) + newToken.raw; text = text.substring(0, text.length - oldToken.text.length) + newToken.text; break; } else if ((lastToken == null ? void 0 : lastToken.type) === "list") { const oldToken = lastToken; const newText = oldToken.raw + "\n" + lines.join("\n"); const newToken = this.list(newText); tokens[tokens.length - 1] = newToken; raw = raw.substring(0, raw.length - lastToken.raw.length) + newToken.raw; text = text.substring(0, text.length - oldToken.raw.length) + newToken.raw; lines = newText.substring(tokens[tokens.length - 1].raw.length).split("\n"); continue; } } return { type: "blockquote", raw, tokens, text }; } } list(src) { let cap = this.rules.block.list.exec(src); if (cap) { let bull = cap[1].trim(); const isordered = bull.length > 1; const list2 = { type: "list", raw: "", ordered: isordered, start: isordered ? +bull.slice(0, -1) : "", loose: false, items: [] }; bull = isordered ? `\\d{1,9}\\${bull.slice(-1)}` : `\\${bull}`; if (this.options.pedantic) { bull = isordered ? bull : "[*+-]"; } const itemRegex = new RegExp(`^( {0,3}${bull})((?:[ ][^\\n]*)?(?:\\n|$))`); let endsWithBlankLine = false; while (src) { let endEarly = false; let raw = ""; let itemContents = ""; if (!(cap = itemRegex.exec(src))) { break; } if (this.rules.block.hr.test(src)) { break; } raw = cap[0]; src = src.substring(raw.length); let line = cap[2].split("\n", 1)[0].replace(/^\t+/, (t) => " ".repeat(3 * t.length)); let nextLine = src.split("\n", 1)[0]; let blankLine = !line.trim(); let indent = 0; if (this.options.pedantic) { indent = 2; itemContents = line.trimStart(); } else if (blankLine) { indent = cap[1].length + 1; } else { indent = cap[2].search(/[^ ]/); indent = indent > 4 ? 1 : indent; itemContents = line.slice(indent); indent += cap[1].length; } if (blankLine && /^ *$/.test(nextLine)) { raw += nextLine + "\n"; src = src.substring(nextLine.length + 1); endEarly = true; } if (!endEarly) { const nextBulletRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`); const hrRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`); const fencesBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:\`\`\`|~~~)`); const headingBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}#`); while (src) { const rawLine = src.split("\n", 1)[0]; nextLine = rawLine; if (this.options.pedantic) { nextLine = nextLine.replace(/^ {1,4}(?=( {4})*[^ ])/g, " "); } if (fencesBeginRegex.test(nextLine)) { break; } if (headingBeginRegex.test(nextLine)) { break; } if (nextBulletRegex.test(nextLine)) { break; } if (hrRegex.test(src)) { break; } if (nextLine.search(/[^ ]/) >= indent || !nextLine.trim()) { itemContents += "\n" + nextLine.slice(indent); } else { if (blankLine) { break; } if (line.search(/[^ ]/) >= 4) { break; } if (fencesBeginRegex.test(line)) { break; } if (headingBeginRegex.test(line)) { break; } if (hrRegex.test(line)) { break; } itemContents += "\n" + nextLine; } if (!blankLine && !nextLine.trim()) { blankLine = true; } raw += rawLine + "\n"; src = src.substring(rawLine.length + 1); line = nextLine.slice(indent); } } if (!list2.loose) { if (endsWithBlankLine) { list2.loose = true; } else if (/\n *\n *$/.test(raw)) { endsWithBlankLine = true; } } let istask = null; let ischecked; if (this.options.gfm) { istask = /^\[[ xX]\] /.exec(itemContents); if (istask) { ischecked = istask[0] !== "[ ] "; itemContents = itemContents.replace(/^\[[ xX]\] +/, ""); } } list2.items.push({ type: "list_item", raw, task: !!istask, checked: ischecked, loose: false, text: itemContents, tokens: [] }); list2.raw += raw; } list2.items[list2.items.length - 1].raw = list2.items[list2.items.length - 1].raw.trimEnd(); list2.items[list2.items.length - 1].text = list2.items[list2.items.length - 1].text.trimEnd(); list2.raw = list2.raw.trimEnd(); for (let i = 0; i < list2.items.length; i++) { this.lexer.state.top = false; list2.items[i].tokens = this.lexer.blockTokens(list2.items[i].text, []); if (!list2.loose) { const spacers = list2.items[i].tokens.filter((t) => t.type === "space"); const hasMultipleLineBreaks = spacers.length > 0 && spacers.some((t) => /\n.*\n/.test(t.raw)); list2.loose = hasMultipleLineBreaks; } } if (list2.loose) { for (let i = 0; i < list2.items.length; i++) { list2.items[i].loose = true; } } return list2; } } html(src) { const cap = this.rules.block.html.exec(src); if (cap) { const token = { type: "html", block: true, raw: cap[0], pre: cap[1] === "pre" || cap[1] === "script" || cap[1] === "style", text: cap[0] }; return token; } } def(src) { const cap = this.rules.block.def.exec(src); if (cap) { const tag2 = cap[1].toLowerCase().replace(/\s+/g, " "); const href = cap[2] ? cap[2].replace(/^<(.*)>$/, "$1").replace(this.rules.inline.anyPunctuation, "$1") : ""; const title = cap[3] ? cap[3].substring(1, cap[3].length - 1).replace(this.rules.inline.anyPunctuation, "$1") : cap[3]; return { type: "def", tag: tag2, raw: cap[0], href, title }; } } table(src) { const cap = this.rules.block.table.exec(src); if (!cap) { return; } if (!/[:|]/.test(cap[2])) { return; } const headers = splitCells(cap[1]); const aligns = cap[2].replace(/^\||\| *$/g, "").split("|"); const rows = cap[3] && cap[3].trim() ? cap[3].replace(/\n[ \t]*$/, "").split("\n") : []; const item = { type: "table", raw: cap[0], header: [], align: [], rows: [] }; if (headers.length !== aligns.length) { return; } for (const align of aligns) { if (/^ *-+: *$/.test(align)) { item.align.push("right"); } else if (/^ *:-+: *$/.test(align)) { item.align.push("center"); } else if (/^ *:-+ *$/.test(align)) { item.align.push("left"); } else { item.align.push(null); } } for (let i = 0; i < headers.length; i++) { item.header.push({ text: headers[i], tokens: this.lexer.inline(headers[i]), header: true, align: item.align[i] }); } for (const row of rows) { item.rows.push(splitCells(row, item.header.length).map((cell, i) => { return { text: cell, tokens: this.lexer.inline(cell), header: false, align: item.align[i] }; })); } return item; } lheading(src) { const cap = this.rules.block.lheading.exec(src); if (cap) { return { type: "heading", raw: cap[0], depth: cap[2].charAt(0) === "=" ? 1 : 2, text: cap[1], tokens: this.lexer.inline(cap[1]) }; } } paragraph(src) { const cap = this.rules.block.paragraph.exec(src); if (cap) { const text = cap[1].charAt(cap[1].length - 1) === "\n" ? cap[1].slice(0, -1) : cap[1]; return { type: "paragraph", raw: cap[0], text, tokens: this.lexer.inline(text) }; } } text(src) { const cap = this.rules.block.text.exec(src); if (cap) { return { type: "text", raw: cap[0], text: cap[0], tokens: this.lexer.inline(cap[0]) }; } } escape(src) { const cap = this.rules.inline.escape.exec(src); if (cap) { return { type: "escape", raw: cap[0], text: escape$1(cap[1]) }; } } tag(src) { const cap = this.rules.inline.tag.exec(src); if (cap) { if (!this.lexer.state.inLink && /^<a /i.test(cap[0])) { this.lexer.state.inLink = true; } else if (this.lexer.state.inLink && /^<\/a>/i.test(cap[0])) { this.lexer.state.inLink = false; } if (!this.lexer.state.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { this.lexer.state.inRawBlock = true; } else if (this.lexer.state.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { this.lexer.state.inRawBlock = false; } return { type: "html", raw: cap[0], inLink: this.lexer.state.inLink, inRawBlock: this.lexer.state.inRawBlock, block: false, text: cap[0] }; } } link(src) { const cap = this.rules.inline.link.exec(src); if (cap) { const trimmedUrl = cap[2].trim(); if (!this.options.pedantic && /^</.test(trimmedUrl)) { if (!/>$/.test(trimmedUrl)) { return; } const rtrimSlash = rtrim(trimmedUrl.slice(0, -1), "\\"); if ((trimmedUrl.length - rtrimSlash.length) % 2 === 0) { return; } } else { const lastParenIndex = findClosingBracket(cap[2], "()"); if (lastParenIndex > -1) { const start = cap[0].indexOf("!") === 0 ? 5 : 4; const linkLen = start + cap[1].length + lastParenIndex; cap[2] = cap[2].substring(0, lastParenIndex); cap[0] = cap[0].substring(0, linkLen).trim(); cap[3] = ""; } } let href = cap[2]; let title = ""; if (this.options.pedantic) { const link2 = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href); if (link2) { href = link2[1]; title = link2[3]; } } else { title = cap[3] ? cap[3].slice(1, -1) : ""; } href = href.trim(); if (/^</.test(href)) { if (this.options.pedantic && !/>$/.test(trimmedUrl)) { href = href.slice(1); } else { href = href.slice(1, -1); } } return outputLink(cap, { href: href ? href.replace(this.rules.inline.anyPunctuation, "$1") : href, title: title ? title.replace(this.rules.inline.anyPunctuation, "$1") : title }, cap[0], this.lexer); } } reflink(src, links) { let cap; if ((cap = this.rules.inline.reflink.exec(src)) || (cap = this.rules.inline.nolink.exec(src))) { const linkString = (cap[2] || cap[1]).replace(/\s+/g, " "); const link2 = links[linkString.toLowerCase()]; if (!link2) { const text = cap[0].charAt(0); return { type: "text", raw: text, text }; } return outputLink(cap, link2, cap[0], this.lexer); } } emStrong(src, maskedSrc, prevChar = "") { let match = this.rules.inline.emStrongLDelim.exec(src); if (!match) return; if (match[3] && prevChar.match(/[\p{L}\p{N}]/u)) return; const nextChar = match[1] || match[2] || ""; if (!nextChar || !prevChar || this.rules.inline.punctuation.exec(prevChar)) { const lLength = [...match[0]].length - 1; let rDelim, rLength, delimTotal = lLength, midDelimTotal = 0; const endReg = match[0][0] === "*" ? this.rules.inline.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd; endReg.lastIndex = 0; maskedSrc = maskedSrc.slice(-1 * src.length + lLength); while ((match = endReg.exec(maskedSrc)) != null) { rDelim = match[1] || match[2] || match[3] || match[4] || match[5] || match[6]; if (!rDelim) continue; rLength = [...rDelim].length; if (match[3] || match[4]) { delimTotal += rLength; continue; } else if (match[5] || match[6]) { if (lLength % 3 && !((lLength + rLength) % 3)) { midDelimTotal += rLength; continue; } } delimTotal -= rLength; if (delimTotal > 0) continue; rLength = Math.min(rLength, rLength + delimTotal + midDelimTotal); const lastCharLength = [...match[0]][0].length; const raw = src.slice(0, lLength + match.index + lastCharLength + rLength); if (Math.min(lLength, rLength) % 2) { const text2 = raw.slice(1, -1); return { type: "em", raw, text: text2, tokens: this.lexer.inlineTokens(text2) }; } const text = raw.slice(2, -2); return { type: "strong", raw, text, tokens: this.lexer.inlineTokens(text) }; } } } codespan(src) { const cap = this.rules.inline.code.exec(src); if (cap) { let text = cap[2].replace(/\n/g, " "); const hasNonSpaceChars = /[^ ]/.test(text); const hasSpaceCharsOnBothEnds = /^ /.test(text) && / $/.test(text); if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) { text = text.substring(1, text.length - 1); } text = escape$1(text, true); return { type: "codespan", raw: cap[0], text }; } } br(src) { const cap = this.rules.inline.br.exec(src); if (cap) { return { type: "br", raw: cap[0] }; } } del(src) { const cap = this.rules.inline.del.exec(src); if (cap) { return { type: "del", raw: cap[0], text: cap[2], tokens: this.lexer.inlineTokens(cap[2]) }; } } autolink(src) { const cap = this.rules.inline.autolink.exec(src); if (cap) { let text, href; if (cap[2] === "@") { text = escape$1(cap[1]); href = "mailto:" + text; } else { text = escape$1(cap[1]); href = text; } return { type: "link", raw: cap[0], text, href, tokens: [{ type: "text", raw: text, text }] }; } } url(src) { var _a; let cap; if (cap = this.rules.inline.url.exec(src)) { let text, href; if (cap[2] === "@") { text = escape$1(cap[0]); href = "mailto:" + text; } else { let prevCapZero; do { prevCapZero = cap[0]; let tmp = ((_a = this.rules.inline._backpedal.exec(cap[0])) == null ? void 0 : _a[0]) cap[0] = tmp ? tmp : ""; } while (prevCapZero !== cap[0]); text = escape$1(cap[0]); if (cap[1] === "www.") { href = "http://" + cap[0]; } else { href = cap[0]; } } return { type: "link", raw: cap[0], text, href, tokens: [{ type: "text", raw: text, text }] }; } } inlineText(src) { const cap = this.rules.inline.text.exec(src); if (cap) { let text; if (this.lexer.state.inRawBlock) { text = cap[0]; } else { text = escape$1(cap[0]); } return { type: "text", raw: cap[0], text }; } } } const newline = /^(?: *(?:\n|$))+/; const blockCode = /^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/; const fences = /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/; const hr = /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/; const heading = /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/; const bullet = /(?:[*+-]|\d{1,9}[.)])/; const lheading = edit(/^(?!bull |blockCode|fences|blockquote|heading|html)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html))+?)\n {0,3}(=+|-+) *(?:\n+|$)/).replace(/bull/g, bullet).replace(/blockCode/g, / {4}/).replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g, / {0,3}>/).replace(/heading/g, / {0,3}#{1,6}/).replace(/html/g, / {0,3}<[^\n>]+>\n/).getRegex(); const _paragraph = /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/; const blockText = /^[^\n]+/; const _blockLabel = /(?!\s*\])(?:\\.|[^\[\]\\])+/; const def = edit(/^ {0,3}\[(label)\]: *(?:\n *)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/).replace("label", _blockLabel).replace("title", /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(); const list = edit(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g, bullet).getRegex(); const _tag = "address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul"; const _comment = /<!--(?:-?>|[\s\S]*?(?:-->|$))/; const html = edit("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|<![A-Z][\\s\\S]*?(?:>\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n *)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$))", "i").replace("comment", _comment).replace("tag", _tag).replace("attribute", / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(); const paragraph = edit(_paragraph).replace("hr", hr).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("|table", "").replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)]) ").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", _tag).getRegex(); const blockquote = edit(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph", paragraph).getRegex(); const blockNormal = { blockquote, code: blockCode, def, fences, heading, hr, html, lheading, list, newline, paragraph, table: noopTest, text: blockText }; const gfmTable = edit("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr", hr).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("blockquote", " {0,3}>").replace("code", " {4}[^\\n]").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)]) ").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", _tag).getRegex(); const blockGfm = { ...blockNormal, table: gfmTable, paragraph: edit(_paragraph).replace("hr", hr).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("table", gfmTable).replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)]) ").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", _tag).getRegex() }; const blockPedantic = { ...blockNormal, html: edit(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:"[^"]*"|'[^']*'|\\s[^'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment", _comment).replace(/tag/g, "(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(), def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/, heading: /^(#{1,6})(.*)(?:\n+|$)/, fences: noopTest, // fences not supported lheading: /^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/, paragraph: edit(_paragraph).replace("hr", hr).replace("heading", " *#{1,6} *[^\n]").replace("lheading", lheading).replace("|table", "").replace("blockquote", " {0,3}>").replace("|fences", "").replace("|list", "").replace("|html", "").replace("|tag", "").getRegex() }; const escape = /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/; const inlineCode = /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/; const br = /^( {2,}|\\)\n(?!\s*$)/; const inlineText = /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/; const _punctuation = "\\p{P}\\p{S}"; const punctuation = edit(/^((?![*_])[\spunctuation])/, "u").replace(/punctuation/g, _punctuation).getRegex(); const blockSkip = /\[[^[\]]*?\]\([^\(\)]*?\)|`[^`]*?`|<[^<>]*?>/g; const emStrongLDelim = edit(/^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/, "u").replace(/punct/g, _punctuation).getRegex(); const emStrongRDelimAst = edit("^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)[punct](\\*+)(?=[\\s]|$)|[^punct\\s](\\*+)(?!\\*)(?=[punct\\s]|$)|(?!\\*)[punct\\s](\\*+)(?=[^punct\\s])|[\\s](\\*+)(?!\\*)(?=[punct])|(?!\\*)[punct](\\*+)(?!\\*)(?=[punct])|[^punct\\s](\\*+)(?=[^punct\\s])", "gu").replace(/punct/g, _punctuation).getRegex(); const emStrongRDelimUnd = edit("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)[punct](_+)(?=[\\s]|$)|[^punct\\s](_+)(?!_)(?=[punct\\s]|$)|(?!_)[punct\\s](_+)(?=[^punct\\s])|[\\s](_+)(?!_)(?=[punct])|(?!_)[punct](_+)(?!_)(?=[punct])", "gu").replace(/punct/g, _punctuation).getRegex(); const anyPunctuation = edit(/\\([punct])/, "gu").replace(/punct/g, _punctuation).getRegex(); const autolink = edit(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme", /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email", /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(); const _inlineComment = edit(_comment).replace("(?:-->|$)", "-->").getRegex(); const tag = edit("^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>").replace("comment", _inlineComment).replace("attribute", /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(); const _inlineLabel = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/; const link = edit(/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/).replace("label", _inlineLabel).replace("href", /<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/).replace("title", /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(); const reflink = edit(/^!?\[(label)\]\[(ref)\]/).replace("label", _inlineLabel).replace("ref", _blockLabel).getRegex(); const nolink = edit(/^!?\[(ref)\](?:\[\])?/).replace("ref", _blockLabel).getRegex(); const reflinkSearch = edit("reflink|nolink(?!\\()", "g").replace("reflink", reflink).replace("nolink", nolink).getRegex(); const inlineNormal = { _backpedal: noopTest, // only used for GFM url anyPunctuation, autolink, blockSkip, br, code: inlineCode, del: noopTest, emStrongLDelim, emStrongRDelimAst, emStrongRDelimUnd, escape, link, nolink, punctuation, reflink, reflinkSearch, tag, text: inlineText, url: noopTest }; const inlinePedantic = { ...inlineNormal, link: edit(/^!?\[(label)\]\((.*?)\)/).replace("label", _inlineLabel).getRegex(), reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label", _inlineLabel).getRegex() }; const inlineGfm = { ...inlineNormal, escape: edit(escape).replace("])", "~|])").getRegex(), url: edit(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/, "i").replace("email", /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(), _backpedal: /(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/, del: /^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/, text: /^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/ }; const inlineBreaks = { ...inlineGfm, br: edit(br).replace("{2,}", "*").getRegex(), text: edit(inlineGfm.text).replace("\\b_", "\\b_| {2,}\\n").replace(/\{2,\}/g, "*").getRegex() }; const block = { normal: blockNormal, gfm: blockGfm, pedantic: blockPedantic }; const inline = { normal: inlineNormal, gfm: inlineGfm, breaks: inlineBreaks, pedantic: inlinePedantic }; class _Lexer { constructor(options) { __publicField(this, "tokens"); __publicField(this, "options"); __publicField(this, "state"); __publicField(this, "tokenizer"); __publicField(this, "inlineQueue"); this.tokens = []; this.tokens.links = /* @__PURE__ */ Object.create(null); this.options = options || _defaults; this.options.tokenizer = this.options.tokenizer || new _Tokenizer(); this.tokenizer = this.options.tokenizer; this.tokenizer.options = this.options; this.tokenizer.lexer = this; this.inlineQueue = []; this.state = { inLink: false, inRawBlock: false, top: true }; const rules = { block: block.normal, inline: inline.normal }; if (this.options.pedantic) { rules.block = block.pedantic; rules.inline = inline.pedantic; } else if (this.options.gfm) { rules.block = block.gfm; if (this.options.breaks) { rules.inline = inline.breaks; } else { rules.inline = inline.gfm; } } this.tokenizer.rules = rules; } /** * Expose Rules */ static get rules() { return { block, inline }; } /** * Static Lex Method */ static lex(src, options) { const lexer = new _Lexer(options); return lexer.lex(src); } /** * Static Lex Inline Method */ static lexInline(src, options) { const lexer = new _Lexer(options); return lexer.inlineTokens(src); } /** * Preprocessing */ lex(src) { src = src.replace(/\r\n|\r/g, "\n"); this.blockTokens(src, this.tokens); for (let i = 0; i < this.inlineQueue.length; i++) { const next = this.inlineQueue[i]; this.inlineTokens(next.src, next.tokens); } this.inlineQueue = []; return this.tokens; } blockTokens(src, tokens = [], lastParagraphClipped = false) { if (this.options.pedantic) { src = src.replace(/\t/g, " ").replace(/^ +$/gm, ""); } else { src = src.replace(/^( *)(\t+)/gm, (_, leading, tabs) => { return leading + " ".repeat(tabs.length); }); } let token; let lastToken; let cutSrc; while (src) { if (this.options.extensions && this.options.extensions.block && this.options.extensions.block.some((extTokenizer) => { if (token = extTokenizer.call({ lexer: this }, src, tokens)) { src = src.substring(token.raw.length); tokens.push(token); return true; } return false; })) { continue; } if (token = this.tokenizer.space(src)) { src = src.substring(token.raw.length); if (token.raw.length === 1 && tokens.length > 0) { tokens[tokens.length - 1].raw += "\n"; } else { tokens.push(token); } continue; } if (token = this.tokenizer.code(src)) { src = src.substring(token.raw.length); lastToken = tokens[tokens.length - 1]; if (lastToken && (lastToken.type === "paragraph" || lastToken.type === "text")) { lastToken.raw += "\n" + token.raw; lastToken.text += "\n" + token.text; this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text; } else { tokens.push(token); } continue; } if (token = this.tokenizer.fences(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } if (token = this.tokenizer.heading(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } if (token = this.tokenizer.hr(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } if (token = this.tokenizer.blockquote(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } if (token = this.tokenizer.list(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } if (token = this.tokenizer.html(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } if (token = this.tokenizer.def(src)) { src = src.substring(token.raw.length); lastToken = tokens[tokens.length - 1]; if (lastToken && (lastToken.type === "paragraph" || lastToken.type === "text")) { lastToken.raw += "\n" + token.raw; lastToken.text += "\n" + token.raw; this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text; } else if (!this.tokens.links[token.tag]) { this.tokens.links[token.tag] = { href: token.href, title: token.title }; } continue; } if (token = this.tokenizer.table(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } if (token = this.tokenizer.lheading(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } cutSrc = src; if (this.options.extensions && this.options.extensions.startBlock) { let startIndex = Infinity; const tempSrc = src.slice(1); let tempStart; this.options.extensions.startBlock.forEach((getStartIndex) => { tempStart = getStartIndex.call({ lexer: this }, tempSrc); if (typeof tempStart === "number" && tempStart >= 0) { startIndex = Math.min(startIndex, tempStart); } }); if (startIndex < Infinity && startIndex >= 0) { cutSrc = src.substring(0, startIndex + 1); } } if (this.state.top && (token = this.tokenizer.paragraph(cutSrc))) { lastToken = tokens[tokens.length - 1]; if (lastParagraphClipped && (lastToken == null ? void 0 : lastToken.type) === "paragraph") { lastToken.raw += "\n" + token.raw; lastToken.text += "\n" + token.text; this.inlineQueue.pop(); this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text; } else { tokens.push(token); } lastParagraphClipped = cutSrc.length !== src.length; src = src.substring(token.raw.length); continue; } if (token = this.tokenizer.text(src)) { src = src.substring(token.raw.length); lastToken = tokens[tokens.length - 1]; if (lastToken && lastToken.type === "text") { lastToken.raw += "\n" + token.raw; lastToken.text += "\n" + token.text; this.inlineQueue.pop(); this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text; } else { tokens.push(token); } continue; } if (src) { const errMsg = "Infinite loop on byte: " + src.charCodeAt(0); if (this.options.silent) { console.error(errMsg); break; } else { throw new Error(errMsg); } } } this.state.top = true; return tokens; } inline(src, tokens = []) { this.inlineQueue.push({ src, tokens }); return tokens; } /** * Lexing/Compiling */ inlineTokens(src, tokens = []) { let token, lastToken, cutSrc; let maskedSrc = src; let match; let keepPrevChar, prevChar; if (this.tokens.links) { const links = Object.keys(this.tokens.links); if (links.length > 0) { while ((match = this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc)) != null) { if (links.includes(match[0].slice(match[0].lastIndexOf("[") + 1, -1))) { maskedSrc = maskedSrc.slice(0, match.index) + "[" + "a".repeat(match[0].length - 2) + "]" + maskedSrc.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex); } } } } while ((match = this.tokenizer.rules.inline.blockSkip.exec(maskedSrc)) != null) { maskedSrc = maskedSrc.slice(0, match.index) + "[" + "a".repeat(match[0].length - 2) + "]" + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex); } while ((match = this.tokenizer.rules.inline.anyPunctuation.exec(maskedSrc)) != null) { maskedSrc = maskedSrc.slice(0, match.index) + "++" + maskedSrc.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex); } while (src) { if (!keepPrevChar) { prevChar = ""; } keepPrevChar = false; if (this.options.extensions && this.options.extensions.inline && this.options.extensions.inline.some((extTokenizer) => { if (token = extTokenizer.call({ lexer: this }, src, tokens)) { src = src.substring(token.raw.length); tokens.push(token); return true; } return false; })) { continue; } if (token = this.tokenizer.escape(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } if (token = this.tokenizer.tag(src)) { src = src.substring(token.raw.length); lastToken = tokens[tokens.length - 1]; if (lastToken && token.type === "text" && lastToken.type === "text") { lastToken.raw += token.raw; lastToken.text += token.text; } else { tokens.push(token); } continue; } if (token = this.tokenizer.link(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } if (token = this.tokenizer.reflink(src, this.tokens.links)) { src = src.substring(token.raw.length); lastToken = tokens[tokens.length - 1]; if (lastToken && token.type === "text" && lastToken.type === "text") { lastToken.raw += token.raw; lastToken.text += token.text; } else { tokens.push(token); } continue; } if (token = this.tokenizer.emStrong(src, maskedSrc, prevChar)) { src = src.substring(token.raw.length); tokens.push(token); continue; } if (token = this.tokenizer.codespan(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } if (token = this.tokenizer.br(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } if (token = this.tokenizer.del(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } if (token = this.tokenizer.autolink(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } if (!this.state.inLink && (token = this.tokenizer.url(src))) { src = src.substring(token.raw.length); tokens.push(token); continue; } cutSrc = src; if (this.options.extensions && this.options.extensions.startInline) { let startIndex = Infinity; const tempSrc = src.slice(1); let tempStart; this.options.extensions.startInline.forEach((getStartIndex) => { tempStart = getStartIndex.call({ lexer: this }, tempSrc); if (typeof tempStart === "number" && tempStart >= 0) { startIndex = Math.min(startIndex, tempStart); } }); if (startIndex < Infinity && startIndex >= 0) { cutSrc = src.substring(0, startIndex + 1); } } if (token = this.tokenizer.inlineText(cutSrc)) { src = src.substring(token.raw.length); if (token.raw.slice(-1) !== "_") { prevChar = token.raw.slice(-1); } keepPrevChar = true; lastToken = tokens[tokens.length - 1]; if (lastToken && lastToken.type === "text") { lastToken.raw += token.raw; lastToken.text += token.text; } else { tokens.push(token); } continue; } if (src) { const errMsg = "Infinite loop on byte: " + src.charCodeAt(0); if (this.options.silent) { console.error(errMsg); break; } else { throw new Error(errMsg); } } } return tokens; } } class _Renderer { // set by the parser constructor(options) { __publicField(this, "options"); __publicField(this, "parser"); this.options = options || _defaults; } space(token) { return ""; } code({ text, lang, escaped }) { var _a; const langString = (_a = (lang || "").match(/^\S*/)) == null ? void 0 : _a[0]; const code = text.replace(/\n$/, "") + "\n"; if (!langString) { return "<pre><code>" + (escaped ? code : escape$1(code, true)) + "</code></pre>\n"; } return '<pre><code class="language-' + escape$1(langString) + '">' + (escaped ? code : escape$1(code, true)) + "</code></pre>\n"; } blockquote({ tokens }) { const body = this.parser.parse(tokens); return `<blockquote> ${body}</blockquote> `; } html({ text }) { return text; } heading({ tokens, depth }) { return `<h${depth}>${this.parser.parseInline(tokens)}</h${depth}> `; } hr(token) { return "<hr>\n"; } list(token) { const ordered = token.ordered; const start = token.start; let body = ""; for (let j = 0; j < token.items.length; j++) { const item = token.items[j]; body += this.listitem(item); } const type = ordered ? "ol" : "ul"; const startAttr = ordered && start !== 1 ? ' start="' + start + '"' : ""; return "<" + type + startAttr + ">\n" + body + "</" + type + ">\n"; } listitem(item) { let itemBody = ""; if (item.task) { const checkbox = this.checkbox({ checked: !!item.checked }); if (item.loose) { if (item.tokens.length > 0 && item.tokens[0].type === "paragraph") { item.tokens[0].text = checkbox + " " + item.tokens[0].text; if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === "text") { item.tokens[0].tokens[0].text = checkbox + " " + item.tokens[0].tokens[0].text; } } else { item.tokens.unshift({ type: "text", raw: checkbox + " ", text: checkbox + " " }); } } else { itemBody += checkbox + " "; } } itemBody += this.parser.parse(item.tokens, !!item.loose); return `<li>${itemBody}</li> `; } checkbox({ checked }) { return "<input " + (checked ? 'checked="" ' : "") + 'disabled="" type="checkbox">'; } paragraph({ tokens }) { return `<p>${this.parser.parseInline(tokens)}</p> `; } table(token) { let header = ""; let cell = ""; for (let j = 0; j < token.header.length; j++) { cell += this.tablecell(token.header[j]); } header += this.tablerow({ text: cell }); let body = ""; for (let j = 0; j < token.rows.length; j++) { const row = token.rows[j]; cell = ""; for (let k = 0; k < row.length; k++) { cell += this.tablecell(row[k]); } body += this.tablerow({ text: cell }); } if (body) body = `<tbody>${body}</tbody>`; return "<table>\n<thead>\n" + header + "</thead>\n" + body + "</table>\n"; } tablerow({ text }) { return `<tr> ${text}</tr> `; } tablecell(token) { const content = this.parser.parseInline(token.tokens); const type = token.header ? "th" : "td"; const tag2 = token.align ? `<${type} align="${token.align}">` : `<${type}>`; return tag2 + content + `</${type}> `; } /** * span level renderer */ strong({ tokens }) { return `<strong>${this.parser.parseInline(tokens)}</strong>`; } em({ tokens }) { return `<em>${this.parser.parseInline(tokens)}</em>`; } codespan({ text }) { return `<code>${text}</code>`; } br(token) { return "<br>"; } del({ tokens }) { return `<del>${this.parser.parseInline(tokens)}</del>`; } link({ href, title, tokens }) { const text = this.parser.parseInline(tokens); const cleanHref = cleanUrl(href); if (cleanHref === null) { return text; } href = cleanHref; let out = '<a href="' + href + '"'; if (title) { out += ' title="' + title + '"'; } out += ">" + text + "</a>"; return out; } image({ href, title, text }) { const cleanHref = cleanUrl(href); if (cleanHref === null) { return text; } href = cleanHref; let out = `<img src="${href}" alt="${text}"`; if (title) { out += ` title="${title}"`; } out += ">"; return out; } text(token) { return "tokens" in token && token.tokens ? this.parser.parseInline(token.tokens) : token.text; } } class _TextRenderer { // no need for block level renderers strong({ text }) { return text; } em({ text }) { return text; } codespan({ text }) { return text; } del({ text }) { return text; } html({ text }) { return text; } text({ text }) { return text; } link({ text }) { return "" + text; } image({ text }) { return "" + text; } br() { return ""; } } class _Parser { constructor(options) { __publicField(this, "options"); __publicField(this, "renderer"); __publicField(this, "textRenderer"); this.options = options || _defaults; this.options.renderer = this.options.renderer || new _Renderer(); this.renderer = this.options.renderer; this.renderer.options = this.options; this.renderer.parser = this; this.textRenderer = new _TextRenderer(); } /** * Static Parse Method */ static parse(tokens, options) { const parser = new _Parser(options); return parser.parse(tokens); } /** * Static Parse Inline Method */ static parseInline(tokens, options) { const parser = new _Parser(options); return parser.parseInline(tokens); } /** * Parse Loop */ parse(tokens, top = true) { let out = ""; for (let i = 0; i < tokens.length; i++) { const anyToken = tokens[i]; if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[anyToken.type]) { const genericToken = anyToken; const ret = this.options.extensions.renderers[genericToken.type].call({ parser: this }, genericToken); if (ret !== false || !["space", "hr", "heading", "code", "table", "blockquote", "list", "html", "paragraph", "text"].includes(genericToken.type)) { out += ret || ""; continue; } } const token = anyToken; switch (token.type) { case "space": { out += this.renderer.space(token); continue; } case "hr": { out += this.renderer.hr(token); continue; } case "heading": { out += this.renderer.heading(token); continue; } case "code": { out += this.renderer.code(token); continue; } case "table": { out += this.renderer.table(token); continue; } case "blockquote": { out += this.renderer.blockquote(token); continue; } case "list": { out += this.renderer.list(token); continue; } case "html": { out += this.renderer.html(token); continue; } case "paragraph": { out += this.renderer.paragraph(token); continue; } case "text": { let textToken = token; let body = this.renderer.text(textToken); while (i + 1 < tokens.length && tokens[i + 1].type === "text") { textToken = tokens[++i]; body += "\n" + this.renderer.text(textToken); } if (top) { out += this.renderer.paragraph({ type: "paragraph", raw: body, text: body, tokens: [{ type: "text", raw: body, text: body }] }); } else { out += body; } continue; } default: { const errMsg = 'Token with "' + token.type + '" type was not found.'; if (this.options.silent) { console.error(errMsg); return ""; } else { throw new Error(errMsg); } } } } return out; } /** * Parse Inline Tokens */ parseInline(tokens, renderer) { renderer = renderer || this.renderer; let out = ""; for (let i = 0; i < tokens.length; i++) { const anyToken = tokens[i]; if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[anyToken.type]) { const ret = this.options.extensions.renderers[anyToken.type].call({ parser: this }, anyToken); if (ret !== false || !["escape", "html", "link", "image", "strong", "em", "codespan", "br", "del", "text"].includes(anyToken.type)) { out += ret || ""; continue; } } const token = anyToken; switch (token.type) { case "escape": { out += renderer.text(token); break; } case "html": { out += renderer.html(token); break; } case "link": { out += renderer.link(token); break; } case "image": { out += renderer.image(token); break; } case "strong": { out += renderer.strong(token); break; } case "em": { out += renderer.em(token); break; } case "codespan": { out += renderer.codespan(token); break; } case "br": { out += renderer.br(token); break; } case "del": { out += renderer.del(token); break; } case "text": { out += renderer.text(token); break; } default: { const errMsg = 'Token with "' + token.type + '" type was not found.'; if (this.options.silent) { console.error(errMsg); return ""; } else { throw new Error(errMsg); } } } } return out; } } class _Hooks { constructor(options) { __publicField(this, "options"); __publicField(this, "block"); this.options = options || _defaults; } /** * Process markdown before marked */ preprocess(markdown) { return markdown; } /** * Process HTML after marked is finished */ postprocess(html2) { return html2; } /** * Process all tokens before walk tokens */ processAllTokens(tokens) { return tokens; } /** * Provide function to tokenize markdown */ provideLexer() { return this.block ? _Lexer.lex : _Lexer.lexInline; } /** * Provide function to parse tokens */ provideParser() { return this.block ? _Parser.parse : _Parser.parseInline; } } __publicField(_Hooks, "passThroughHooks", /* @__PURE__ */ new Set([ "preprocess", "postprocess", "processAllTokens" ])); class Marked { constructor(...args) { __publicField(this, "defaults", _getDefaults()); __publicField(this, "options", this.setOptions); __publicField(this, "parse", this.parseMarkdown(true)); __publicField(this, "parseInline", this.parseMarkdown(false)); __publicField(this, "Parser", _Parser); __publicField(this, "Renderer", _Renderer); __publicField(this, "TextRenderer", _TextRenderer); __publicField(this, "Lexer", _Lexer); __publicField(this, "Tokenizer", _Tokenizer); __publicField(this, "Hooks", _Hooks); this.use(...args); } /** * Run callback for every token */ walkTokens(tokens, callback) { var _a, _b; let values = []; for (const token of tokens) { values = values.concat(callback.call(this, token)); switch (token.type) { case "table": { const tableToken = token; for (const cell of tableToken.header) { values = values.concat(this.walkTokens(cell.tokens, callback)); } for (const row of tableToken.rows) { for (const cell of row) { values = values.concat(this.walkTokens(cell.tokens, callback)); } } break; } case "list": { const listToken = token; values = values.concat(this.walkTokens(listToken.items, callback)); break; } default: { const genericToken = token; if ((_b = (_a = this.defaults.extensions) == null ? void 0 : _a.childTokens) == null ? void 0 : _b[genericToken.type]) { this.defaults.extensions.childTokens[genericToken.type].forEach((childTokens) => { const tokens2 = genericToken[childTokens].flat(Infinity); values = values.concat(this.walkTokens(tokens2, callback)); }); } else if (genericToken.tokens) { values = values.concat(this.walkTokens(genericToken.tokens, callback)); } } } } return values; } use(...args) { const extensions = this.defaults.extensions || { renderers: {}, childTokens: {} }; args.forEach((pack) => { const opts = { ...pack }; opts.async = this.defaults.async || opts.async || false; if (pack.extensions) { pack.extensions.forEach((ext) => { if (!ext.name) { throw new Error("extension name required"); } if ("renderer" in ext) { const prevRenderer = extensions.renderers[ext.name]; if (prevRenderer) { extensions.renderers[ext.name] = function (...args2) { let ret = ext.renderer.apply(this, args2); if (ret === false) { ret = prevRenderer.apply(this, args2); } return ret; }; } else { extensions.renderers[ext.name] = ext.renderer; } } if ("tokenizer" in ext) { if (!ext.level || ext.level !== "block" && ext.level !== "inline") { throw new Error("extension level must be 'block' or 'inline'"); } const extLevel = extensions[ext.level]; if (extLevel) { extLevel.unshift(ext.tokenizer); } else { extensions[ext.level] = [ext.tokenizer]; } if (ext.start) { if (ext.level === "block") { if (extensions.startBlock) { extensions.startBlock.push(ext.start); } else { extensions.startBlock = [ext.start]; } } else if (ext.level === "inline") { if (extensions.startInline) { extensions.startInline.push(ext.start); } else { extensions.startInline = [ext.start]; } } } } if ("childTokens" in ext && ext.childTokens) { extensions.childTokens[ext.name] = ext.childTokens; } }); opts.extensions = extensions; } if (pack.renderer) { const renderer = this.defaults.renderer || new _Renderer(this.defaults); for (const prop in pack.renderer) { if (!(prop in renderer)) { throw new Error(`renderer '${prop}' does not exist`); } if (["options", "parser"].includes(prop)) { continue; } const rendererProp = prop; const rendererFunc = pack.renderer[rendererProp]; const prevRenderer = renderer[rendererProp]; renderer[rendererProp] = (...args2) => { let ret = rendererFunc.apply(renderer, args2); if (ret === false) { ret = prevRenderer.apply(renderer, args2); } return ret || ""; }; } opts.renderer = renderer; } if (pack.tokenizer) { const tokenizer = this.defaults.tokenizer || new _Tokenizer(this.defaults); for (const prop in pack.tokenizer) { if (!(prop in tokenizer)) { throw new Error(`tokenizer '${prop}' does not exist`); } if (["options", "rules", "lexer"].includes(prop)) { continue; } const tokenizerProp = prop; const tokenizerFunc = pack.tokenizer[tokenizerProp]; const prevTokenizer = tokenizer[tokenizerProp]; tokenizer[tokenizerProp] = (...args2) => { let ret = tokenizerFunc.apply(tokenizer, args2); if (ret === false) { ret = prevTokenizer.apply(tokenizer, args2); } return ret; }; } opts.tokenizer = tokenizer; } if (pack.hooks) { const hooks = this.defaults.hooks || new _Hooks(); for (const prop in pack.hooks) { if (!(prop in hooks)) { throw new Error(`hook '${prop}' does not exist`); } if (["options", "block"].includes(prop)) { continue; } const hooksProp = prop; const hooksFunc = pack.hooks[hooksProp]; const prevHook = hooks[hooksProp]; if (_Hooks.passThroughHooks.has(prop)) { hooks[hooksProp] = (arg) => { if (this.defaults.async) { return Promise.resolve(hooksFunc.call(hooks, arg)).then((ret2) => { return prevHook.call(hooks, ret2); }); } const ret = hooksFunc.call(hooks, arg); return prevHook.call(hooks, ret); }; } else { hooks[hooksProp] = (...args2) => { let ret = hooksFunc.apply(hooks, args2); if (ret === false) { ret = prevHook.apply(hooks, args2); } return ret; }; } } opts.hooks = hooks; } if (pack.walkTokens) { const walkTokens = this.defaults.walkTokens; const packWalktokens = pack.walkTokens; opts.walkTokens = function (token) { let values = []; values.push(packWalktokens.call(this, token)); if (walkTokens) { values = values.concat(walkTokens.call(this, token)); } return values; }; } this.defaults = { ...this.defaults, ...opts }; }); return this; } setOptions(opt) { this.defaults = { ...this.defaults, ...opt }; return this; } lexer(src, options) { return _Lexer.lex(src, options ? options : this.defaults); } parser(tokens, options) { return _Parser.parse(tokens, options ? options : this.defaults); } parseMarkdown(blockType) { const parse = (src, options) => { const origOpt = { ...options }; const opt = { ...this.defaults, ...origOpt }; const throwError = this.onError(!!opt.silent, !!opt.async); if (this.defaults.async === true && origOpt.async === false) { return throwError(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise.")); } if (typeof src === "undefined" || src === null) { return throwError(new Error("marked(): input parameter is undefined or null")); } if (typeof src !== "string") { return throwError(new Error("marked(): input parameter is of type " + Object.prototype.toString.call(src) + ", string expected")); } if (opt.hooks) { opt.hooks.options = opt; opt.hooks.block = blockType; } const lexer = opt.hooks ? opt.hooks.provideLexer() : blockType ? _Lexer.lex : _Lexer.lexInline; const parser = opt.hooks ? opt.hooks.provideParser() : blockType ? _Parser.parse : _Parser.parseInline; if (opt.async) { return Promise.resolve(opt.hooks ? opt.hooks.preprocess(src) : src).then((src2) => lexer(src2, opt)).then((tokens) => opt.hooks ? opt.hooks.processAllTokens(tokens) : tokens).then((tokens) => opt.walkTokens ? Promise.all(this.walkTokens(tokens, opt.walkTokens)).then(() => tokens) : tokens).then((tokens) => parser(tokens, opt)).then((html2) => opt.hooks ? opt.hooks.postprocess(html2) : html2).catch(throwError); } try { if (opt.hooks) { src = opt.hooks.preprocess(src); } let tokens = lexer(src, opt); if (opt.hooks) { tokens = opt.hooks.processAllTokens(tokens); } if (opt.walkTokens) { this.walkTokens(tokens, opt.walkTokens); } let html2 = parser(tokens, opt); if (opt.hooks) { html2 = opt.hooks.postprocess(html2); } return html2; } catch (e) { return throwError(e); } }; return parse; } onError(silent, async) { return (e) => { e.message += "\nPlease report this to https://github.com/markedjs/marked."; if (silent) { const msg = "<p>An error occurred:</p><pre>" + escape$1(e.message + "", true) + "</pre>"; if (async) { return Promise.resolve(msg); } return msg; } if (async) { return Promise.reject(e); } throw e; }; } } const markedInstance = new Marked(); function marked(src, opt) { return markedInstance.parse(src, opt); } marked.options = marked.setOptions = function (options) { markedInstance.setOptions(options); marked.defaults = markedInstance.defaults; changeDefaults(marked.defaults); return marked; }; marked.getDefaults = _getDefaults; marked.defaults = _defaults; marked.use = function (...args) { markedInstance.use(...args); marked.defaults = markedInstance.defaults; changeDefaults(marked.defaults); return marked; }; marked.walkTokens = function (tokens, callback) { return markedInstance.walkTokens(tokens, callback); }; marked.parseInline = markedInstance.parseInline; marked.Parser = _Parser; marked.parser = _Parser.parse; marked.Renderer = _Renderer; marked.TextRenderer = _TextRenderer; marked.Lexer = _Lexer; marked.lexer = _Lexer.lex; marked.Tokenizer = _Tokenizer; marked.Hooks = _Hooks; marked.parse = marked; marked.options; marked.setOptions; marked.use; marked.walkTokens; marked.parseInline; _Parser.parse; _Lexer.lex; function md2html(md) { return marked(md); } const _export_sfc = (sfc, props) => { const target = sfc.__vccOpts || sfc; for (const [key, val] of props) { target[key] = val; } return target; }; const _withScopeId = (n) => (vue.pushScopeId("data-v-b0fd14ee"), n = n(), vue.popScopeId(), n); const _hoisted_1 = { class: "monkeygpt-card" }; const _hoisted_2 = { class: "monkeygpt-header" }; const _hoisted_3 = { key: 0, class: "nav" }; const _hoisted_4 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("a", { href: "https://github.com/weekend-project-space/monkey-gpt" }, [ /* @__PURE__ */ vue.createElementVNode("img", { src: "https://img.shields.io/github/stars/weekend-project-space/monkey-gpt.svg?style=social&label=Stars", alt: "" }) ], -1)); const _hoisted_5 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("path", { d: "M18 6L6 18M6 6l12 12", stroke: "black", "stroke-width": "2", "stroke-linecap": "round" }, null, -1)); const _hoisted_6 = [ _hoisted_5 ]; const _hoisted_7 = { key: 0, class: "monkeygpt-body" }; const _hoisted_8 = { key: 0, class: "loading", viewBox: "0 0 100 100", xmlns: "http://www.w3.org/2000/svg" }; const _hoisted_9 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("circle", { cx: "50", cy: "50", r: "0", fill: "black" }, [ /* @__PURE__ */ vue.createElementVNode("animate", { attributeName: "r", values: "10;30;10", dur: "1s", repeatCount: "indefinite" }) ], -1)); const _hoisted_10 = [ _hoisted_9 ]; const _hoisted_11 = ["innerHTML"]; const _sfc_main$1 = { __name: "MonkeyGPT", props: { msg: String }, setup(__props) { const txt = vue.ref(""); const loading = vue.ref(false); function getText() { loading.value = true; txt.value = md2html(getSimpleText()); loading.value = false; } async function chat2(chatfun) { clear(); loading.value = true; try { txt.value = md2html(await chatfun(getSimpleText())); } catch { txt.value = "生成失败,请检查配置是否正确并刷新重试!"; } loading.value = false; } function clear() { txt.value = ""; } window.addEventListener("popstate", clear); const bodyShow = vue.computed(() => loading.value || txt.value); return (_ctx, _cache) => { return vue.openBlock(), vue.createElementBlock("div", { class: vue.normalizeClass({ "monkeygpt-warp": bodyShow.value }) }, [ vue.createElementVNode("div", _hoisted_1, [ vue.createElementVNode("div", _hoisted_2, [ bodyShow.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_3, [ vue.createElementVNode("h3", null, [ vue.createTextVNode(vue.toDisplayString(__props.msg) + " ", 1), _hoisted_4 ]), (vue.openBlock(), vue.createElementBlock("svg", { class: "close", onClick: clear, viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, _hoisted_6)) ])) : vue.createCommentVNode("", true), vue.createElementVNode("div", null, [ vue.createElementVNode("button", { onClick: getText }, "正文"), vue.createElementVNode("button", { onClick: _cache[0] || (_cache[0] = ($event) => chat2(vue.unref(summarize))) }, "总结"), vue.createElementVNode("button", { onClick: _cache[1] || (_cache[1] = ($event) => chat2(vue.unref(ask))) }, "回复") ]) ]), txt.value || loading.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_7, [ loading.value ? (vue.openBlock(), vue.createElementBlock("svg", _hoisted_8, _hoisted_10)) : txt.value ? (vue.openBlock(), vue.createElementBlock("div", { key: 1, innerHTML: txt.value }, null, 8, _hoisted_11)) : vue.createCommentVNode("", true) ])) : vue.createCommentVNode("", true) ]) ], 2); }; } }; const MonkeyGPT = /* @__PURE__ */ _export_sfc(_sfc_main$1, [ ["__scopeId", "data-v-b0fd14ee"] ]); const _sfc_main = { __name: "App", setup(__props) { return (_ctx, _cache) => { return vue.openBlock(), vue.createBlock(MonkeyGPT, { msg: "monkey gpt" }); }; } }; vue.createApp(_sfc_main).mount( (() => { const app = document.createElement("div"); app.id = "monkeygpt"; const firstChild = document.body.firstChild; document.body.insertBefore(app, firstChild); return app; })() ); })(Vue);