monkey-gpt

monkeygpt

当前为 2024-08-29 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name monkey-gpt
  3. // @namespace monkeygpt
  4. // @version 0.0.1
  5. // @author monkey
  6. // @icon https://jisuai.cn/logo.png
  7. // @match *://*/*
  8. // @require https://cdn.jsdelivr.net/npm/vue@3.4.38/dist/vue.global.prod.js
  9. // @grant GM_addStyle
  10. // @grant GM_getValue
  11. // @grant GM_setValue
  12. // @description monkeygpt
  13. // ==/UserScript==
  14.  
  15. (e => {
  16. if (typeof GM_addStyle == "function") {
  17. GM_addStyle(e);
  18. return
  19. }
  20. const t = document.createElement("style");
  21. t.textContent = e, document.head.append(t)
  22. })(" :root{font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-text-size-adjust:100%}#monkeygpt{max-width:360px;margin:0 auto;padding:1rem;position:fixed;top:0;right:0;z-index:10000;background:#fff9;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border-radius:.3rem;box-shadow:0 4px 6px #0000001a;color:#666;max-height:100vh;overflow:auto;box-sizing:border-box}#monkeygpt .loader{border:8px solid #f3f3f3;border-top:8px solid #3498db;border-radius:50%;width:60px;height:60px;animation:spin 1s linear infinite}#monkeygpt button{border:none;background:none;margin:0 7px 0 0;text-decoration:none;font-weight:700;color:#009a61;cursor:pointer;width:auto;overflow:visible;padding:4px 7px 3px;font-size:12px;line-height:130%;font-family:Lucida Grande,Tahoma,Arial,Verdana,sans-serif}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.monkeygpt-header[data-v-479cc38e]{top:0}.loader[data-v-479cc38e]{margin:1rem auto}img[data-v-479cc38e]{height:1rem;margin:0 .5rem}h3[data-v-479cc38e]{margin-block-end:1rem;margin-block-start:.5rem;margin-left:.6rem}.card[data-v-479cc38e]{padding:.8rem} ");
  23.  
  24. (function (vue) {
  25. 'use strict';
  26.  
  27. var __defProp = Object.defineProperty;
  28. var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, {
  29. enumerable: true,
  30. configurable: true,
  31. writable: true,
  32. value
  33. }) : obj[key] = value;
  34. var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
  35. var Readability$1 = {
  36. exports: {}
  37. };
  38. (function (module) {
  39. function Readability2(doc, options) {
  40. if (options && options.documentElement) {
  41. doc = options;
  42. options = arguments[2];
  43. } else if (!doc || !doc.documentElement) {
  44. throw new Error("First argument to Readability constructor should be a document object.");
  45. }
  46. options = options || {};
  47. this._doc = doc;
  48. this._docJSDOMParser = this._doc.firstChild.__JSDOMParser__;
  49. this._articleTitle = null;
  50. this._articleByline = null;
  51. this._articleDir = null;
  52. this._articleSiteName = null;
  53. this._attempts = [];
  54. this._debug = !!options.debug;
  55. this._maxElemsToParse = options.maxElemsToParse || this.DEFAULT_MAX_ELEMS_TO_PARSE;
  56. this._nbTopCandidates = options.nbTopCandidates || this.DEFAULT_N_TOP_CANDIDATES;
  57. this._charThreshold = options.charThreshold || this.DEFAULT_CHAR_THRESHOLD;
  58. this._classesToPreserve = this.CLASSES_TO_PRESERVE.concat(options.classesToPreserve || []);
  59. this._keepClasses = !!options.keepClasses;
  60. this._serializer = options.serializer || function (el) {
  61. return el.innerHTML;
  62. };
  63. this._disableJSONLD = !!options.disableJSONLD;
  64. this._allowedVideoRegex = options.allowedVideoRegex || this.REGEXPS.videos;
  65. this._flags = this.FLAG_STRIP_UNLIKELYS | this.FLAG_WEIGHT_CLASSES | this.FLAG_CLEAN_CONDITIONALLY;
  66. if (this._debug) {
  67. let logNode = function (node) {
  68. if (node.nodeType == node.TEXT_NODE) {
  69. return `${node.nodeName} ("${node.textContent}")`;
  70. }
  71. let attrPairs = Array.from(node.attributes || [], function (attr) {
  72. return `${attr.name}="${attr.value}"`;
  73. }).join(" ");
  74. return `<${node.localName} ${attrPairs}>`;
  75. };
  76. this.log = function () {
  77. if (typeof console !== "undefined") {
  78. let args = Array.from(arguments, (arg) => {
  79. if (arg && arg.nodeType == this.ELEMENT_NODE) {
  80. return logNode(arg);
  81. }
  82. return arg;
  83. });
  84. args.unshift("Reader: (Readability)");
  85. console.log.apply(console, args);
  86. } else if (typeof dump !== "undefined") {
  87. var msg = Array.prototype.map.call(arguments, function (x) {
  88. return x && x.nodeName ? logNode(x) : x;
  89. }).join(" ");
  90. dump("Reader: (Readability) " + msg + "\n");
  91. }
  92. };
  93. } else {
  94. this.log = function () {};
  95. }
  96. }
  97. Readability2.prototype = {
  98. FLAG_STRIP_UNLIKELYS: 1,
  99. FLAG_WEIGHT_CLASSES: 2,
  100. FLAG_CLEAN_CONDITIONALLY: 4,
  101. // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
  102. ELEMENT_NODE: 1,
  103. TEXT_NODE: 3,
  104. // Max number of nodes supported by this parser. Default: 0 (no limit)
  105. DEFAULT_MAX_ELEMS_TO_PARSE: 0,
  106. // The number of top candidates to consider when analysing how
  107. // tight the competition is among candidates.
  108. DEFAULT_N_TOP_CANDIDATES: 5,
  109. // Element tags to score by default.
  110. DEFAULT_TAGS_TO_SCORE: "section,h2,h3,h4,h5,h6,p,td,pre".toUpperCase().split(","),
  111. // The default number of chars an article must have in order to return a result
  112. DEFAULT_CHAR_THRESHOLD: 500,
  113. // All of the regular expressions in use within readability.
  114. // Defined up here so we don't instantiate them repeatedly in loops.
  115. REGEXPS: {
  116. // NOTE: These two regular expressions are duplicated in
  117. // Readability-readerable.js. Please keep both copies in sync.
  118. 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,
  119. okMaybeItsACandidate: /and|article|body|column|content|main|shadow/i,
  120. positive: /article|body|content|entry|hentry|h-entry|main|page|pagination|post|text|blog|story/i,
  121. 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,
  122. extraneous: /print|archive|comment|discuss|e[\-]?mail|share|reply|all|login|sign|single|utility/i,
  123. byline: /byline|author|dateline|writtenby|p-author/i,
  124. replaceFonts: /<(\/?)font[^>]*>/gi,
  125. normalize: /\s{2,}/g,
  126. videos: /\/\/(www\.)?((dailymotion|youtube|youtube-nocookie|player\.vimeo|v\.qq)\.com|(archive|upload\.wikimedia)\.org|player\.twitch\.tv)/i,
  127. shareElements: /(\b|_)(share|sharedaddy)(\b|_)/i,
  128. nextLink: /(next|weiter|continue|>([^\|]|$)|»([^\|]|$))/i,
  129. prevLink: /(prev|earl|old|new|<|«)/i,
  130. tokenize: /\W+/g,
  131. whitespace: /^\s*$/,
  132. hasContent: /\S$/,
  133. hashUrl: /^#.+/,
  134. srcsetUrl: /(\S+)(\s+[\d.]+[xw])?(\s*(?:,|$))/g,
  135. b64DataUrl: /^data:\s*([^\s;,]+)\s*;\s*base64\s*,/i,
  136. // Commas as used in Latin, Sindhi, Chinese and various other scripts.
  137. // see: https://en.wikipedia.org/wiki/Comma#Comma_variants
  138. commas: /\u002C|\u060C|\uFE50|\uFE10|\uFE11|\u2E41|\u2E34|\u2E32|\uFF0C/g,
  139. // See: https://schema.org/Article
  140. jsonLdArticleTypes: /^Article|AdvertiserContentArticle|NewsArticle|AnalysisNewsArticle|AskPublicNewsArticle|BackgroundNewsArticle|OpinionNewsArticle|ReportageNewsArticle|ReviewNewsArticle|Report|SatiricalArticle|ScholarlyArticle|MedicalScholarlyArticle|SocialMediaPosting|BlogPosting|LiveBlogPosting|DiscussionForumPosting|TechArticle|APIReference$/
  141. },
  142. UNLIKELY_ROLES: ["menu", "menubar", "complementary", "navigation", "alert", "alertdialog", "dialog"],
  143. DIV_TO_P_ELEMS: /* @__PURE__ */ new Set(["BLOCKQUOTE", "DL", "DIV", "IMG", "OL", "P", "PRE", "TABLE", "UL"]),
  144. ALTER_TO_DIV_EXCEPTIONS: ["DIV", "ARTICLE", "SECTION", "P"],
  145. PRESENTATIONAL_ATTRIBUTES: ["align", "background", "bgcolor", "border", "cellpadding", "cellspacing", "frame", "hspace", "rules", "style", "valign", "vspace"],
  146. DEPRECATED_SIZE_ATTRIBUTE_ELEMS: ["TABLE", "TH", "TD", "HR", "PRE"],
  147. // The commented out elements qualify as phrasing content but tend to be
  148. // removed by readability when put into paragraphs, so we ignore them here.
  149. PHRASING_ELEMS: [
  150. // "CANVAS", "IFRAME", "SVG", "VIDEO",
  151. "ABBR",
  152. "AUDIO",
  153. "B",
  154. "BDO",
  155. "BR",
  156. "BUTTON",
  157. "CITE",
  158. "CODE",
  159. "DATA",
  160. "DATALIST",
  161. "DFN",
  162. "EM",
  163. "EMBED",
  164. "I",
  165. "IMG",
  166. "INPUT",
  167. "KBD",
  168. "LABEL",
  169. "MARK",
  170. "MATH",
  171. "METER",
  172. "NOSCRIPT",
  173. "OBJECT",
  174. "OUTPUT",
  175. "PROGRESS",
  176. "Q",
  177. "RUBY",
  178. "SAMP",
  179. "SCRIPT",
  180. "SELECT",
  181. "SMALL",
  182. "SPAN",
  183. "STRONG",
  184. "SUB",
  185. "SUP",
  186. "TEXTAREA",
  187. "TIME",
  188. "VAR",
  189. "WBR"
  190. ],
  191. // These are the classes that readability sets itself.
  192. CLASSES_TO_PRESERVE: ["page"],
  193. // These are the list of HTML entities that need to be escaped.
  194. HTML_ESCAPE_MAP: {
  195. "lt": "<",
  196. "gt": ">",
  197. "amp": "&",
  198. "quot": '"',
  199. "apos": "'"
  200. },
  201. /**
  202. * Run any post-process modifications to article content as necessary.
  203. *
  204. * @param Element
  205. * @return void
  206. **/
  207. _postProcessContent: function (articleContent) {
  208. this._fixRelativeUris(articleContent);
  209. this._simplifyNestedElements(articleContent);
  210. if (!this._keepClasses) {
  211. this._cleanClasses(articleContent);
  212. }
  213. },
  214. /**
  215. * Iterates over a NodeList, calls `filterFn` for each node and removes node
  216. * if function returned `true`.
  217. *
  218. * If function is not passed, removes all the nodes in node list.
  219. *
  220. * @param NodeList nodeList The nodes to operate on
  221. * @param Function filterFn the function to use as a filter
  222. * @return void
  223. */
  224. _removeNodes: function (nodeList, filterFn) {
  225. if (this._docJSDOMParser && nodeList._isLiveNodeList) {
  226. throw new Error("Do not pass live node lists to _removeNodes");
  227. }
  228. for (var i = nodeList.length - 1; i >= 0; i--) {
  229. var node = nodeList[i];
  230. var parentNode = node.parentNode;
  231. if (parentNode) {
  232. if (!filterFn || filterFn.call(this, node, i, nodeList)) {
  233. parentNode.removeChild(node);
  234. }
  235. }
  236. }
  237. },
  238. /**
  239. * Iterates over a NodeList, and calls _setNodeTag for each node.
  240. *
  241. * @param NodeList nodeList The nodes to operate on
  242. * @param String newTagName the new tag name to use
  243. * @return void
  244. */
  245. _replaceNodeTags: function (nodeList, newTagName) {
  246. if (this._docJSDOMParser && nodeList._isLiveNodeList) {
  247. throw new Error("Do not pass live node lists to _replaceNodeTags");
  248. }
  249. for (const node of nodeList) {
  250. this._setNodeTag(node, newTagName);
  251. }
  252. },
  253. /**
  254. * Iterate over a NodeList, which doesn't natively fully implement the Array
  255. * interface.
  256. *
  257. * For convenience, the current object context is applied to the provided
  258. * iterate function.
  259. *
  260. * @param NodeList nodeList The NodeList.
  261. * @param Function fn The iterate function.
  262. * @return void
  263. */
  264. _forEachNode: function (nodeList, fn) {
  265. Array.prototype.forEach.call(nodeList, fn, this);
  266. },
  267. /**
  268. * Iterate over a NodeList, and return the first node that passes
  269. * the supplied test function
  270. *
  271. * For convenience, the current object context is applied to the provided
  272. * test function.
  273. *
  274. * @param NodeList nodeList The NodeList.
  275. * @param Function fn The test function.
  276. * @return void
  277. */
  278. _findNode: function (nodeList, fn) {
  279. return Array.prototype.find.call(nodeList, fn, this);
  280. },
  281. /**
  282. * Iterate over a NodeList, return true if any of the provided iterate
  283. * function calls returns true, false otherwise.
  284. *
  285. * For convenience, the current object context is applied to the
  286. * provided iterate function.
  287. *
  288. * @param NodeList nodeList The NodeList.
  289. * @param Function fn The iterate function.
  290. * @return Boolean
  291. */
  292. _someNode: function (nodeList, fn) {
  293. return Array.prototype.some.call(nodeList, fn, this);
  294. },
  295. /**
  296. * Iterate over a NodeList, return true if all of the provided iterate
  297. * function calls return true, false otherwise.
  298. *
  299. * For convenience, the current object context is applied to the
  300. * provided iterate function.
  301. *
  302. * @param NodeList nodeList The NodeList.
  303. * @param Function fn The iterate function.
  304. * @return Boolean
  305. */
  306. _everyNode: function (nodeList, fn) {
  307. return Array.prototype.every.call(nodeList, fn, this);
  308. },
  309. /**
  310. * Concat all nodelists passed as arguments.
  311. *
  312. * @return ...NodeList
  313. * @return Array
  314. */
  315. _concatNodeLists: function () {
  316. var slice = Array.prototype.slice;
  317. var args = slice.call(arguments);
  318. var nodeLists = args.map(function (list2) {
  319. return slice.call(list2);
  320. });
  321. return Array.prototype.concat.apply([], nodeLists);
  322. },
  323. _getAllNodesWithTag: function (node, tagNames) {
  324. if (node.querySelectorAll) {
  325. return node.querySelectorAll(tagNames.join(","));
  326. }
  327. return [].concat.apply([], tagNames.map(function (tag2) {
  328. var collection = node.getElementsByTagName(tag2);
  329. return Array.isArray(collection) ? collection : Array.from(collection);
  330. }));
  331. },
  332. /**
  333. * Removes the class="" attribute from every element in the given
  334. * subtree, except those that match CLASSES_TO_PRESERVE and
  335. * the classesToPreserve array from the options object.
  336. *
  337. * @param Element
  338. * @return void
  339. */
  340. _cleanClasses: function (node) {
  341. var classesToPreserve = this._classesToPreserve;
  342. var className = (node.getAttribute("class") || "").split(/\s+/).filter(function (cls) {
  343. return classesToPreserve.indexOf(cls) != -1;
  344. }).join(" ");
  345. if (className) {
  346. node.setAttribute("class", className);
  347. } else {
  348. node.removeAttribute("class");
  349. }
  350. for (node = node.firstElementChild; node; node = node.nextElementSibling) {
  351. this._cleanClasses(node);
  352. }
  353. },
  354. /**
  355. * Converts each <a> and <img> uri in the given element to an absolute URI,
  356. * ignoring #ref URIs.
  357. *
  358. * @param Element
  359. * @return void
  360. */
  361. _fixRelativeUris: function (articleContent) {
  362. var baseURI = this._doc.baseURI;
  363. var documentURI = this._doc.documentURI;
  364.  
  365. function toAbsoluteURI(uri) {
  366. if (baseURI == documentURI && uri.charAt(0) == "#") {
  367. return uri;
  368. }
  369. try {
  370. return new URL(uri, baseURI).href;
  371. } catch (ex) {}
  372. return uri;
  373. }
  374. var links = this._getAllNodesWithTag(articleContent, ["a"]);
  375. this._forEachNode(links, function (link2) {
  376. var href = link2.getAttribute("href");
  377. if (href) {
  378. if (href.indexOf("javascript:") === 0) {
  379. if (link2.childNodes.length === 1 && link2.childNodes[0].nodeType === this.TEXT_NODE) {
  380. var text = this._doc.createTextNode(link2.textContent);
  381. link2.parentNode.replaceChild(text, link2);
  382. } else {
  383. var container = this._doc.createElement("span");
  384. while (link2.firstChild) {
  385. container.appendChild(link2.firstChild);
  386. }
  387. link2.parentNode.replaceChild(container, link2);
  388. }
  389. } else {
  390. link2.setAttribute("href", toAbsoluteURI(href));
  391. }
  392. }
  393. });
  394. var medias = this._getAllNodesWithTag(articleContent, [
  395. "img",
  396. "picture",
  397. "figure",
  398. "video",
  399. "audio",
  400. "source"
  401. ]);
  402. this._forEachNode(medias, function (media) {
  403. var src = media.getAttribute("src");
  404. var poster = media.getAttribute("poster");
  405. var srcset = media.getAttribute("srcset");
  406. if (src) {
  407. media.setAttribute("src", toAbsoluteURI(src));
  408. }
  409. if (poster) {
  410. media.setAttribute("poster", toAbsoluteURI(poster));
  411. }
  412. if (srcset) {
  413. var newSrcset = srcset.replace(this.REGEXPS.srcsetUrl, function (_, p1, p2, p3) {
  414. return toAbsoluteURI(p1) + (p2 || "") + p3;
  415. });
  416. media.setAttribute("srcset", newSrcset);
  417. }
  418. });
  419. },
  420. _simplifyNestedElements: function (articleContent) {
  421. var node = articleContent;
  422. while (node) {
  423. if (node.parentNode && ["DIV", "SECTION"].includes(node.tagName) && !(node.id && node.id.startsWith("readability"))) {
  424. if (this._isElementWithoutContent(node)) {
  425. node = this._removeAndGetNext(node);
  426. continue;
  427. } else if (this._hasSingleTagInsideElement(node, "DIV") || this._hasSingleTagInsideElement(node, "SECTION")) {
  428. var child = node.children[0];
  429. for (var i = 0; i < node.attributes.length; i++) {
  430. child.setAttribute(node.attributes[i].name, node.attributes[i].value);
  431. }
  432. node.parentNode.replaceChild(child, node);
  433. node = child;
  434. continue;
  435. }
  436. }
  437. node = this._getNextNode(node);
  438. }
  439. },
  440. /**
  441. * Get the article title as an H1.
  442. *
  443. * @return string
  444. **/
  445. _getArticleTitle: function () {
  446. var doc = this._doc;
  447. var curTitle = "";
  448. var origTitle = "";
  449. try {
  450. curTitle = origTitle = doc.title.trim();
  451. if (typeof curTitle !== "string")
  452. curTitle = origTitle = this._getInnerText(doc.getElementsByTagName("title")[0]);
  453. } catch (e) {}
  454. var titleHadHierarchicalSeparators = false;
  455.  
  456. function wordCount(str) {
  457. return str.split(/\s+/).length;
  458. }
  459. if (/ [\|\-\\\/>»] /.test(curTitle)) {
  460. titleHadHierarchicalSeparators = / [\\\/>»] /.test(curTitle);
  461. curTitle = origTitle.replace(/(.*)[\|\-\\\/>»] .*/gi, "$1");
  462. if (wordCount(curTitle) < 3)
  463. curTitle = origTitle.replace(/[^\|\-\\\/>»]*[\|\-\\\/>»](.*)/gi, "$1");
  464. } else if (curTitle.indexOf(": ") !== -1) {
  465. var headings = this._concatNodeLists(
  466. doc.getElementsByTagName("h1"),
  467. doc.getElementsByTagName("h2")
  468. );
  469. var trimmedTitle = curTitle.trim();
  470. var match = this._someNode(headings, function (heading2) {
  471. return heading2.textContent.trim() === trimmedTitle;
  472. });
  473. if (!match) {
  474. curTitle = origTitle.substring(origTitle.lastIndexOf(":") + 1);
  475. if (wordCount(curTitle) < 3) {
  476. curTitle = origTitle.substring(origTitle.indexOf(":") + 1);
  477. } else if (wordCount(origTitle.substr(0, origTitle.indexOf(":"))) > 5) {
  478. curTitle = origTitle;
  479. }
  480. }
  481. } else if (curTitle.length > 150 || curTitle.length < 15) {
  482. var hOnes = doc.getElementsByTagName("h1");
  483. if (hOnes.length === 1)
  484. curTitle = this._getInnerText(hOnes[0]);
  485. }
  486. curTitle = curTitle.trim().replace(this.REGEXPS.normalize, " ");
  487. var curTitleWordCount = wordCount(curTitle);
  488. if (curTitleWordCount <= 4 && (!titleHadHierarchicalSeparators || curTitleWordCount != wordCount(origTitle.replace(/[\|\-\\\/>»]+/g, "")) - 1)) {
  489. curTitle = origTitle;
  490. }
  491. return curTitle;
  492. },
  493. /**
  494. * Prepare the HTML document for readability to scrape it.
  495. * This includes things like stripping javascript, CSS, and handling terrible markup.
  496. *
  497. * @return void
  498. **/
  499. _prepDocument: function () {
  500. var doc = this._doc;
  501. this._removeNodes(this._getAllNodesWithTag(doc, ["style"]));
  502. if (doc.body) {
  503. this._replaceBrs(doc.body);
  504. }
  505. this._replaceNodeTags(this._getAllNodesWithTag(doc, ["font"]), "SPAN");
  506. },
  507. /**
  508. * Finds the next node, starting from the given node, and ignoring
  509. * whitespace in between. If the given node is an element, the same node is
  510. * returned.
  511. */
  512. _nextNode: function (node) {
  513. var next = node;
  514. while (next && next.nodeType != this.ELEMENT_NODE && this.REGEXPS.whitespace.test(next.textContent)) {
  515. next = next.nextSibling;
  516. }
  517. return next;
  518. },
  519. /**
  520. * Replaces 2 or more successive <br> elements with a single <p>.
  521. * Whitespace between <br> elements are ignored. For example:
  522. * <div>foo<br>bar<br> <br><br>abc</div>
  523. * will become:
  524. * <div>foo<br>bar<p>abc</p></div>
  525. */
  526. _replaceBrs: function (elem) {
  527. this._forEachNode(this._getAllNodesWithTag(elem, ["br"]), function (br2) {
  528. var next = br2.nextSibling;
  529. var replaced = false;
  530. while ((next = this._nextNode(next)) && next.tagName == "BR") {
  531. replaced = true;
  532. var brSibling = next.nextSibling;
  533. next.parentNode.removeChild(next);
  534. next = brSibling;
  535. }
  536. if (replaced) {
  537. var p = this._doc.createElement("p");
  538. br2.parentNode.replaceChild(p, br2);
  539. next = p.nextSibling;
  540. while (next) {
  541. if (next.tagName == "BR") {
  542. var nextElem = this._nextNode(next.nextSibling);
  543. if (nextElem && nextElem.tagName == "BR")
  544. break;
  545. }
  546. if (!this._isPhrasingContent(next))
  547. break;
  548. var sibling = next.nextSibling;
  549. p.appendChild(next);
  550. next = sibling;
  551. }
  552. while (p.lastChild && this._isWhitespace(p.lastChild)) {
  553. p.removeChild(p.lastChild);
  554. }
  555. if (p.parentNode.tagName === "P")
  556. this._setNodeTag(p.parentNode, "DIV");
  557. }
  558. });
  559. },
  560. _setNodeTag: function (node, tag2) {
  561. this.log("_setNodeTag", node, tag2);
  562. if (this._docJSDOMParser) {
  563. node.localName = tag2.toLowerCase();
  564. node.tagName = tag2.toUpperCase();
  565. return node;
  566. }
  567. var replacement = node.ownerDocument.createElement(tag2);
  568. while (node.firstChild) {
  569. replacement.appendChild(node.firstChild);
  570. }
  571. node.parentNode.replaceChild(replacement, node);
  572. if (node.readability)
  573. replacement.readability = node.readability;
  574. for (var i = 0; i < node.attributes.length; i++) {
  575. try {
  576. replacement.setAttribute(node.attributes[i].name, node.attributes[i].value);
  577. } catch (ex) {}
  578. }
  579. return replacement;
  580. },
  581. /**
  582. * Prepare the article node for display. Clean out any inline styles,
  583. * iframes, forms, strip extraneous <p> tags, etc.
  584. *
  585. * @param Element
  586. * @return void
  587. **/
  588. _prepArticle: function (articleContent) {
  589. this._cleanStyles(articleContent);
  590. this._markDataTables(articleContent);
  591. this._fixLazyImages(articleContent);
  592. this._cleanConditionally(articleContent, "form");
  593. this._cleanConditionally(articleContent, "fieldset");
  594. this._clean(articleContent, "object");
  595. this._clean(articleContent, "embed");
  596. this._clean(articleContent, "footer");
  597. this._clean(articleContent, "link");
  598. this._clean(articleContent, "aside");
  599. var shareElementThreshold = this.DEFAULT_CHAR_THRESHOLD;
  600. this._forEachNode(articleContent.children, function (topCandidate) {
  601. this._cleanMatchedNodes(topCandidate, function (node, matchString) {
  602. return this.REGEXPS.shareElements.test(matchString) && node.textContent.length < shareElementThreshold;
  603. });
  604. });
  605. this._clean(articleContent, "iframe");
  606. this._clean(articleContent, "input");
  607. this._clean(articleContent, "textarea");
  608. this._clean(articleContent, "select");
  609. this._clean(articleContent, "button");
  610. this._cleanHeaders(articleContent);
  611. this._cleanConditionally(articleContent, "table");
  612. this._cleanConditionally(articleContent, "ul");
  613. this._cleanConditionally(articleContent, "div");
  614. this._replaceNodeTags(this._getAllNodesWithTag(articleContent, ["h1"]), "h2");
  615. this._removeNodes(this._getAllNodesWithTag(articleContent, ["p"]), function (paragraph2) {
  616. var imgCount = paragraph2.getElementsByTagName("img").length;
  617. var embedCount = paragraph2.getElementsByTagName("embed").length;
  618. var objectCount = paragraph2.getElementsByTagName("object").length;
  619. var iframeCount = paragraph2.getElementsByTagName("iframe").length;
  620. var totalCount = imgCount + embedCount + objectCount + iframeCount;
  621. return totalCount === 0 && !this._getInnerText(paragraph2, false);
  622. });
  623. this._forEachNode(this._getAllNodesWithTag(articleContent, ["br"]), function (br2) {
  624. var next = this._nextNode(br2.nextSibling);
  625. if (next && next.tagName == "P")
  626. br2.parentNode.removeChild(br2);
  627. });
  628. this._forEachNode(this._getAllNodesWithTag(articleContent, ["table"]), function (table) {
  629. var tbody = this._hasSingleTagInsideElement(table, "TBODY") ? table.firstElementChild : table;
  630. if (this._hasSingleTagInsideElement(tbody, "TR")) {
  631. var row = tbody.firstElementChild;
  632. if (this._hasSingleTagInsideElement(row, "TD")) {
  633. var cell = row.firstElementChild;
  634. cell = this._setNodeTag(cell, this._everyNode(cell.childNodes, this._isPhrasingContent) ? "P" : "DIV");
  635. table.parentNode.replaceChild(cell, table);
  636. }
  637. }
  638. });
  639. },
  640. /**
  641. * Initialize a node with the readability object. Also checks the
  642. * className/id for special names to add to its score.
  643. *
  644. * @param Element
  645. * @return void
  646. **/
  647. _initializeNode: function (node) {
  648. node.readability = {
  649. "contentScore": 0
  650. };
  651. switch (node.tagName) {
  652. case "DIV":
  653. node.readability.contentScore += 5;
  654. break;
  655. case "PRE":
  656. case "TD":
  657. case "BLOCKQUOTE":
  658. node.readability.contentScore += 3;
  659. break;
  660. case "ADDRESS":
  661. case "OL":
  662. case "UL":
  663. case "DL":
  664. case "DD":
  665. case "DT":
  666. case "LI":
  667. case "FORM":
  668. node.readability.contentScore -= 3;
  669. break;
  670. case "H1":
  671. case "H2":
  672. case "H3":
  673. case "H4":
  674. case "H5":
  675. case "H6":
  676. case "TH":
  677. node.readability.contentScore -= 5;
  678. break;
  679. }
  680. node.readability.contentScore += this._getClassWeight(node);
  681. },
  682. _removeAndGetNext: function (node) {
  683. var nextNode = this._getNextNode(node, true);
  684. node.parentNode.removeChild(node);
  685. return nextNode;
  686. },
  687. /**
  688. * Traverse the DOM from node to node, starting at the node passed in.
  689. * Pass true for the second parameter to indicate this node itself
  690. * (and its kids) are going away, and we want the next node over.
  691. *
  692. * Calling this in a loop will traverse the DOM depth-first.
  693. */
  694. _getNextNode: function (node, ignoreSelfAndKids) {
  695. if (!ignoreSelfAndKids && node.firstElementChild) {
  696. return node.firstElementChild;
  697. }
  698. if (node.nextElementSibling) {
  699. return node.nextElementSibling;
  700. }
  701. do {
  702. node = node.parentNode;
  703. } while (node && !node.nextElementSibling);
  704. return node && node.nextElementSibling;
  705. },
  706. // compares second text to first one
  707. // 1 = same text, 0 = completely different text
  708. // works the way that it splits both texts into words and then finds words that are unique in second text
  709. // the result is given by the lower length of unique parts
  710. _textSimilarity: function (textA, textB) {
  711. var tokensA = textA.toLowerCase().split(this.REGEXPS.tokenize).filter(Boolean);
  712. var tokensB = textB.toLowerCase().split(this.REGEXPS.tokenize).filter(Boolean);
  713. if (!tokensA.length || !tokensB.length) {
  714. return 0;
  715. }
  716. var uniqTokensB = tokensB.filter((token) => !tokensA.includes(token));
  717. var distanceB = uniqTokensB.join(" ").length / tokensB.join(" ").length;
  718. return 1 - distanceB;
  719. },
  720. _checkByline: function (node, matchString) {
  721. if (this._articleByline) {
  722. return false;
  723. }
  724. if (node.getAttribute !== void 0) {
  725. var rel = node.getAttribute("rel");
  726. var itemprop = node.getAttribute("itemprop");
  727. }
  728. if ((rel === "author" || itemprop && itemprop.indexOf("author") !== -1 || this.REGEXPS.byline.test(matchString)) && this._isValidByline(node.textContent)) {
  729. this._articleByline = node.textContent.trim();
  730. return true;
  731. }
  732. return false;
  733. },
  734. _getNodeAncestors: function (node, maxDepth) {
  735. maxDepth = maxDepth || 0;
  736. var i = 0,
  737. ancestors = [];
  738. while (node.parentNode) {
  739. ancestors.push(node.parentNode);
  740. if (maxDepth && ++i === maxDepth)
  741. break;
  742. node = node.parentNode;
  743. }
  744. return ancestors;
  745. },
  746. /***
  747. * grabArticle - Using a variety of metrics (content score, classname, element types), find the content that is
  748. * most likely to be the stuff a user wants to read. Then return it wrapped up in a div.
  749. *
  750. * @param page a document to run upon. Needs to be a full document, complete with body.
  751. * @return Element
  752. **/
  753. _grabArticle: function (page) {
  754. this.log("**** grabArticle ****");
  755. var doc = this._doc;
  756. var isPaging = page !== null;
  757. page = page ? page : this._doc.body;
  758. if (!page) {
  759. this.log("No body found in document. Abort.");
  760. return null;
  761. }
  762. var pageCacheHtml = page.innerHTML;
  763. while (true) {
  764. this.log("Starting grabArticle loop");
  765. var stripUnlikelyCandidates = this._flagIsActive(this.FLAG_STRIP_UNLIKELYS);
  766. var elementsToScore = [];
  767. var node = this._doc.documentElement;
  768. let shouldRemoveTitleHeader = true;
  769. while (node) {
  770. if (node.tagName === "HTML") {
  771. this._articleLang = node.getAttribute("lang");
  772. }
  773. var matchString = node.className + " " + node.id;
  774. if (!this._isProbablyVisible(node)) {
  775. this.log("Removing hidden node - " + matchString);
  776. node = this._removeAndGetNext(node);
  777. continue;
  778. }
  779. if (node.getAttribute("aria-modal") == "true" && node.getAttribute("role") == "dialog") {
  780. node = this._removeAndGetNext(node);
  781. continue;
  782. }
  783. if (this._checkByline(node, matchString)) {
  784. node = this._removeAndGetNext(node);
  785. continue;
  786. }
  787. if (shouldRemoveTitleHeader && this._headerDuplicatesTitle(node)) {
  788. this.log("Removing header: ", node.textContent.trim(), this._articleTitle.trim());
  789. shouldRemoveTitleHeader = false;
  790. node = this._removeAndGetNext(node);
  791. continue;
  792. }
  793. if (stripUnlikelyCandidates) {
  794. 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") {
  795. this.log("Removing unlikely candidate - " + matchString);
  796. node = this._removeAndGetNext(node);
  797. continue;
  798. }
  799. if (this.UNLIKELY_ROLES.includes(node.getAttribute("role"))) {
  800. this.log("Removing content with role " + node.getAttribute("role") + " - " + matchString);
  801. node = this._removeAndGetNext(node);
  802. continue;
  803. }
  804. }
  805. 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)) {
  806. node = this._removeAndGetNext(node);
  807. continue;
  808. }
  809. if (this.DEFAULT_TAGS_TO_SCORE.indexOf(node.tagName) !== -1) {
  810. elementsToScore.push(node);
  811. }
  812. if (node.tagName === "DIV") {
  813. var p = null;
  814. var childNode = node.firstChild;
  815. while (childNode) {
  816. var nextSibling = childNode.nextSibling;
  817. if (this._isPhrasingContent(childNode)) {
  818. if (p !== null) {
  819. p.appendChild(childNode);
  820. } else if (!this._isWhitespace(childNode)) {
  821. p = doc.createElement("p");
  822. node.replaceChild(p, childNode);
  823. p.appendChild(childNode);
  824. }
  825. } else if (p !== null) {
  826. while (p.lastChild && this._isWhitespace(p.lastChild)) {
  827. p.removeChild(p.lastChild);
  828. }
  829. p = null;
  830. }
  831. childNode = nextSibling;
  832. }
  833. if (this._hasSingleTagInsideElement(node, "P") && this._getLinkDensity(node) < 0.25) {
  834. var newNode = node.children[0];
  835. node.parentNode.replaceChild(newNode, node);
  836. node = newNode;
  837. elementsToScore.push(node);
  838. } else if (!this._hasChildBlockElement(node)) {
  839. node = this._setNodeTag(node, "P");
  840. elementsToScore.push(node);
  841. }
  842. }
  843. node = this._getNextNode(node);
  844. }
  845. var candidates = [];
  846. this._forEachNode(elementsToScore, function (elementToScore) {
  847. if (!elementToScore.parentNode || typeof elementToScore.parentNode.tagName === "undefined")
  848. return;
  849. var innerText = this._getInnerText(elementToScore);
  850. if (innerText.length < 25)
  851. return;
  852. var ancestors2 = this._getNodeAncestors(elementToScore, 5);
  853. if (ancestors2.length === 0)
  854. return;
  855. var contentScore = 0;
  856. contentScore += 1;
  857. contentScore += innerText.split(this.REGEXPS.commas).length;
  858. contentScore += Math.min(Math.floor(innerText.length / 100), 3);
  859. this._forEachNode(ancestors2, function (ancestor, level) {
  860. if (!ancestor.tagName || !ancestor.parentNode || typeof ancestor.parentNode.tagName === "undefined")
  861. return;
  862. if (typeof ancestor.readability === "undefined") {
  863. this._initializeNode(ancestor);
  864. candidates.push(ancestor);
  865. }
  866. if (level === 0)
  867. var scoreDivider = 1;
  868. else if (level === 1)
  869. scoreDivider = 2;
  870. else
  871. scoreDivider = level * 3;
  872. ancestor.readability.contentScore += contentScore / scoreDivider;
  873. });
  874. });
  875. var topCandidates = [];
  876. for (var c = 0, cl = candidates.length; c < cl; c += 1) {
  877. var candidate = candidates[c];
  878. var candidateScore = candidate.readability.contentScore * (1 - this._getLinkDensity(candidate));
  879. candidate.readability.contentScore = candidateScore;
  880. this.log("Candidate:", candidate, "with score " + candidateScore);
  881. for (var t = 0; t < this._nbTopCandidates; t++) {
  882. var aTopCandidate = topCandidates[t];
  883. if (!aTopCandidate || candidateScore > aTopCandidate.readability.contentScore) {
  884. topCandidates.splice(t, 0, candidate);
  885. if (topCandidates.length > this._nbTopCandidates)
  886. topCandidates.pop();
  887. break;
  888. }
  889. }
  890. }
  891. var topCandidate = topCandidates[0] || null;
  892. var neededToCreateTopCandidate = false;
  893. var parentOfTopCandidate;
  894. if (topCandidate === null || topCandidate.tagName === "BODY") {
  895. topCandidate = doc.createElement("DIV");
  896. neededToCreateTopCandidate = true;
  897. while (page.firstChild) {
  898. this.log("Moving child out:", page.firstChild);
  899. topCandidate.appendChild(page.firstChild);
  900. }
  901. page.appendChild(topCandidate);
  902. this._initializeNode(topCandidate);
  903. } else if (topCandidate) {
  904. var alternativeCandidateAncestors = [];
  905. for (var i = 1; i < topCandidates.length; i++) {
  906. if (topCandidates[i].readability.contentScore / topCandidate.readability.contentScore >= 0.75) {
  907. alternativeCandidateAncestors.push(this._getNodeAncestors(topCandidates[i]));
  908. }
  909. }
  910. var MINIMUM_TOPCANDIDATES = 3;
  911. if (alternativeCandidateAncestors.length >= MINIMUM_TOPCANDIDATES) {
  912. parentOfTopCandidate = topCandidate.parentNode;
  913. while (parentOfTopCandidate.tagName !== "BODY") {
  914. var listsContainingThisAncestor = 0;
  915. for (var ancestorIndex = 0; ancestorIndex < alternativeCandidateAncestors.length && listsContainingThisAncestor < MINIMUM_TOPCANDIDATES; ancestorIndex++) {
  916. listsContainingThisAncestor += Number(alternativeCandidateAncestors[ancestorIndex].includes(parentOfTopCandidate));
  917. }
  918. if (listsContainingThisAncestor >= MINIMUM_TOPCANDIDATES) {
  919. topCandidate = parentOfTopCandidate;
  920. break;
  921. }
  922. parentOfTopCandidate = parentOfTopCandidate.parentNode;
  923. }
  924. }
  925. if (!topCandidate.readability) {
  926. this._initializeNode(topCandidate);
  927. }
  928. parentOfTopCandidate = topCandidate.parentNode;
  929. var lastScore = topCandidate.readability.contentScore;
  930. var scoreThreshold = lastScore / 3;
  931. while (parentOfTopCandidate.tagName !== "BODY") {
  932. if (!parentOfTopCandidate.readability) {
  933. parentOfTopCandidate = parentOfTopCandidate.parentNode;
  934. continue;
  935. }
  936. var parentScore = parentOfTopCandidate.readability.contentScore;
  937. if (parentScore < scoreThreshold)
  938. break;
  939. if (parentScore > lastScore) {
  940. topCandidate = parentOfTopCandidate;
  941. break;
  942. }
  943. lastScore = parentOfTopCandidate.readability.contentScore;
  944. parentOfTopCandidate = parentOfTopCandidate.parentNode;
  945. }
  946. parentOfTopCandidate = topCandidate.parentNode;
  947. while (parentOfTopCandidate.tagName != "BODY" && parentOfTopCandidate.children.length == 1) {
  948. topCandidate = parentOfTopCandidate;
  949. parentOfTopCandidate = topCandidate.parentNode;
  950. }
  951. if (!topCandidate.readability) {
  952. this._initializeNode(topCandidate);
  953. }
  954. }
  955. var articleContent = doc.createElement("DIV");
  956. if (isPaging)
  957. articleContent.id = "readability-content";
  958. var siblingScoreThreshold = Math.max(10, topCandidate.readability.contentScore * 0.2);
  959. parentOfTopCandidate = topCandidate.parentNode;
  960. var siblings = parentOfTopCandidate.children;
  961. for (var s = 0, sl = siblings.length; s < sl; s++) {
  962. var sibling = siblings[s];
  963. var append = false;
  964. this.log("Looking at sibling node:", sibling, sibling.readability ? "with score " + sibling.readability.contentScore : "");
  965. this.log("Sibling has score", sibling.readability ? sibling.readability.contentScore : "Unknown");
  966. if (sibling === topCandidate) {
  967. append = true;
  968. } else {
  969. var contentBonus = 0;
  970. if (sibling.className === topCandidate.className && topCandidate.className !== "")
  971. contentBonus += topCandidate.readability.contentScore * 0.2;
  972. if (sibling.readability && sibling.readability.contentScore + contentBonus >= siblingScoreThreshold) {
  973. append = true;
  974. } else if (sibling.nodeName === "P") {
  975. var linkDensity = this._getLinkDensity(sibling);
  976. var nodeContent = this._getInnerText(sibling);
  977. var nodeLength = nodeContent.length;
  978. if (nodeLength > 80 && linkDensity < 0.25) {
  979. append = true;
  980. } else if (nodeLength < 80 && nodeLength > 0 && linkDensity === 0 && nodeContent.search(/\.( |$)/) !== -1) {
  981. append = true;
  982. }
  983. }
  984. }
  985. if (append) {
  986. this.log("Appending node:", sibling);
  987. if (this.ALTER_TO_DIV_EXCEPTIONS.indexOf(sibling.nodeName) === -1) {
  988. this.log("Altering sibling:", sibling, "to div.");
  989. sibling = this._setNodeTag(sibling, "DIV");
  990. }
  991. articleContent.appendChild(sibling);
  992. siblings = parentOfTopCandidate.children;
  993. s -= 1;
  994. sl -= 1;
  995. }
  996. }
  997. if (this._debug)
  998. this.log("Article content pre-prep: " + articleContent.innerHTML);
  999. this._prepArticle(articleContent);
  1000. if (this._debug)
  1001. this.log("Article content post-prep: " + articleContent.innerHTML);
  1002. if (neededToCreateTopCandidate) {
  1003. topCandidate.id = "readability-page-1";
  1004. topCandidate.className = "page";
  1005. } else {
  1006. var div = doc.createElement("DIV");
  1007. div.id = "readability-page-1";
  1008. div.className = "page";
  1009. while (articleContent.firstChild) {
  1010. div.appendChild(articleContent.firstChild);
  1011. }
  1012. articleContent.appendChild(div);
  1013. }
  1014. if (this._debug)
  1015. this.log("Article content after paging: " + articleContent.innerHTML);
  1016. var parseSuccessful = true;
  1017. var textLength = this._getInnerText(articleContent, true).length;
  1018. if (textLength < this._charThreshold) {
  1019. parseSuccessful = false;
  1020. page.innerHTML = pageCacheHtml;
  1021. if (this._flagIsActive(this.FLAG_STRIP_UNLIKELYS)) {
  1022. this._removeFlag(this.FLAG_STRIP_UNLIKELYS);
  1023. this._attempts.push({
  1024. articleContent,
  1025. textLength
  1026. });
  1027. } else if (this._flagIsActive(this.FLAG_WEIGHT_CLASSES)) {
  1028. this._removeFlag(this.FLAG_WEIGHT_CLASSES);
  1029. this._attempts.push({
  1030. articleContent,
  1031. textLength
  1032. });
  1033. } else if (this._flagIsActive(this.FLAG_CLEAN_CONDITIONALLY)) {
  1034. this._removeFlag(this.FLAG_CLEAN_CONDITIONALLY);
  1035. this._attempts.push({
  1036. articleContent,
  1037. textLength
  1038. });
  1039. } else {
  1040. this._attempts.push({
  1041. articleContent,
  1042. textLength
  1043. });
  1044. this._attempts.sort(function (a, b) {
  1045. return b.textLength - a.textLength;
  1046. });
  1047. if (!this._attempts[0].textLength) {
  1048. return null;
  1049. }
  1050. articleContent = this._attempts[0].articleContent;
  1051. parseSuccessful = true;
  1052. }
  1053. }
  1054. if (parseSuccessful) {
  1055. var ancestors = [parentOfTopCandidate, topCandidate].concat(this._getNodeAncestors(parentOfTopCandidate));
  1056. this._someNode(ancestors, function (ancestor) {
  1057. if (!ancestor.tagName)
  1058. return false;
  1059. var articleDir = ancestor.getAttribute("dir");
  1060. if (articleDir) {
  1061. this._articleDir = articleDir;
  1062. return true;
  1063. }
  1064. return false;
  1065. });
  1066. return articleContent;
  1067. }
  1068. }
  1069. },
  1070. /**
  1071. * Check whether the input string could be a byline.
  1072. * This verifies that the input is a string, and that the length
  1073. * is less than 100 chars.
  1074. *
  1075. * @param possibleByline {string} - a string to check whether its a byline.
  1076. * @return Boolean - whether the input string is a byline.
  1077. */
  1078. _isValidByline: function (byline) {
  1079. if (typeof byline == "string" || byline instanceof String) {
  1080. byline = byline.trim();
  1081. return byline.length > 0 && byline.length < 100;
  1082. }
  1083. return false;
  1084. },
  1085. /**
  1086. * Converts some of the common HTML entities in string to their corresponding characters.
  1087. *
  1088. * @param str {string} - a string to unescape.
  1089. * @return string without HTML entity.
  1090. */
  1091. _unescapeHtmlEntities: function (str) {
  1092. if (!str) {
  1093. return str;
  1094. }
  1095. var htmlEscapeMap = this.HTML_ESCAPE_MAP;
  1096. return str.replace(/&(quot|amp|apos|lt|gt);/g, function (_, tag2) {
  1097. return htmlEscapeMap[tag2];
  1098. }).replace(/&#(?:x([0-9a-z]{1,4})|([0-9]{1,4}));/gi, function (_, hex, numStr) {
  1099. var num = parseInt(hex || numStr, hex ? 16 : 10);
  1100. return String.fromCharCode(num);
  1101. });
  1102. },
  1103. /**
  1104. * Try to extract metadata from JSON-LD object.
  1105. * For now, only Schema.org objects of type Article or its subtypes are supported.
  1106. * @return Object with any metadata that could be extracted (possibly none)
  1107. */
  1108. _getJSONLD: function (doc) {
  1109. var scripts = this._getAllNodesWithTag(doc, ["script"]);
  1110. var metadata;
  1111. this._forEachNode(scripts, function (jsonLdElement) {
  1112. if (!metadata && jsonLdElement.getAttribute("type") === "application/ld+json") {
  1113. try {
  1114. var content = jsonLdElement.textContent.replace(/^\s*<!\[CDATA\[|\]\]>\s*$/g, "");
  1115. var parsed = JSON.parse(content);
  1116. if (!parsed["@context"] || !parsed["@context"].match(/^https?\:\/\/schema\.org$/)) {
  1117. return;
  1118. }
  1119. if (!parsed["@type"] && Array.isArray(parsed["@graph"])) {
  1120. parsed = parsed["@graph"].find(function (it) {
  1121. return (it["@type"] || "").match(
  1122. this.REGEXPS.jsonLdArticleTypes
  1123. );
  1124. });
  1125. }
  1126. if (!parsed || !parsed["@type"] || !parsed["@type"].match(this.REGEXPS.jsonLdArticleTypes)) {
  1127. return;
  1128. }
  1129. metadata = {};
  1130. if (typeof parsed.name === "string" && typeof parsed.headline === "string" && parsed.name !== parsed.headline) {
  1131. var title = this._getArticleTitle();
  1132. var nameMatches = this._textSimilarity(parsed.name, title) > 0.75;
  1133. var headlineMatches = this._textSimilarity(parsed.headline, title) > 0.75;
  1134. if (headlineMatches && !nameMatches) {
  1135. metadata.title = parsed.headline;
  1136. } else {
  1137. metadata.title = parsed.name;
  1138. }
  1139. } else if (typeof parsed.name === "string") {
  1140. metadata.title = parsed.name.trim();
  1141. } else if (typeof parsed.headline === "string") {
  1142. metadata.title = parsed.headline.trim();
  1143. }
  1144. if (parsed.author) {
  1145. if (typeof parsed.author.name === "string") {
  1146. metadata.byline = parsed.author.name.trim();
  1147. } else if (Array.isArray(parsed.author) && parsed.author[0] && typeof parsed.author[0].name === "string") {
  1148. metadata.byline = parsed.author.filter(function (author) {
  1149. return author && typeof author.name === "string";
  1150. }).map(function (author) {
  1151. return author.name.trim();
  1152. }).join(", ");
  1153. }
  1154. }
  1155. if (typeof parsed.description === "string") {
  1156. metadata.excerpt = parsed.description.trim();
  1157. }
  1158. if (parsed.publisher && typeof parsed.publisher.name === "string") {
  1159. metadata.siteName = parsed.publisher.name.trim();
  1160. }
  1161. if (typeof parsed.datePublished === "string") {
  1162. metadata.datePublished = parsed.datePublished.trim();
  1163. }
  1164. return;
  1165. } catch (err) {
  1166. this.log(err.message);
  1167. }
  1168. }
  1169. });
  1170. return metadata ? metadata : {};
  1171. },
  1172. /**
  1173. * Attempts to get excerpt and byline metadata for the article.
  1174. *
  1175. * @param {Object} jsonld — object containing any metadata that
  1176. * could be extracted from JSON-LD object.
  1177. *
  1178. * @return Object with optional "excerpt" and "byline" properties
  1179. */
  1180. _getArticleMetadata: function (jsonld) {
  1181. var metadata = {};
  1182. var values = {};
  1183. var metaElements = this._doc.getElementsByTagName("meta");
  1184. var propertyPattern = /\s*(article|dc|dcterm|og|twitter)\s*:\s*(author|creator|description|published_time|title|site_name)\s*/gi;
  1185. var namePattern = /^\s*(?:(dc|dcterm|og|twitter|weibo:(article|webpage))\s*[\.:]\s*)?(author|creator|description|title|site_name)\s*$/i;
  1186. this._forEachNode(metaElements, function (element) {
  1187. var elementName = element.getAttribute("name");
  1188. var elementProperty = element.getAttribute("property");
  1189. var content = element.getAttribute("content");
  1190. if (!content) {
  1191. return;
  1192. }
  1193. var matches = null;
  1194. var name = null;
  1195. if (elementProperty) {
  1196. matches = elementProperty.match(propertyPattern);
  1197. if (matches) {
  1198. name = matches[0].toLowerCase().replace(/\s/g, "");
  1199. values[name] = content.trim();
  1200. }
  1201. }
  1202. if (!matches && elementName && namePattern.test(elementName)) {
  1203. name = elementName;
  1204. if (content) {
  1205. name = name.toLowerCase().replace(/\s/g, "").replace(/\./g, ":");
  1206. values[name] = content.trim();
  1207. }
  1208. }
  1209. });
  1210. 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"];
  1211. if (!metadata.title) {
  1212. metadata.title = this._getArticleTitle();
  1213. }
  1214. metadata.byline = jsonld.byline || values["dc:creator"] || values["dcterm:creator"] || values["author"];
  1215. 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"];
  1216. metadata.siteName = jsonld.siteName || values["og:site_name"];
  1217. metadata.publishedTime = jsonld.datePublished || values["article:published_time"] || null;
  1218. metadata.title = this._unescapeHtmlEntities(metadata.title);
  1219. metadata.byline = this._unescapeHtmlEntities(metadata.byline);
  1220. metadata.excerpt = this._unescapeHtmlEntities(metadata.excerpt);
  1221. metadata.siteName = this._unescapeHtmlEntities(metadata.siteName);
  1222. metadata.publishedTime = this._unescapeHtmlEntities(metadata.publishedTime);
  1223. return metadata;
  1224. },
  1225. /**
  1226. * Check if node is image, or if node contains exactly only one image
  1227. * whether as a direct child or as its descendants.
  1228. *
  1229. * @param Element
  1230. **/
  1231. _isSingleImage: function (node) {
  1232. if (node.tagName === "IMG") {
  1233. return true;
  1234. }
  1235. if (node.children.length !== 1 || node.textContent.trim() !== "") {
  1236. return false;
  1237. }
  1238. return this._isSingleImage(node.children[0]);
  1239. },
  1240. /**
  1241. * Find all <noscript> that are located after <img> nodes, and which contain only one
  1242. * <img> element. Replace the first image with the image from inside the <noscript> tag,
  1243. * and remove the <noscript> tag. This improves the quality of the images we use on
  1244. * some sites (e.g. Medium).
  1245. *
  1246. * @param Element
  1247. **/
  1248. _unwrapNoscriptImages: function (doc) {
  1249. var imgs = Array.from(doc.getElementsByTagName("img"));
  1250. this._forEachNode(imgs, function (img) {
  1251. for (var i = 0; i < img.attributes.length; i++) {
  1252. var attr = img.attributes[i];
  1253. switch (attr.name) {
  1254. case "src":
  1255. case "srcset":
  1256. case "data-src":
  1257. case "data-srcset":
  1258. return;
  1259. }
  1260. if (/\.(jpg|jpeg|png|webp)/i.test(attr.value)) {
  1261. return;
  1262. }
  1263. }
  1264. img.parentNode.removeChild(img);
  1265. });
  1266. var noscripts = Array.from(doc.getElementsByTagName("noscript"));
  1267. this._forEachNode(noscripts, function (noscript) {
  1268. var tmp = doc.createElement("div");
  1269. tmp.innerHTML = noscript.innerHTML;
  1270. if (!this._isSingleImage(tmp)) {
  1271. return;
  1272. }
  1273. var prevElement = noscript.previousElementSibling;
  1274. if (prevElement && this._isSingleImage(prevElement)) {
  1275. var prevImg = prevElement;
  1276. if (prevImg.tagName !== "IMG") {
  1277. prevImg = prevElement.getElementsByTagName("img")[0];
  1278. }
  1279. var newImg = tmp.getElementsByTagName("img")[0];
  1280. for (var i = 0; i < prevImg.attributes.length; i++) {
  1281. var attr = prevImg.attributes[i];
  1282. if (attr.value === "") {
  1283. continue;
  1284. }
  1285. if (attr.name === "src" || attr.name === "srcset" || /\.(jpg|jpeg|png|webp)/i.test(attr.value)) {
  1286. if (newImg.getAttribute(attr.name) === attr.value) {
  1287. continue;
  1288. }
  1289. var attrName = attr.name;
  1290. if (newImg.hasAttribute(attrName)) {
  1291. attrName = "data-old-" + attrName;
  1292. }
  1293. newImg.setAttribute(attrName, attr.value);
  1294. }
  1295. }
  1296. noscript.parentNode.replaceChild(tmp.firstElementChild, prevElement);
  1297. }
  1298. });
  1299. },
  1300. /**
  1301. * Removes script tags from the document.
  1302. *
  1303. * @param Element
  1304. **/
  1305. _removeScripts: function (doc) {
  1306. this._removeNodes(this._getAllNodesWithTag(doc, ["script", "noscript"]));
  1307. },
  1308. /**
  1309. * Check if this node has only whitespace and a single element with given tag
  1310. * Returns false if the DIV node contains non-empty text nodes
  1311. * or if it contains no element with given tag or more than 1 element.
  1312. *
  1313. * @param Element
  1314. * @param string tag of child element
  1315. **/
  1316. _hasSingleTagInsideElement: function (element, tag2) {
  1317. if (element.children.length != 1 || element.children[0].tagName !== tag2) {
  1318. return false;
  1319. }
  1320. return !this._someNode(element.childNodes, function (node) {
  1321. return node.nodeType === this.TEXT_NODE && this.REGEXPS.hasContent.test(node.textContent);
  1322. });
  1323. },
  1324. _isElementWithoutContent: function (node) {
  1325. 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);
  1326. },
  1327. /**
  1328. * Determine whether element has any children block level elements.
  1329. *
  1330. * @param Element
  1331. */
  1332. _hasChildBlockElement: function (element) {
  1333. return this._someNode(element.childNodes, function (node) {
  1334. return this.DIV_TO_P_ELEMS.has(node.tagName) || this._hasChildBlockElement(node);
  1335. });
  1336. },
  1337. /***
  1338. * Determine if a node qualifies as phrasing content.
  1339. * https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_categories#Phrasing_content
  1340. **/
  1341. _isPhrasingContent: function (node) {
  1342. 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);
  1343. },
  1344. _isWhitespace: function (node) {
  1345. return node.nodeType === this.TEXT_NODE && node.textContent.trim().length === 0 || node.nodeType === this.ELEMENT_NODE && node.tagName === "BR";
  1346. },
  1347. /**
  1348. * Get the inner text of a node - cross browser compatibly.
  1349. * This also strips out any excess whitespace to be found.
  1350. *
  1351. * @param Element
  1352. * @param Boolean normalizeSpaces (default: true)
  1353. * @return string
  1354. **/
  1355. _getInnerText: function (e, normalizeSpaces) {
  1356. normalizeSpaces = typeof normalizeSpaces === "undefined" ? true : normalizeSpaces;
  1357. var textContent = e.textContent.trim();
  1358. if (normalizeSpaces) {
  1359. return textContent.replace(this.REGEXPS.normalize, " ");
  1360. }
  1361. return textContent;
  1362. },
  1363. /**
  1364. * Get the number of times a string s appears in the node e.
  1365. *
  1366. * @param Element
  1367. * @param string - what to split on. Default is ","
  1368. * @return number (integer)
  1369. **/
  1370. _getCharCount: function (e, s) {
  1371. s = s || ",";
  1372. return this._getInnerText(e).split(s).length - 1;
  1373. },
  1374. /**
  1375. * Remove the style attribute on every e and under.
  1376. * TODO: Test if getElementsByTagName(*) is faster.
  1377. *
  1378. * @param Element
  1379. * @return void
  1380. **/
  1381. _cleanStyles: function (e) {
  1382. if (!e || e.tagName.toLowerCase() === "svg")
  1383. return;
  1384. for (var i = 0; i < this.PRESENTATIONAL_ATTRIBUTES.length; i++) {
  1385. e.removeAttribute(this.PRESENTATIONAL_ATTRIBUTES[i]);
  1386. }
  1387. if (this.DEPRECATED_SIZE_ATTRIBUTE_ELEMS.indexOf(e.tagName) !== -1) {
  1388. e.removeAttribute("width");
  1389. e.removeAttribute("height");
  1390. }
  1391. var cur = e.firstElementChild;
  1392. while (cur !== null) {
  1393. this._cleanStyles(cur);
  1394. cur = cur.nextElementSibling;
  1395. }
  1396. },
  1397. /**
  1398. * Get the density of links as a percentage of the content
  1399. * This is the amount of text that is inside a link divided by the total text in the node.
  1400. *
  1401. * @param Element
  1402. * @return number (float)
  1403. **/
  1404. _getLinkDensity: function (element) {
  1405. var textLength = this._getInnerText(element).length;
  1406. if (textLength === 0)
  1407. return 0;
  1408. var linkLength = 0;
  1409. this._forEachNode(element.getElementsByTagName("a"), function (linkNode) {
  1410. var href = linkNode.getAttribute("href");
  1411. var coefficient = href && this.REGEXPS.hashUrl.test(href) ? 0.3 : 1;
  1412. linkLength += this._getInnerText(linkNode).length * coefficient;
  1413. });
  1414. return linkLength / textLength;
  1415. },
  1416. /**
  1417. * Get an elements class/id weight. Uses regular expressions to tell if this
  1418. * element looks good or bad.
  1419. *
  1420. * @param Element
  1421. * @return number (Integer)
  1422. **/
  1423. _getClassWeight: function (e) {
  1424. if (!this._flagIsActive(this.FLAG_WEIGHT_CLASSES))
  1425. return 0;
  1426. var weight = 0;
  1427. if (typeof e.className === "string" && e.className !== "") {
  1428. if (this.REGEXPS.negative.test(e.className))
  1429. weight -= 25;
  1430. if (this.REGEXPS.positive.test(e.className))
  1431. weight += 25;
  1432. }
  1433. if (typeof e.id === "string" && e.id !== "") {
  1434. if (this.REGEXPS.negative.test(e.id))
  1435. weight -= 25;
  1436. if (this.REGEXPS.positive.test(e.id))
  1437. weight += 25;
  1438. }
  1439. return weight;
  1440. },
  1441. /**
  1442. * Clean a node of all elements of type "tag".
  1443. * (Unless it's a youtube/vimeo video. People love movies.)
  1444. *
  1445. * @param Element
  1446. * @param string tag to clean
  1447. * @return void
  1448. **/
  1449. _clean: function (e, tag2) {
  1450. var isEmbed = ["object", "embed", "iframe"].indexOf(tag2) !== -1;
  1451. this._removeNodes(this._getAllNodesWithTag(e, [tag2]), function (element) {
  1452. if (isEmbed) {
  1453. for (var i = 0; i < element.attributes.length; i++) {
  1454. if (this._allowedVideoRegex.test(element.attributes[i].value)) {
  1455. return false;
  1456. }
  1457. }
  1458. if (element.tagName === "object" && this._allowedVideoRegex.test(element.innerHTML)) {
  1459. return false;
  1460. }
  1461. }
  1462. return true;
  1463. });
  1464. },
  1465. /**
  1466. * Check if a given node has one of its ancestor tag name matching the
  1467. * provided one.
  1468. * @param HTMLElement node
  1469. * @param String tagName
  1470. * @param Number maxDepth
  1471. * @param Function filterFn a filter to invoke to determine whether this node 'counts'
  1472. * @return Boolean
  1473. */
  1474. _hasAncestorTag: function (node, tagName, maxDepth, filterFn) {
  1475. maxDepth = maxDepth || 3;
  1476. tagName = tagName.toUpperCase();
  1477. var depth = 0;
  1478. while (node.parentNode) {
  1479. if (maxDepth > 0 && depth > maxDepth)
  1480. return false;
  1481. if (node.parentNode.tagName === tagName && (!filterFn || filterFn(node.parentNode)))
  1482. return true;
  1483. node = node.parentNode;
  1484. depth++;
  1485. }
  1486. return false;
  1487. },
  1488. /**
  1489. * Return an object indicating how many rows and columns this table has.
  1490. */
  1491. _getRowAndColumnCount: function (table) {
  1492. var rows = 0;
  1493. var columns = 0;
  1494. var trs = table.getElementsByTagName("tr");
  1495. for (var i = 0; i < trs.length; i++) {
  1496. var rowspan = trs[i].getAttribute("rowspan") || 0;
  1497. if (rowspan) {
  1498. rowspan = parseInt(rowspan, 10);
  1499. }
  1500. rows += rowspan || 1;
  1501. var columnsInThisRow = 0;
  1502. var cells = trs[i].getElementsByTagName("td");
  1503. for (var j = 0; j < cells.length; j++) {
  1504. var colspan = cells[j].getAttribute("colspan") || 0;
  1505. if (colspan) {
  1506. colspan = parseInt(colspan, 10);
  1507. }
  1508. columnsInThisRow += colspan || 1;
  1509. }
  1510. columns = Math.max(columns, columnsInThisRow);
  1511. }
  1512. return {
  1513. rows,
  1514. columns
  1515. };
  1516. },
  1517. /**
  1518. * Look for 'data' (as opposed to 'layout') tables, for which we use
  1519. * similar checks as
  1520. * https://searchfox.org/mozilla-central/rev/f82d5c549f046cb64ce5602bfd894b7ae807c8f8/accessible/generic/TableAccessible.cpp#19
  1521. */
  1522. _markDataTables: function (root) {
  1523. var tables = root.getElementsByTagName("table");
  1524. for (var i = 0; i < tables.length; i++) {
  1525. var table = tables[i];
  1526. var role = table.getAttribute("role");
  1527. if (role == "presentation") {
  1528. table._readabilityDataTable = false;
  1529. continue;
  1530. }
  1531. var datatable = table.getAttribute("datatable");
  1532. if (datatable == "0") {
  1533. table._readabilityDataTable = false;
  1534. continue;
  1535. }
  1536. var summary = table.getAttribute("summary");
  1537. if (summary) {
  1538. table._readabilityDataTable = true;
  1539. continue;
  1540. }
  1541. var caption = table.getElementsByTagName("caption")[0];
  1542. if (caption && caption.childNodes.length > 0) {
  1543. table._readabilityDataTable = true;
  1544. continue;
  1545. }
  1546. var dataTableDescendants = ["col", "colgroup", "tfoot", "thead", "th"];
  1547. var descendantExists = function (tag2) {
  1548. return !!table.getElementsByTagName(tag2)[0];
  1549. };
  1550. if (dataTableDescendants.some(descendantExists)) {
  1551. this.log("Data table because found data-y descendant");
  1552. table._readabilityDataTable = true;
  1553. continue;
  1554. }
  1555. if (table.getElementsByTagName("table")[0]) {
  1556. table._readabilityDataTable = false;
  1557. continue;
  1558. }
  1559. var sizeInfo = this._getRowAndColumnCount(table);
  1560. if (sizeInfo.rows >= 10 || sizeInfo.columns > 4) {
  1561. table._readabilityDataTable = true;
  1562. continue;
  1563. }
  1564. table._readabilityDataTable = sizeInfo.rows * sizeInfo.columns > 10;
  1565. }
  1566. },
  1567. /* convert images and figures that have properties like data-src into images that can be loaded without JS */
  1568. _fixLazyImages: function (root) {
  1569. this._forEachNode(this._getAllNodesWithTag(root, ["img", "picture", "figure"]), function (elem) {
  1570. if (elem.src && this.REGEXPS.b64DataUrl.test(elem.src)) {
  1571. var parts = this.REGEXPS.b64DataUrl.exec(elem.src);
  1572. if (parts[1] === "image/svg+xml") {
  1573. return;
  1574. }
  1575. var srcCouldBeRemoved = false;
  1576. for (var i = 0; i < elem.attributes.length; i++) {
  1577. var attr = elem.attributes[i];
  1578. if (attr.name === "src") {
  1579. continue;
  1580. }
  1581. if (/\.(jpg|jpeg|png|webp)/i.test(attr.value)) {
  1582. srcCouldBeRemoved = true;
  1583. break;
  1584. }
  1585. }
  1586. if (srcCouldBeRemoved) {
  1587. var b64starts = elem.src.search(/base64\s*/i) + 7;
  1588. var b64length = elem.src.length - b64starts;
  1589. if (b64length < 133) {
  1590. elem.removeAttribute("src");
  1591. }
  1592. }
  1593. }
  1594. if ((elem.src || elem.srcset && elem.srcset != "null") && elem.className.toLowerCase().indexOf("lazy") === -1) {
  1595. return;
  1596. }
  1597. for (var j = 0; j < elem.attributes.length; j++) {
  1598. attr = elem.attributes[j];
  1599. if (attr.name === "src" || attr.name === "srcset" || attr.name === "alt") {
  1600. continue;
  1601. }
  1602. var copyTo = null;
  1603. if (/\.(jpg|jpeg|png|webp)\s+\d/.test(attr.value)) {
  1604. copyTo = "srcset";
  1605. } else if (/^\s*\S+\.(jpg|jpeg|png|webp)\S*\s*$/.test(attr.value)) {
  1606. copyTo = "src";
  1607. }
  1608. if (copyTo) {
  1609. if (elem.tagName === "IMG" || elem.tagName === "PICTURE") {
  1610. elem.setAttribute(copyTo, attr.value);
  1611. } else if (elem.tagName === "FIGURE" && !this._getAllNodesWithTag(elem, ["img", "picture"]).length) {
  1612. var img = this._doc.createElement("img");
  1613. img.setAttribute(copyTo, attr.value);
  1614. elem.appendChild(img);
  1615. }
  1616. }
  1617. }
  1618. });
  1619. },
  1620. _getTextDensity: function (e, tags) {
  1621. var textLength = this._getInnerText(e, true).length;
  1622. if (textLength === 0) {
  1623. return 0;
  1624. }
  1625. var childrenLength = 0;
  1626. var children = this._getAllNodesWithTag(e, tags);
  1627. this._forEachNode(children, (child) => childrenLength += this._getInnerText(child, true).length);
  1628. return childrenLength / textLength;
  1629. },
  1630. /**
  1631. * Clean an element of all tags of type "tag" if they look fishy.
  1632. * "Fishy" is an algorithm based on content length, classnames, link density, number of images & embeds, etc.
  1633. *
  1634. * @return void
  1635. **/
  1636. _cleanConditionally: function (e, tag2) {
  1637. if (!this._flagIsActive(this.FLAG_CLEAN_CONDITIONALLY))
  1638. return;
  1639. this._removeNodes(this._getAllNodesWithTag(e, [tag2]), function (node) {
  1640. var isDataTable = function (t) {
  1641. return t._readabilityDataTable;
  1642. };
  1643. var isList = tag2 === "ul" || tag2 === "ol";
  1644. if (!isList) {
  1645. var listLength = 0;
  1646. var listNodes = this._getAllNodesWithTag(node, ["ul", "ol"]);
  1647. this._forEachNode(listNodes, (list2) => listLength += this._getInnerText(list2).length);
  1648. isList = listLength / this._getInnerText(node).length > 0.9;
  1649. }
  1650. if (tag2 === "table" && isDataTable(node)) {
  1651. return false;
  1652. }
  1653. if (this._hasAncestorTag(node, "table", -1, isDataTable)) {
  1654. return false;
  1655. }
  1656. if (this._hasAncestorTag(node, "code")) {
  1657. return false;
  1658. }
  1659. var weight = this._getClassWeight(node);
  1660. this.log("Cleaning Conditionally", node);
  1661. var contentScore = 0;
  1662. if (weight + contentScore < 0) {
  1663. return true;
  1664. }
  1665. if (this._getCharCount(node, ",") < 10) {
  1666. var p = node.getElementsByTagName("p").length;
  1667. var img = node.getElementsByTagName("img").length;
  1668. var li = node.getElementsByTagName("li").length - 100;
  1669. var input = node.getElementsByTagName("input").length;
  1670. var headingDensity = this._getTextDensity(node, ["h1", "h2", "h3", "h4", "h5", "h6"]);
  1671. var embedCount = 0;
  1672. var embeds = this._getAllNodesWithTag(node, ["object", "embed", "iframe"]);
  1673. for (var i = 0; i < embeds.length; i++) {
  1674. for (var j = 0; j < embeds[i].attributes.length; j++) {
  1675. if (this._allowedVideoRegex.test(embeds[i].attributes[j].value)) {
  1676. return false;
  1677. }
  1678. }
  1679. if (embeds[i].tagName === "object" && this._allowedVideoRegex.test(embeds[i].innerHTML)) {
  1680. return false;
  1681. }
  1682. embedCount++;
  1683. }
  1684. var linkDensity = this._getLinkDensity(node);
  1685. var contentLength = this._getInnerText(node).length;
  1686. 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);
  1687. if (isList && haveToRemove) {
  1688. for (var x = 0; x < node.children.length; x++) {
  1689. let child = node.children[x];
  1690. if (child.children.length > 1) {
  1691. return haveToRemove;
  1692. }
  1693. }
  1694. let li_count = node.getElementsByTagName("li").length;
  1695. if (img == li_count) {
  1696. return false;
  1697. }
  1698. }
  1699. return haveToRemove;
  1700. }
  1701. return false;
  1702. });
  1703. },
  1704. /**
  1705. * Clean out elements that match the specified conditions
  1706. *
  1707. * @param Element
  1708. * @param Function determines whether a node should be removed
  1709. * @return void
  1710. **/
  1711. _cleanMatchedNodes: function (e, filter) {
  1712. var endOfSearchMarkerNode = this._getNextNode(e, true);
  1713. var next = this._getNextNode(e);
  1714. while (next && next != endOfSearchMarkerNode) {
  1715. if (filter.call(this, next, next.className + " " + next.id)) {
  1716. next = this._removeAndGetNext(next);
  1717. } else {
  1718. next = this._getNextNode(next);
  1719. }
  1720. }
  1721. },
  1722. /**
  1723. * Clean out spurious headers from an Element.
  1724. *
  1725. * @param Element
  1726. * @return void
  1727. **/
  1728. _cleanHeaders: function (e) {
  1729. let headingNodes = this._getAllNodesWithTag(e, ["h1", "h2"]);
  1730. this._removeNodes(headingNodes, function (node) {
  1731. let shouldRemove = this._getClassWeight(node) < 0;
  1732. if (shouldRemove) {
  1733. this.log("Removing header with low class weight:", node);
  1734. }
  1735. return shouldRemove;
  1736. });
  1737. },
  1738. /**
  1739. * Check if this node is an H1 or H2 element whose content is mostly
  1740. * the same as the article title.
  1741. *
  1742. * @param Element the node to check.
  1743. * @return boolean indicating whether this is a title-like header.
  1744. */
  1745. _headerDuplicatesTitle: function (node) {
  1746. if (node.tagName != "H1" && node.tagName != "H2") {
  1747. return false;
  1748. }
  1749. var heading2 = this._getInnerText(node, false);
  1750. this.log("Evaluating similarity of header:", heading2, this._articleTitle);
  1751. return this._textSimilarity(this._articleTitle, heading2) > 0.75;
  1752. },
  1753. _flagIsActive: function (flag) {
  1754. return (this._flags & flag) > 0;
  1755. },
  1756. _removeFlag: function (flag) {
  1757. this._flags = this._flags & ~flag;
  1758. },
  1759. _isProbablyVisible: function (node) {
  1760. 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);
  1761. },
  1762. /**
  1763. * Runs readability.
  1764. *
  1765. * Workflow:
  1766. * 1. Prep the document by removing script tags, css, etc.
  1767. * 2. Build readability's DOM tree.
  1768. * 3. Grab the article content from the current dom tree.
  1769. * 4. Replace the current DOM tree with the new one.
  1770. * 5. Read peacefully.
  1771. *
  1772. * @return void
  1773. **/
  1774. parse: function () {
  1775. if (this._maxElemsToParse > 0) {
  1776. var numTags = this._doc.getElementsByTagName("*").length;
  1777. if (numTags > this._maxElemsToParse) {
  1778. throw new Error("Aborting parsing document; " + numTags + " elements found");
  1779. }
  1780. }
  1781. this._unwrapNoscriptImages(this._doc);
  1782. var jsonLd = this._disableJSONLD ? {} : this._getJSONLD(this._doc);
  1783. this._removeScripts(this._doc);
  1784. this._prepDocument();
  1785. var metadata = this._getArticleMetadata(jsonLd);
  1786. this._articleTitle = metadata.title;
  1787. var articleContent = this._grabArticle();
  1788. if (!articleContent)
  1789. return null;
  1790. this.log("Grabbed: " + articleContent.innerHTML);
  1791. this._postProcessContent(articleContent);
  1792. if (!metadata.excerpt) {
  1793. var paragraphs = articleContent.getElementsByTagName("p");
  1794. if (paragraphs.length > 0) {
  1795. metadata.excerpt = paragraphs[0].textContent.trim();
  1796. }
  1797. }
  1798. var textContent = articleContent.textContent;
  1799. return {
  1800. title: this._articleTitle,
  1801. byline: metadata.byline || this._articleByline,
  1802. dir: this._articleDir,
  1803. lang: this._articleLang,
  1804. content: this._serializer(articleContent),
  1805. textContent,
  1806. length: textContent.length,
  1807. excerpt: metadata.excerpt,
  1808. siteName: metadata.siteName || this._articleSiteName,
  1809. publishedTime: metadata.publishedTime
  1810. };
  1811. }
  1812. }; {
  1813. module.exports = Readability2;
  1814. }
  1815. })(Readability$1);
  1816. var ReadabilityExports = Readability$1.exports;
  1817. var ReadabilityReaderable = {
  1818. exports: {}
  1819. };
  1820. (function (module) {
  1821. var REGEXPS = {
  1822. // NOTE: These two regular expressions are duplicated in
  1823. // Readability.js. Please keep both copies in sync.
  1824. 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,
  1825. okMaybeItsACandidate: /and|article|body|column|content|main|shadow/i
  1826. };
  1827.  
  1828. function isNodeVisible(node) {
  1829. 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);
  1830. }
  1831.  
  1832. function isProbablyReaderable2(doc, options = {}) {
  1833. if (typeof options == "function") {
  1834. options = {
  1835. visibilityChecker: options
  1836. };
  1837. }
  1838. var defaultOptions = {
  1839. minScore: 20,
  1840. minContentLength: 140,
  1841. visibilityChecker: isNodeVisible
  1842. };
  1843. options = Object.assign(defaultOptions, options);
  1844. var nodes = doc.querySelectorAll("p, pre, article");
  1845. var brNodes = doc.querySelectorAll("div > br");
  1846. if (brNodes.length) {
  1847. var set = new Set(nodes);
  1848. [].forEach.call(brNodes, function (node) {
  1849. set.add(node.parentNode);
  1850. });
  1851. nodes = Array.from(set);
  1852. }
  1853. var score = 0;
  1854. return [].some.call(nodes, function (node) {
  1855. if (!options.visibilityChecker(node)) {
  1856. return false;
  1857. }
  1858. var matchString = node.className + " " + node.id;
  1859. if (REGEXPS.unlikelyCandidates.test(matchString) && !REGEXPS.okMaybeItsACandidate.test(matchString)) {
  1860. return false;
  1861. }
  1862. if (node.matches("li p")) {
  1863. return false;
  1864. }
  1865. var textContentLength = node.textContent.trim().length;
  1866. if (textContentLength < options.minContentLength) {
  1867. return false;
  1868. }
  1869. score += Math.sqrt(textContentLength - options.minContentLength);
  1870. if (score > options.minScore) {
  1871. return true;
  1872. }
  1873. return false;
  1874. });
  1875. } {
  1876. module.exports = isProbablyReaderable2;
  1877. }
  1878. })(ReadabilityReaderable);
  1879. var ReadabilityReaderableExports = ReadabilityReaderable.exports;
  1880. var Readability = ReadabilityExports;
  1881. var isProbablyReaderable = ReadabilityReaderableExports;
  1882. var readability = {
  1883. Readability,
  1884. isProbablyReaderable
  1885. };
  1886.  
  1887. function getSimpleText(doc) {
  1888. doc = doc ? doc : document;
  1889. doc = doc.cloneNode(true);
  1890. const app = doc.querySelector("#monkeygpt");
  1891. app.remove();
  1892. let article = new readability.Readability(doc).parse();
  1893. return article.textContent;
  1894. }
  1895. async function chat$1(messages, model = "gpt-4o-mini", apiKey, apiEndpoint = "https://api.openai.com/v1/chat/completions") {
  1896. const headers = {
  1897. "Content-Type": "application/json",
  1898. "Authorization": `Bearer ${apiKey}`
  1899. };
  1900. const requestBody = {
  1901. model,
  1902. // 使用的模型名称
  1903. messages
  1904. };
  1905. return fetch(apiEndpoint, {
  1906. method: "POST",
  1907. headers,
  1908. body: JSON.stringify(requestBody)
  1909. }).then((response) => response.json()).then(async (data) => {
  1910. const reply = data.choices[0].message.content;
  1911. return reply;
  1912. });
  1913. }
  1914. const defaultConfig = {
  1915. model: "gpt-4o-mini",
  1916. apiKey: "",
  1917. apiEndpoint: "https://ai.01234.fun/v1/chat/completions"
  1918. };
  1919. async function chat(content, config = defaultConfig) {
  1920. return await chat$1([{
  1921. role: "user",
  1922. content
  1923. }], config.model, config.apiKey, config.apiEndpoint);
  1924. }
  1925. async function summarize(text, config = defaultConfig) {
  1926. return chat(`请帮忙总结一下 :"${text}"`, config);
  1927. }
  1928. async function ask(text, config = defaultConfig) {
  1929. return chat(`请帮忙回复一下 :"${text}"`, config);
  1930. }
  1931.  
  1932. function _getDefaults() {
  1933. return {
  1934. async: false,
  1935. breaks: false,
  1936. extensions: null,
  1937. gfm: true,
  1938. hooks: null,
  1939. pedantic: false,
  1940. renderer: null,
  1941. silent: false,
  1942. tokenizer: null,
  1943. walkTokens: null
  1944. };
  1945. }
  1946. let _defaults = _getDefaults();
  1947.  
  1948. function changeDefaults(newDefaults) {
  1949. _defaults = newDefaults;
  1950. }
  1951. const escapeTest = /[&<>"']/;
  1952. const escapeReplace = new RegExp(escapeTest.source, "g");
  1953. const escapeTestNoEncode = /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/;
  1954. const escapeReplaceNoEncode = new RegExp(escapeTestNoEncode.source, "g");
  1955. const escapeReplacements = {
  1956. "&": "&amp;",
  1957. "<": "&lt;",
  1958. ">": "&gt;",
  1959. '"': "&quot;",
  1960. "'": "&#39;"
  1961. };
  1962. const getEscapeReplacement = (ch) => escapeReplacements[ch];
  1963.  
  1964. function escape$1(html2, encode) {
  1965. if (encode) {
  1966. if (escapeTest.test(html2)) {
  1967. return html2.replace(escapeReplace, getEscapeReplacement);
  1968. }
  1969. } else {
  1970. if (escapeTestNoEncode.test(html2)) {
  1971. return html2.replace(escapeReplaceNoEncode, getEscapeReplacement);
  1972. }
  1973. }
  1974. return html2;
  1975. }
  1976. const caret = /(^|[^\[])\^/g;
  1977.  
  1978. function edit(regex, opt) {
  1979. let source = typeof regex === "string" ? regex : regex.source;
  1980. opt = opt || "";
  1981. const obj = {
  1982. replace: (name, val) => {
  1983. let valSource = typeof val === "string" ? val : val.source;
  1984. valSource = valSource.replace(caret, "$1");
  1985. source = source.replace(name, valSource);
  1986. return obj;
  1987. },
  1988. getRegex: () => {
  1989. return new RegExp(source, opt);
  1990. }
  1991. };
  1992. return obj;
  1993. }
  1994.  
  1995. function cleanUrl(href) {
  1996. try {
  1997. href = encodeURI(href).replace(/%25/g, "%");
  1998. } catch {
  1999. return null;
  2000. }
  2001. return href;
  2002. }
  2003. const noopTest = {
  2004. exec: () => null
  2005. };
  2006.  
  2007. function splitCells(tableRow, count) {
  2008. const row = tableRow.replace(/\|/g, (match, offset, str) => {
  2009. let escaped = false;
  2010. let curr = offset;
  2011. while (--curr >= 0 && str[curr] === "\\")
  2012. escaped = !escaped;
  2013. if (escaped) {
  2014. return "|";
  2015. } else {
  2016. return " |";
  2017. }
  2018. }),
  2019. cells = row.split(/ \|/);
  2020. let i = 0;
  2021. if (!cells[0].trim()) {
  2022. cells.shift();
  2023. }
  2024. if (cells.length > 0 && !cells[cells.length - 1].trim()) {
  2025. cells.pop();
  2026. }
  2027. if (count) {
  2028. if (cells.length > count) {
  2029. cells.splice(count);
  2030. } else {
  2031. while (cells.length < count)
  2032. cells.push("");
  2033. }
  2034. }
  2035. for (; i < cells.length; i++) {
  2036. cells[i] = cells[i].trim().replace(/\\\|/g, "|");
  2037. }
  2038. return cells;
  2039. }
  2040.  
  2041. function rtrim(str, c, invert) {
  2042. const l = str.length;
  2043. if (l === 0) {
  2044. return "";
  2045. }
  2046. let suffLen = 0;
  2047. while (suffLen < l) {
  2048. const currChar = str.charAt(l - suffLen - 1);
  2049. if (currChar === c && !invert) {
  2050. suffLen++;
  2051. } else if (currChar !== c && invert) {
  2052. suffLen++;
  2053. } else {
  2054. break;
  2055. }
  2056. }
  2057. return str.slice(0, l - suffLen);
  2058. }
  2059.  
  2060. function findClosingBracket(str, b) {
  2061. if (str.indexOf(b[1]) === -1) {
  2062. return -1;
  2063. }
  2064. let level = 0;
  2065. for (let i = 0; i < str.length; i++) {
  2066. if (str[i] === "\\") {
  2067. i++;
  2068. } else if (str[i] === b[0]) {
  2069. level++;
  2070. } else if (str[i] === b[1]) {
  2071. level--;
  2072. if (level < 0) {
  2073. return i;
  2074. }
  2075. }
  2076. }
  2077. return -1;
  2078. }
  2079.  
  2080. function outputLink(cap, link2, raw, lexer) {
  2081. const href = link2.href;
  2082. const title = link2.title ? escape$1(link2.title) : null;
  2083. const text = cap[1].replace(/\\([\[\]])/g, "$1");
  2084. if (cap[0].charAt(0) !== "!") {
  2085. lexer.state.inLink = true;
  2086. const token = {
  2087. type: "link",
  2088. raw,
  2089. href,
  2090. title,
  2091. text,
  2092. tokens: lexer.inlineTokens(text)
  2093. };
  2094. lexer.state.inLink = false;
  2095. return token;
  2096. }
  2097. return {
  2098. type: "image",
  2099. raw,
  2100. href,
  2101. title,
  2102. text: escape$1(text)
  2103. };
  2104. }
  2105.  
  2106. function indentCodeCompensation(raw, text) {
  2107. const matchIndentToCode = raw.match(/^(\s+)(?:```)/);
  2108. if (matchIndentToCode === null) {
  2109. return text;
  2110. }
  2111. const indentToCode = matchIndentToCode[1];
  2112. return text.split("\n").map((node) => {
  2113. const matchIndentInNode = node.match(/^\s+/);
  2114. if (matchIndentInNode === null) {
  2115. return node;
  2116. }
  2117. const [indentInNode] = matchIndentInNode;
  2118. if (indentInNode.length >= indentToCode.length) {
  2119. return node.slice(indentToCode.length);
  2120. }
  2121. return node;
  2122. }).join("\n");
  2123. }
  2124. class _Tokenizer {
  2125. // set by the lexer
  2126. constructor(options) {
  2127. __publicField(this, "options");
  2128. __publicField(this, "rules");
  2129. // set by the lexer
  2130. __publicField(this, "lexer");
  2131. this.options = options || _defaults;
  2132. }
  2133. space(src) {
  2134. const cap = this.rules.block.newline.exec(src);
  2135. if (cap && cap[0].length > 0) {
  2136. return {
  2137. type: "space",
  2138. raw: cap[0]
  2139. };
  2140. }
  2141. }
  2142. code(src) {
  2143. const cap = this.rules.block.code.exec(src);
  2144. if (cap) {
  2145. const text = cap[0].replace(/^ {1,4}/gm, "");
  2146. return {
  2147. type: "code",
  2148. raw: cap[0],
  2149. codeBlockStyle: "indented",
  2150. text: !this.options.pedantic ? rtrim(text, "\n") : text
  2151. };
  2152. }
  2153. }
  2154. fences(src) {
  2155. const cap = this.rules.block.fences.exec(src);
  2156. if (cap) {
  2157. const raw = cap[0];
  2158. const text = indentCodeCompensation(raw, cap[3] || "");
  2159. return {
  2160. type: "code",
  2161. raw,
  2162. lang: cap[2] ? cap[2].trim().replace(this.rules.inline.anyPunctuation, "$1") : cap[2],
  2163. text
  2164. };
  2165. }
  2166. }
  2167. heading(src) {
  2168. const cap = this.rules.block.heading.exec(src);
  2169. if (cap) {
  2170. let text = cap[2].trim();
  2171. if (/#$/.test(text)) {
  2172. const trimmed = rtrim(text, "#");
  2173. if (this.options.pedantic) {
  2174. text = trimmed.trim();
  2175. } else if (!trimmed || / $/.test(trimmed)) {
  2176. text = trimmed.trim();
  2177. }
  2178. }
  2179. return {
  2180. type: "heading",
  2181. raw: cap[0],
  2182. depth: cap[1].length,
  2183. text,
  2184. tokens: this.lexer.inline(text)
  2185. };
  2186. }
  2187. }
  2188. hr(src) {
  2189. const cap = this.rules.block.hr.exec(src);
  2190. if (cap) {
  2191. return {
  2192. type: "hr",
  2193. raw: rtrim(cap[0], "\n")
  2194. };
  2195. }
  2196. }
  2197. blockquote(src) {
  2198. const cap = this.rules.block.blockquote.exec(src);
  2199. if (cap) {
  2200. let lines = rtrim(cap[0], "\n").split("\n");
  2201. let raw = "";
  2202. let text = "";
  2203. const tokens = [];
  2204. while (lines.length > 0) {
  2205. let inBlockquote = false;
  2206. const currentLines = [];
  2207. let i;
  2208. for (i = 0; i < lines.length; i++) {
  2209. if (/^ {0,3}>/.test(lines[i])) {
  2210. currentLines.push(lines[i]);
  2211. inBlockquote = true;
  2212. } else if (!inBlockquote) {
  2213. currentLines.push(lines[i]);
  2214. } else {
  2215. break;
  2216. }
  2217. }
  2218. lines = lines.slice(i);
  2219. const currentRaw = currentLines.join("\n");
  2220. const currentText = currentRaw.replace(/\n {0,3}((?:=+|-+) *)(?=\n|$)/g, "\n $1").replace(/^ {0,3}>[ \t]?/gm, "");
  2221. raw = raw ? `${raw}
  2222. ${currentRaw}` : currentRaw;
  2223. text = text ? `${text}
  2224. ${currentText}` : currentText;
  2225. const top = this.lexer.state.top;
  2226. this.lexer.state.top = true;
  2227. this.lexer.blockTokens(currentText, tokens, true);
  2228. this.lexer.state.top = top;
  2229. if (lines.length === 0) {
  2230. break;
  2231. }
  2232. const lastToken = tokens[tokens.length - 1];
  2233. if ((lastToken == null ? void 0 : lastToken.type) === "code") {
  2234. break;
  2235. } else if ((lastToken == null ? void 0 : lastToken.type) === "blockquote") {
  2236. const oldToken = lastToken;
  2237. const newText = oldToken.raw + "\n" + lines.join("\n");
  2238. const newToken = this.blockquote(newText);
  2239. tokens[tokens.length - 1] = newToken;
  2240. raw = raw.substring(0, raw.length - oldToken.raw.length) + newToken.raw;
  2241. text = text.substring(0, text.length - oldToken.text.length) + newToken.text;
  2242. break;
  2243. } else if ((lastToken == null ? void 0 : lastToken.type) === "list") {
  2244. const oldToken = lastToken;
  2245. const newText = oldToken.raw + "\n" + lines.join("\n");
  2246. const newToken = this.list(newText);
  2247. tokens[tokens.length - 1] = newToken;
  2248. raw = raw.substring(0, raw.length - lastToken.raw.length) + newToken.raw;
  2249. text = text.substring(0, text.length - oldToken.raw.length) + newToken.raw;
  2250. lines = newText.substring(tokens[tokens.length - 1].raw.length).split("\n");
  2251. continue;
  2252. }
  2253. }
  2254. return {
  2255. type: "blockquote",
  2256. raw,
  2257. tokens,
  2258. text
  2259. };
  2260. }
  2261. }
  2262. list(src) {
  2263. let cap = this.rules.block.list.exec(src);
  2264. if (cap) {
  2265. let bull = cap[1].trim();
  2266. const isordered = bull.length > 1;
  2267. const list2 = {
  2268. type: "list",
  2269. raw: "",
  2270. ordered: isordered,
  2271. start: isordered ? +bull.slice(0, -1) : "",
  2272. loose: false,
  2273. items: []
  2274. };
  2275. bull = isordered ? `\\d{1,9}\\${bull.slice(-1)}` : `\\${bull}`;
  2276. if (this.options.pedantic) {
  2277. bull = isordered ? bull : "[*+-]";
  2278. }
  2279. const itemRegex = new RegExp(`^( {0,3}${bull})((?:[ ][^\\n]*)?(?:\\n|$))`);
  2280. let endsWithBlankLine = false;
  2281. while (src) {
  2282. let endEarly = false;
  2283. let raw = "";
  2284. let itemContents = "";
  2285. if (!(cap = itemRegex.exec(src))) {
  2286. break;
  2287. }
  2288. if (this.rules.block.hr.test(src)) {
  2289. break;
  2290. }
  2291. raw = cap[0];
  2292. src = src.substring(raw.length);
  2293. let line = cap[2].split("\n", 1)[0].replace(/^\t+/, (t) => " ".repeat(3 * t.length));
  2294. let nextLine = src.split("\n", 1)[0];
  2295. let blankLine = !line.trim();
  2296. let indent = 0;
  2297. if (this.options.pedantic) {
  2298. indent = 2;
  2299. itemContents = line.trimStart();
  2300. } else if (blankLine) {
  2301. indent = cap[1].length + 1;
  2302. } else {
  2303. indent = cap[2].search(/[^ ]/);
  2304. indent = indent > 4 ? 1 : indent;
  2305. itemContents = line.slice(indent);
  2306. indent += cap[1].length;
  2307. }
  2308. if (blankLine && /^ *$/.test(nextLine)) {
  2309. raw += nextLine + "\n";
  2310. src = src.substring(nextLine.length + 1);
  2311. endEarly = true;
  2312. }
  2313. if (!endEarly) {
  2314. const nextBulletRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`);
  2315. const hrRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`);
  2316. const fencesBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:\`\`\`|~~~)`);
  2317. const headingBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}#`);
  2318. while (src) {
  2319. const rawLine = src.split("\n", 1)[0];
  2320. nextLine = rawLine;
  2321. if (this.options.pedantic) {
  2322. nextLine = nextLine.replace(/^ {1,4}(?=( {4})*[^ ])/g, " ");
  2323. }
  2324. if (fencesBeginRegex.test(nextLine)) {
  2325. break;
  2326. }
  2327. if (headingBeginRegex.test(nextLine)) {
  2328. break;
  2329. }
  2330. if (nextBulletRegex.test(nextLine)) {
  2331. break;
  2332. }
  2333. if (hrRegex.test(src)) {
  2334. break;
  2335. }
  2336. if (nextLine.search(/[^ ]/) >= indent || !nextLine.trim()) {
  2337. itemContents += "\n" + nextLine.slice(indent);
  2338. } else {
  2339. if (blankLine) {
  2340. break;
  2341. }
  2342. if (line.search(/[^ ]/) >= 4) {
  2343. break;
  2344. }
  2345. if (fencesBeginRegex.test(line)) {
  2346. break;
  2347. }
  2348. if (headingBeginRegex.test(line)) {
  2349. break;
  2350. }
  2351. if (hrRegex.test(line)) {
  2352. break;
  2353. }
  2354. itemContents += "\n" + nextLine;
  2355. }
  2356. if (!blankLine && !nextLine.trim()) {
  2357. blankLine = true;
  2358. }
  2359. raw += rawLine + "\n";
  2360. src = src.substring(rawLine.length + 1);
  2361. line = nextLine.slice(indent);
  2362. }
  2363. }
  2364. if (!list2.loose) {
  2365. if (endsWithBlankLine) {
  2366. list2.loose = true;
  2367. } else if (/\n *\n *$/.test(raw)) {
  2368. endsWithBlankLine = true;
  2369. }
  2370. }
  2371. let istask = null;
  2372. let ischecked;
  2373. if (this.options.gfm) {
  2374. istask = /^\[[ xX]\] /.exec(itemContents);
  2375. if (istask) {
  2376. ischecked = istask[0] !== "[ ] ";
  2377. itemContents = itemContents.replace(/^\[[ xX]\] +/, "");
  2378. }
  2379. }
  2380. list2.items.push({
  2381. type: "list_item",
  2382. raw,
  2383. task: !!istask,
  2384. checked: ischecked,
  2385. loose: false,
  2386. text: itemContents,
  2387. tokens: []
  2388. });
  2389. list2.raw += raw;
  2390. }
  2391. list2.items[list2.items.length - 1].raw = list2.items[list2.items.length - 1].raw.trimEnd();
  2392. list2.items[list2.items.length - 1].text = list2.items[list2.items.length - 1].text.trimEnd();
  2393. list2.raw = list2.raw.trimEnd();
  2394. for (let i = 0; i < list2.items.length; i++) {
  2395. this.lexer.state.top = false;
  2396. list2.items[i].tokens = this.lexer.blockTokens(list2.items[i].text, []);
  2397. if (!list2.loose) {
  2398. const spacers = list2.items[i].tokens.filter((t) => t.type === "space");
  2399. const hasMultipleLineBreaks = spacers.length > 0 && spacers.some((t) => /\n.*\n/.test(t.raw));
  2400. list2.loose = hasMultipleLineBreaks;
  2401. }
  2402. }
  2403. if (list2.loose) {
  2404. for (let i = 0; i < list2.items.length; i++) {
  2405. list2.items[i].loose = true;
  2406. }
  2407. }
  2408. return list2;
  2409. }
  2410. }
  2411. html(src) {
  2412. const cap = this.rules.block.html.exec(src);
  2413. if (cap) {
  2414. const token = {
  2415. type: "html",
  2416. block: true,
  2417. raw: cap[0],
  2418. pre: cap[1] === "pre" || cap[1] === "script" || cap[1] === "style",
  2419. text: cap[0]
  2420. };
  2421. return token;
  2422. }
  2423. }
  2424. def(src) {
  2425. const cap = this.rules.block.def.exec(src);
  2426. if (cap) {
  2427. const tag2 = cap[1].toLowerCase().replace(/\s+/g, " ");
  2428. const href = cap[2] ? cap[2].replace(/^<(.*)>$/, "$1").replace(this.rules.inline.anyPunctuation, "$1") : "";
  2429. const title = cap[3] ? cap[3].substring(1, cap[3].length - 1).replace(this.rules.inline.anyPunctuation, "$1") : cap[3];
  2430. return {
  2431. type: "def",
  2432. tag: tag2,
  2433. raw: cap[0],
  2434. href,
  2435. title
  2436. };
  2437. }
  2438. }
  2439. table(src) {
  2440. const cap = this.rules.block.table.exec(src);
  2441. if (!cap) {
  2442. return;
  2443. }
  2444. if (!/[:|]/.test(cap[2])) {
  2445. return;
  2446. }
  2447. const headers = splitCells(cap[1]);
  2448. const aligns = cap[2].replace(/^\||\| *$/g, "").split("|");
  2449. const rows = cap[3] && cap[3].trim() ? cap[3].replace(/\n[ \t]*$/, "").split("\n") : [];
  2450. const item = {
  2451. type: "table",
  2452. raw: cap[0],
  2453. header: [],
  2454. align: [],
  2455. rows: []
  2456. };
  2457. if (headers.length !== aligns.length) {
  2458. return;
  2459. }
  2460. for (const align of aligns) {
  2461. if (/^ *-+: *$/.test(align)) {
  2462. item.align.push("right");
  2463. } else if (/^ *:-+: *$/.test(align)) {
  2464. item.align.push("center");
  2465. } else if (/^ *:-+ *$/.test(align)) {
  2466. item.align.push("left");
  2467. } else {
  2468. item.align.push(null);
  2469. }
  2470. }
  2471. for (let i = 0; i < headers.length; i++) {
  2472. item.header.push({
  2473. text: headers[i],
  2474. tokens: this.lexer.inline(headers[i]),
  2475. header: true,
  2476. align: item.align[i]
  2477. });
  2478. }
  2479. for (const row of rows) {
  2480. item.rows.push(splitCells(row, item.header.length).map((cell, i) => {
  2481. return {
  2482. text: cell,
  2483. tokens: this.lexer.inline(cell),
  2484. header: false,
  2485. align: item.align[i]
  2486. };
  2487. }));
  2488. }
  2489. return item;
  2490. }
  2491. lheading(src) {
  2492. const cap = this.rules.block.lheading.exec(src);
  2493. if (cap) {
  2494. return {
  2495. type: "heading",
  2496. raw: cap[0],
  2497. depth: cap[2].charAt(0) === "=" ? 1 : 2,
  2498. text: cap[1],
  2499. tokens: this.lexer.inline(cap[1])
  2500. };
  2501. }
  2502. }
  2503. paragraph(src) {
  2504. const cap = this.rules.block.paragraph.exec(src);
  2505. if (cap) {
  2506. const text = cap[1].charAt(cap[1].length - 1) === "\n" ? cap[1].slice(0, -1) : cap[1];
  2507. return {
  2508. type: "paragraph",
  2509. raw: cap[0],
  2510. text,
  2511. tokens: this.lexer.inline(text)
  2512. };
  2513. }
  2514. }
  2515. text(src) {
  2516. const cap = this.rules.block.text.exec(src);
  2517. if (cap) {
  2518. return {
  2519. type: "text",
  2520. raw: cap[0],
  2521. text: cap[0],
  2522. tokens: this.lexer.inline(cap[0])
  2523. };
  2524. }
  2525. }
  2526. escape(src) {
  2527. const cap = this.rules.inline.escape.exec(src);
  2528. if (cap) {
  2529. return {
  2530. type: "escape",
  2531. raw: cap[0],
  2532. text: escape$1(cap[1])
  2533. };
  2534. }
  2535. }
  2536. tag(src) {
  2537. const cap = this.rules.inline.tag.exec(src);
  2538. if (cap) {
  2539. if (!this.lexer.state.inLink && /^<a /i.test(cap[0])) {
  2540. this.lexer.state.inLink = true;
  2541. } else if (this.lexer.state.inLink && /^<\/a>/i.test(cap[0])) {
  2542. this.lexer.state.inLink = false;
  2543. }
  2544. if (!this.lexer.state.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
  2545. this.lexer.state.inRawBlock = true;
  2546. } else if (this.lexer.state.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
  2547. this.lexer.state.inRawBlock = false;
  2548. }
  2549. return {
  2550. type: "html",
  2551. raw: cap[0],
  2552. inLink: this.lexer.state.inLink,
  2553. inRawBlock: this.lexer.state.inRawBlock,
  2554. block: false,
  2555. text: cap[0]
  2556. };
  2557. }
  2558. }
  2559. link(src) {
  2560. const cap = this.rules.inline.link.exec(src);
  2561. if (cap) {
  2562. const trimmedUrl = cap[2].trim();
  2563. if (!this.options.pedantic && /^</.test(trimmedUrl)) {
  2564. if (!/>$/.test(trimmedUrl)) {
  2565. return;
  2566. }
  2567. const rtrimSlash = rtrim(trimmedUrl.slice(0, -1), "\\");
  2568. if ((trimmedUrl.length - rtrimSlash.length) % 2 === 0) {
  2569. return;
  2570. }
  2571. } else {
  2572. const lastParenIndex = findClosingBracket(cap[2], "()");
  2573. if (lastParenIndex > -1) {
  2574. const start = cap[0].indexOf("!") === 0 ? 5 : 4;
  2575. const linkLen = start + cap[1].length + lastParenIndex;
  2576. cap[2] = cap[2].substring(0, lastParenIndex);
  2577. cap[0] = cap[0].substring(0, linkLen).trim();
  2578. cap[3] = "";
  2579. }
  2580. }
  2581. let href = cap[2];
  2582. let title = "";
  2583. if (this.options.pedantic) {
  2584. const link2 = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href);
  2585. if (link2) {
  2586. href = link2[1];
  2587. title = link2[3];
  2588. }
  2589. } else {
  2590. title = cap[3] ? cap[3].slice(1, -1) : "";
  2591. }
  2592. href = href.trim();
  2593. if (/^</.test(href)) {
  2594. if (this.options.pedantic && !/>$/.test(trimmedUrl)) {
  2595. href = href.slice(1);
  2596. } else {
  2597. href = href.slice(1, -1);
  2598. }
  2599. }
  2600. return outputLink(cap, {
  2601. href: href ? href.replace(this.rules.inline.anyPunctuation, "$1") : href,
  2602. title: title ? title.replace(this.rules.inline.anyPunctuation, "$1") : title
  2603. }, cap[0], this.lexer);
  2604. }
  2605. }
  2606. reflink(src, links) {
  2607. let cap;
  2608. if ((cap = this.rules.inline.reflink.exec(src)) || (cap = this.rules.inline.nolink.exec(src))) {
  2609. const linkString = (cap[2] || cap[1]).replace(/\s+/g, " ");
  2610. const link2 = links[linkString.toLowerCase()];
  2611. if (!link2) {
  2612. const text = cap[0].charAt(0);
  2613. return {
  2614. type: "text",
  2615. raw: text,
  2616. text
  2617. };
  2618. }
  2619. return outputLink(cap, link2, cap[0], this.lexer);
  2620. }
  2621. }
  2622. emStrong(src, maskedSrc, prevChar = "") {
  2623. let match = this.rules.inline.emStrongLDelim.exec(src);
  2624. if (!match)
  2625. return;
  2626. if (match[3] && prevChar.match(/[\p{L}\p{N}]/u))
  2627. return;
  2628. const nextChar = match[1] || match[2] || "";
  2629. if (!nextChar || !prevChar || this.rules.inline.punctuation.exec(prevChar)) {
  2630. const lLength = [...match[0]].length - 1;
  2631. let rDelim, rLength, delimTotal = lLength,
  2632. midDelimTotal = 0;
  2633. const endReg = match[0][0] === "*" ? this.rules.inline.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd;
  2634. endReg.lastIndex = 0;
  2635. maskedSrc = maskedSrc.slice(-1 * src.length + lLength);
  2636. while ((match = endReg.exec(maskedSrc)) != null) {
  2637. rDelim = match[1] || match[2] || match[3] || match[4] || match[5] || match[6];
  2638. if (!rDelim)
  2639. continue;
  2640. rLength = [...rDelim].length;
  2641. if (match[3] || match[4]) {
  2642. delimTotal += rLength;
  2643. continue;
  2644. } else if (match[5] || match[6]) {
  2645. if (lLength % 3 && !((lLength + rLength) % 3)) {
  2646. midDelimTotal += rLength;
  2647. continue;
  2648. }
  2649. }
  2650. delimTotal -= rLength;
  2651. if (delimTotal > 0)
  2652. continue;
  2653. rLength = Math.min(rLength, rLength + delimTotal + midDelimTotal);
  2654. const lastCharLength = [...match[0]][0].length;
  2655. const raw = src.slice(0, lLength + match.index + lastCharLength + rLength);
  2656. if (Math.min(lLength, rLength) % 2) {
  2657. const text2 = raw.slice(1, -1);
  2658. return {
  2659. type: "em",
  2660. raw,
  2661. text: text2,
  2662. tokens: this.lexer.inlineTokens(text2)
  2663. };
  2664. }
  2665. const text = raw.slice(2, -2);
  2666. return {
  2667. type: "strong",
  2668. raw,
  2669. text,
  2670. tokens: this.lexer.inlineTokens(text)
  2671. };
  2672. }
  2673. }
  2674. }
  2675. codespan(src) {
  2676. const cap = this.rules.inline.code.exec(src);
  2677. if (cap) {
  2678. let text = cap[2].replace(/\n/g, " ");
  2679. const hasNonSpaceChars = /[^ ]/.test(text);
  2680. const hasSpaceCharsOnBothEnds = /^ /.test(text) && / $/.test(text);
  2681. if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
  2682. text = text.substring(1, text.length - 1);
  2683. }
  2684. text = escape$1(text, true);
  2685. return {
  2686. type: "codespan",
  2687. raw: cap[0],
  2688. text
  2689. };
  2690. }
  2691. }
  2692. br(src) {
  2693. const cap = this.rules.inline.br.exec(src);
  2694. if (cap) {
  2695. return {
  2696. type: "br",
  2697. raw: cap[0]
  2698. };
  2699. }
  2700. }
  2701. del(src) {
  2702. const cap = this.rules.inline.del.exec(src);
  2703. if (cap) {
  2704. return {
  2705. type: "del",
  2706. raw: cap[0],
  2707. text: cap[2],
  2708. tokens: this.lexer.inlineTokens(cap[2])
  2709. };
  2710. }
  2711. }
  2712. autolink(src) {
  2713. const cap = this.rules.inline.autolink.exec(src);
  2714. if (cap) {
  2715. let text, href;
  2716. if (cap[2] === "@") {
  2717. text = escape$1(cap[1]);
  2718. href = "mailto:" + text;
  2719. } else {
  2720. text = escape$1(cap[1]);
  2721. href = text;
  2722. }
  2723. return {
  2724. type: "link",
  2725. raw: cap[0],
  2726. text,
  2727. href,
  2728. tokens: [{
  2729. type: "text",
  2730. raw: text,
  2731. text
  2732. }]
  2733. };
  2734. }
  2735. }
  2736. url(src) {
  2737. var _a;
  2738. let cap;
  2739. if (cap = this.rules.inline.url.exec(src)) {
  2740. let text, href;
  2741. if (cap[2] === "@") {
  2742. text = escape$1(cap[0]);
  2743. href = "mailto:" + text;
  2744. } else {
  2745. let prevCapZero;
  2746. do {
  2747. prevCapZero = cap[0];
  2748. let t = ((_a = this.rules.inline._backpedal.exec(cap[0])) == null ? void 0 : _a[0])
  2749. cap[0] = t ? t : "";
  2750. } while (prevCapZero !== cap[0]);
  2751. text = escape$1(cap[0]);
  2752. if (cap[1] === "www.") {
  2753. href = "http://" + cap[0];
  2754. } else {
  2755. href = cap[0];
  2756. }
  2757. }
  2758. return {
  2759. type: "link",
  2760. raw: cap[0],
  2761. text,
  2762. href,
  2763. tokens: [{
  2764. type: "text",
  2765. raw: text,
  2766. text
  2767. }]
  2768. };
  2769. }
  2770. }
  2771. inlineText(src) {
  2772. const cap = this.rules.inline.text.exec(src);
  2773. if (cap) {
  2774. let text;
  2775. if (this.lexer.state.inRawBlock) {
  2776. text = cap[0];
  2777. } else {
  2778. text = escape$1(cap[0]);
  2779. }
  2780. return {
  2781. type: "text",
  2782. raw: cap[0],
  2783. text
  2784. };
  2785. }
  2786. }
  2787. }
  2788. const newline = /^(?: *(?:\n|$))+/;
  2789. const blockCode = /^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/;
  2790. const fences = /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/;
  2791. const hr = /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/;
  2792. const heading = /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/;
  2793. const bullet = /(?:[*+-]|\d{1,9}[.)])/;
  2794. 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();
  2795. const _paragraph = /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/;
  2796. const blockText = /^[^\n]+/;
  2797. const _blockLabel = /(?!\s*\])(?:\\.|[^\[\]\\])+/;
  2798. const def = edit(/^ {0,3}\[(label)\]: *(?:\n *)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/).replace("label", _blockLabel).replace("title", /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex();
  2799. const list = edit(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g, bullet).getRegex();
  2800. 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";
  2801. const _comment = /<!--(?:-?>|[\s\S]*?(?:-->|$))/;
  2802. 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();
  2803. 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();
  2804. const blockquote = edit(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph", paragraph).getRegex();
  2805. const blockNormal = {
  2806. blockquote,
  2807. code: blockCode,
  2808. def,
  2809. fences,
  2810. heading,
  2811. hr,
  2812. html,
  2813. lheading,
  2814. list,
  2815. newline,
  2816. paragraph,
  2817. table: noopTest,
  2818. text: blockText
  2819. };
  2820. 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();
  2821. const blockGfm = {
  2822. ...blockNormal,
  2823. table: gfmTable,
  2824. 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()
  2825. };
  2826. const blockPedantic = {
  2827. ...blockNormal,
  2828. 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(),
  2829. def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
  2830. heading: /^(#{1,6})(.*)(?:\n+|$)/,
  2831. fences: noopTest,
  2832. // fences not supported
  2833. lheading: /^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,
  2834. 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()
  2835. };
  2836. const escape = /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/;
  2837. const inlineCode = /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/;
  2838. const br = /^( {2,}|\\)\n(?!\s*$)/;
  2839. const inlineText = /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/;
  2840. const _punctuation = "\\p{P}\\p{S}";
  2841. const punctuation = edit(/^((?![*_])[\spunctuation])/, "u").replace(/punctuation/g, _punctuation).getRegex();
  2842. const blockSkip = /\[[^[\]]*?\]\([^\(\)]*?\)|`[^`]*?`|<[^<>]*?>/g;
  2843. const emStrongLDelim = edit(/^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/, "u").replace(/punct/g, _punctuation).getRegex();
  2844. 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();
  2845. const emStrongRDelimUnd = edit("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)[punct](_+)(?=[\\s]|$)|[^punct\\s](_+)(?!_)(?=[punct\\s]|$)|(?!_)[punct\\s](_+)(?=[^punct\\s])|[\\s](_+)(?!_)(?=[punct])|(?!_)[punct](_+)(?!_)(?=[punct])", "gu").replace(/punct/g, _punctuation).getRegex();
  2846. const anyPunctuation = edit(/\\([punct])/, "gu").replace(/punct/g, _punctuation).getRegex();
  2847. 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();
  2848. const _inlineComment = edit(_comment).replace("(?:-->|$)", "-->").getRegex();
  2849. 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();
  2850. const _inlineLabel = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
  2851. const link = edit(/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/).replace("label", _inlineLabel).replace("href", /<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/).replace("title", /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex();
  2852. const reflink = edit(/^!?\[(label)\]\[(ref)\]/).replace("label", _inlineLabel).replace("ref", _blockLabel).getRegex();
  2853. const nolink = edit(/^!?\[(ref)\](?:\[\])?/).replace("ref", _blockLabel).getRegex();
  2854. const reflinkSearch = edit("reflink|nolink(?!\\()", "g").replace("reflink", reflink).replace("nolink", nolink).getRegex();
  2855. const inlineNormal = {
  2856. _backpedal: noopTest,
  2857. // only used for GFM url
  2858. anyPunctuation,
  2859. autolink,
  2860. blockSkip,
  2861. br,
  2862. code: inlineCode,
  2863. del: noopTest,
  2864. emStrongLDelim,
  2865. emStrongRDelimAst,
  2866. emStrongRDelimUnd,
  2867. escape,
  2868. link,
  2869. nolink,
  2870. punctuation,
  2871. reflink,
  2872. reflinkSearch,
  2873. tag,
  2874. text: inlineText,
  2875. url: noopTest
  2876. };
  2877. const inlinePedantic = {
  2878. ...inlineNormal,
  2879. link: edit(/^!?\[(label)\]\((.*?)\)/).replace("label", _inlineLabel).getRegex(),
  2880. reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label", _inlineLabel).getRegex()
  2881. };
  2882. const inlineGfm = {
  2883. ...inlineNormal,
  2884. escape: edit(escape).replace("])", "~|])").getRegex(),
  2885. 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(),
  2886. _backpedal: /(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,
  2887. del: /^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,
  2888. text: /^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/
  2889. };
  2890. const inlineBreaks = {
  2891. ...inlineGfm,
  2892. br: edit(br).replace("{2,}", "*").getRegex(),
  2893. text: edit(inlineGfm.text).replace("\\b_", "\\b_| {2,}\\n").replace(/\{2,\}/g, "*").getRegex()
  2894. };
  2895. const block = {
  2896. normal: blockNormal,
  2897. gfm: blockGfm,
  2898. pedantic: blockPedantic
  2899. };
  2900. const inline = {
  2901. normal: inlineNormal,
  2902. gfm: inlineGfm,
  2903. breaks: inlineBreaks,
  2904. pedantic: inlinePedantic
  2905. };
  2906. class _Lexer {
  2907. constructor(options) {
  2908. __publicField(this, "tokens");
  2909. __publicField(this, "options");
  2910. __publicField(this, "state");
  2911. __publicField(this, "tokenizer");
  2912. __publicField(this, "inlineQueue");
  2913. this.tokens = [];
  2914. this.tokens.links = /* @__PURE__ */ Object.create(null);
  2915. this.options = options || _defaults;
  2916. this.options.tokenizer = this.options.tokenizer || new _Tokenizer();
  2917. this.tokenizer = this.options.tokenizer;
  2918. this.tokenizer.options = this.options;
  2919. this.tokenizer.lexer = this;
  2920. this.inlineQueue = [];
  2921. this.state = {
  2922. inLink: false,
  2923. inRawBlock: false,
  2924. top: true
  2925. };
  2926. const rules = {
  2927. block: block.normal,
  2928. inline: inline.normal
  2929. };
  2930. if (this.options.pedantic) {
  2931. rules.block = block.pedantic;
  2932. rules.inline = inline.pedantic;
  2933. } else if (this.options.gfm) {
  2934. rules.block = block.gfm;
  2935. if (this.options.breaks) {
  2936. rules.inline = inline.breaks;
  2937. } else {
  2938. rules.inline = inline.gfm;
  2939. }
  2940. }
  2941. this.tokenizer.rules = rules;
  2942. }
  2943. /**
  2944. * Expose Rules
  2945. */
  2946. static get rules() {
  2947. return {
  2948. block,
  2949. inline
  2950. };
  2951. }
  2952. /**
  2953. * Static Lex Method
  2954. */
  2955. static lex(src, options) {
  2956. const lexer = new _Lexer(options);
  2957. return lexer.lex(src);
  2958. }
  2959. /**
  2960. * Static Lex Inline Method
  2961. */
  2962. static lexInline(src, options) {
  2963. const lexer = new _Lexer(options);
  2964. return lexer.inlineTokens(src);
  2965. }
  2966. /**
  2967. * Preprocessing
  2968. */
  2969. lex(src) {
  2970. src = src.replace(/\r\n|\r/g, "\n");
  2971. this.blockTokens(src, this.tokens);
  2972. for (let i = 0; i < this.inlineQueue.length; i++) {
  2973. const next = this.inlineQueue[i];
  2974. this.inlineTokens(next.src, next.tokens);
  2975. }
  2976. this.inlineQueue = [];
  2977. return this.tokens;
  2978. }
  2979. blockTokens(src, tokens = [], lastParagraphClipped = false) {
  2980. if (this.options.pedantic) {
  2981. src = src.replace(/\t/g, " ").replace(/^ +$/gm, "");
  2982. } else {
  2983. src = src.replace(/^( *)(\t+)/gm, (_, leading, tabs) => {
  2984. return leading + " ".repeat(tabs.length);
  2985. });
  2986. }
  2987. let token;
  2988. let lastToken;
  2989. let cutSrc;
  2990. while (src) {
  2991. if (this.options.extensions && this.options.extensions.block && this.options.extensions.block.some((extTokenizer) => {
  2992. if (token = extTokenizer.call({
  2993. lexer: this
  2994. }, src, tokens)) {
  2995. src = src.substring(token.raw.length);
  2996. tokens.push(token);
  2997. return true;
  2998. }
  2999. return false;
  3000. })) {
  3001. continue;
  3002. }
  3003. if (token = this.tokenizer.space(src)) {
  3004. src = src.substring(token.raw.length);
  3005. if (token.raw.length === 1 && tokens.length > 0) {
  3006. tokens[tokens.length - 1].raw += "\n";
  3007. } else {
  3008. tokens.push(token);
  3009. }
  3010. continue;
  3011. }
  3012. if (token = this.tokenizer.code(src)) {
  3013. src = src.substring(token.raw.length);
  3014. lastToken = tokens[tokens.length - 1];
  3015. if (lastToken && (lastToken.type === "paragraph" || lastToken.type === "text")) {
  3016. lastToken.raw += "\n" + token.raw;
  3017. lastToken.text += "\n" + token.text;
  3018. this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
  3019. } else {
  3020. tokens.push(token);
  3021. }
  3022. continue;
  3023. }
  3024. if (token = this.tokenizer.fences(src)) {
  3025. src = src.substring(token.raw.length);
  3026. tokens.push(token);
  3027. continue;
  3028. }
  3029. if (token = this.tokenizer.heading(src)) {
  3030. src = src.substring(token.raw.length);
  3031. tokens.push(token);
  3032. continue;
  3033. }
  3034. if (token = this.tokenizer.hr(src)) {
  3035. src = src.substring(token.raw.length);
  3036. tokens.push(token);
  3037. continue;
  3038. }
  3039. if (token = this.tokenizer.blockquote(src)) {
  3040. src = src.substring(token.raw.length);
  3041. tokens.push(token);
  3042. continue;
  3043. }
  3044. if (token = this.tokenizer.list(src)) {
  3045. src = src.substring(token.raw.length);
  3046. tokens.push(token);
  3047. continue;
  3048. }
  3049. if (token = this.tokenizer.html(src)) {
  3050. src = src.substring(token.raw.length);
  3051. tokens.push(token);
  3052. continue;
  3053. }
  3054. if (token = this.tokenizer.def(src)) {
  3055. src = src.substring(token.raw.length);
  3056. lastToken = tokens[tokens.length - 1];
  3057. if (lastToken && (lastToken.type === "paragraph" || lastToken.type === "text")) {
  3058. lastToken.raw += "\n" + token.raw;
  3059. lastToken.text += "\n" + token.raw;
  3060. this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
  3061. } else if (!this.tokens.links[token.tag]) {
  3062. this.tokens.links[token.tag] = {
  3063. href: token.href,
  3064. title: token.title
  3065. };
  3066. }
  3067. continue;
  3068. }
  3069. if (token = this.tokenizer.table(src)) {
  3070. src = src.substring(token.raw.length);
  3071. tokens.push(token);
  3072. continue;
  3073. }
  3074. if (token = this.tokenizer.lheading(src)) {
  3075. src = src.substring(token.raw.length);
  3076. tokens.push(token);
  3077. continue;
  3078. }
  3079. cutSrc = src;
  3080. if (this.options.extensions && this.options.extensions.startBlock) {
  3081. let startIndex = Infinity;
  3082. const tempSrc = src.slice(1);
  3083. let tempStart;
  3084. this.options.extensions.startBlock.forEach((getStartIndex) => {
  3085. tempStart = getStartIndex.call({
  3086. lexer: this
  3087. }, tempSrc);
  3088. if (typeof tempStart === "number" && tempStart >= 0) {
  3089. startIndex = Math.min(startIndex, tempStart);
  3090. }
  3091. });
  3092. if (startIndex < Infinity && startIndex >= 0) {
  3093. cutSrc = src.substring(0, startIndex + 1);
  3094. }
  3095. }
  3096. if (this.state.top && (token = this.tokenizer.paragraph(cutSrc))) {
  3097. lastToken = tokens[tokens.length - 1];
  3098. if (lastParagraphClipped && (lastToken == null ? void 0 : lastToken.type) === "paragraph") {
  3099. lastToken.raw += "\n" + token.raw;
  3100. lastToken.text += "\n" + token.text;
  3101. this.inlineQueue.pop();
  3102. this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
  3103. } else {
  3104. tokens.push(token);
  3105. }
  3106. lastParagraphClipped = cutSrc.length !== src.length;
  3107. src = src.substring(token.raw.length);
  3108. continue;
  3109. }
  3110. if (token = this.tokenizer.text(src)) {
  3111. src = src.substring(token.raw.length);
  3112. lastToken = tokens[tokens.length - 1];
  3113. if (lastToken && lastToken.type === "text") {
  3114. lastToken.raw += "\n" + token.raw;
  3115. lastToken.text += "\n" + token.text;
  3116. this.inlineQueue.pop();
  3117. this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
  3118. } else {
  3119. tokens.push(token);
  3120. }
  3121. continue;
  3122. }
  3123. if (src) {
  3124. const errMsg = "Infinite loop on byte: " + src.charCodeAt(0);
  3125. if (this.options.silent) {
  3126. console.error(errMsg);
  3127. break;
  3128. } else {
  3129. throw new Error(errMsg);
  3130. }
  3131. }
  3132. }
  3133. this.state.top = true;
  3134. return tokens;
  3135. }
  3136. inline(src, tokens = []) {
  3137. this.inlineQueue.push({
  3138. src,
  3139. tokens
  3140. });
  3141. return tokens;
  3142. }
  3143. /**
  3144. * Lexing/Compiling
  3145. */
  3146. inlineTokens(src, tokens = []) {
  3147. let token, lastToken, cutSrc;
  3148. let maskedSrc = src;
  3149. let match;
  3150. let keepPrevChar, prevChar;
  3151. if (this.tokens.links) {
  3152. const links = Object.keys(this.tokens.links);
  3153. if (links.length > 0) {
  3154. while ((match = this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc)) != null) {
  3155. if (links.includes(match[0].slice(match[0].lastIndexOf("[") + 1, -1))) {
  3156. maskedSrc = maskedSrc.slice(0, match.index) + "[" + "a".repeat(match[0].length - 2) + "]" + maskedSrc.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex);
  3157. }
  3158. }
  3159. }
  3160. }
  3161. while ((match = this.tokenizer.rules.inline.blockSkip.exec(maskedSrc)) != null) {
  3162. maskedSrc = maskedSrc.slice(0, match.index) + "[" + "a".repeat(match[0].length - 2) + "]" + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);
  3163. }
  3164. while ((match = this.tokenizer.rules.inline.anyPunctuation.exec(maskedSrc)) != null) {
  3165. maskedSrc = maskedSrc.slice(0, match.index) + "++" + maskedSrc.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);
  3166. }
  3167. while (src) {
  3168. if (!keepPrevChar) {
  3169. prevChar = "";
  3170. }
  3171. keepPrevChar = false;
  3172. if (this.options.extensions && this.options.extensions.inline && this.options.extensions.inline.some((extTokenizer) => {
  3173. if (token = extTokenizer.call({
  3174. lexer: this
  3175. }, src, tokens)) {
  3176. src = src.substring(token.raw.length);
  3177. tokens.push(token);
  3178. return true;
  3179. }
  3180. return false;
  3181. })) {
  3182. continue;
  3183. }
  3184. if (token = this.tokenizer.escape(src)) {
  3185. src = src.substring(token.raw.length);
  3186. tokens.push(token);
  3187. continue;
  3188. }
  3189. if (token = this.tokenizer.tag(src)) {
  3190. src = src.substring(token.raw.length);
  3191. lastToken = tokens[tokens.length - 1];
  3192. if (lastToken && token.type === "text" && lastToken.type === "text") {
  3193. lastToken.raw += token.raw;
  3194. lastToken.text += token.text;
  3195. } else {
  3196. tokens.push(token);
  3197. }
  3198. continue;
  3199. }
  3200. if (token = this.tokenizer.link(src)) {
  3201. src = src.substring(token.raw.length);
  3202. tokens.push(token);
  3203. continue;
  3204. }
  3205. if (token = this.tokenizer.reflink(src, this.tokens.links)) {
  3206. src = src.substring(token.raw.length);
  3207. lastToken = tokens[tokens.length - 1];
  3208. if (lastToken && token.type === "text" && lastToken.type === "text") {
  3209. lastToken.raw += token.raw;
  3210. lastToken.text += token.text;
  3211. } else {
  3212. tokens.push(token);
  3213. }
  3214. continue;
  3215. }
  3216. if (token = this.tokenizer.emStrong(src, maskedSrc, prevChar)) {
  3217. src = src.substring(token.raw.length);
  3218. tokens.push(token);
  3219. continue;
  3220. }
  3221. if (token = this.tokenizer.codespan(src)) {
  3222. src = src.substring(token.raw.length);
  3223. tokens.push(token);
  3224. continue;
  3225. }
  3226. if (token = this.tokenizer.br(src)) {
  3227. src = src.substring(token.raw.length);
  3228. tokens.push(token);
  3229. continue;
  3230. }
  3231. if (token = this.tokenizer.del(src)) {
  3232. src = src.substring(token.raw.length);
  3233. tokens.push(token);
  3234. continue;
  3235. }
  3236. if (token = this.tokenizer.autolink(src)) {
  3237. src = src.substring(token.raw.length);
  3238. tokens.push(token);
  3239. continue;
  3240. }
  3241. if (!this.state.inLink && (token = this.tokenizer.url(src))) {
  3242. src = src.substring(token.raw.length);
  3243. tokens.push(token);
  3244. continue;
  3245. }
  3246. cutSrc = src;
  3247. if (this.options.extensions && this.options.extensions.startInline) {
  3248. let startIndex = Infinity;
  3249. const tempSrc = src.slice(1);
  3250. let tempStart;
  3251. this.options.extensions.startInline.forEach((getStartIndex) => {
  3252. tempStart = getStartIndex.call({
  3253. lexer: this
  3254. }, tempSrc);
  3255. if (typeof tempStart === "number" && tempStart >= 0) {
  3256. startIndex = Math.min(startIndex, tempStart);
  3257. }
  3258. });
  3259. if (startIndex < Infinity && startIndex >= 0) {
  3260. cutSrc = src.substring(0, startIndex + 1);
  3261. }
  3262. }
  3263. if (token = this.tokenizer.inlineText(cutSrc)) {
  3264. src = src.substring(token.raw.length);
  3265. if (token.raw.slice(-1) !== "_") {
  3266. prevChar = token.raw.slice(-1);
  3267. }
  3268. keepPrevChar = true;
  3269. lastToken = tokens[tokens.length - 1];
  3270. if (lastToken && lastToken.type === "text") {
  3271. lastToken.raw += token.raw;
  3272. lastToken.text += token.text;
  3273. } else {
  3274. tokens.push(token);
  3275. }
  3276. continue;
  3277. }
  3278. if (src) {
  3279. const errMsg = "Infinite loop on byte: " + src.charCodeAt(0);
  3280. if (this.options.silent) {
  3281. console.error(errMsg);
  3282. break;
  3283. } else {
  3284. throw new Error(errMsg);
  3285. }
  3286. }
  3287. }
  3288. return tokens;
  3289. }
  3290. }
  3291. class _Renderer {
  3292. // set by the parser
  3293. constructor(options) {
  3294. __publicField(this, "options");
  3295. __publicField(this, "parser");
  3296. this.options = options || _defaults;
  3297. }
  3298. space(token) {
  3299. return "";
  3300. }
  3301. code({
  3302. text,
  3303. lang,
  3304. escaped
  3305. }) {
  3306. var _a;
  3307. const langString = (_a = (lang || "").match(/^\S*/)) == null ? void 0 : _a[0];
  3308. const code = text.replace(/\n$/, "") + "\n";
  3309. if (!langString) {
  3310. return "<pre><code>" + (escaped ? code : escape$1(code, true)) + "</code></pre>\n";
  3311. }
  3312. return '<pre><code class="language-' + escape$1(langString) + '">' + (escaped ? code : escape$1(code, true)) + "</code></pre>\n";
  3313. }
  3314. blockquote({
  3315. tokens
  3316. }) {
  3317. const body = this.parser.parse(tokens);
  3318. return `<blockquote>
  3319. ${body}</blockquote>
  3320. `;
  3321. }
  3322. html({
  3323. text
  3324. }) {
  3325. return text;
  3326. }
  3327. heading({
  3328. tokens,
  3329. depth
  3330. }) {
  3331. return `<h${depth}>${this.parser.parseInline(tokens)}</h${depth}>
  3332. `;
  3333. }
  3334. hr(token) {
  3335. return "<hr>\n";
  3336. }
  3337. list(token) {
  3338. const ordered = token.ordered;
  3339. const start = token.start;
  3340. let body = "";
  3341. for (let j = 0; j < token.items.length; j++) {
  3342. const item = token.items[j];
  3343. body += this.listitem(item);
  3344. }
  3345. const type = ordered ? "ol" : "ul";
  3346. const startAttr = ordered && start !== 1 ? ' start="' + start + '"' : "";
  3347. return "<" + type + startAttr + ">\n" + body + "</" + type + ">\n";
  3348. }
  3349. listitem(item) {
  3350. let itemBody = "";
  3351. if (item.task) {
  3352. const checkbox = this.checkbox({
  3353. checked: !!item.checked
  3354. });
  3355. if (item.loose) {
  3356. if (item.tokens.length > 0 && item.tokens[0].type === "paragraph") {
  3357. item.tokens[0].text = checkbox + " " + item.tokens[0].text;
  3358. if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === "text") {
  3359. item.tokens[0].tokens[0].text = checkbox + " " + item.tokens[0].tokens[0].text;
  3360. }
  3361. } else {
  3362. item.tokens.unshift({
  3363. type: "text",
  3364. raw: checkbox + " ",
  3365. text: checkbox + " "
  3366. });
  3367. }
  3368. } else {
  3369. itemBody += checkbox + " ";
  3370. }
  3371. }
  3372. itemBody += this.parser.parse(item.tokens, !!item.loose);
  3373. return `<li>${itemBody}</li>
  3374. `;
  3375. }
  3376. checkbox({
  3377. checked
  3378. }) {
  3379. return "<input " + (checked ? 'checked="" ' : "") + 'disabled="" type="checkbox">';
  3380. }
  3381. paragraph({
  3382. tokens
  3383. }) {
  3384. return `<p>${this.parser.parseInline(tokens)}</p>
  3385. `;
  3386. }
  3387. table(token) {
  3388. let header = "";
  3389. let cell = "";
  3390. for (let j = 0; j < token.header.length; j++) {
  3391. cell += this.tablecell(token.header[j]);
  3392. }
  3393. header += this.tablerow({
  3394. text: cell
  3395. });
  3396. let body = "";
  3397. for (let j = 0; j < token.rows.length; j++) {
  3398. const row = token.rows[j];
  3399. cell = "";
  3400. for (let k = 0; k < row.length; k++) {
  3401. cell += this.tablecell(row[k]);
  3402. }
  3403. body += this.tablerow({
  3404. text: cell
  3405. });
  3406. }
  3407. if (body)
  3408. body = `<tbody>${body}</tbody>`;
  3409. return "<table>\n<thead>\n" + header + "</thead>\n" + body + "</table>\n";
  3410. }
  3411. tablerow({
  3412. text
  3413. }) {
  3414. return `<tr>
  3415. ${text}</tr>
  3416. `;
  3417. }
  3418. tablecell(token) {
  3419. const content = this.parser.parseInline(token.tokens);
  3420. const type = token.header ? "th" : "td";
  3421. const tag2 = token.align ? `<${type} align="${token.align}">` : `<${type}>`;
  3422. return tag2 + content + `</${type}>
  3423. `;
  3424. }
  3425. /**
  3426. * span level renderer
  3427. */
  3428. strong({
  3429. tokens
  3430. }) {
  3431. return `<strong>${this.parser.parseInline(tokens)}</strong>`;
  3432. }
  3433. em({
  3434. tokens
  3435. }) {
  3436. return `<em>${this.parser.parseInline(tokens)}</em>`;
  3437. }
  3438. codespan({
  3439. text
  3440. }) {
  3441. return `<code>${text}</code>`;
  3442. }
  3443. br(token) {
  3444. return "<br>";
  3445. }
  3446. del({
  3447. tokens
  3448. }) {
  3449. return `<del>${this.parser.parseInline(tokens)}</del>`;
  3450. }
  3451. link({
  3452. href,
  3453. title,
  3454. tokens
  3455. }) {
  3456. const text = this.parser.parseInline(tokens);
  3457. const cleanHref = cleanUrl(href);
  3458. if (cleanHref === null) {
  3459. return text;
  3460. }
  3461. href = cleanHref;
  3462. let out = '<a href="' + href + '"';
  3463. if (title) {
  3464. out += ' title="' + title + '"';
  3465. }
  3466. out += ">" + text + "</a>";
  3467. return out;
  3468. }
  3469. image({
  3470. href,
  3471. title,
  3472. text
  3473. }) {
  3474. const cleanHref = cleanUrl(href);
  3475. if (cleanHref === null) {
  3476. return text;
  3477. }
  3478. href = cleanHref;
  3479. let out = `<img src="${href}" alt="${text}"`;
  3480. if (title) {
  3481. out += ` title="${title}"`;
  3482. }
  3483. out += ">";
  3484. return out;
  3485. }
  3486. text(token) {
  3487. return "tokens" in token && token.tokens ? this.parser.parseInline(token.tokens) : token.text;
  3488. }
  3489. }
  3490. class _TextRenderer {
  3491. // no need for block level renderers
  3492. strong({
  3493. text
  3494. }) {
  3495. return text;
  3496. }
  3497. em({
  3498. text
  3499. }) {
  3500. return text;
  3501. }
  3502. codespan({
  3503. text
  3504. }) {
  3505. return text;
  3506. }
  3507. del({
  3508. text
  3509. }) {
  3510. return text;
  3511. }
  3512. html({
  3513. text
  3514. }) {
  3515. return text;
  3516. }
  3517. text({
  3518. text
  3519. }) {
  3520. return text;
  3521. }
  3522. link({
  3523. text
  3524. }) {
  3525. return "" + text;
  3526. }
  3527. image({
  3528. text
  3529. }) {
  3530. return "" + text;
  3531. }
  3532. br() {
  3533. return "";
  3534. }
  3535. }
  3536. class _Parser {
  3537. constructor(options) {
  3538. __publicField(this, "options");
  3539. __publicField(this, "renderer");
  3540. __publicField(this, "textRenderer");
  3541. this.options = options || _defaults;
  3542. this.options.renderer = this.options.renderer || new _Renderer();
  3543. this.renderer = this.options.renderer;
  3544. this.renderer.options = this.options;
  3545. this.renderer.parser = this;
  3546. this.textRenderer = new _TextRenderer();
  3547. }
  3548. /**
  3549. * Static Parse Method
  3550. */
  3551. static parse(tokens, options) {
  3552. const parser = new _Parser(options);
  3553. return parser.parse(tokens);
  3554. }
  3555. /**
  3556. * Static Parse Inline Method
  3557. */
  3558. static parseInline(tokens, options) {
  3559. const parser = new _Parser(options);
  3560. return parser.parseInline(tokens);
  3561. }
  3562. /**
  3563. * Parse Loop
  3564. */
  3565. parse(tokens, top = true) {
  3566. let out = "";
  3567. for (let i = 0; i < tokens.length; i++) {
  3568. const anyToken = tokens[i];
  3569. if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[anyToken.type]) {
  3570. const genericToken = anyToken;
  3571. const ret = this.options.extensions.renderers[genericToken.type].call({
  3572. parser: this
  3573. }, genericToken);
  3574. if (ret !== false || !["space", "hr", "heading", "code", "table", "blockquote", "list", "html", "paragraph", "text"].includes(genericToken.type)) {
  3575. out += ret || "";
  3576. continue;
  3577. }
  3578. }
  3579. const token = anyToken;
  3580. switch (token.type) {
  3581. case "space": {
  3582. out += this.renderer.space(token);
  3583. continue;
  3584. }
  3585. case "hr": {
  3586. out += this.renderer.hr(token);
  3587. continue;
  3588. }
  3589. case "heading": {
  3590. out += this.renderer.heading(token);
  3591. continue;
  3592. }
  3593. case "code": {
  3594. out += this.renderer.code(token);
  3595. continue;
  3596. }
  3597. case "table": {
  3598. out += this.renderer.table(token);
  3599. continue;
  3600. }
  3601. case "blockquote": {
  3602. out += this.renderer.blockquote(token);
  3603. continue;
  3604. }
  3605. case "list": {
  3606. out += this.renderer.list(token);
  3607. continue;
  3608. }
  3609. case "html": {
  3610. out += this.renderer.html(token);
  3611. continue;
  3612. }
  3613. case "paragraph": {
  3614. out += this.renderer.paragraph(token);
  3615. continue;
  3616. }
  3617. case "text": {
  3618. let textToken = token;
  3619. let body = this.renderer.text(textToken);
  3620. while (i + 1 < tokens.length && tokens[i + 1].type === "text") {
  3621. textToken = tokens[++i];
  3622. body += "\n" + this.renderer.text(textToken);
  3623. }
  3624. if (top) {
  3625. out += this.renderer.paragraph({
  3626. type: "paragraph",
  3627. raw: body,
  3628. text: body,
  3629. tokens: [{
  3630. type: "text",
  3631. raw: body,
  3632. text: body
  3633. }]
  3634. });
  3635. } else {
  3636. out += body;
  3637. }
  3638. continue;
  3639. }
  3640. default: {
  3641. const errMsg = 'Token with "' + token.type + '" type was not found.';
  3642. if (this.options.silent) {
  3643. console.error(errMsg);
  3644. return "";
  3645. } else {
  3646. throw new Error(errMsg);
  3647. }
  3648. }
  3649. }
  3650. }
  3651. return out;
  3652. }
  3653. /**
  3654. * Parse Inline Tokens
  3655. */
  3656. parseInline(tokens, renderer) {
  3657. renderer = renderer || this.renderer;
  3658. let out = "";
  3659. for (let i = 0; i < tokens.length; i++) {
  3660. const anyToken = tokens[i];
  3661. if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[anyToken.type]) {
  3662. const ret = this.options.extensions.renderers[anyToken.type].call({
  3663. parser: this
  3664. }, anyToken);
  3665. if (ret !== false || !["escape", "html", "link", "image", "strong", "em", "codespan", "br", "del", "text"].includes(anyToken.type)) {
  3666. out += ret || "";
  3667. continue;
  3668. }
  3669. }
  3670. const token = anyToken;
  3671. switch (token.type) {
  3672. case "escape": {
  3673. out += renderer.text(token);
  3674. break;
  3675. }
  3676. case "html": {
  3677. out += renderer.html(token);
  3678. break;
  3679. }
  3680. case "link": {
  3681. out += renderer.link(token);
  3682. break;
  3683. }
  3684. case "image": {
  3685. out += renderer.image(token);
  3686. break;
  3687. }
  3688. case "strong": {
  3689. out += renderer.strong(token);
  3690. break;
  3691. }
  3692. case "em": {
  3693. out += renderer.em(token);
  3694. break;
  3695. }
  3696. case "codespan": {
  3697. out += renderer.codespan(token);
  3698. break;
  3699. }
  3700. case "br": {
  3701. out += renderer.br(token);
  3702. break;
  3703. }
  3704. case "del": {
  3705. out += renderer.del(token);
  3706. break;
  3707. }
  3708. case "text": {
  3709. out += renderer.text(token);
  3710. break;
  3711. }
  3712. default: {
  3713. const errMsg = 'Token with "' + token.type + '" type was not found.';
  3714. if (this.options.silent) {
  3715. console.error(errMsg);
  3716. return "";
  3717. } else {
  3718. throw new Error(errMsg);
  3719. }
  3720. }
  3721. }
  3722. }
  3723. return out;
  3724. }
  3725. }
  3726. class _Hooks {
  3727. constructor(options) {
  3728. __publicField(this, "options");
  3729. __publicField(this, "block");
  3730. this.options = options || _defaults;
  3731. }
  3732. /**
  3733. * Process markdown before marked
  3734. */
  3735. preprocess(markdown) {
  3736. return markdown;
  3737. }
  3738. /**
  3739. * Process HTML after marked is finished
  3740. */
  3741. postprocess(html2) {
  3742. return html2;
  3743. }
  3744. /**
  3745. * Process all tokens before walk tokens
  3746. */
  3747. processAllTokens(tokens) {
  3748. return tokens;
  3749. }
  3750. /**
  3751. * Provide function to tokenize markdown
  3752. */
  3753. provideLexer() {
  3754. return this.block ? _Lexer.lex : _Lexer.lexInline;
  3755. }
  3756. /**
  3757. * Provide function to parse tokens
  3758. */
  3759. provideParser() {
  3760. return this.block ? _Parser.parse : _Parser.parseInline;
  3761. }
  3762. }
  3763. __publicField(_Hooks, "passThroughHooks", /* @__PURE__ */ new Set([
  3764. "preprocess",
  3765. "postprocess",
  3766. "processAllTokens"
  3767. ]));
  3768. class Marked {
  3769. constructor(...args) {
  3770. __publicField(this, "defaults", _getDefaults());
  3771. __publicField(this, "options", this.setOptions);
  3772. __publicField(this, "parse", this.parseMarkdown(true));
  3773. __publicField(this, "parseInline", this.parseMarkdown(false));
  3774. __publicField(this, "Parser", _Parser);
  3775. __publicField(this, "Renderer", _Renderer);
  3776. __publicField(this, "TextRenderer", _TextRenderer);
  3777. __publicField(this, "Lexer", _Lexer);
  3778. __publicField(this, "Tokenizer", _Tokenizer);
  3779. __publicField(this, "Hooks", _Hooks);
  3780. this.use(...args);
  3781. }
  3782. /**
  3783. * Run callback for every token
  3784. */
  3785. walkTokens(tokens, callback) {
  3786. var _a, _b;
  3787. let values = [];
  3788. for (const token of tokens) {
  3789. values = values.concat(callback.call(this, token));
  3790. switch (token.type) {
  3791. case "table": {
  3792. const tableToken = token;
  3793. for (const cell of tableToken.header) {
  3794. values = values.concat(this.walkTokens(cell.tokens, callback));
  3795. }
  3796. for (const row of tableToken.rows) {
  3797. for (const cell of row) {
  3798. values = values.concat(this.walkTokens(cell.tokens, callback));
  3799. }
  3800. }
  3801. break;
  3802. }
  3803. case "list": {
  3804. const listToken = token;
  3805. values = values.concat(this.walkTokens(listToken.items, callback));
  3806. break;
  3807. }
  3808. default: {
  3809. const genericToken = token;
  3810. if ((_b = (_a = this.defaults.extensions) == null ? void 0 : _a.childTokens) == null ? void 0 : _b[genericToken.type]) {
  3811. this.defaults.extensions.childTokens[genericToken.type].forEach((childTokens) => {
  3812. const tokens2 = genericToken[childTokens].flat(Infinity);
  3813. values = values.concat(this.walkTokens(tokens2, callback));
  3814. });
  3815. } else if (genericToken.tokens) {
  3816. values = values.concat(this.walkTokens(genericToken.tokens, callback));
  3817. }
  3818. }
  3819. }
  3820. }
  3821. return values;
  3822. }
  3823. use(...args) {
  3824. const extensions = this.defaults.extensions || {
  3825. renderers: {},
  3826. childTokens: {}
  3827. };
  3828. args.forEach((pack) => {
  3829. const opts = {
  3830. ...pack
  3831. };
  3832. opts.async = this.defaults.async || opts.async || false;
  3833. if (pack.extensions) {
  3834. pack.extensions.forEach((ext) => {
  3835. if (!ext.name) {
  3836. throw new Error("extension name required");
  3837. }
  3838. if ("renderer" in ext) {
  3839. const prevRenderer = extensions.renderers[ext.name];
  3840. if (prevRenderer) {
  3841. extensions.renderers[ext.name] = function (...args2) {
  3842. let ret = ext.renderer.apply(this, args2);
  3843. if (ret === false) {
  3844. ret = prevRenderer.apply(this, args2);
  3845. }
  3846. return ret;
  3847. };
  3848. } else {
  3849. extensions.renderers[ext.name] = ext.renderer;
  3850. }
  3851. }
  3852. if ("tokenizer" in ext) {
  3853. if (!ext.level || ext.level !== "block" && ext.level !== "inline") {
  3854. throw new Error("extension level must be 'block' or 'inline'");
  3855. }
  3856. const extLevel = extensions[ext.level];
  3857. if (extLevel) {
  3858. extLevel.unshift(ext.tokenizer);
  3859. } else {
  3860. extensions[ext.level] = [ext.tokenizer];
  3861. }
  3862. if (ext.start) {
  3863. if (ext.level === "block") {
  3864. if (extensions.startBlock) {
  3865. extensions.startBlock.push(ext.start);
  3866. } else {
  3867. extensions.startBlock = [ext.start];
  3868. }
  3869. } else if (ext.level === "inline") {
  3870. if (extensions.startInline) {
  3871. extensions.startInline.push(ext.start);
  3872. } else {
  3873. extensions.startInline = [ext.start];
  3874. }
  3875. }
  3876. }
  3877. }
  3878. if ("childTokens" in ext && ext.childTokens) {
  3879. extensions.childTokens[ext.name] = ext.childTokens;
  3880. }
  3881. });
  3882. opts.extensions = extensions;
  3883. }
  3884. if (pack.renderer) {
  3885. const renderer = this.defaults.renderer || new _Renderer(this.defaults);
  3886. for (const prop in pack.renderer) {
  3887. if (!(prop in renderer)) {
  3888. throw new Error(`renderer '${prop}' does not exist`);
  3889. }
  3890. if (["options", "parser"].includes(prop)) {
  3891. continue;
  3892. }
  3893. const rendererProp = prop;
  3894. const rendererFunc = pack.renderer[rendererProp];
  3895. const prevRenderer = renderer[rendererProp];
  3896. renderer[rendererProp] = (...args2) => {
  3897. let ret = rendererFunc.apply(renderer, args2);
  3898. if (ret === false) {
  3899. ret = prevRenderer.apply(renderer, args2);
  3900. }
  3901. return ret || "";
  3902. };
  3903. }
  3904. opts.renderer = renderer;
  3905. }
  3906. if (pack.tokenizer) {
  3907. const tokenizer = this.defaults.tokenizer || new _Tokenizer(this.defaults);
  3908. for (const prop in pack.tokenizer) {
  3909. if (!(prop in tokenizer)) {
  3910. throw new Error(`tokenizer '${prop}' does not exist`);
  3911. }
  3912. if (["options", "rules", "lexer"].includes(prop)) {
  3913. continue;
  3914. }
  3915. const tokenizerProp = prop;
  3916. const tokenizerFunc = pack.tokenizer[tokenizerProp];
  3917. const prevTokenizer = tokenizer[tokenizerProp];
  3918. tokenizer[tokenizerProp] = (...args2) => {
  3919. let ret = tokenizerFunc.apply(tokenizer, args2);
  3920. if (ret === false) {
  3921. ret = prevTokenizer.apply(tokenizer, args2);
  3922. }
  3923. return ret;
  3924. };
  3925. }
  3926. opts.tokenizer = tokenizer;
  3927. }
  3928. if (pack.hooks) {
  3929. const hooks = this.defaults.hooks || new _Hooks();
  3930. for (const prop in pack.hooks) {
  3931. if (!(prop in hooks)) {
  3932. throw new Error(`hook '${prop}' does not exist`);
  3933. }
  3934. if (["options", "block"].includes(prop)) {
  3935. continue;
  3936. }
  3937. const hooksProp = prop;
  3938. const hooksFunc = pack.hooks[hooksProp];
  3939. const prevHook = hooks[hooksProp];
  3940. if (_Hooks.passThroughHooks.has(prop)) {
  3941. hooks[hooksProp] = (arg) => {
  3942. if (this.defaults.async) {
  3943. return Promise.resolve(hooksFunc.call(hooks, arg)).then((ret2) => {
  3944. return prevHook.call(hooks, ret2);
  3945. });
  3946. }
  3947. const ret = hooksFunc.call(hooks, arg);
  3948. return prevHook.call(hooks, ret);
  3949. };
  3950. } else {
  3951. hooks[hooksProp] = (...args2) => {
  3952. let ret = hooksFunc.apply(hooks, args2);
  3953. if (ret === false) {
  3954. ret = prevHook.apply(hooks, args2);
  3955. }
  3956. return ret;
  3957. };
  3958. }
  3959. }
  3960. opts.hooks = hooks;
  3961. }
  3962. if (pack.walkTokens) {
  3963. const walkTokens = this.defaults.walkTokens;
  3964. const packWalktokens = pack.walkTokens;
  3965. opts.walkTokens = function (token) {
  3966. let values = [];
  3967. values.push(packWalktokens.call(this, token));
  3968. if (walkTokens) {
  3969. values = values.concat(walkTokens.call(this, token));
  3970. }
  3971. return values;
  3972. };
  3973. }
  3974. this.defaults = {
  3975. ...this.defaults,
  3976. ...opts
  3977. };
  3978. });
  3979. return this;
  3980. }
  3981. setOptions(opt) {
  3982. this.defaults = {
  3983. ...this.defaults,
  3984. ...opt
  3985. };
  3986. return this;
  3987. }
  3988. lexer(src, options) {
  3989. return _Lexer.lex(src, options ? options : this.defaults);
  3990. }
  3991. parser(tokens, options) {
  3992. return _Parser.parse(tokens, options ? options : this.defaults);
  3993. }
  3994. parseMarkdown(blockType) {
  3995. const parse = (src, options) => {
  3996. const origOpt = {
  3997. ...options
  3998. };
  3999. const opt = {
  4000. ...this.defaults,
  4001. ...origOpt
  4002. };
  4003. const throwError = this.onError(!!opt.silent, !!opt.async);
  4004. if (this.defaults.async === true && origOpt.async === false) {
  4005. 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."));
  4006. }
  4007. if (typeof src === "undefined" || src === null) {
  4008. return throwError(new Error("marked(): input parameter is undefined or null"));
  4009. }
  4010. if (typeof src !== "string") {
  4011. return throwError(new Error("marked(): input parameter is of type " + Object.prototype.toString.call(src) + ", string expected"));
  4012. }
  4013. if (opt.hooks) {
  4014. opt.hooks.options = opt;
  4015. opt.hooks.block = blockType;
  4016. }
  4017. const lexer = opt.hooks ? opt.hooks.provideLexer() : blockType ? _Lexer.lex : _Lexer.lexInline;
  4018. const parser = opt.hooks ? opt.hooks.provideParser() : blockType ? _Parser.parse : _Parser.parseInline;
  4019. if (opt.async) {
  4020. 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);
  4021. }
  4022. try {
  4023. if (opt.hooks) {
  4024. src = opt.hooks.preprocess(src);
  4025. }
  4026. let tokens = lexer(src, opt);
  4027. if (opt.hooks) {
  4028. tokens = opt.hooks.processAllTokens(tokens);
  4029. }
  4030. if (opt.walkTokens) {
  4031. this.walkTokens(tokens, opt.walkTokens);
  4032. }
  4033. let html2 = parser(tokens, opt);
  4034. if (opt.hooks) {
  4035. html2 = opt.hooks.postprocess(html2);
  4036. }
  4037. return html2;
  4038. } catch (e) {
  4039. return throwError(e);
  4040. }
  4041. };
  4042. return parse;
  4043. }
  4044. onError(silent, async) {
  4045. return (e) => {
  4046. e.message += "\nPlease report this to https://github.com/markedjs/marked.";
  4047. if (silent) {
  4048. const msg = "<p>An error occurred:</p><pre>" + escape$1(e.message + "", true) + "</pre>";
  4049. if (async) {
  4050. return Promise.resolve(msg);
  4051. }
  4052. return msg;
  4053. }
  4054. if (async) {
  4055. return Promise.reject(e);
  4056. }
  4057. throw e;
  4058. };
  4059. }
  4060. }
  4061. const markedInstance = new Marked();
  4062.  
  4063. function marked(src, opt) {
  4064. return markedInstance.parse(src, opt);
  4065. }
  4066. marked.options = marked.setOptions = function (options) {
  4067. markedInstance.setOptions(options);
  4068. marked.defaults = markedInstance.defaults;
  4069. changeDefaults(marked.defaults);
  4070. return marked;
  4071. };
  4072. marked.getDefaults = _getDefaults;
  4073. marked.defaults = _defaults;
  4074. marked.use = function (...args) {
  4075. markedInstance.use(...args);
  4076. marked.defaults = markedInstance.defaults;
  4077. changeDefaults(marked.defaults);
  4078. return marked;
  4079. };
  4080. marked.walkTokens = function (tokens, callback) {
  4081. return markedInstance.walkTokens(tokens, callback);
  4082. };
  4083. marked.parseInline = markedInstance.parseInline;
  4084. marked.Parser = _Parser;
  4085. marked.parser = _Parser.parse;
  4086. marked.Renderer = _Renderer;
  4087. marked.TextRenderer = _TextRenderer;
  4088. marked.Lexer = _Lexer;
  4089. marked.lexer = _Lexer.lex;
  4090. marked.Tokenizer = _Tokenizer;
  4091. marked.Hooks = _Hooks;
  4092. marked.parse = marked;
  4093. marked.options;
  4094. marked.setOptions;
  4095. marked.use;
  4096. marked.walkTokens;
  4097. marked.parseInline;
  4098. _Parser.parse;
  4099. _Lexer.lex;
  4100.  
  4101. function md2html(md) {
  4102. return marked(md);
  4103. }
  4104. const _export_sfc = (sfc, props) => {
  4105. const target = sfc.__vccOpts || sfc;
  4106. for (const [key, val] of props) {
  4107. target[key] = val;
  4108. }
  4109. return target;
  4110. };
  4111. const _withScopeId = (n) => (vue.pushScopeId("data-v-479cc38e"), n = n(), vue.popScopeId(), n);
  4112. const _hoisted_1 = {
  4113. class: "monkeygpt-header"
  4114. };
  4115. const _hoisted_2 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("a", {
  4116. href: "https://github.com/weekend-project-space/monkey-gpt"
  4117. }, [
  4118. /* @__PURE__ */
  4119. vue.createElementVNode("img", {
  4120. src: "https://img.shields.io/github/stars/weekend-project-space/monkey-gpt.svg?style=social&label=Stars",
  4121. alt: ""
  4122. })
  4123. ], -1));
  4124. const _hoisted_3 = {
  4125. key: 0,
  4126. class: "loader"
  4127. };
  4128. const _hoisted_4 = ["innerHTML"];
  4129. const _sfc_main$1 = {
  4130. __name: "MonkeyGPT",
  4131. props: {
  4132. msg: String
  4133. },
  4134. setup(__props) {
  4135. const txt = vue.ref("");
  4136. const loading = vue.ref(false);
  4137.  
  4138. function getText() {
  4139. loading.value = true;
  4140. txt.value = md2html(getSimpleText());
  4141. loading.value = false;
  4142. }
  4143. async function chat2(chatfun) {
  4144. loading.value = true;
  4145. try {
  4146. txt.value = md2html(await chatfun(getSimpleText()));
  4147. } catch {
  4148. txt.value = "生成失败,请检查配置是否正确并刷新重试!";
  4149. }
  4150. loading.value = false;
  4151. }
  4152.  
  4153. function clear() {
  4154. txt.value = "";
  4155. }
  4156. setTimeout(() => {
  4157. console.log(GM_setValue, GM_getValue);
  4158. }, 3e3);
  4159. window.addEventListener("popstate", clear);
  4160. return (_ctx, _cache) => {
  4161. return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
  4162. vue.createElementVNode("div", _hoisted_1, [
  4163. vue.createElementVNode("h3", null, [
  4164. vue.createTextVNode(vue.toDisplayString(__props.msg) + " ", 1),
  4165. _hoisted_2
  4166. ]),
  4167. vue.createElementVNode("div", null, [
  4168. vue.createElementVNode("button", {
  4169. onClick: getText
  4170. }, "正文"),
  4171. vue.createElementVNode("button", {
  4172. onClick: _cache[0] || (_cache[0] = ($event) => chat2(vue.unref(summarize)))
  4173. }, "总结"),
  4174. vue.createElementVNode("button", {
  4175. onClick: _cache[1] || (_cache[1] = ($event) => chat2(vue.unref(ask)))
  4176. }, "回复"),
  4177. vue.createElementVNode("button", {
  4178. onClick: clear
  4179. }, "清空")
  4180. ])
  4181. ]),
  4182. vue.createElementVNode("div", null, [
  4183. loading.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_3)) : txt.value ? (vue.openBlock(), vue.createElementBlock("div", {
  4184. key: 1,
  4185. class: "card",
  4186. innerHTML: txt.value
  4187. }, null, 8, _hoisted_4)) : vue.createCommentVNode("", true)
  4188. ])
  4189. ], 64);
  4190. };
  4191. }
  4192. };
  4193. const MonkeyGPT = /* @__PURE__ */ _export_sfc(_sfc_main$1, [
  4194. ["__scopeId", "data-v-479cc38e"]
  4195. ]);
  4196. const _sfc_main = {
  4197. __name: "App",
  4198. setup(__props) {
  4199. return (_ctx, _cache) => {
  4200. return vue.openBlock(), vue.createBlock(MonkeyGPT, {
  4201. msg: "monkey gpt"
  4202. });
  4203. };
  4204. }
  4205. };
  4206. vue.createApp(_sfc_main).mount(
  4207. (() => {
  4208. const app = document.createElement("div");
  4209. app.id = "monkeygpt";
  4210. const firstChild = document.body.firstChild;
  4211. document.body.insertBefore(app, firstChild);
  4212. return app;
  4213. })()
  4214. );
  4215.  
  4216. })(Vue);