ibc-ai-web-sdk 2.0.4 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js CHANGED
@@ -2,7 +2,6 @@
2
2
  * 错误码常量
3
3
  * 统一定义所有错误码,方便维护
4
4
  */
5
-
6
5
  const ERROR_CODES = {
7
6
  // 客户端错误 (40000-49999)
8
7
  AGENT_NOT_FOUND: 40001,
@@ -11,7 +10,6 @@ const ERROR_CODES = {
11
10
  // 提示词不能为空
12
11
  AUTH_FAILED: 40301,
13
12
  // 鉴权失败
14
-
15
13
  // 服务器错误 (50000-59999)
16
14
  NETWORK_ERROR: 500,
17
15
  // 网络请求失败
@@ -19,7 +17,6 @@ const ERROR_CODES = {
19
17
  // 服务器内部错误
20
18
  TIMEOUT_ERROR: 50002,
21
19
  // 请求超时
22
-
23
20
  // 取消
24
21
  REQUEST_CANCELLED: 0 // 请求已取消
25
22
  };
@@ -380,8 +377,25 @@ class AIChatClient {
380
377
  if (conversationId) payload.conversationId = conversationId;
381
378
  const attachmentIds = options.attachmentIds || this.normalizeAttachmentIds(options.attachments);
382
379
  if (attachmentIds.length > 0) payload.attachmentIds = attachmentIds;
383
- const bizParams = options.bizParams || options.extendInfo || this.config.extendInfo;
384
- if (bizParams) payload.bizParams = typeof bizParams === 'string' ? bizParams : JSON.stringify(bizParams);
380
+ let bizParams = options.bizParams || options.extendInfo || this.config.extendInfo;
381
+ if (bizParams) {
382
+ if (typeof bizParams === 'string') {
383
+ try {
384
+ bizParams = JSON.parse(bizParams);
385
+ } catch (e) {
386
+ bizParams = {};
387
+ }
388
+ }
389
+ } else {
390
+ bizParams = {};
391
+ }
392
+ // P3: 将页面上下文合并到 bizParams(contextMode='bizParams' 时由 dialog 传入)
393
+ if (options.context) {
394
+ Object.assign(bizParams, options.context);
395
+ }
396
+ if (Object.keys(bizParams).length > 0) {
397
+ payload.bizParams = JSON.stringify(bizParams);
398
+ }
385
399
  return payload;
386
400
  }
387
401
  normalizeAttachmentIds(attachments) {
@@ -603,14 +617,14 @@ class AIChatClient {
603
617
  const message = parsed && (parsed.message || parsed.errorMessage) || data || '流式请求失败';
604
618
  const code = parsed && (parsed.code || parsed.errCode || parsed.status);
605
619
  if (code && this.isAuthErrorCode(code)) {
606
- const error = new Error(message);
607
- error.authError = true;
608
- error.code = code;
609
- throw error;
620
+ const authErr = new Error(message);
621
+ authErr.authError = true;
622
+ authErr.code = code;
623
+ throw authErr;
610
624
  }
611
- const error = new Error(message);
612
- error.sseData = parsed || data;
613
- throw error;
625
+ const sseErr = new Error(message);
626
+ sseErr.sseData = parsed || data;
627
+ throw sseErr;
614
628
  }
615
629
  if ((META_EVENTS.has(event) || MESSAGE_EVENTS.has(event)) && data.startsWith('[META]')) {
616
630
  const meta = tryParseJson(data.slice('[META]'.length));
@@ -855,7 +869,7 @@ class AIChatClient {
855
869
  }
856
870
 
857
871
  /**
858
- * marked v18.0.5 - a markdown parser
872
+ * marked v18.0.2 - a markdown parser
859
873
  * Copyright (c) 2018-2026, MarkedJS. (MIT License)
860
874
  * Copyright (c) 2011-2018, Christopher Jeffrey. (MIT License)
861
875
  * https://github.com/markedjs/marked
@@ -866,12 +880,12 @@ class AIChatClient {
866
880
  * The code in this file is generated from files in ./src/
867
881
  */
868
882
 
869
- function M(){return {async:false,breaks:false,extensions:null,gfm:true,hooks:null,pedantic:false,renderer:null,silent:false,tokenizer:null,walkTokens:null}}var T=M();function N(l){T=l;}var _={exec:()=>null};function E(l){let e=[];return t=>{let n=Math.max(0,Math.min(3,t-1)),s=e[n];return s||(s=l(n),e[n]=s),s}}function d(l,e=""){let t=typeof l=="string"?l:l.source,n={replace:(s,r)=>{let i=typeof r=="string"?r:r.source;return i=i.replace(m.caret,"$1"),t=t.replace(s,i),n},getRegex:()=>new RegExp(t,e)};return n}var Te=((l="")=>{try{return !!new RegExp("(?<=1)(?<!1)"+l)}catch{return false}})(),m={codeRemoveIndent:/^(?: {1,4}| {0,3}\t)/gm,outputLinkReplace:/\\([\[\]])/g,indentCodeCompensation:/^(\s+)(?:```)/,beginningSpace:/^\s+/,endingHash:/#$/,startingSpaceChar:/^ /,endingSpaceChar:/ $/,nonSpaceChar:/[^ ]/,newLineCharGlobal:/\n/g,tabCharGlobal:/\t/g,multipleSpaceGlobal:/\s+/g,blankLine:/^[ \t]*$/,doubleBlankLine:/\n[ \t]*\n[ \t]*$/,blockquoteStart:/^ {0,3}>/,blockquoteSetextReplace:/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,blockquoteSetextReplace2:/^ {0,3}>[ \t]?/gm,listReplaceNesting:/^ {1,4}(?=( {4})*[^ ])/g,listIsTask:/^\[[ xX]\] +\S/,listReplaceTask:/^\[[ xX]\] +/,listTaskCheckbox:/\[[ xX]\]/,anyLine:/\n.*\n/,hrefBrackets:/^<(.*)>$/,tableDelimiter:/[:|]/,tableAlignChars:/^\||\| *$/g,tableRowBlankLine:/\n[ \t]*$/,tableAlignRight:/^ *-+: *$/,tableAlignCenter:/^ *:-+: *$/,tableAlignLeft:/^ *:-+ *$/,startATag:/^<a /i,endATag:/^<\/a>/i,startPreScriptTag:/^<(pre|code|kbd|script)(\s|>)/i,endPreScriptTag:/^<\/(pre|code|kbd|script)(\s|>)/i,startAngleBracket:/^</,endAngleBracket:/>$/,pedanticHrefTitle:/^([^'"]*[^\s])\s+(['"])(.*)\2/,unicodeAlphaNumeric:/[\p{L}\p{N}]/u,escapeTest:/[&<>"']/,escapeReplace:/[&<>"']/g,escapeTestNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,escapeReplaceNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g,caret:/(^|[^\[])\^/g,percentDecode:/%25/g,findPipe:/\|/g,splitPipe:/ \|/,slashPipe:/\\\|/g,carriageReturn:/\r\n|\r/g,spaceLine:/^ +$/gm,notSpaceStart:/^\S*/,endingNewline:/\n$/,listItemRegex:l=>new RegExp(`^( {0,3}${l})((?:[ ][^\\n]*)?(?:\\n|$))`),nextBulletRegex:E(l=>new RegExp(`^ {0,${l}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`)),hrRegex:E(l=>new RegExp(`^ {0,${l}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`)),fencesBeginRegex:E(l=>new RegExp(`^ {0,${l}}(?:\`\`\`|~~~)`)),headingBeginRegex:E(l=>new RegExp(`^ {0,${l}}#`)),htmlBeginRegex:E(l=>new RegExp(`^ {0,${l}}<(?:[a-z].*>|!--)`,"i")),blockquoteBeginRegex:E(l=>new RegExp(`^ {0,${l}}>`))},Oe=/^(?:[ \t]*(?:\n|$))+/,we=/^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/,ye=/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,B=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,Pe=/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,j=/ {0,3}(?:[*+-]|\d{1,9}[.)])/,oe=/^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/,ae=d(oe).replace(/bull/g,j).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).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/).replace(/\|table/g,"").getRegex(),Se=d(oe).replace(/bull/g,j).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).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/).replace(/table/g,/ {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex(),F=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,$e=/^[^\n]+/,U=/(?!\s*\])(?:\\[\s\S]|[^\[\]\\])+/,Le=d(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label",U).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),_e=d(/^(bull)([ \t][^\n]*?)?(?:\n|$)/).replace(/bull/g,j).getRegex(),H="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",K=/<!--(?:-?>|[\s\S]*?(?:-->|$))/,ze=d("^ {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",K).replace("tag",H).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),le=d(F).replace("hr",B).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[.)])[ \\t]+[^ \\t\\n]").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",H).getRegex(),Me=d(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",le).getRegex(),W={blockquote:Me,code:we,def:Le,fences:ye,heading:Pe,hr:B,html:ze,lheading:ae,list:_e,newline:Oe,paragraph:le,table:_,text:$e},se=d("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",B).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code","(?: {4}| {0,3} )[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)])[ \\t]").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",H).getRegex(),Ee={...W,lheading:Se,table:se,paragraph:d(F).replace("hr",B).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",se).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)])[ \\t]+[^ \\t\\n]").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",H).getRegex()},Ie={...W,html:d(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:"[^"]*"|'[^']*'|\\s[^'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment",K).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:_,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:d(F).replace("hr",B).replace("heading",` *#{1,6} *[^
870
- ]`).replace("lheading",ae).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},Ae=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,Ce=/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,ue=/^( {2,}|\\)\n(?!\s*$)/,Be=/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,I=/[\p{P}\p{S}]/u,Z=/[\s\p{P}\p{S}]/u,X=/[^\s\p{P}\p{S}]/u,De=d(/^((?![*_])punctSpace)/,"u").replace(/punctSpace/g,Z).getRegex(),pe=/(?!~)[\p{P}\p{S}]/u,qe=/(?!~)[\s\p{P}\p{S}]/u,ve=/(?:[^\s\p{P}\p{S}]|~)/u,He=d(/link|precode-code|html/,"g").replace("link",/\[(?:[^\[\]`]|(?<a>`+)[^`]+\k<a>(?!`))*?\]\((?:\\[\s\S]|[^\\\(\)]|\((?:\\[\s\S]|[^\\\(\)])*\))*\)/).replace("precode-",Te?"(?<!`)()":"(^^|[^`])").replace("code",/(?<b>`+)[^`]+\k<b>(?!`)/).replace("html",/<(?! )[^<>]*?>/).getRegex(),ce=/^(?:\*+(?:((?!\*)punct)|([^\s*]))?)|^_+(?:((?!_)punct)|([^\s_]))?/,Ze=d(ce,"u").replace(/punct/g,I).getRegex(),Ge=d(ce,"u").replace(/punct/g,pe).getRegex(),he="^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)",Ne=d(he,"gu").replace(/notPunctSpace/g,X).replace(/punctSpace/g,Z).replace(/punct/g,I).getRegex(),Qe=d(he,"gu").replace(/notPunctSpace/g,ve).replace(/punctSpace/g,qe).replace(/punct/g,pe).getRegex(),je=d("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)","gu").replace(/notPunctSpace/g,X).replace(/punctSpace/g,Z).replace(/punct/g,I).getRegex(),Fe=d(/^~~?(?:((?!~)punct)|[^\s~])/,"u").replace(/punct/g,I).getRegex(),Ue="^[^~]+(?=[^~])|(?!~)punct(~~?)(?=[\\s]|$)|notPunctSpace(~~?)(?!~)(?=punctSpace|$)|(?!~)punctSpace(~~?)(?=notPunctSpace)|[\\s](~~?)(?!~)(?=punct)|(?!~)punct(~~?)(?!~)(?=punct)|notPunctSpace(~~?)(?=notPunctSpace)",Ke=d(Ue,"gu").replace(/notPunctSpace/g,X).replace(/punctSpace/g,Z).replace(/punct/g,I).getRegex(),We=d(/\\(punct)/,"gu").replace(/punct/g,I).getRegex(),Xe=d(/^<(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(),Je=d(K).replace("(?:-->|$)","-->").getRegex(),Ve=d("^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",Je).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),v=/(?:\[(?:\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\])|[^\[\]\\`])*?/,Ye=d(/^!?\[(label)\]\(\s*(href)(?:(?:[ \t]+(?:\n[ \t]*)?|\n[ \t]*)(title))?\s*\)/).replace("label",v).replace("href",/<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]*/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),ke=d(/^!?\[(label)\]\[(ref)\]/).replace("label",v).replace("ref",U).getRegex(),de=d(/^!?\[(ref)\](?:\[\])?/).replace("ref",U).getRegex(),et=d("reflink|nolink(?!\\()","g").replace("reflink",ke).replace("nolink",de).getRegex(),ie=/[hH][tT][tT][pP][sS]?|[fF][tT][pP]/,J={_backpedal:_,anyPunctuation:We,autolink:Xe,blockSkip:He,br:ue,code:Ce,del:_,delLDelim:_,delRDelim:_,emStrongLDelim:Ze,emStrongRDelimAst:Ne,emStrongRDelimUnd:je,escape:Ae,link:Ye,nolink:de,punctuation:De,reflink:ke,reflinkSearch:et,tag:Ve,text:Be,url:_},tt={...J,link:d(/^!?\[(label)\]\((.*?)\)/).replace("label",v).getRegex(),reflink:d(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",v).getRegex()},Q={...J,emStrongRDelimAst:Qe,emStrongLDelim:Ge,delLDelim:Fe,delRDelim:Ke,url:d(/^((?:protocol):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace("protocol",ie).replace("email",/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(),_backpedal:/(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])((?:\\[\s\S]|[^\\])*?(?:\\[\s\S]|[^\s~\\]))\1(?=[^~]|$)/,text:d(/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|protocol:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/).replace("protocol",ie).getRegex()},nt={...Q,br:d(ue).replace("{2,}","*").getRegex(),text:d(Q.text).replace("\\b_","\\b_| {2,}\\n").replace(/\{2,\}/g,"*").getRegex()},D={normal:W,gfm:Ee,pedantic:Ie},A={normal:J,gfm:Q,breaks:nt,pedantic:tt};var rt={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},ge=l=>rt[l];function O(l,e){if(e){if(m.escapeTest.test(l))return l.replace(m.escapeReplace,ge)}else if(m.escapeTestNoEncode.test(l))return l.replace(m.escapeReplaceNoEncode,ge);return l}function V(l){try{l=encodeURI(l).replace(m.percentDecode,"%");}catch{return null}return l}function Y(l,e){let t=l.replace(m.findPipe,(r,i,o)=>{let u=false,a=i;for(;--a>=0&&o[a]==="\\";)u=!u;return u?"|":" |"}),n=t.split(m.splitPipe),s=0;if(n[0].trim()||n.shift(),n.length>0&&!n.at(-1)?.trim()&&n.pop(),e)if(n.length>e)n.splice(e);else for(;n.length<e;)n.push("");for(;s<n.length;s++)n[s]=n[s].trim().replace(m.slashPipe,"|");return n}function $(l,e,t){let n=l.length;if(n===0)return "";let s=0;for(;s<n;){let r=l.charAt(n-s-1);if(r===e&&true)s++;else break}return l.slice(0,n-s)}function ee(l){let e=l.split(`
883
+ function z(){return {async:false,breaks:false,extensions:null,gfm:true,hooks:null,pedantic:false,renderer:null,silent:false,tokenizer:null,walkTokens:null}}var T=z();function G(l){T=l;}var _={exec:()=>null};function k(l,e=""){let t=typeof l=="string"?l:l.source,n={replace:(s,r)=>{let i=typeof r=="string"?r:r.source;return i=i.replace(m.caret,"$1"),t=t.replace(s,i),n},getRegex:()=>new RegExp(t,e)};return n}var Re=((l="")=>{try{return !!new RegExp("(?<=1)(?<!1)"+l)}catch{return false}})(),m={codeRemoveIndent:/^(?: {1,4}| {0,3}\t)/gm,outputLinkReplace:/\\([\[\]])/g,indentCodeCompensation:/^(\s+)(?:```)/,beginningSpace:/^\s+/,endingHash:/#$/,startingSpaceChar:/^ /,endingSpaceChar:/ $/,nonSpaceChar:/[^ ]/,newLineCharGlobal:/\n/g,tabCharGlobal:/\t/g,multipleSpaceGlobal:/\s+/g,blankLine:/^[ \t]*$/,doubleBlankLine:/\n[ \t]*\n[ \t]*$/,blockquoteStart:/^ {0,3}>/,blockquoteSetextReplace:/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,blockquoteSetextReplace2:/^ {0,3}>[ \t]?/gm,listReplaceNesting:/^ {1,4}(?=( {4})*[^ ])/g,listIsTask:/^\[[ xX]\] +\S/,listReplaceTask:/^\[[ xX]\] +/,listTaskCheckbox:/\[[ xX]\]/,anyLine:/\n.*\n/,hrefBrackets:/^<(.*)>$/,tableDelimiter:/[:|]/,tableAlignChars:/^\||\| *$/g,tableRowBlankLine:/\n[ \t]*$/,tableAlignRight:/^ *-+: *$/,tableAlignCenter:/^ *:-+: *$/,tableAlignLeft:/^ *:-+ *$/,startATag:/^<a /i,endATag:/^<\/a>/i,startPreScriptTag:/^<(pre|code|kbd|script)(\s|>)/i,endPreScriptTag:/^<\/(pre|code|kbd|script)(\s|>)/i,startAngleBracket:/^</,endAngleBracket:/>$/,pedanticHrefTitle:/^([^'"]*[^\s])\s+(['"])(.*)\2/,unicodeAlphaNumeric:/[\p{L}\p{N}]/u,escapeTest:/[&<>"']/,escapeReplace:/[&<>"']/g,escapeTestNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,escapeReplaceNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g,caret:/(^|[^\[])\^/g,percentDecode:/%25/g,findPipe:/\|/g,splitPipe:/ \|/,slashPipe:/\\\|/g,carriageReturn:/\r\n|\r/g,spaceLine:/^ +$/gm,notSpaceStart:/^\S*/,endingNewline:/\n$/,listItemRegex:l=>new RegExp(`^( {0,3}${l})((?:[ ][^\\n]*)?(?:\\n|$))`),nextBulletRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`),hrRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),fencesBeginRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}(?:\`\`\`|~~~)`),headingBeginRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}#`),htmlBeginRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}<(?:[a-z].*>|!--)`,"i"),blockquoteBeginRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}>`)},Te=/^(?:[ \t]*(?:\n|$))+/,Oe=/^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/,we=/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,I=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,ye=/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,Q=/ {0,3}(?:[*+-]|\d{1,9}[.)])/,ie=/^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/,oe=k(ie).replace(/bull/g,Q).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).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/).replace(/\|table/g,"").getRegex(),Pe=k(ie).replace(/bull/g,Q).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).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/).replace(/table/g,/ {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex(),j=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,Se=/^[^\n]+/,F=/(?!\s*\])(?:\\[\s\S]|[^\[\]\\])+/,$e=k(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label",F).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),Le=k(/^(bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g,Q).getRegex(),v="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",U=/<!--(?:-?>|[\s\S]*?(?:-->|$))/,_e=k("^ {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",U).replace("tag",v).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),ae=k(j).replace("hr",I).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[.)])[ \\t]").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",v).getRegex(),Me=k(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",ae).getRegex(),K={blockquote:Me,code:Oe,def:$e,fences:we,heading:ye,hr:I,html:_e,lheading:oe,list:Le,newline:Te,paragraph:ae,table:_,text:Se},re=k("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",I).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code","(?: {4}| {0,3} )[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)])[ \\t]").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",v).getRegex(),ze={...K,lheading:Pe,table:re,paragraph:k(j).replace("hr",I).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",re).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)])[ \\t]").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",v).getRegex()},Ee={...K,html:k(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:"[^"]*"|'[^']*'|\\s[^'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment",U).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:_,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:k(j).replace("hr",I).replace("heading",` *#{1,6} *[^
884
+ ]`).replace("lheading",oe).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},Ae=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,Ce=/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,le=/^( {2,}|\\)\n(?!\s*$)/,Ie=/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,E=/[\p{P}\p{S}]/u,H=/[\s\p{P}\p{S}]/u,W=/[^\s\p{P}\p{S}]/u,Be=k(/^((?![*_])punctSpace)/,"u").replace(/punctSpace/g,H).getRegex(),ue=/(?!~)[\p{P}\p{S}]/u,De=/(?!~)[\s\p{P}\p{S}]/u,qe=/(?:[^\s\p{P}\p{S}]|~)/u,ve=k(/link|precode-code|html/,"g").replace("link",/\[(?:[^\[\]`]|(?<a>`+)[^`]+\k<a>(?!`))*?\]\((?:\\[\s\S]|[^\\\(\)]|\((?:\\[\s\S]|[^\\\(\)])*\))*\)/).replace("precode-",Re?"(?<!`)()":"(^^|[^`])").replace("code",/(?<b>`+)[^`]+\k<b>(?!`)/).replace("html",/<(?! )[^<>]*?>/).getRegex(),pe=/^(?:\*+(?:((?!\*)punct)|([^\s*]))?)|^_+(?:((?!_)punct)|([^\s_]))?/,He=k(pe,"u").replace(/punct/g,E).getRegex(),Ze=k(pe,"u").replace(/punct/g,ue).getRegex(),ce="^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)",Ge=k(ce,"gu").replace(/notPunctSpace/g,W).replace(/punctSpace/g,H).replace(/punct/g,E).getRegex(),Ne=k(ce,"gu").replace(/notPunctSpace/g,qe).replace(/punctSpace/g,De).replace(/punct/g,ue).getRegex(),Qe=k("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)","gu").replace(/notPunctSpace/g,W).replace(/punctSpace/g,H).replace(/punct/g,E).getRegex(),je=k(/^~~?(?:((?!~)punct)|[^\s~])/,"u").replace(/punct/g,E).getRegex(),Fe="^[^~]+(?=[^~])|(?!~)punct(~~?)(?=[\\s]|$)|notPunctSpace(~~?)(?!~)(?=punctSpace|$)|(?!~)punctSpace(~~?)(?=notPunctSpace)|[\\s](~~?)(?!~)(?=punct)|(?!~)punct(~~?)(?!~)(?=punct)|notPunctSpace(~~?)(?=notPunctSpace)",Ue=k(Fe,"gu").replace(/notPunctSpace/g,W).replace(/punctSpace/g,H).replace(/punct/g,E).getRegex(),Ke=k(/\\(punct)/,"gu").replace(/punct/g,E).getRegex(),We=k(/^<(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(),Xe=k(U).replace("(?:-->|$)","-->").getRegex(),Je=k("^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",Xe).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),q=/(?:\[(?:\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\])|[^\[\]\\`])*?/,Ve=k(/^!?\[(label)\]\(\s*(href)(?:(?:[ \t]+(?:\n[ \t]*)?|\n[ \t]*)(title))?\s*\)/).replace("label",q).replace("href",/<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]*/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),he=k(/^!?\[(label)\]\[(ref)\]/).replace("label",q).replace("ref",F).getRegex(),ke=k(/^!?\[(ref)\](?:\[\])?/).replace("ref",F).getRegex(),Ye=k("reflink|nolink(?!\\()","g").replace("reflink",he).replace("nolink",ke).getRegex(),se=/[hH][tT][tT][pP][sS]?|[fF][tT][pP]/,X={_backpedal:_,anyPunctuation:Ke,autolink:We,blockSkip:ve,br:le,code:Ce,del:_,delLDelim:_,delRDelim:_,emStrongLDelim:He,emStrongRDelimAst:Ge,emStrongRDelimUnd:Qe,escape:Ae,link:Ve,nolink:ke,punctuation:Be,reflink:he,reflinkSearch:Ye,tag:Je,text:Ie,url:_},et={...X,link:k(/^!?\[(label)\]\((.*?)\)/).replace("label",q).getRegex(),reflink:k(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",q).getRegex()},N={...X,emStrongRDelimAst:Ne,emStrongLDelim:Ze,delLDelim:je,delRDelim:Ue,url:k(/^((?:protocol):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace("protocol",se).replace("email",/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(),_backpedal:/(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])((?:\\[\s\S]|[^\\])*?(?:\\[\s\S]|[^\s~\\]))\1(?=[^~]|$)/,text:k(/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|protocol:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/).replace("protocol",se).getRegex()},tt={...N,br:k(le).replace("{2,}","*").getRegex(),text:k(N.text).replace("\\b_","\\b_| {2,}\\n").replace(/\{2,\}/g,"*").getRegex()},B={normal:K,gfm:ze,pedantic:Ee},A={normal:X,gfm:N,breaks:tt,pedantic:et};var nt={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},de=l=>nt[l];function O(l,e){if(e){if(m.escapeTest.test(l))return l.replace(m.escapeReplace,de)}else if(m.escapeTestNoEncode.test(l))return l.replace(m.escapeReplaceNoEncode,de);return l}function J(l){try{l=encodeURI(l).replace(m.percentDecode,"%");}catch{return null}return l}function V(l,e){let t=l.replace(m.findPipe,(r,i,o)=>{let u=false,a=i;for(;--a>=0&&o[a]==="\\";)u=!u;return u?"|":" |"}),n=t.split(m.splitPipe),s=0;if(n[0].trim()||n.shift(),n.length>0&&!n.at(-1)?.trim()&&n.pop(),e)if(n.length>e)n.splice(e);else for(;n.length<e;)n.push("");for(;s<n.length;s++)n[s]=n[s].trim().replace(m.slashPipe,"|");return n}function $(l,e,t){let n=l.length;if(n===0)return "";let s=0;for(;s<n;){let r=l.charAt(n-s-1);if(r===e&&true)s++;else break}return l.slice(0,n-s)}function Y(l){let e=l.split(`
871
885
  `),t=e.length-1;for(;t>=0&&m.blankLine.test(e[t]);)t--;return e.length-t<=2?l:e.slice(0,t+1).join(`
872
- `)}function fe(l,e){if(l.indexOf(e[1])===-1)return -1;let t=0;for(let n=0;n<l.length;n++)if(l[n]==="\\")n++;else if(l[n]===e[0])t++;else if(l[n]===e[1]&&(t--,t<0))return n;return t>0?-2:-1}function me(l,e=0){let t=e,n="";for(let s of l)if(s===" "){let r=4-t%4;n+=" ".repeat(r),t+=r;}else n+=s,t++;return n}function xe(l,e,t,n,s){let r=e.href,i=e.title||null,o=l[1].replace(s.other.outputLinkReplace,"$1");n.state.inLink=true;let u={type:l[0].charAt(0)==="!"?"image":"link",raw:t,href:r,title:i,text:o,tokens:n.inlineTokens(o)};return n.state.inLink=false,u}function st(l,e,t){let n=l.match(t.other.indentCodeCompensation);if(n===null)return e;let s=n[1];return e.split(`
886
+ `)}function ge(l,e){if(l.indexOf(e[1])===-1)return -1;let t=0;for(let n=0;n<l.length;n++)if(l[n]==="\\")n++;else if(l[n]===e[0])t++;else if(l[n]===e[1]&&(t--,t<0))return n;return t>0?-2:-1}function fe(l,e=0){let t=e,n="";for(let s of l)if(s===" "){let r=4-t%4;n+=" ".repeat(r),t+=r;}else n+=s,t++;return n}function me(l,e,t,n,s){let r=e.href,i=e.title||null,o=l[1].replace(s.other.outputLinkReplace,"$1");n.state.inLink=true;let u={type:l[0].charAt(0)==="!"?"image":"link",raw:t,href:r,title:i,text:o,tokens:n.inlineTokens(o)};return n.state.inLink=false,u}function rt(l,e,t){let n=l.match(t.other.indentCodeCompensation);if(n===null)return e;let s=n[1];return e.split(`
873
887
  `).map(r=>{let i=r.match(t.other.beginningSpace);if(i===null)return r;let[o]=i;return o.length>=s.length?r.slice(s.length):r}).join(`
874
- `)}var w=class{options;rules;lexer;constructor(e){this.options=e||T;}space(e){let t=this.rules.block.newline.exec(e);if(t&&t[0].length>0)return {type:"space",raw:t[0]}}code(e){let t=this.rules.block.code.exec(e);if(t){let n=this.options.pedantic?t[0]:ee(t[0]),s=n.replace(this.rules.other.codeRemoveIndent,"");return {type:"code",raw:n,codeBlockStyle:"indented",text:s}}}fences(e){let t=this.rules.block.fences.exec(e);if(t){let n=t[0],s=st(n,t[3]||"",this.rules);return {type:"code",raw:n,lang:t[2]?t[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):t[2],text:s}}}heading(e){let t=this.rules.block.heading.exec(e);if(t){let n=t[2].trim();if(this.rules.other.endingHash.test(n)){let s=$(n,"#");(this.options.pedantic||!s||this.rules.other.endingSpaceChar.test(s))&&(n=s.trim());}return {type:"heading",raw:$(t[0],`
888
+ `)}var w=class{options;rules;lexer;constructor(e){this.options=e||T;}space(e){let t=this.rules.block.newline.exec(e);if(t&&t[0].length>0)return {type:"space",raw:t[0]}}code(e){let t=this.rules.block.code.exec(e);if(t){let n=this.options.pedantic?t[0]:Y(t[0]),s=n.replace(this.rules.other.codeRemoveIndent,"");return {type:"code",raw:n,codeBlockStyle:"indented",text:s}}}fences(e){let t=this.rules.block.fences.exec(e);if(t){let n=t[0],s=rt(n,t[3]||"",this.rules);return {type:"code",raw:n,lang:t[2]?t[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):t[2],text:s}}}heading(e){let t=this.rules.block.heading.exec(e);if(t){let n=t[2].trim();if(this.rules.other.endingHash.test(n)){let s=$(n,"#");(this.options.pedantic||!s||this.rules.other.endingSpaceChar.test(s))&&(n=s.trim());}return {type:"heading",raw:$(t[0],`
875
889
  `),depth:t[1].length,text:n,tokens:this.lexer.inline(n)}}}hr(e){let t=this.rules.block.hr.exec(e);if(t)return {type:"hr",raw:$(t[0],`
876
890
  `)}}blockquote(e){let t=this.rules.block.blockquote.exec(e);if(t){let n=$(t[0],`
877
891
  `).split(`
@@ -879,24 +893,24 @@ function M(){return {async:false,breaks:false,extensions:null,gfm:true,hooks:nul
879
893
  `),p=c.replace(this.rules.other.blockquoteSetextReplace,`
880
894
  $1`).replace(this.rules.other.blockquoteSetextReplace2,"");s=s?`${s}
881
895
  ${c}`:c,r=r?`${r}
882
- ${p}`:p;let k=this.lexer.state.top;if(this.lexer.state.top=true,this.lexer.blockTokens(p,i,true),this.lexer.state.top=k,n.length===0)break;let h=i.at(-1);if(h?.type==="code")break;if(h?.type==="blockquote"){let R=h,f=R.raw+`
896
+ ${p}`:p;let d=this.lexer.state.top;if(this.lexer.state.top=true,this.lexer.blockTokens(p,i,true),this.lexer.state.top=d,n.length===0)break;let h=i.at(-1);if(h?.type==="code")break;if(h?.type==="blockquote"){let R=h,f=R.raw+`
883
897
  `+n.join(`
884
898
  `),S=this.blockquote(f);i[i.length-1]=S,s=s.substring(0,s.length-R.raw.length)+S.raw,r=r.substring(0,r.length-R.text.length)+S.text;break}else if(h?.type==="list"){let R=h,f=R.raw+`
885
899
  `+n.join(`
886
900
  `),S=this.list(f);i[i.length-1]=S,s=s.substring(0,s.length-h.raw.length)+S.raw,r=r.substring(0,r.length-R.raw.length)+S.raw,n=f.substring(i.at(-1).raw.length).split(`
887
- `);continue}}return {type:"blockquote",raw:s,tokens:i,text:r}}}list(e){let t=this.rules.block.list.exec(e);if(t){let n=t[1].trim(),s=n.length>1,r={type:"list",raw:"",ordered:s,start:s?+n.slice(0,-1):"",loose:false,items:[]};n=s?`\\d{1,9}\\${n.slice(-1)}`:`\\${n}`,this.options.pedantic&&(n=s?n:"[*+-]");let i=this.rules.other.listItemRegex(n),o=false;for(;e;){let a=false,c="",p="";if(!(t=i.exec(e))||this.rules.block.hr.test(e))break;c=t[0],e=e.substring(c.length);let k=me(t[2].split(`
901
+ `);continue}}return {type:"blockquote",raw:s,tokens:i,text:r}}}list(e){let t=this.rules.block.list.exec(e);if(t){let n=t[1].trim(),s=n.length>1,r={type:"list",raw:"",ordered:s,start:s?+n.slice(0,-1):"",loose:false,items:[]};n=s?`\\d{1,9}\\${n.slice(-1)}`:`\\${n}`,this.options.pedantic&&(n=s?n:"[*+-]");let i=this.rules.other.listItemRegex(n),o=false;for(;e;){let a=false,c="",p="";if(!(t=i.exec(e))||this.rules.block.hr.test(e))break;c=t[0],e=e.substring(c.length);let d=fe(t[2].split(`
888
902
  `,1)[0],t[1].length),h=e.split(`
889
- `,1)[0],R=!k.trim(),f=0;if(this.options.pedantic?(f=2,p=k.trimStart()):R?f=t[1].length+1:(f=k.search(this.rules.other.nonSpaceChar),f=f>4?1:f,p=k.slice(f),f+=t[1].length),R&&this.rules.other.blankLine.test(h)&&(c+=h+`
890
- `,e=e.substring(h.length+1),a=true),!a){let S=this.rules.other.nextBulletRegex(f),te=this.rules.other.hrRegex(f),ne=this.rules.other.fencesBeginRegex(f),re=this.rules.other.headingBeginRegex(f),be=this.rules.other.htmlBeginRegex(f),Re=this.rules.other.blockquoteBeginRegex(f);for(;e;){let G=e.split(`
891
- `,1)[0],C;if(h=G,this.options.pedantic?(h=h.replace(this.rules.other.listReplaceNesting," "),C=h):C=h.replace(this.rules.other.tabCharGlobal," "),ne.test(h)||re.test(h)||be.test(h)||Re.test(h)||S.test(h)||te.test(h))break;if(C.search(this.rules.other.nonSpaceChar)>=f||!h.trim())p+=`
892
- `+C.slice(f);else {if(R||k.replace(this.rules.other.tabCharGlobal," ").search(this.rules.other.nonSpaceChar)>=4||ne.test(k)||re.test(k)||te.test(k))break;p+=`
893
- `+h;}R=!h.trim(),c+=G+`
894
- `,e=e.substring(G.length+1),k=C.slice(f);}}r.loose||(o?r.loose=true:this.rules.other.doubleBlankLine.test(c)&&(o=true)),r.items.push({type:"list_item",raw:c,task:!!this.options.gfm&&this.rules.other.listIsTask.test(p),loose:false,text:p,tokens:[]}),r.raw+=c;}let u=r.items.at(-1);if(u)u.raw=u.raw.trimEnd(),u.text=u.text.trimEnd();else return;r.raw=r.raw.trimEnd();for(let a of r.items){this.lexer.state.top=false,a.tokens=this.lexer.blockTokens(a.text,[]);let c=a.tokens[0];if(a.task&&(c?.type==="text"||c?.type==="paragraph")){a.text=a.text.replace(this.rules.other.listReplaceTask,""),c.raw=c.raw.replace(this.rules.other.listReplaceTask,""),c.text=c.text.replace(this.rules.other.listReplaceTask,"");for(let k=this.lexer.inlineQueue.length-1;k>=0;k--)if(this.rules.other.listIsTask.test(this.lexer.inlineQueue[k].src)){this.lexer.inlineQueue[k].src=this.lexer.inlineQueue[k].src.replace(this.rules.other.listReplaceTask,"");break}let p=this.rules.other.listTaskCheckbox.exec(a.raw);if(p){let k={type:"checkbox",raw:p[0]+" ",checked:p[0]!=="[ ]"};a.checked=k.checked,r.loose?a.tokens[0]&&["paragraph","text"].includes(a.tokens[0].type)&&"tokens"in a.tokens[0]&&a.tokens[0].tokens?(a.tokens[0].raw=k.raw+a.tokens[0].raw,a.tokens[0].text=k.raw+a.tokens[0].text,a.tokens[0].tokens.unshift(k)):a.tokens.unshift({type:"paragraph",raw:k.raw,text:k.raw,tokens:[k]}):a.tokens.unshift(k);}}else a.task&&(a.task=false);if(!r.loose){let p=a.tokens.filter(h=>h.type==="space"),k=p.length>0&&p.some(h=>this.rules.other.anyLine.test(h.raw));r.loose=k;}}if(r.loose)for(let a of r.items){a.loose=true;for(let c of a.tokens)c.type==="text"&&(c.type="paragraph");}return r}}html(e){let t=this.rules.block.html.exec(e);if(t){let n=ee(t[0]);return {type:"html",block:true,raw:n,pre:t[1]==="pre"||t[1]==="script"||t[1]==="style",text:n}}}def(e){let t=this.rules.block.def.exec(e);if(t){let n=t[1].toLowerCase().replace(this.rules.other.multipleSpaceGlobal," "),s=t[2]?t[2].replace(this.rules.other.hrefBrackets,"$1").replace(this.rules.inline.anyPunctuation,"$1"):"",r=t[3]?t[3].substring(1,t[3].length-1).replace(this.rules.inline.anyPunctuation,"$1"):t[3];return {type:"def",tag:n,raw:$(t[0],`
895
- `),href:s,title:r}}}table(e){let t=this.rules.block.table.exec(e);if(!t||!this.rules.other.tableDelimiter.test(t[2]))return;let n=Y(t[1]),s=t[2].replace(this.rules.other.tableAlignChars,"").split("|"),r=t[3]?.trim()?t[3].replace(this.rules.other.tableRowBlankLine,"").split(`
903
+ `,1)[0],R=!d.trim(),f=0;if(this.options.pedantic?(f=2,p=d.trimStart()):R?f=t[1].length+1:(f=d.search(this.rules.other.nonSpaceChar),f=f>4?1:f,p=d.slice(f),f+=t[1].length),R&&this.rules.other.blankLine.test(h)&&(c+=h+`
904
+ `,e=e.substring(h.length+1),a=true),!a){let S=this.rules.other.nextBulletRegex(f),ee=this.rules.other.hrRegex(f),te=this.rules.other.fencesBeginRegex(f),ne=this.rules.other.headingBeginRegex(f),xe=this.rules.other.htmlBeginRegex(f),be=this.rules.other.blockquoteBeginRegex(f);for(;e;){let Z=e.split(`
905
+ `,1)[0],C;if(h=Z,this.options.pedantic?(h=h.replace(this.rules.other.listReplaceNesting," "),C=h):C=h.replace(this.rules.other.tabCharGlobal," "),te.test(h)||ne.test(h)||xe.test(h)||be.test(h)||S.test(h)||ee.test(h))break;if(C.search(this.rules.other.nonSpaceChar)>=f||!h.trim())p+=`
906
+ `+C.slice(f);else {if(R||d.replace(this.rules.other.tabCharGlobal," ").search(this.rules.other.nonSpaceChar)>=4||te.test(d)||ne.test(d)||ee.test(d))break;p+=`
907
+ `+h;}R=!h.trim(),c+=Z+`
908
+ `,e=e.substring(Z.length+1),d=C.slice(f);}}r.loose||(o?r.loose=true:this.rules.other.doubleBlankLine.test(c)&&(o=true)),r.items.push({type:"list_item",raw:c,task:!!this.options.gfm&&this.rules.other.listIsTask.test(p),loose:false,text:p,tokens:[]}),r.raw+=c;}let u=r.items.at(-1);if(u)u.raw=u.raw.trimEnd(),u.text=u.text.trimEnd();else return;r.raw=r.raw.trimEnd();for(let a of r.items){if(this.lexer.state.top=false,a.tokens=this.lexer.blockTokens(a.text,[]),a.task){if(a.text=a.text.replace(this.rules.other.listReplaceTask,""),a.tokens[0]?.type==="text"||a.tokens[0]?.type==="paragraph"){a.tokens[0].raw=a.tokens[0].raw.replace(this.rules.other.listReplaceTask,""),a.tokens[0].text=a.tokens[0].text.replace(this.rules.other.listReplaceTask,"");for(let p=this.lexer.inlineQueue.length-1;p>=0;p--)if(this.rules.other.listIsTask.test(this.lexer.inlineQueue[p].src)){this.lexer.inlineQueue[p].src=this.lexer.inlineQueue[p].src.replace(this.rules.other.listReplaceTask,"");break}}let c=this.rules.other.listTaskCheckbox.exec(a.raw);if(c){let p={type:"checkbox",raw:c[0]+" ",checked:c[0]!=="[ ]"};a.checked=p.checked,r.loose?a.tokens[0]&&["paragraph","text"].includes(a.tokens[0].type)&&"tokens"in a.tokens[0]&&a.tokens[0].tokens?(a.tokens[0].raw=p.raw+a.tokens[0].raw,a.tokens[0].text=p.raw+a.tokens[0].text,a.tokens[0].tokens.unshift(p)):a.tokens.unshift({type:"paragraph",raw:p.raw,text:p.raw,tokens:[p]}):a.tokens.unshift(p);}}if(!r.loose){let c=a.tokens.filter(d=>d.type==="space"),p=c.length>0&&c.some(d=>this.rules.other.anyLine.test(d.raw));r.loose=p;}}if(r.loose)for(let a of r.items){a.loose=true;for(let c of a.tokens)c.type==="text"&&(c.type="paragraph");}return r}}html(e){let t=this.rules.block.html.exec(e);if(t){let n=Y(t[0]);return {type:"html",block:true,raw:n,pre:t[1]==="pre"||t[1]==="script"||t[1]==="style",text:n}}}def(e){let t=this.rules.block.def.exec(e);if(t){let n=t[1].toLowerCase().replace(this.rules.other.multipleSpaceGlobal," "),s=t[2]?t[2].replace(this.rules.other.hrefBrackets,"$1").replace(this.rules.inline.anyPunctuation,"$1"):"",r=t[3]?t[3].substring(1,t[3].length-1).replace(this.rules.inline.anyPunctuation,"$1"):t[3];return {type:"def",tag:n,raw:$(t[0],`
909
+ `),href:s,title:r}}}table(e){let t=this.rules.block.table.exec(e);if(!t||!this.rules.other.tableDelimiter.test(t[2]))return;let n=V(t[1]),s=t[2].replace(this.rules.other.tableAlignChars,"").split("|"),r=t[3]?.trim()?t[3].replace(this.rules.other.tableRowBlankLine,"").split(`
896
910
  `):[],i={type:"table",raw:$(t[0],`
897
- `),header:[],align:[],rows:[]};if(n.length===s.length){for(let o of s)this.rules.other.tableAlignRight.test(o)?i.align.push("right"):this.rules.other.tableAlignCenter.test(o)?i.align.push("center"):this.rules.other.tableAlignLeft.test(o)?i.align.push("left"):i.align.push(null);for(let o=0;o<n.length;o++)i.header.push({text:n[o],tokens:this.lexer.inline(n[o]),header:true,align:i.align[o]});for(let o of r)i.rows.push(Y(o,i.header.length).map((u,a)=>({text:u,tokens:this.lexer.inline(u),header:false,align:i.align[a]})));return i}}lheading(e){let t=this.rules.block.lheading.exec(e);if(t){let n=t[1].trim();return {type:"heading",raw:$(t[0],`
911
+ `),header:[],align:[],rows:[]};if(n.length===s.length){for(let o of s)this.rules.other.tableAlignRight.test(o)?i.align.push("right"):this.rules.other.tableAlignCenter.test(o)?i.align.push("center"):this.rules.other.tableAlignLeft.test(o)?i.align.push("left"):i.align.push(null);for(let o=0;o<n.length;o++)i.header.push({text:n[o],tokens:this.lexer.inline(n[o]),header:true,align:i.align[o]});for(let o of r)i.rows.push(V(o,i.header.length).map((u,a)=>({text:u,tokens:this.lexer.inline(u),header:false,align:i.align[a]})));return i}}lheading(e){let t=this.rules.block.lheading.exec(e);if(t){let n=t[1].trim();return {type:"heading",raw:$(t[0],`
898
912
  `),depth:t[2].charAt(0)==="="?1:2,text:n,tokens:this.lexer.inline(n)}}}paragraph(e){let t=this.rules.block.paragraph.exec(e);if(t){let n=t[1].charAt(t[1].length-1)===`
899
- `?t[1].slice(0,-1):t[1];return {type:"paragraph",raw:t[0],text:n,tokens:this.lexer.inline(n)}}}text(e){let t=this.rules.block.text.exec(e);if(t)return {type:"text",raw:t[0],text:t[0],tokens:this.lexer.inline(t[0])}}escape(e){let t=this.rules.inline.escape.exec(e);if(t)return {type:"escape",raw:t[0],text:t[1]}}tag(e){let t=this.rules.inline.tag.exec(e);if(t)return !this.lexer.state.inLink&&this.rules.other.startATag.test(t[0])?this.lexer.state.inLink=true:this.lexer.state.inLink&&this.rules.other.endATag.test(t[0])&&(this.lexer.state.inLink=false),!this.lexer.state.inRawBlock&&this.rules.other.startPreScriptTag.test(t[0])?this.lexer.state.inRawBlock=true:this.lexer.state.inRawBlock&&this.rules.other.endPreScriptTag.test(t[0])&&(this.lexer.state.inRawBlock=false),{type:"html",raw:t[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:false,text:t[0]}}link(e){let t=this.rules.inline.link.exec(e);if(t){let n=t[2].trim();if(!this.options.pedantic&&this.rules.other.startAngleBracket.test(n)){if(!this.rules.other.endAngleBracket.test(n))return;let i=$(n.slice(0,-1),"\\");if((n.length-i.length)%2===0)return}else {let i=fe(t[2],"()");if(i===-2)return;if(i>-1){let u=(t[0].indexOf("!")===0?5:4)+t[1].length+i;t[2]=t[2].substring(0,i),t[0]=t[0].substring(0,u).trim(),t[3]="";}}let s=t[2],r="";if(this.options.pedantic){let i=this.rules.other.pedanticHrefTitle.exec(s);i&&(s=i[1],r=i[3]);}else r=t[3]?t[3].slice(1,-1):"";return s=s.trim(),this.rules.other.startAngleBracket.test(s)&&(this.options.pedantic&&!this.rules.other.endAngleBracket.test(n)?s=s.slice(1):s=s.slice(1,-1)),xe(t,{href:s&&s.replace(this.rules.inline.anyPunctuation,"$1"),title:r&&r.replace(this.rules.inline.anyPunctuation,"$1")},t[0],this.lexer,this.rules)}}reflink(e,t){let n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){let s=(n[2]||n[1]).replace(this.rules.other.multipleSpaceGlobal," "),r=t[s.toLowerCase()];if(!r){let i=n[0].charAt(0);return {type:"text",raw:i,text:i}}return xe(n,r,n[0],this.lexer,this.rules)}}emStrong(e,t,n=""){let s=this.rules.inline.emStrongLDelim.exec(e);if(!s||!s[1]&&!s[2]&&!s[3]&&!s[4]||s[4]&&n.match(this.rules.other.unicodeAlphaNumeric))return;if(!(s[1]||s[3]||"")||!n||this.rules.inline.punctuation.exec(n)){let i=[...s[0]].length-1,o,u,a=i,c=0,p=s[0][0]==="*"?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(p.lastIndex=0,t=t.slice(-1*e.length+i);(s=p.exec(t))!==null;){if(o=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!o)continue;if(u=[...o].length,s[3]||s[4]){a+=u;continue}else if((s[5]||s[6])&&i%3&&!((i+u)%3)){c+=u;continue}if(a-=u,a>0)continue;u=Math.min(u,u+a+c);let k=[...s[0]][0].length,h=e.slice(0,i+s.index+k+u);if(Math.min(i,u)%2){let f=h.slice(1,-1);return {type:"em",raw:h,text:f,tokens:this.lexer.inlineTokens(f)}}let R=h.slice(2,-2);return {type:"strong",raw:h,text:R,tokens:this.lexer.inlineTokens(R)}}}}codespan(e){let t=this.rules.inline.code.exec(e);if(t){let n=t[2].replace(this.rules.other.newLineCharGlobal," "),s=this.rules.other.nonSpaceChar.test(n),r=this.rules.other.startingSpaceChar.test(n)&&this.rules.other.endingSpaceChar.test(n);return s&&r&&(n=n.substring(1,n.length-1)),{type:"codespan",raw:t[0],text:n}}}br(e){let t=this.rules.inline.br.exec(e);if(t)return {type:"br",raw:t[0]}}del(e,t,n=""){let s=this.rules.inline.delLDelim.exec(e);if(!s)return;if(!(s[1]||"")||!n||this.rules.inline.punctuation.exec(n)){let i=[...s[0]].length-1,o,u,a=i,c=this.rules.inline.delRDelim;for(c.lastIndex=0,t=t.slice(-1*e.length+i);(s=c.exec(t))!==null;){if(o=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!o||(u=[...o].length,u!==i))continue;if(s[3]||s[4]){a+=u;continue}if(a-=u,a>0)continue;u=Math.min(u,u+a);let p=[...s[0]][0].length,k=e.slice(0,i+s.index+p+u),h=k.slice(i,-i);return {type:"del",raw:k,text:h,tokens:this.lexer.inlineTokens(h)}}}}autolink(e){let t=this.rules.inline.autolink.exec(e);if(t){let n,s;return t[2]==="@"?(n=t[1],s="mailto:"+n):(n=t[1],s=n),{type:"link",raw:t[0],text:n,href:s,tokens:[{type:"text",raw:n,text:n}]}}}url(e){let t;if(t=this.rules.inline.url.exec(e)){let n,s;if(t[2]==="@")n=t[0],s="mailto:"+n;else {let r;do r=t[0],t[0]=this.rules.inline._backpedal.exec(t[0])?.[0]??"";while(r!==t[0]);n=t[0],t[1]==="www."?s="http://"+t[0]:s=t[0];}return {type:"link",raw:t[0],text:n,href:s,tokens:[{type:"text",raw:n,text:n}]}}}inlineText(e){let t=this.rules.inline.text.exec(e);if(t){let n=this.lexer.state.inRawBlock;return {type:"text",raw:t[0],text:t[0],escaped:n}}}};var x=class l{tokens;options;state;inlineQueue;tokenizer;constructor(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||T,this.options.tokenizer=this.options.tokenizer||new w,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options,this.tokenizer.lexer=this,this.inlineQueue=[],this.state={inLink:false,inRawBlock:false,top:true};let t={other:m,block:D.normal,inline:A.normal};this.options.pedantic?(t.block=D.pedantic,t.inline=A.pedantic):this.options.gfm&&(t.block=D.gfm,this.options.breaks?t.inline=A.breaks:t.inline=A.gfm),this.tokenizer.rules=t;}static get rules(){return {block:D,inline:A}}static lex(e,t){return new l(t).lex(e)}static lexInline(e,t){return new l(t).inlineTokens(e)}lex(e){e=e.replace(m.carriageReturn,`
913
+ `?t[1].slice(0,-1):t[1];return {type:"paragraph",raw:t[0],text:n,tokens:this.lexer.inline(n)}}}text(e){let t=this.rules.block.text.exec(e);if(t)return {type:"text",raw:t[0],text:t[0],tokens:this.lexer.inline(t[0])}}escape(e){let t=this.rules.inline.escape.exec(e);if(t)return {type:"escape",raw:t[0],text:t[1]}}tag(e){let t=this.rules.inline.tag.exec(e);if(t)return !this.lexer.state.inLink&&this.rules.other.startATag.test(t[0])?this.lexer.state.inLink=true:this.lexer.state.inLink&&this.rules.other.endATag.test(t[0])&&(this.lexer.state.inLink=false),!this.lexer.state.inRawBlock&&this.rules.other.startPreScriptTag.test(t[0])?this.lexer.state.inRawBlock=true:this.lexer.state.inRawBlock&&this.rules.other.endPreScriptTag.test(t[0])&&(this.lexer.state.inRawBlock=false),{type:"html",raw:t[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:false,text:t[0]}}link(e){let t=this.rules.inline.link.exec(e);if(t){let n=t[2].trim();if(!this.options.pedantic&&this.rules.other.startAngleBracket.test(n)){if(!this.rules.other.endAngleBracket.test(n))return;let i=$(n.slice(0,-1),"\\");if((n.length-i.length)%2===0)return}else {let i=ge(t[2],"()");if(i===-2)return;if(i>-1){let u=(t[0].indexOf("!")===0?5:4)+t[1].length+i;t[2]=t[2].substring(0,i),t[0]=t[0].substring(0,u).trim(),t[3]="";}}let s=t[2],r="";if(this.options.pedantic){let i=this.rules.other.pedanticHrefTitle.exec(s);i&&(s=i[1],r=i[3]);}else r=t[3]?t[3].slice(1,-1):"";return s=s.trim(),this.rules.other.startAngleBracket.test(s)&&(this.options.pedantic&&!this.rules.other.endAngleBracket.test(n)?s=s.slice(1):s=s.slice(1,-1)),me(t,{href:s&&s.replace(this.rules.inline.anyPunctuation,"$1"),title:r&&r.replace(this.rules.inline.anyPunctuation,"$1")},t[0],this.lexer,this.rules)}}reflink(e,t){let n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){let s=(n[2]||n[1]).replace(this.rules.other.multipleSpaceGlobal," "),r=t[s.toLowerCase()];if(!r){let i=n[0].charAt(0);return {type:"text",raw:i,text:i}}return me(n,r,n[0],this.lexer,this.rules)}}emStrong(e,t,n=""){let s=this.rules.inline.emStrongLDelim.exec(e);if(!s||!s[1]&&!s[2]&&!s[3]&&!s[4]||s[4]&&n.match(this.rules.other.unicodeAlphaNumeric))return;if(!(s[1]||s[3]||"")||!n||this.rules.inline.punctuation.exec(n)){let i=[...s[0]].length-1,o,u,a=i,c=0,p=s[0][0]==="*"?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(p.lastIndex=0,t=t.slice(-1*e.length+i);(s=p.exec(t))!==null;){if(o=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!o)continue;if(u=[...o].length,s[3]||s[4]){a+=u;continue}else if((s[5]||s[6])&&i%3&&!((i+u)%3)){c+=u;continue}if(a-=u,a>0)continue;u=Math.min(u,u+a+c);let d=[...s[0]][0].length,h=e.slice(0,i+s.index+d+u);if(Math.min(i,u)%2){let f=h.slice(1,-1);return {type:"em",raw:h,text:f,tokens:this.lexer.inlineTokens(f)}}let R=h.slice(2,-2);return {type:"strong",raw:h,text:R,tokens:this.lexer.inlineTokens(R)}}}}codespan(e){let t=this.rules.inline.code.exec(e);if(t){let n=t[2].replace(this.rules.other.newLineCharGlobal," "),s=this.rules.other.nonSpaceChar.test(n),r=this.rules.other.startingSpaceChar.test(n)&&this.rules.other.endingSpaceChar.test(n);return s&&r&&(n=n.substring(1,n.length-1)),{type:"codespan",raw:t[0],text:n}}}br(e){let t=this.rules.inline.br.exec(e);if(t)return {type:"br",raw:t[0]}}del(e,t,n=""){let s=this.rules.inline.delLDelim.exec(e);if(!s)return;if(!(s[1]||"")||!n||this.rules.inline.punctuation.exec(n)){let i=[...s[0]].length-1,o,u,a=i,c=this.rules.inline.delRDelim;for(c.lastIndex=0,t=t.slice(-1*e.length+i);(s=c.exec(t))!==null;){if(o=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!o||(u=[...o].length,u!==i))continue;if(s[3]||s[4]){a+=u;continue}if(a-=u,a>0)continue;u=Math.min(u,u+a);let p=[...s[0]][0].length,d=e.slice(0,i+s.index+p+u),h=d.slice(i,-i);return {type:"del",raw:d,text:h,tokens:this.lexer.inlineTokens(h)}}}}autolink(e){let t=this.rules.inline.autolink.exec(e);if(t){let n,s;return t[2]==="@"?(n=t[1],s="mailto:"+n):(n=t[1],s=n),{type:"link",raw:t[0],text:n,href:s,tokens:[{type:"text",raw:n,text:n}]}}}url(e){let t;if(t=this.rules.inline.url.exec(e)){let n,s;if(t[2]==="@")n=t[0],s="mailto:"+n;else {let r;do r=t[0],t[0]=this.rules.inline._backpedal.exec(t[0])?.[0]??"";while(r!==t[0]);n=t[0],t[1]==="www."?s="http://"+t[0]:s=t[0];}return {type:"link",raw:t[0],text:n,href:s,tokens:[{type:"text",raw:n,text:n}]}}}inlineText(e){let t=this.rules.inline.text.exec(e);if(t){let n=this.lexer.state.inRawBlock;return {type:"text",raw:t[0],text:t[0],escaped:n}}}};var x=class l{tokens;options;state;inlineQueue;tokenizer;constructor(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||T,this.options.tokenizer=this.options.tokenizer||new w,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options,this.tokenizer.lexer=this,this.inlineQueue=[],this.state={inLink:false,inRawBlock:false,top:true};let t={other:m,block:B.normal,inline:A.normal};this.options.pedantic?(t.block=B.pedantic,t.inline=A.pedantic):this.options.gfm&&(t.block=B.gfm,this.options.breaks?t.inline=A.breaks:t.inline=A.gfm),this.tokenizer.rules=t;}static get rules(){return {block:B,inline:A}}static lex(e,t){return new l(t).lex(e)}static lexInline(e,t){return new l(t).inlineTokens(e)}lex(e){e=e.replace(m.carriageReturn,`
900
914
  `),this.blockTokens(e,this.tokens);for(let t=0;t<this.inlineQueue.length;t++){let n=this.inlineQueue[t];this.inlineTokens(n.src,n.tokens);}return this.inlineQueue=[],this.tokens}blockTokens(e,t=[],n=false){this.tokenizer.lexer=this,this.options.pedantic&&(e=e.replace(m.tabCharGlobal," ").replace(m.spaceLine,""));let s=1/0;for(;e;){if(e.length<s)s=e.length;else {this.infiniteLoopError(e.charCodeAt(0));break}let r;if(this.options.extensions?.block?.some(o=>(r=o.call({lexer:this},e,t))?(e=e.substring(r.raw.length),t.push(r),true):false))continue;if(r=this.tokenizer.space(e)){e=e.substring(r.raw.length);let o=t.at(-1);r.raw.length===1&&o!==void 0?o.raw+=`
901
915
  `:t.push(r);continue}if(r=this.tokenizer.code(e)){e=e.substring(r.raw.length);let o=t.at(-1);o?.type==="paragraph"||o?.type==="text"?(o.raw+=(o.raw.endsWith(`
902
916
  `)?"":`
@@ -910,7 +924,7 @@ ${p}`:p;let k=this.lexer.state.top;if(this.lexer.state.top=true,this.lexer.block
910
924
  `+r.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=o.text):t.push(r),n=i.length!==e.length,e=e.substring(r.raw.length);continue}if(r=this.tokenizer.text(e)){e=e.substring(r.raw.length);let o=t.at(-1);o?.type==="text"?(o.raw+=(o.raw.endsWith(`
911
925
  `)?"":`
912
926
  `)+r.raw,o.text+=`
913
- `+r.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=o.text):t.push(r);continue}if(e){this.infiniteLoopError(e.charCodeAt(0));break}}return this.state.top=true,t}inline(e,t=[]){return this.inlineQueue.push({src:e,tokens:t}),t}inlineTokens(e,t=[]){this.tokenizer.lexer=this;let n=e,s=null;if(this.tokens.links){let a=Object.keys(this.tokens.links);if(a.length>0)for(;(s=this.tokenizer.rules.inline.reflinkSearch.exec(n))!==null;)a.includes(s[0].slice(s[0].lastIndexOf("[")+1,-1))&&(n=n.slice(0,s.index)+"["+"a".repeat(s[0].length-2)+"]"+n.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex));}for(;(s=this.tokenizer.rules.inline.anyPunctuation.exec(n))!==null;)n=n.slice(0,s.index)+"++"+n.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);let r;for(;(s=this.tokenizer.rules.inline.blockSkip.exec(n))!==null;)r=s[2]?s[2].length:0,n=n.slice(0,s.index+r)+"["+"a".repeat(s[0].length-r-2)+"]"+n.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);n=this.options.hooks?.emStrongMask?.call({lexer:this},n)??n;let i=false,o="",u=1/0;for(;e;){if(e.length<u)u=e.length;else {this.infiniteLoopError(e.charCodeAt(0));break}i||(o=""),i=false;let a;if(this.options.extensions?.inline?.some(p=>(a=p.call({lexer:this},e,t))?(e=e.substring(a.raw.length),t.push(a),true):false))continue;if(a=this.tokenizer.escape(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.tag(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.link(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.reflink(e,this.tokens.links)){e=e.substring(a.raw.length);let p=t.at(-1);a.type==="text"&&p?.type==="text"?(p.raw+=a.raw,p.text+=a.text):t.push(a);continue}if(a=this.tokenizer.emStrong(e,n,o)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.codespan(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.br(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.del(e,n,o)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.autolink(e)){e=e.substring(a.raw.length),t.push(a);continue}if(!this.state.inLink&&(a=this.tokenizer.url(e))){e=e.substring(a.raw.length),t.push(a);continue}let c=e;if(this.options.extensions?.startInline){let p=1/0,k=e.slice(1),h;this.options.extensions.startInline.forEach(R=>{h=R.call({lexer:this},k),typeof h=="number"&&h>=0&&(p=Math.min(p,h));}),p<1/0&&p>=0&&(c=e.substring(0,p+1));}if(a=this.tokenizer.inlineText(c)){e=e.substring(a.raw.length),a.raw.slice(-1)!=="_"&&(o=a.raw.slice(-1)),i=true;let p=t.at(-1);p?.type==="text"?(p.raw+=a.raw,p.text+=a.text):t.push(a);continue}if(e){this.infiniteLoopError(e.charCodeAt(0));break}}return t}infiniteLoopError(e){let t="Infinite loop on byte: "+e;if(this.options.silent)console.error(t);else throw new Error(t)}};var y=class{options;parser;constructor(e){this.options=e||T;}space(e){return ""}code({text:e,lang:t,escaped:n}){let s=(t||"").match(m.notSpaceStart)?.[0],r=e.replace(m.endingNewline,"")+`
927
+ `+r.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=o.text):t.push(r);continue}if(e){this.infiniteLoopError(e.charCodeAt(0));break}}return this.state.top=true,t}inline(e,t=[]){return this.inlineQueue.push({src:e,tokens:t}),t}inlineTokens(e,t=[]){this.tokenizer.lexer=this;let n=e,s=null;if(this.tokens.links){let a=Object.keys(this.tokens.links);if(a.length>0)for(;(s=this.tokenizer.rules.inline.reflinkSearch.exec(n))!==null;)a.includes(s[0].slice(s[0].lastIndexOf("[")+1,-1))&&(n=n.slice(0,s.index)+"["+"a".repeat(s[0].length-2)+"]"+n.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex));}for(;(s=this.tokenizer.rules.inline.anyPunctuation.exec(n))!==null;)n=n.slice(0,s.index)+"++"+n.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);let r;for(;(s=this.tokenizer.rules.inline.blockSkip.exec(n))!==null;)r=s[2]?s[2].length:0,n=n.slice(0,s.index+r)+"["+"a".repeat(s[0].length-r-2)+"]"+n.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);n=this.options.hooks?.emStrongMask?.call({lexer:this},n)??n;let i=false,o="",u=1/0;for(;e;){if(e.length<u)u=e.length;else {this.infiniteLoopError(e.charCodeAt(0));break}i||(o=""),i=false;let a;if(this.options.extensions?.inline?.some(p=>(a=p.call({lexer:this},e,t))?(e=e.substring(a.raw.length),t.push(a),true):false))continue;if(a=this.tokenizer.escape(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.tag(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.link(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.reflink(e,this.tokens.links)){e=e.substring(a.raw.length);let p=t.at(-1);a.type==="text"&&p?.type==="text"?(p.raw+=a.raw,p.text+=a.text):t.push(a);continue}if(a=this.tokenizer.emStrong(e,n,o)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.codespan(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.br(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.del(e,n,o)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.autolink(e)){e=e.substring(a.raw.length),t.push(a);continue}if(!this.state.inLink&&(a=this.tokenizer.url(e))){e=e.substring(a.raw.length),t.push(a);continue}let c=e;if(this.options.extensions?.startInline){let p=1/0,d=e.slice(1),h;this.options.extensions.startInline.forEach(R=>{h=R.call({lexer:this},d),typeof h=="number"&&h>=0&&(p=Math.min(p,h));}),p<1/0&&p>=0&&(c=e.substring(0,p+1));}if(a=this.tokenizer.inlineText(c)){e=e.substring(a.raw.length),a.raw.slice(-1)!=="_"&&(o=a.raw.slice(-1)),i=true;let p=t.at(-1);p?.type==="text"?(p.raw+=a.raw,p.text+=a.text):t.push(a);continue}if(e){this.infiniteLoopError(e.charCodeAt(0));break}}return t}infiniteLoopError(e){let t="Infinite loop on byte: "+e;if(this.options.silent)console.error(t);else throw new Error(t)}};var y=class{options;parser;constructor(e){this.options=e||T;}space(e){return ""}code({text:e,lang:t,escaped:n}){let s=(t||"").match(m.notSpaceStart)?.[0],r=e.replace(m.endingNewline,"")+`
914
928
  `;return s?'<pre><code class="language-'+O(s)+'">'+(n?r:O(r,true))+`</code></pre>
915
929
  `:"<pre><code>"+(n?r:O(r,true))+`</code></pre>
916
930
  `}blockquote({tokens:e}){return `<blockquote>
@@ -928,68 +942,27 @@ ${this.parser.parse(e)}</blockquote>
928
942
  `}tablerow({text:e}){return `<tr>
929
943
  ${e}</tr>
930
944
  `}tablecell(e){let t=this.parser.parseInline(e.tokens),n=e.header?"th":"td";return (e.align?`<${n} align="${e.align}">`:`<${n}>`)+t+`</${n}>
931
- `}strong({tokens:e}){return `<strong>${this.parser.parseInline(e)}</strong>`}em({tokens:e}){return `<em>${this.parser.parseInline(e)}</em>`}codespan({text:e}){return `<code>${O(e,true)}</code>`}br(e){return "<br>"}del({tokens:e}){return `<del>${this.parser.parseInline(e)}</del>`}link({href:e,title:t,tokens:n}){let s=this.parser.parseInline(n),r=V(e);if(r===null)return s;e=r;let i='<a href="'+e+'"';return t&&(i+=' title="'+O(t)+'"'),i+=">"+s+"</a>",i}image({href:e,title:t,text:n,tokens:s}){s&&(n=this.parser.parseInline(s,this.parser.textRenderer));let r=V(e);if(r===null)return O(n);e=r;let i=`<img src="${e}" alt="${O(n)}"`;return t&&(i+=` title="${O(t)}"`),i+=">",i}text(e){return "tokens"in e&&e.tokens?this.parser.parseInline(e.tokens):"escaped"in e&&e.escaped?e.text:O(e.text)}};var L=class{strong({text:e}){return e}em({text:e}){return e}codespan({text:e}){return e}del({text:e}){return e}html({text:e}){return e}text({text:e}){return e}link({text:e}){return ""+e}image({text:e}){return ""+e}br(){return ""}checkbox({raw:e}){return e}};var b=class l{options;renderer;textRenderer;constructor(e){this.options=e||T,this.options.renderer=this.options.renderer||new y,this.renderer=this.options.renderer,this.renderer.options=this.options,this.renderer.parser=this,this.textRenderer=new L;}static parse(e,t){return new l(t).parse(e)}static parseInline(e,t){return new l(t).parseInline(e)}parse(e){this.renderer.parser=this;let t="";for(let n=0;n<e.length;n++){let s=e[n];if(this.options.extensions?.renderers?.[s.type]){let i=s,o=this.options.extensions.renderers[i.type].call({parser:this},i);if(o!==false||!["space","hr","heading","code","table","blockquote","list","html","def","paragraph","text"].includes(i.type)){t+=o||"";continue}}let r=s;switch(r.type){case "space":{t+=this.renderer.space(r);break}case "hr":{t+=this.renderer.hr(r);break}case "heading":{t+=this.renderer.heading(r);break}case "code":{t+=this.renderer.code(r);break}case "table":{t+=this.renderer.table(r);break}case "blockquote":{t+=this.renderer.blockquote(r);break}case "list":{t+=this.renderer.list(r);break}case "checkbox":{t+=this.renderer.checkbox(r);break}case "html":{t+=this.renderer.html(r);break}case "def":{t+=this.renderer.def(r);break}case "paragraph":{t+=this.renderer.paragraph(r);break}case "text":{t+=this.renderer.text(r);break}default:{let i='Token with "'+r.type+'" type was not found.';if(this.options.silent)return console.error(i),"";throw new Error(i)}}}return t}parseInline(e,t=this.renderer){this.renderer.parser=this;let n="";for(let s=0;s<e.length;s++){let r=e[s];if(this.options.extensions?.renderers?.[r.type]){let o=this.options.extensions.renderers[r.type].call({parser:this},r);if(o!==false||!["escape","html","link","image","strong","em","codespan","br","del","text"].includes(r.type)){n+=o||"";continue}}let i=r;switch(i.type){case "escape":{n+=t.text(i);break}case "html":{n+=t.html(i);break}case "link":{n+=t.link(i);break}case "image":{n+=t.image(i);break}case "checkbox":{n+=t.checkbox(i);break}case "strong":{n+=t.strong(i);break}case "em":{n+=t.em(i);break}case "codespan":{n+=t.codespan(i);break}case "br":{n+=t.br(i);break}case "del":{n+=t.del(i);break}case "text":{n+=t.text(i);break}default:{let o='Token with "'+i.type+'" type was not found.';if(this.options.silent)return console.error(o),"";throw new Error(o)}}}return n}};var P=class{options;block;constructor(e){this.options=e||T;}static passThroughHooks=new Set(["preprocess","postprocess","processAllTokens","emStrongMask"]);static passThroughHooksRespectAsync=new Set(["preprocess","postprocess","processAllTokens"]);preprocess(e){return e}postprocess(e){return e}processAllTokens(e){return e}emStrongMask(e){return e}provideLexer(e=this.block){return e?x.lex:x.lexInline}provideParser(e=this.block){return e?b.parse:b.parseInline}};var q=class{defaults=M();options=this.setOptions;parse=this.parseMarkdown(true);parseInline=this.parseMarkdown(false);Parser=b;Renderer=y;TextRenderer=L;Lexer=x;Tokenizer=w;Hooks=P;constructor(...e){this.use(...e);}walkTokens(e,t){let n=[];for(let s of e)switch(n=n.concat(t.call(this,s)),s.type){case "table":{let r=s;for(let i of r.header)n=n.concat(this.walkTokens(i.tokens,t));for(let i of r.rows)for(let o of i)n=n.concat(this.walkTokens(o.tokens,t));break}case "list":{let r=s;n=n.concat(this.walkTokens(r.items,t));break}default:{let r=s;this.defaults.extensions?.childTokens?.[r.type]?this.defaults.extensions.childTokens[r.type].forEach(i=>{let o=r[i].flat(1/0);n=n.concat(this.walkTokens(o,t));}):r.tokens&&(n=n.concat(this.walkTokens(r.tokens,t)));}}return n}use(...e){let t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach(n=>{let s={...n};if(s.async=this.defaults.async||s.async||false,n.extensions&&(n.extensions.forEach(r=>{if(!r.name)throw new Error("extension name required");if("renderer"in r){let i=t.renderers[r.name];i?t.renderers[r.name]=function(...o){let u=r.renderer.apply(this,o);return u===false&&(u=i.apply(this,o)),u}:t.renderers[r.name]=r.renderer;}if("tokenizer"in r){if(!r.level||r.level!=="block"&&r.level!=="inline")throw new Error("extension level must be 'block' or 'inline'");let i=t[r.level];i?i.unshift(r.tokenizer):t[r.level]=[r.tokenizer],r.start&&(r.level==="block"?t.startBlock?t.startBlock.push(r.start):t.startBlock=[r.start]:r.level==="inline"&&(t.startInline?t.startInline.push(r.start):t.startInline=[r.start]));}"childTokens"in r&&r.childTokens&&(t.childTokens[r.name]=r.childTokens);}),s.extensions=t),n.renderer){let r=this.defaults.renderer||new y(this.defaults);for(let i in n.renderer){if(!(i in r))throw new Error(`renderer '${i}' does not exist`);if(["options","parser"].includes(i))continue;let o=i,u=n.renderer[o],a=r[o];r[o]=(...c)=>{let p=u.apply(r,c);return p===false&&(p=a.apply(r,c)),p||""};}s.renderer=r;}if(n.tokenizer){let r=this.defaults.tokenizer||new w(this.defaults);for(let i in n.tokenizer){if(!(i in r))throw new Error(`tokenizer '${i}' does not exist`);if(["options","rules","lexer"].includes(i))continue;let o=i,u=n.tokenizer[o],a=r[o];r[o]=(...c)=>{let p=u.apply(r,c);return p===false&&(p=a.apply(r,c)),p};}s.tokenizer=r;}if(n.hooks){let r=this.defaults.hooks||new P;for(let i in n.hooks){if(!(i in r))throw new Error(`hook '${i}' does not exist`);if(["options","block"].includes(i))continue;let o=i,u=n.hooks[o],a=r[o];P.passThroughHooks.has(i)?r[o]=c=>{if(this.defaults.async&&P.passThroughHooksRespectAsync.has(i))return (async()=>{let k=await u.call(r,c);return a.call(r,k)})();let p=u.call(r,c);return a.call(r,p)}:r[o]=(...c)=>{if(this.defaults.async)return (async()=>{let k=await u.apply(r,c);return k===false&&(k=await a.apply(r,c)),k})();let p=u.apply(r,c);return p===false&&(p=a.apply(r,c)),p};}s.hooks=r;}if(n.walkTokens){let r=this.defaults.walkTokens,i=n.walkTokens;s.walkTokens=function(o){let u=[];return u.push(i.call(this,o)),r&&(u=u.concat(r.call(this,o))),u};}this.defaults={...this.defaults,...s};}),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return x.lex(e,t??this.defaults)}parser(e,t){return b.parse(e,t??this.defaults)}parseMarkdown(e){return (n,s)=>{let r={...s},i={...this.defaults,...r},o=this.onError(!!i.silent,!!i.async);if(this.defaults.async===true&&r.async===false)return o(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));if(typeof n>"u"||n===null)return o(new Error("marked(): input parameter is undefined or null"));if(typeof n!="string")return o(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(n)+", string expected"));if(i.hooks&&(i.hooks.options=i,i.hooks.block=e),i.async)return (async()=>{let u=i.hooks?await i.hooks.preprocess(n):n,c=await(i.hooks?await i.hooks.provideLexer(e):e?x.lex:x.lexInline)(u,i),p=i.hooks?await i.hooks.processAllTokens(c):c;i.walkTokens&&await Promise.all(this.walkTokens(p,i.walkTokens));let h=await(i.hooks?await i.hooks.provideParser(e):e?b.parse:b.parseInline)(p,i);return i.hooks?await i.hooks.postprocess(h):h})().catch(o);try{i.hooks&&(n=i.hooks.preprocess(n));let a=(i.hooks?i.hooks.provideLexer(e):e?x.lex:x.lexInline)(n,i);i.hooks&&(a=i.hooks.processAllTokens(a)),i.walkTokens&&this.walkTokens(a,i.walkTokens);let p=(i.hooks?i.hooks.provideParser(e):e?b.parse:b.parseInline)(a,i);return i.hooks&&(p=i.hooks.postprocess(p)),p}catch(u){return o(u)}}}onError(e,t){return n=>{if(n.message+=`
932
- Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error occurred:</p><pre>"+O(n.message+"",true)+"</pre>";return t?Promise.resolve(s):s}if(t)return Promise.reject(n);throw n}}};var z=new q;function g(l,e){return z.parse(l,e)}g.options=g.setOptions=function(l){return z.setOptions(l),g.defaults=z.defaults,N(g.defaults),g};g.getDefaults=M;g.defaults=T;g.use=function(...l){return z.use(...l),g.defaults=z.defaults,N(g.defaults),g};g.walkTokens=function(l,e){return z.walkTokens(l,e)};g.parseInline=z.parseInline;g.Parser=b;g.parser=b.parse;g.Renderer=y;g.TextRenderer=L;g.Lexer=x;g.lexer=x.lex;g.Tokenizer=w;g.Hooks=P;g.parse=g;g.options;g.setOptions;g.use;g.walkTokens;g.parseInline;b.parse;x.lex;
933
-
934
- /*! @license DOMPurify 3.4.8 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.8/LICENSE */
935
-
936
- function _arrayLikeToArray(r, a) {
937
- (null == a || a > r.length) && (a = r.length);
938
- for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
939
- return n;
940
- }
941
- function _arrayWithHoles(r) {
942
- if (Array.isArray(r)) return r;
943
- }
944
- function _iterableToArrayLimit(r, l) {
945
- var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
946
- if (null != t) {
947
- var e,
948
- n,
949
- i,
950
- u,
951
- a = [],
952
- f = true,
953
- o = false;
954
- try {
955
- if (i = (t = t.call(r)).next, 0 === l) ; else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
956
- } catch (r) {
957
- o = true, n = r;
958
- } finally {
959
- try {
960
- if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
961
- } finally {
962
- if (o) throw n;
963
- }
964
- }
965
- return a;
966
- }
967
- }
968
- function _nonIterableRest() {
969
- throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
970
- }
971
- function _slicedToArray(r, e) {
972
- return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
973
- }
974
- function _unsupportedIterableToArray(r, a) {
975
- if (r) {
976
- if ("string" == typeof r) return _arrayLikeToArray(r, a);
977
- var t = {}.toString.call(r).slice(8, -1);
978
- return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
979
- }
980
- }
981
-
982
- const entries = Object.entries,
983
- setPrototypeOf = Object.setPrototypeOf,
984
- isFrozen = Object.isFrozen,
985
- getPrototypeOf = Object.getPrototypeOf,
986
- getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
987
- let freeze = Object.freeze,
988
- seal = Object.seal,
989
- create = Object.create; // eslint-disable-line import/no-mutable-exports
990
- let _ref = typeof Reflect !== 'undefined' && Reflect,
991
- apply = _ref.apply,
992
- construct = _ref.construct;
945
+ `}strong({tokens:e}){return `<strong>${this.parser.parseInline(e)}</strong>`}em({tokens:e}){return `<em>${this.parser.parseInline(e)}</em>`}codespan({text:e}){return `<code>${O(e,true)}</code>`}br(e){return "<br>"}del({tokens:e}){return `<del>${this.parser.parseInline(e)}</del>`}link({href:e,title:t,tokens:n}){let s=this.parser.parseInline(n),r=J(e);if(r===null)return s;e=r;let i='<a href="'+e+'"';return t&&(i+=' title="'+O(t)+'"'),i+=">"+s+"</a>",i}image({href:e,title:t,text:n,tokens:s}){s&&(n=this.parser.parseInline(s,this.parser.textRenderer));let r=J(e);if(r===null)return O(n);e=r;let i=`<img src="${e}" alt="${O(n)}"`;return t&&(i+=` title="${O(t)}"`),i+=">",i}text(e){return "tokens"in e&&e.tokens?this.parser.parseInline(e.tokens):"escaped"in e&&e.escaped?e.text:O(e.text)}};var L=class{strong({text:e}){return e}em({text:e}){return e}codespan({text:e}){return e}del({text:e}){return e}html({text:e}){return e}text({text:e}){return e}link({text:e}){return ""+e}image({text:e}){return ""+e}br(){return ""}checkbox({raw:e}){return e}};var b=class l{options;renderer;textRenderer;constructor(e){this.options=e||T,this.options.renderer=this.options.renderer||new y,this.renderer=this.options.renderer,this.renderer.options=this.options,this.renderer.parser=this,this.textRenderer=new L;}static parse(e,t){return new l(t).parse(e)}static parseInline(e,t){return new l(t).parseInline(e)}parse(e){this.renderer.parser=this;let t="";for(let n=0;n<e.length;n++){let s=e[n];if(this.options.extensions?.renderers?.[s.type]){let i=s,o=this.options.extensions.renderers[i.type].call({parser:this},i);if(o!==false||!["space","hr","heading","code","table","blockquote","list","html","def","paragraph","text"].includes(i.type)){t+=o||"";continue}}let r=s;switch(r.type){case "space":{t+=this.renderer.space(r);break}case "hr":{t+=this.renderer.hr(r);break}case "heading":{t+=this.renderer.heading(r);break}case "code":{t+=this.renderer.code(r);break}case "table":{t+=this.renderer.table(r);break}case "blockquote":{t+=this.renderer.blockquote(r);break}case "list":{t+=this.renderer.list(r);break}case "checkbox":{t+=this.renderer.checkbox(r);break}case "html":{t+=this.renderer.html(r);break}case "def":{t+=this.renderer.def(r);break}case "paragraph":{t+=this.renderer.paragraph(r);break}case "text":{t+=this.renderer.text(r);break}default:{let i='Token with "'+r.type+'" type was not found.';if(this.options.silent)return console.error(i),"";throw new Error(i)}}}return t}parseInline(e,t=this.renderer){this.renderer.parser=this;let n="";for(let s=0;s<e.length;s++){let r=e[s];if(this.options.extensions?.renderers?.[r.type]){let o=this.options.extensions.renderers[r.type].call({parser:this},r);if(o!==false||!["escape","html","link","image","strong","em","codespan","br","del","text"].includes(r.type)){n+=o||"";continue}}let i=r;switch(i.type){case "escape":{n+=t.text(i);break}case "html":{n+=t.html(i);break}case "link":{n+=t.link(i);break}case "image":{n+=t.image(i);break}case "checkbox":{n+=t.checkbox(i);break}case "strong":{n+=t.strong(i);break}case "em":{n+=t.em(i);break}case "codespan":{n+=t.codespan(i);break}case "br":{n+=t.br(i);break}case "del":{n+=t.del(i);break}case "text":{n+=t.text(i);break}default:{let o='Token with "'+i.type+'" type was not found.';if(this.options.silent)return console.error(o),"";throw new Error(o)}}}return n}};var P=class{options;block;constructor(e){this.options=e||T;}static passThroughHooks=new Set(["preprocess","postprocess","processAllTokens","emStrongMask"]);static passThroughHooksRespectAsync=new Set(["preprocess","postprocess","processAllTokens"]);preprocess(e){return e}postprocess(e){return e}processAllTokens(e){return e}emStrongMask(e){return e}provideLexer(e=this.block){return e?x.lex:x.lexInline}provideParser(e=this.block){return e?b.parse:b.parseInline}};var D=class{defaults=z();options=this.setOptions;parse=this.parseMarkdown(true);parseInline=this.parseMarkdown(false);Parser=b;Renderer=y;TextRenderer=L;Lexer=x;Tokenizer=w;Hooks=P;constructor(...e){this.use(...e);}walkTokens(e,t){let n=[];for(let s of e)switch(n=n.concat(t.call(this,s)),s.type){case "table":{let r=s;for(let i of r.header)n=n.concat(this.walkTokens(i.tokens,t));for(let i of r.rows)for(let o of i)n=n.concat(this.walkTokens(o.tokens,t));break}case "list":{let r=s;n=n.concat(this.walkTokens(r.items,t));break}default:{let r=s;this.defaults.extensions?.childTokens?.[r.type]?this.defaults.extensions.childTokens[r.type].forEach(i=>{let o=r[i].flat(1/0);n=n.concat(this.walkTokens(o,t));}):r.tokens&&(n=n.concat(this.walkTokens(r.tokens,t)));}}return n}use(...e){let t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach(n=>{let s={...n};if(s.async=this.defaults.async||s.async||false,n.extensions&&(n.extensions.forEach(r=>{if(!r.name)throw new Error("extension name required");if("renderer"in r){let i=t.renderers[r.name];i?t.renderers[r.name]=function(...o){let u=r.renderer.apply(this,o);return u===false&&(u=i.apply(this,o)),u}:t.renderers[r.name]=r.renderer;}if("tokenizer"in r){if(!r.level||r.level!=="block"&&r.level!=="inline")throw new Error("extension level must be 'block' or 'inline'");let i=t[r.level];i?i.unshift(r.tokenizer):t[r.level]=[r.tokenizer],r.start&&(r.level==="block"?t.startBlock?t.startBlock.push(r.start):t.startBlock=[r.start]:r.level==="inline"&&(t.startInline?t.startInline.push(r.start):t.startInline=[r.start]));}"childTokens"in r&&r.childTokens&&(t.childTokens[r.name]=r.childTokens);}),s.extensions=t),n.renderer){let r=this.defaults.renderer||new y(this.defaults);for(let i in n.renderer){if(!(i in r))throw new Error(`renderer '${i}' does not exist`);if(["options","parser"].includes(i))continue;let o=i,u=n.renderer[o],a=r[o];r[o]=(...c)=>{let p=u.apply(r,c);return p===false&&(p=a.apply(r,c)),p||""};}s.renderer=r;}if(n.tokenizer){let r=this.defaults.tokenizer||new w(this.defaults);for(let i in n.tokenizer){if(!(i in r))throw new Error(`tokenizer '${i}' does not exist`);if(["options","rules","lexer"].includes(i))continue;let o=i,u=n.tokenizer[o],a=r[o];r[o]=(...c)=>{let p=u.apply(r,c);return p===false&&(p=a.apply(r,c)),p};}s.tokenizer=r;}if(n.hooks){let r=this.defaults.hooks||new P;for(let i in n.hooks){if(!(i in r))throw new Error(`hook '${i}' does not exist`);if(["options","block"].includes(i))continue;let o=i,u=n.hooks[o],a=r[o];P.passThroughHooks.has(i)?r[o]=c=>{if(this.defaults.async&&P.passThroughHooksRespectAsync.has(i))return (async()=>{let d=await u.call(r,c);return a.call(r,d)})();let p=u.call(r,c);return a.call(r,p)}:r[o]=(...c)=>{if(this.defaults.async)return (async()=>{let d=await u.apply(r,c);return d===false&&(d=await a.apply(r,c)),d})();let p=u.apply(r,c);return p===false&&(p=a.apply(r,c)),p};}s.hooks=r;}if(n.walkTokens){let r=this.defaults.walkTokens,i=n.walkTokens;s.walkTokens=function(o){let u=[];return u.push(i.call(this,o)),r&&(u=u.concat(r.call(this,o))),u};}this.defaults={...this.defaults,...s};}),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return x.lex(e,t??this.defaults)}parser(e,t){return b.parse(e,t??this.defaults)}parseMarkdown(e){return (n,s)=>{let r={...s},i={...this.defaults,...r},o=this.onError(!!i.silent,!!i.async);if(this.defaults.async===true&&r.async===false)return o(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));if(typeof n>"u"||n===null)return o(new Error("marked(): input parameter is undefined or null"));if(typeof n!="string")return o(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(n)+", string expected"));if(i.hooks&&(i.hooks.options=i,i.hooks.block=e),i.async)return (async()=>{let u=i.hooks?await i.hooks.preprocess(n):n,c=await(i.hooks?await i.hooks.provideLexer(e):e?x.lex:x.lexInline)(u,i),p=i.hooks?await i.hooks.processAllTokens(c):c;i.walkTokens&&await Promise.all(this.walkTokens(p,i.walkTokens));let h=await(i.hooks?await i.hooks.provideParser(e):e?b.parse:b.parseInline)(p,i);return i.hooks?await i.hooks.postprocess(h):h})().catch(o);try{i.hooks&&(n=i.hooks.preprocess(n));let a=(i.hooks?i.hooks.provideLexer(e):e?x.lex:x.lexInline)(n,i);i.hooks&&(a=i.hooks.processAllTokens(a)),i.walkTokens&&this.walkTokens(a,i.walkTokens);let p=(i.hooks?i.hooks.provideParser(e):e?b.parse:b.parseInline)(a,i);return i.hooks&&(p=i.hooks.postprocess(p)),p}catch(u){return o(u)}}}onError(e,t){return n=>{if(n.message+=`
946
+ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error occurred:</p><pre>"+O(n.message+"",true)+"</pre>";return t?Promise.resolve(s):s}if(t)return Promise.reject(n);throw n}}};var M=new D;function g(l,e){return M.parse(l,e)}g.options=g.setOptions=function(l){return M.setOptions(l),g.defaults=M.defaults,G(g.defaults),g};g.getDefaults=z;g.defaults=T;g.use=function(...l){return M.use(...l),g.defaults=M.defaults,G(g.defaults),g};g.walkTokens=function(l,e){return M.walkTokens(l,e)};g.parseInline=M.parseInline;g.Parser=b;g.parser=b.parse;g.Renderer=y;g.TextRenderer=L;g.Lexer=x;g.lexer=x.lex;g.Tokenizer=w;g.Hooks=P;g.parse=g;g.options;g.setOptions;g.use;g.walkTokens;g.parseInline;b.parse;x.lex;
947
+
948
+ /*! @license DOMPurify 3.4.1 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.1/LICENSE */
949
+
950
+ const {
951
+ entries,
952
+ setPrototypeOf,
953
+ isFrozen,
954
+ getPrototypeOf,
955
+ getOwnPropertyDescriptor
956
+ } = Object;
957
+ let {
958
+ freeze,
959
+ seal,
960
+ create
961
+ } = Object; // eslint-disable-line import/no-mutable-exports
962
+ let {
963
+ apply,
964
+ construct
965
+ } = typeof Reflect !== 'undefined' && Reflect;
993
966
  if (!freeze) {
994
967
  freeze = function freeze(x) {
995
968
  return x;
@@ -1126,10 +1099,7 @@ function cleanArray(array) {
1126
1099
  */
1127
1100
  function clone(object) {
1128
1101
  const newObject = create(null);
1129
- for (const _ref2 of entries(object)) {
1130
- var _ref3 = _slicedToArray(_ref2, 2);
1131
- const property = _ref3[0];
1132
- const value = _ref3[1];
1102
+ for (const [property, value] of entries(object)) {
1133
1103
  const isPropertyExist = objectHasOwnProperty(object, property);
1134
1104
  if (isPropertyExist) {
1135
1105
  if (arrayIsArray(value)) {
@@ -1243,14 +1213,15 @@ const mathMl$1 = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mgly
1243
1213
  const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
1244
1214
  const text = freeze(['#text']);
1245
1215
 
1246
- const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'command', 'commandfor', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns']);
1216
+ const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns']);
1247
1217
  const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'exponent', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'intercept', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'mask-type', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
1248
1218
  const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnalign', 'columnlines', 'columnspacing', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lquote', 'lspace', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
1249
1219
  const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
1250
1220
 
1251
- const MUSTACHE_EXPR = seal(/{{[\w\W]*|^[\w\W]*}}/g);
1252
- const ERB_EXPR = seal(/<%[\w\W]*|^[\w\W]*%>/g);
1253
- const TMPLIT_EXPR = seal(/\${[\w\W]*/g);
1221
+ // eslint-disable-next-line unicorn/better-regex
1222
+ const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
1223
+ const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
1224
+ const TMPLIT_EXPR = seal(/\$\{[\w\W]*/gm); // eslint-disable-line unicorn/better-regex
1254
1225
  const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); // eslint-disable-line no-useless-escape
1255
1226
  const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
1256
1227
  const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
@@ -1261,24 +1232,29 @@ const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205
1261
1232
  const DOCTYPE_NAME = seal(/^html$/i);
1262
1233
  const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
1263
1234
 
1235
+ var EXPRESSIONS = /*#__PURE__*/Object.freeze({
1236
+ __proto__: null,
1237
+ ARIA_ATTR: ARIA_ATTR,
1238
+ ATTR_WHITESPACE: ATTR_WHITESPACE,
1239
+ CUSTOM_ELEMENT: CUSTOM_ELEMENT,
1240
+ DATA_ATTR: DATA_ATTR,
1241
+ DOCTYPE_NAME: DOCTYPE_NAME,
1242
+ ERB_EXPR: ERB_EXPR,
1243
+ IS_ALLOWED_URI: IS_ALLOWED_URI,
1244
+ IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
1245
+ MUSTACHE_EXPR: MUSTACHE_EXPR,
1246
+ TMPLIT_EXPR: TMPLIT_EXPR
1247
+ });
1248
+
1264
1249
  /* eslint-disable @typescript-eslint/indent */
1265
1250
  // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
1266
1251
  const NODE_TYPE = {
1267
1252
  element: 1,
1268
- attribute: 2,
1269
1253
  text: 3,
1270
- cdataSection: 4,
1271
- entityReference: 5,
1272
- // Deprecated
1273
- entityNode: 6,
1274
1254
  // Deprecated
1275
1255
  progressingInstruction: 7,
1276
1256
  comment: 8,
1277
- document: 9,
1278
- documentType: 10,
1279
- documentFragment: 11,
1280
- notation: 12 // Deprecated
1281
- };
1257
+ document: 9};
1282
1258
  const getGlobal = function getGlobal() {
1283
1259
  return typeof window === 'undefined' ? null : window;
1284
1260
  };
@@ -1336,7 +1312,7 @@ const _createHooksMap = function _createHooksMap() {
1336
1312
  function createDOMPurify() {
1337
1313
  let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
1338
1314
  const DOMPurify = root => createDOMPurify(root);
1339
- DOMPurify.version = '3.4.8';
1315
+ DOMPurify.version = '3.4.1';
1340
1316
  DOMPurify.removed = [];
1341
1317
  if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
1342
1318
  // Not running in a browser, provide a factory function
@@ -1344,29 +1320,28 @@ function createDOMPurify() {
1344
1320
  DOMPurify.isSupported = false;
1345
1321
  return DOMPurify;
1346
1322
  }
1347
- let document = window.document;
1323
+ let {
1324
+ document
1325
+ } = window;
1348
1326
  const originalDocument = document;
1349
1327
  const currentScript = originalDocument.currentScript;
1350
- window.DocumentFragment;
1351
- const HTMLTemplateElement = window.HTMLTemplateElement,
1352
- Node = window.Node,
1353
- Element = window.Element,
1354
- NodeFilter = window.NodeFilter,
1355
- _window$NamedNodeMap = window.NamedNodeMap;
1356
- _window$NamedNodeMap === void 0 ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap;
1357
- window.HTMLFormElement;
1358
- const DOMParser = window.DOMParser,
1359
- trustedTypes = window.trustedTypes;
1328
+ const {
1329
+ DocumentFragment,
1330
+ HTMLTemplateElement,
1331
+ Node,
1332
+ Element,
1333
+ NodeFilter,
1334
+ NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,
1335
+ HTMLFormElement,
1336
+ DOMParser,
1337
+ trustedTypes
1338
+ } = window;
1360
1339
  const ElementPrototype = Element.prototype;
1361
1340
  const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
1362
1341
  const remove = lookupGetter(ElementPrototype, 'remove');
1363
1342
  const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
1364
1343
  const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
1365
1344
  const getParentNode = lookupGetter(ElementPrototype, 'parentNode');
1366
- const getShadowRoot = lookupGetter(ElementPrototype, 'shadowRoot');
1367
- const getAttributes = lookupGetter(ElementPrototype, 'attributes');
1368
- const getNodeType = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeType') : null;
1369
- const getNodeName = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeName') : null;
1370
1345
  // As per issue #47, the web-components registry is inherited by a
1371
1346
  // new document created via createHTMLDocument. As per the spec
1372
1347
  // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
@@ -1381,43 +1356,33 @@ function createDOMPurify() {
1381
1356
  }
1382
1357
  let trustedTypesPolicy;
1383
1358
  let emptyHTML = '';
1384
- // Tracks whether we are already inside a call to the configured Trusted Types
1385
- // policy's `createHTML`. If the supplied `TRUSTED_TYPES_POLICY.createHTML`
1386
- // itself calls `DOMPurify.sanitize` (the cause of #1422), `sanitize` would
1387
- // re-enter the policy and recurse until the stack overflows. We detect that
1388
- // re-entry and throw a clear, actionable error instead.
1389
- let IN_POLICY_CREATE_HTML = 0;
1390
- const _createTrustedHTML = function _createTrustedHTML(html) {
1391
- if (IN_POLICY_CREATE_HTML > 0) {
1392
- throw typeErrorCreate('The configured TRUSTED_TYPES_POLICY.createHTML must not call ' + 'DOMPurify.sanitize, as that causes infinite recursion. Do not pass ' + 'a policy whose createHTML wraps DOMPurify as TRUSTED_TYPES_POLICY; ' + 'see the "DOMPurify and Trusted Types" section of the README.');
1393
- }
1394
- IN_POLICY_CREATE_HTML++;
1395
- try {
1396
- return trustedTypesPolicy.createHTML(html);
1397
- } finally {
1398
- IN_POLICY_CREATE_HTML--;
1399
- }
1400
- };
1401
- const _document = document,
1402
- implementation = _document.implementation,
1403
- createNodeIterator = _document.createNodeIterator,
1404
- createDocumentFragment = _document.createDocumentFragment,
1405
- getElementsByTagName = _document.getElementsByTagName;
1406
- const importNode = originalDocument.importNode;
1359
+ const {
1360
+ implementation,
1361
+ createNodeIterator,
1362
+ createDocumentFragment,
1363
+ getElementsByTagName
1364
+ } = document;
1365
+ const {
1366
+ importNode
1367
+ } = originalDocument;
1407
1368
  let hooks = _createHooksMap();
1408
1369
  /**
1409
1370
  * Expose whether this browser supports running the full DOMPurify.
1410
1371
  */
1411
1372
  DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;
1412
- const MUSTACHE_EXPR$1 = MUSTACHE_EXPR,
1413
- ERB_EXPR$1 = ERB_EXPR,
1414
- TMPLIT_EXPR$1 = TMPLIT_EXPR,
1415
- DATA_ATTR$1 = DATA_ATTR,
1416
- ARIA_ATTR$1 = ARIA_ATTR,
1417
- IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA,
1418
- ATTR_WHITESPACE$1 = ATTR_WHITESPACE,
1419
- CUSTOM_ELEMENT$1 = CUSTOM_ELEMENT;
1420
- let IS_ALLOWED_URI$1 = IS_ALLOWED_URI;
1373
+ const {
1374
+ MUSTACHE_EXPR,
1375
+ ERB_EXPR,
1376
+ TMPLIT_EXPR,
1377
+ DATA_ATTR,
1378
+ ARIA_ATTR,
1379
+ IS_SCRIPT_OR_DATA,
1380
+ ATTR_WHITESPACE,
1381
+ CUSTOM_ELEMENT
1382
+ } = EXPRESSIONS;
1383
+ let {
1384
+ IS_ALLOWED_URI: IS_ALLOWED_URI$1
1385
+ } = EXPRESSIONS;
1421
1386
  /**
1422
1387
  * We consider the elements and attributes below to be safe. Ideally
1423
1388
  * don't add any new ones but feel free to remove unwanted ones.
@@ -1725,47 +1690,19 @@ function createDOMPurify() {
1725
1690
  throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');
1726
1691
  }
1727
1692
  // Overwrite existing TrustedTypes policy.
1728
- const previousTrustedTypesPolicy = trustedTypesPolicy;
1729
1693
  trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;
1730
- // Sign local variables required by `sanitize`. If the supplied policy's
1731
- // `createHTML` is circular (i.e. it calls `DOMPurify.sanitize`), this
1732
- // throws via the re-entrancy guard. Restore the previous policy first so
1733
- // the instance is not left in a poisoned state. See #1422.
1734
- try {
1735
- emptyHTML = _createTrustedHTML('');
1736
- } catch (error) {
1737
- trustedTypesPolicy = previousTrustedTypesPolicy;
1738
- throw error;
1739
- }
1694
+ // Sign local variables required by `sanitize`.
1695
+ emptyHTML = trustedTypesPolicy.createHTML('');
1740
1696
  } else {
1741
1697
  // Uninitialized policy, attempt to initialize the internal dompurify policy.
1742
- if (trustedTypesPolicy === undefined && cfg.TRUSTED_TYPES_POLICY !== null) {
1698
+ if (trustedTypesPolicy === undefined) {
1743
1699
  trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
1744
1700
  }
1745
1701
  // If creating the internal policy succeeded sign internal variables.
1746
- // Note: a falsy `trustedTypesPolicy` (null when policy creation failed or
1747
- // was skipped via `TRUSTED_TYPES_POLICY: null`, or undefined when no
1748
- // policy has been initialized yet) must be excluded here, otherwise we
1749
- // would call `.createHTML` on a non-policy and throw. See #1422.
1750
- if (trustedTypesPolicy && typeof emptyHTML === 'string') {
1751
- emptyHTML = _createTrustedHTML('');
1702
+ if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {
1703
+ emptyHTML = trustedTypesPolicy.createHTML('');
1752
1704
  }
1753
1705
  }
1754
- /*
1755
- * Mirror the clone-before-mutate pattern already applied above for
1756
- * cfg.ADD_TAGS / cfg.ADD_ATTR: if any uponSanitize* hook is
1757
- * registered AND the set still points at the default constant,
1758
- * clone it. The hook then mutates the clone (in-call widening
1759
- * still works exactly as documented) and the next default-cfg
1760
- * call rebinds to the untouched original via the reassignment at
1761
- * the top of this function.
1762
- */
1763
- if ((hooks.uponSanitizeElement.length > 0 || hooks.uponSanitizeAttribute.length > 0) && ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
1764
- ALLOWED_TAGS = clone(ALLOWED_TAGS);
1765
- }
1766
- if (hooks.uponSanitizeAttribute.length > 0 && ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
1767
- ALLOWED_ATTR = clone(ALLOWED_ATTR);
1768
- }
1769
1706
  // Prevent further manipulation of configuration.
1770
1707
  // Not available in IE8, Safari 5, etc.
1771
1708
  if (freeze) {
@@ -1925,7 +1862,7 @@ function createDOMPurify() {
1925
1862
  // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)
1926
1863
  dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
1927
1864
  }
1928
- const dirtyPayload = trustedTypesPolicy ? _createTrustedHTML(dirty) : dirty;
1865
+ const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
1929
1866
  /*
1930
1867
  * Use the DOMParser API by default, fallback later if needs be
1931
1868
  * DOMParser not work for svg when has multiple root element.
@@ -1965,142 +1902,23 @@ function createDOMPurify() {
1965
1902
  // eslint-disable-next-line no-bitwise
1966
1903
  NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);
1967
1904
  };
1968
- /**
1969
- * Strip template-engine expressions ({{...}}, ${...}, <%...%>) from the
1970
- * character data of an element subtree. Used as the final safety net for
1971
- * SAFE_FOR_TEMPLATES on every DOM-returning code path so that expressions
1972
- * which only form after text-node normalization (e.g. fragments split across
1973
- * stripped elements) cannot survive into a template-evaluating framework.
1974
- *
1975
- * Walks text/comment/CDATA/processing-instruction nodes and mutates `.data`
1976
- * in place rather than round-tripping through innerHTML. This preserves
1977
- * descendant node references (important for IN_PLACE callers), avoids a
1978
- * serialize/reparse cycle, and reads literal character data — which means
1979
- * `<%...%>` in text content matches the ERB regex against its real bytes
1980
- * instead of the HTML-entity-escaped form innerHTML would produce.
1981
- *
1982
- * Attribute values are not visited here; SAFE_FOR_TEMPLATES handling for
1983
- * attributes is performed during the per-node `_sanitizeAttributes` pass.
1984
- *
1985
- * @param node The root element whose character data should be scrubbed.
1986
- */
1987
- const _scrubTemplateExpressions2 = function _scrubTemplateExpressions(node) {
1988
- var _node$querySelectorAl, _node$querySelectorAl2;
1989
- node.normalize();
1990
- const walker = createNodeIterator.call(node.ownerDocument || node, node,
1991
- // eslint-disable-next-line no-bitwise
1992
- NodeFilter.SHOW_TEXT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_CDATA_SECTION | NodeFilter.SHOW_PROCESSING_INSTRUCTION, null);
1993
- let currentNode = walker.nextNode();
1994
- while (currentNode) {
1995
- let data = currentNode.data;
1996
- arrayForEach([MUSTACHE_EXPR$1, ERB_EXPR$1, TMPLIT_EXPR$1], expr => {
1997
- data = stringReplace(data, expr, ' ');
1998
- });
1999
- currentNode.data = data;
2000
- currentNode = walker.nextNode();
2001
- }
2002
- // NodeIterator does not descend into <template>.content per the DOM spec,
2003
- // so we must explicitly recurse into each template's content fragment,
2004
- // mirroring the approach used by _sanitizeShadowDOM.
2005
- const templates = (_node$querySelectorAl = (_node$querySelectorAl2 = node.querySelectorAll) === null || _node$querySelectorAl2 === void 0 ? void 0 : _node$querySelectorAl2.call(node, 'template')) !== null && _node$querySelectorAl !== void 0 ? _node$querySelectorAl : [];
2006
- arrayForEach(Array.from(templates), tmpl => {
2007
- if (_isDocumentFragment(tmpl.content)) {
2008
- _scrubTemplateExpressions2(tmpl.content);
2009
- }
2010
- });
2011
- };
2012
1905
  /**
2013
1906
  * _isClobbered
2014
1907
  *
2015
- * Detect DOM-clobbering on HTMLFormElement nodes. Form is the only HTML
2016
- * interface with [LegacyOverrideBuiltIns]; a descendant element with a
2017
- * `name` attribute matching a prototype property shadows that property
2018
- * on direct reads. We use this check at the IN_PLACE entry-point and
2019
- * during attribute sanitization to refuse clobbered forms.
2020
- *
2021
1908
  * @param element element to check for clobbering attacks
2022
1909
  * @return true if clobbered, false if safe
2023
1910
  */
2024
1911
  const _isClobbered = function _isClobbered(element) {
2025
- // Realm-independent tag-name probe. If we can't determine the tag
2026
- // name at all, we can't reason about clobbering — return false
2027
- // (the caller's other defences still apply).
2028
- const realTagName = getNodeName ? getNodeName(element) : null;
2029
- if (typeof realTagName !== 'string') {
2030
- return false;
2031
- }
2032
- if (transformCaseFunc(realTagName) !== 'form') {
2033
- return false;
2034
- }
2035
- return typeof element.nodeName !== 'string' || typeof element.textContent !== 'string' || typeof element.removeChild !== 'function' ||
2036
- // Realm-safe NamedNodeMap detection: equality against the cached
2037
- // prototype getter. Clobbered .attributes (e.g. <input name="attributes">)
2038
- // makes the direct read diverge from the cached read; a clean form
2039
- // (same-realm OR foreign-realm) has both reads pointing at the same
2040
- // canonical NamedNodeMap.
2041
- element.attributes !== getAttributes(element) || typeof element.removeAttribute !== 'function' || typeof element.setAttribute !== 'function' || typeof element.namespaceURI !== 'string' || typeof element.insertBefore !== 'function' || typeof element.hasChildNodes !== 'function' ||
2042
- // NodeType clobbering probe. Cached Node.prototype.nodeType getter
2043
- // returns the integer 1 for any Element regardless of realm; direct
2044
- // read on a clobbered form (e.g. <input name="nodeType">) returns
2045
- // the named child element. Cheap addition — nodeType is read from
2046
- // an internal slot, no serialization cost — and removes a residual
2047
- // clobbering surface used by several mXSS / PI / comment branches
2048
- // in _sanitizeElements that compare currentNode.nodeType directly.
2049
- element.nodeType !== getNodeType(element) ||
2050
- // HTMLFormElement has [LegacyOverrideBuiltIns]: a descendant named
2051
- // "childNodes" shadows the prototype getter. Direct reads of
2052
- // form.childNodes from a clobbered form return the named child
2053
- // instead of the real NodeList, so any walk that reads it directly
2054
- // skips the form's real children. Compare the direct read to the
2055
- // cached Node.prototype getter — when the form's named-property
2056
- // getter intercepts the read, the two values differ and we flag
2057
- // the form. This catches every clobbering child type (input,
2058
- // select, etc.) regardless of whether the named child happens to
2059
- // carry a numeric .length, which a typeof-based probe would miss
2060
- // (e.g. HTMLSelectElement.length is a defined unsigned-long).
2061
- element.childNodes !== getChildNodes(element);
1912
+ return element instanceof HTMLFormElement && (typeof element.nodeName !== 'string' || typeof element.textContent !== 'string' || typeof element.removeChild !== 'function' || !(element.attributes instanceof NamedNodeMap) || typeof element.removeAttribute !== 'function' || typeof element.setAttribute !== 'function' || typeof element.namespaceURI !== 'string' || typeof element.insertBefore !== 'function' || typeof element.hasChildNodes !== 'function');
2062
1913
  };
2063
1914
  /**
2064
- * Checks whether the given value is a DocumentFragment from any realm.
2065
- *
2066
- * The realm-independent replacement reads `nodeType` through the cached
2067
- * Node.prototype getter and compares to the DOCUMENT_FRAGMENT_NODE
2068
- * constant (11). nodeType is a numeric value resolved from the node's
2069
- * internal slot, identical across realms for the same kind of node.
2070
- *
2071
- * @param value object to check
2072
- * @return true if value is a DocumentFragment-shaped node from any realm
2073
- */
2074
- const _isDocumentFragment = function _isDocumentFragment(value) {
2075
- if (!getNodeType || typeof value !== 'object' || value === null) {
2076
- return false;
2077
- }
2078
- try {
2079
- return getNodeType(value) === NODE_TYPE.documentFragment;
2080
- } catch (_) {
2081
- return false;
2082
- }
2083
- };
2084
- /**
2085
- * Checks whether the given object is a DOM node, including nodes that
2086
- * originate from a different window/realm (e.g. an iframe's
2087
- * contentDocument). The previous `value instanceof Node` check was
2088
- * realm-bound: nodes from a different window failed it, causing
2089
- * sanitize() to silently stringify them and reset IN_PLACE to false,
2090
- * returning the original node unsanitized. See GHSA-4w3q-35jp-p934.
1915
+ * Checks whether the given object is a DOM node.
2091
1916
  *
2092
1917
  * @param value object to check whether it's a DOM node
2093
- * @return true if value is a DOM node from any realm
1918
+ * @return true is object is a DOM node
2094
1919
  */
2095
1920
  const _isNode = function _isNode(value) {
2096
- if (!getNodeType || typeof value !== 'object' || value === null) {
2097
- return false;
2098
- }
2099
- try {
2100
- return typeof getNodeType(value) === 'number';
2101
- } catch (_) {
2102
- return false;
2103
- }
1921
+ return typeof Node === 'function' && value instanceof Node;
2104
1922
  };
2105
1923
  function _executeHooks(hooks, currentNode, data) {
2106
1924
  arrayForEach(hooks, hook => {
@@ -2126,7 +1944,7 @@ function createDOMPurify() {
2126
1944
  return true;
2127
1945
  }
2128
1946
  /* Now let's check the element's type and name */
2129
- const tagName = transformCaseFunc(getNodeName ? getNodeName(currentNode) : currentNode.nodeName);
1947
+ const tagName = transformCaseFunc(currentNode.nodeName);
2130
1948
  /* Execute a hook if present */
2131
1949
  _executeHooks(hooks.uponSanitizeElement, currentNode, {
2132
1950
  tagName,
@@ -2163,17 +1981,10 @@ function createDOMPurify() {
2163
1981
  return false;
2164
1982
  }
2165
1983
  }
2166
- /* Keep content except for bad-listed elements.
2167
- Use the cached prototype getters exclusively — the previous code
2168
- had `|| currentNode.parentNode` / `|| currentNode.childNodes`
2169
- fallbacks, but the cached getters always return the canonical
2170
- value (or null for a real parent-less node), so the fallback
2171
- path was dead in safe cases and a clobbering surface in unsafe
2172
- ones. Falsy cached results stay falsy; the `if (childNodes &&
2173
- parentNode)` check already gates correctly. */
1984
+ /* Keep content except for bad-listed elements */
2174
1985
  if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
2175
- const parentNode = getParentNode(currentNode);
2176
- const childNodes = getChildNodes(currentNode);
1986
+ const parentNode = getParentNode(currentNode) || currentNode.parentNode;
1987
+ const childNodes = getChildNodes(currentNode) || currentNode.childNodes;
2177
1988
  if (childNodes && parentNode) {
2178
1989
  const childCount = childNodes.length;
2179
1990
  for (let i = childCount - 1; i >= 0; --i) {
@@ -2185,14 +1996,8 @@ function createDOMPurify() {
2185
1996
  _forceRemove(currentNode);
2186
1997
  return true;
2187
1998
  }
2188
- /* Check whether element has a valid namespace.
2189
- Realm-safe check (GHSA-hpcv-96wg-7vj8): use the cached Node.prototype
2190
- nodeType getter rather than `instanceof Element`, which is realm-
2191
- bound and short-circuits to false for any node minted in a different
2192
- realm — letting a foreign-realm element with a forbidden namespace
2193
- slip past the namespace check entirely. */
2194
- const nt = getNodeType ? getNodeType(currentNode) : currentNode.nodeType;
2195
- if (nt === NODE_TYPE.element && !_checkValidNamespace(currentNode)) {
1999
+ /* Check whether element has a valid namespace */
2000
+ if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
2196
2001
  _forceRemove(currentNode);
2197
2002
  return true;
2198
2003
  }
@@ -2205,7 +2010,7 @@ function createDOMPurify() {
2205
2010
  if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
2206
2011
  /* Get the element's text content */
2207
2012
  content = currentNode.textContent;
2208
- arrayForEach([MUSTACHE_EXPR$1, ERB_EXPR$1, TMPLIT_EXPR$1], expr => {
2013
+ arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
2209
2014
  content = stringReplace(content, expr, ' ');
2210
2015
  });
2211
2016
  if (currentNode.textContent !== content) {
@@ -2237,12 +2042,11 @@ function createDOMPurify() {
2237
2042
  if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
2238
2043
  return false;
2239
2044
  }
2240
- const nameIsPermitted = ALLOWED_ATTR[lcName] || EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag);
2241
2045
  /* Allow valid data-* attributes: At least one character after "-"
2242
2046
  (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
2243
2047
  XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
2244
2048
  We don't need to check the value; it's always URI safe. */
2245
- if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR$1, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$1, lcName)) ; else if (!nameIsPermitted || FORBID_ATTR[lcName]) {
2049
+ if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ; else if (EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
2246
2050
  if (
2247
2051
  // First condition does a very basic check if a) it's basically a valid custom element tagname AND
2248
2052
  // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
@@ -2254,7 +2058,7 @@ function createDOMPurify() {
2254
2058
  return false;
2255
2059
  }
2256
2060
  /* Check value is safe. First, is attr inert? If so, is safe */
2257
- } else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE$1, ''))) ; else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ; else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$1, stringReplace(value, ATTR_WHITESPACE$1, ''))) ; else if (value) {
2061
+ } else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ; else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if (value) {
2258
2062
  return false;
2259
2063
  } else ;
2260
2064
  return true;
@@ -2272,7 +2076,7 @@ function createDOMPurify() {
2272
2076
  * @returns Returns true if the tag name meets the basic criteria for a custom element, otherwise false.
2273
2077
  */
2274
2078
  const _isBasicCustomElement = function _isBasicCustomElement(tagName) {
2275
- return !RESERVED_CUSTOM_ELEMENT_NAMES[stringToLowerCase(tagName)] && regExpTest(CUSTOM_ELEMENT$1, tagName);
2079
+ return !RESERVED_CUSTOM_ELEMENT_NAMES[stringToLowerCase(tagName)] && regExpTest(CUSTOM_ELEMENT, tagName);
2276
2080
  };
2277
2081
  /**
2278
2082
  * _sanitizeAttributes
@@ -2287,7 +2091,9 @@ function createDOMPurify() {
2287
2091
  const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
2288
2092
  /* Execute a hook if present */
2289
2093
  _executeHooks(hooks.beforeSanitizeAttributes, currentNode, null);
2290
- const attributes = currentNode.attributes;
2094
+ const {
2095
+ attributes
2096
+ } = currentNode;
2291
2097
  /* Check if we have attributes; if not we might have a text node */
2292
2098
  if (!attributes || _isClobbered(currentNode)) {
2293
2099
  return;
@@ -2303,9 +2109,11 @@ function createDOMPurify() {
2303
2109
  /* Go backwards over all attributes; safely remove bad ones */
2304
2110
  while (l--) {
2305
2111
  const attr = attributes[l];
2306
- const name = attr.name,
2307
- namespaceURI = attr.namespaceURI,
2308
- attrValue = attr.value;
2112
+ const {
2113
+ name,
2114
+ namespaceURI,
2115
+ value: attrValue
2116
+ } = attr;
2309
2117
  const lcName = transformCaseFunc(name);
2310
2118
  const initValue = attrValue;
2311
2119
  let value = name === 'value' ? initValue : stringTrim(initValue);
@@ -2353,7 +2161,7 @@ function createDOMPurify() {
2353
2161
  }
2354
2162
  /* Sanitize attribute content to be template-safe */
2355
2163
  if (SAFE_FOR_TEMPLATES) {
2356
- arrayForEach([MUSTACHE_EXPR$1, ERB_EXPR$1, TMPLIT_EXPR$1], expr => {
2164
+ arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
2357
2165
  value = stringReplace(value, expr, ' ');
2358
2166
  });
2359
2167
  }
@@ -2369,7 +2177,7 @@ function createDOMPurify() {
2369
2177
  switch (trustedTypes.getAttributeType(lcTag, lcName)) {
2370
2178
  case 'TrustedHTML':
2371
2179
  {
2372
- value = _createTrustedHTML(value);
2180
+ value = trustedTypesPolicy.createHTML(value);
2373
2181
  break;
2374
2182
  }
2375
2183
  case 'TrustedScriptURL':
@@ -2419,98 +2227,14 @@ function createDOMPurify() {
2419
2227
  _sanitizeElements(shadowNode);
2420
2228
  /* Check attributes next */
2421
2229
  _sanitizeAttributes(shadowNode);
2422
- /* Deep shadow DOM detected.
2423
- Realm-safe check (GHSA-hpcv-96wg-7vj8): use nodeType against the
2424
- DOCUMENT_FRAGMENT_NODE constant rather than instanceof, so we
2425
- recurse into <template>.content from foreign realms too. */
2426
- if (_isDocumentFragment(shadowNode.content)) {
2230
+ /* Deep shadow DOM detected */
2231
+ if (shadowNode.content instanceof DocumentFragment) {
2427
2232
  _sanitizeShadowDOM2(shadowNode.content);
2428
2233
  }
2429
- /* An element iterated here may itself host an attached
2430
- shadow root. The default NodeIterator does not enter shadow
2431
- trees, so a shadow root nested inside template.content was
2432
- previously reached by no walk at all (the pre-pass at
2433
- _sanitizeAttachedShadowRoots descends via childNodes, which
2434
- doesn't enter template.content; the template-content recursion
2435
- above iterates the content but never inspected shadowRoot).
2436
- Walk it explicitly. The nodeType guard avoids reading
2437
- shadowRoot off text / comment / CDATA / PI nodes that the
2438
- iterator also surfaces. */
2439
- const shadowNodeType = getNodeType ? getNodeType(shadowNode) : shadowNode.nodeType;
2440
- if (shadowNodeType === NODE_TYPE.element) {
2441
- const innerSr = getShadowRoot ? getShadowRoot(shadowNode) : shadowNode.shadowRoot;
2442
- if (_isDocumentFragment(innerSr)) {
2443
- _sanitizeAttachedShadowRoots2(innerSr);
2444
- _sanitizeShadowDOM2(innerSr);
2445
- }
2446
- }
2447
2234
  }
2448
2235
  /* Execute a hook if present */
2449
2236
  _executeHooks(hooks.afterSanitizeShadowDOM, fragment, null);
2450
2237
  };
2451
- /**
2452
- * _sanitizeAttachedShadowRoots
2453
- *
2454
- * Walks `root` and feeds every attached shadow root we encounter into
2455
- * the existing _sanitizeShadowDOM pipeline. The default node iterator
2456
- * does not descend into shadow trees, so nodes inside an attached
2457
- * shadow root would otherwise be skipped entirely.
2458
- *
2459
- * Two real input paths put attached shadow roots in front of us:
2460
- * 1. IN_PLACE on a DOM node that already has shadow roots attached.
2461
- * 2. DOM-node input where importNode(dirty, true) deep-clones the
2462
- * shadow root because it was created with `clonable: true`.
2463
- *
2464
- * This pass runs once, up front, so the main iteration loop (and the
2465
- * existing _sanitizeShadowDOM template-content recursion) stay
2466
- * untouched — string-input paths are not affected.
2467
- *
2468
- * @param root the subtree root to walk for attached shadow roots
2469
- */
2470
- const _sanitizeAttachedShadowRoots2 = function _sanitizeAttachedShadowRoots(root) {
2471
- const nodeType = getNodeType ? getNodeType(root) : root.nodeType;
2472
- if (nodeType === NODE_TYPE.element) {
2473
- const sr = getShadowRoot ? getShadowRoot(root) : root.shadowRoot;
2474
- // Realm-safe check (GHSA-hpcv-96wg-7vj8): use nodeType-based
2475
- // detection rather than `instanceof DocumentFragment`, which is
2476
- // realm-bound and silently skipped shadow roots whose host element
2477
- // belonged to a foreign realm (e.g. iframe.contentDocument
2478
- // attachShadow). A foreign-realm ShadowRoot extends the foreign
2479
- // realm's DocumentFragment, not ours, so the old instanceof check
2480
- // returned false and the shadow subtree was never walked.
2481
- if (_isDocumentFragment(sr)) {
2482
- // Recurse first so that nested shadow roots are reached even if
2483
- // _sanitizeShadowDOM removes hosts at this level.
2484
- _sanitizeAttachedShadowRoots2(sr);
2485
- _sanitizeShadowDOM2(sr);
2486
- }
2487
- }
2488
- // Snapshot children before recursing. Sanitization of one subtree
2489
- // (e.g. via an uponSanitizeShadowNode hook) may detach siblings,
2490
- // and naive nextSibling traversal would silently skip the rest of
2491
- // the list once a node is detached.
2492
- const childNodes = getChildNodes ? getChildNodes(root) : root.childNodes;
2493
- if (!childNodes) {
2494
- return;
2495
- }
2496
- const snapshot = [];
2497
- arrayForEach(childNodes, child => {
2498
- arrayPush(snapshot, child);
2499
- });
2500
- for (const child of snapshot) {
2501
- _sanitizeAttachedShadowRoots2(child);
2502
- }
2503
- /* When the root is a <template>, also descend into root.content */
2504
- if (nodeType === NODE_TYPE.element) {
2505
- const rootName = getNodeName ? getNodeName(root) : null;
2506
- if (typeof rootName === 'string' && transformCaseFunc(rootName) === 'template') {
2507
- const content = root.content;
2508
- if (_isDocumentFragment(content)) {
2509
- _sanitizeAttachedShadowRoots2(content);
2510
- }
2511
- }
2512
- }
2513
- };
2514
2238
  // eslint-disable-next-line complexity
2515
2239
  DOMPurify.sanitize = function (dirty) {
2516
2240
  let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
@@ -2547,35 +2271,15 @@ function createDOMPurify() {
2547
2271
  IN_PLACE = false;
2548
2272
  }
2549
2273
  if (IN_PLACE) {
2550
- /* Do some early pre-sanitization to avoid unsafe root nodes.
2551
- Read nodeName through the cached prototype getter — a clobbering
2552
- child named "nodeName" on the form root would otherwise shadow
2553
- the property and let this check skip the root-allowlist
2554
- validation entirely. */
2555
- const nn = getNodeName ? getNodeName(dirty) : dirty.nodeName;
2274
+ /* Do some early pre-sanitization to avoid unsafe root nodes */
2275
+ const nn = dirty.nodeName;
2556
2276
  if (typeof nn === 'string') {
2557
2277
  const tagName = transformCaseFunc(nn);
2558
2278
  if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
2559
2279
  throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
2560
2280
  }
2561
2281
  }
2562
- /* Pre-flight the root through _isClobbered. The iterator-driven
2563
- removal path can not detach a parent-less root: _forceRemove
2564
- falls through to Element.prototype.remove(), which per spec
2565
- is a no-op on a node with no parent. A clobbered root would
2566
- then survive the main loop with its attributes uninspected,
2567
- because _sanitizeAttributes early-returns on _isClobbered. The
2568
- result would be an attacker-controlled form, complete with any
2569
- event-handler attributes the caller passed in, handed back to
2570
- the application unsanitized. Refuse to sanitize such a root
2571
- the same way we refuse a forbidden tag. GHSA-r47g-fvhr-h676. */
2572
- if (_isClobbered(dirty)) {
2573
- throw typeErrorCreate('root node is clobbered and cannot be sanitized in-place');
2574
- }
2575
- /* Sanitize attached shadow roots before the main iterator runs.
2576
- The iterator does not descend into shadow trees. */
2577
- _sanitizeAttachedShadowRoots2(dirty);
2578
- } else if (_isNode(dirty)) {
2282
+ } else if (dirty instanceof Node) {
2579
2283
  /* If dirty is a DOM element, append to an empty document to avoid
2580
2284
  elements being stripped by the parser */
2581
2285
  body = _initDocument('<!---->');
@@ -2589,18 +2293,12 @@ function createDOMPurify() {
2589
2293
  // eslint-disable-next-line unicorn/prefer-dom-node-append
2590
2294
  body.appendChild(importedNode);
2591
2295
  }
2592
- /* Clonable shadow roots are deep-cloned by importNode(); sanitize
2593
- them before the main iterator runs, since the iterator does not
2594
- descend into shadow trees. The walk routes every read through a
2595
- cached prototype getter so clobbering descendants on a form root
2596
- cannot hide a shadow host from this pass. */
2597
- _sanitizeAttachedShadowRoots2(importedNode);
2598
2296
  } else {
2599
2297
  /* Exit directly if we have nothing to do */
2600
2298
  if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&
2601
2299
  // eslint-disable-next-line unicorn/prefer-includes
2602
2300
  dirty.indexOf('<') === -1) {
2603
- return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(dirty) : dirty;
2301
+ return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
2604
2302
  }
2605
2303
  /* Initialize the document to work on */
2606
2304
  body = _initDocument(dirty);
@@ -2621,25 +2319,24 @@ function createDOMPurify() {
2621
2319
  _sanitizeElements(currentNode);
2622
2320
  /* Check attributes next */
2623
2321
  _sanitizeAttributes(currentNode);
2624
- /* Shadow DOM detected, sanitize it.
2625
- Realm-safe check (GHSA-hpcv-96wg-7vj8): nodeType-based detection
2626
- instead of instanceof, so foreign-realm <template>.content is
2627
- walked correctly. */
2628
- if (_isDocumentFragment(currentNode.content)) {
2322
+ /* Shadow DOM detected, sanitize it */
2323
+ if (currentNode.content instanceof DocumentFragment) {
2629
2324
  _sanitizeShadowDOM2(currentNode.content);
2630
2325
  }
2631
2326
  }
2632
2327
  /* If we sanitized `dirty` in-place, return it. */
2633
2328
  if (IN_PLACE) {
2634
- if (SAFE_FOR_TEMPLATES) {
2635
- _scrubTemplateExpressions2(dirty);
2636
- }
2637
2329
  return dirty;
2638
2330
  }
2639
2331
  /* Return sanitized string or DOM */
2640
2332
  if (RETURN_DOM) {
2641
2333
  if (SAFE_FOR_TEMPLATES) {
2642
- _scrubTemplateExpressions2(body);
2334
+ body.normalize();
2335
+ let html = body.innerHTML;
2336
+ arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
2337
+ html = stringReplace(html, expr, ' ');
2338
+ });
2339
+ body.innerHTML = html;
2643
2340
  }
2644
2341
  if (RETURN_DOM_FRAGMENT) {
2645
2342
  returnNode = createDocumentFragment.call(body.ownerDocument);
@@ -2669,11 +2366,11 @@ function createDOMPurify() {
2669
2366
  }
2670
2367
  /* Sanitize final string template-safe */
2671
2368
  if (SAFE_FOR_TEMPLATES) {
2672
- arrayForEach([MUSTACHE_EXPR$1, ERB_EXPR$1, TMPLIT_EXPR$1], expr => {
2369
+ arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
2673
2370
  serializedHTML = stringReplace(serializedHTML, expr, ' ');
2674
2371
  });
2675
2372
  }
2676
- return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(serializedHTML) : serializedHTML;
2373
+ return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
2677
2374
  };
2678
2375
  DOMPurify.setConfig = function () {
2679
2376
  let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
@@ -2720,7 +2417,6 @@ var purify = createDOMPurify();
2720
2417
  * 预设主题配置
2721
2418
  * 提供多种常用主题,用户可以直接使用或自定义
2722
2419
  */
2723
-
2724
2420
  /**
2725
2421
  * 默认主题(蓝色渐变)
2726
2422
  */
@@ -2771,7 +2467,6 @@ const DEFAULT_THEME = {
2771
2467
  button: '0 4px 12px rgba(24, 144, 255, 0.35)'
2772
2468
  }
2773
2469
  };
2774
-
2775
2470
  /**
2776
2471
  * 深色主题
2777
2472
  */
@@ -2822,7 +2517,6 @@ const DARK_THEME = {
2822
2517
  button: '0 4px 12px rgba(24, 144, 255, 0.4)'
2823
2518
  }
2824
2519
  };
2825
-
2826
2520
  /**
2827
2521
  * 清新主题(绿色系)
2828
2522
  */
@@ -2873,7 +2567,6 @@ const FRESH_THEME = {
2873
2567
  button: '0 4px 12px rgba(82, 196, 26, 0.35)'
2874
2568
  }
2875
2569
  };
2876
-
2877
2570
  /**
2878
2571
  * 活力主题(橙色系)
2879
2572
  */
@@ -2924,7 +2617,6 @@ const VIBRANT_THEME = {
2924
2617
  button: '0 4px 12px rgba(250, 140, 22, 0.35)'
2925
2618
  }
2926
2619
  };
2927
-
2928
2620
  /**
2929
2621
  * 浪漫主题(粉色系)
2930
2622
  */
@@ -2975,7 +2667,6 @@ const ROMANTIC_THEME = {
2975
2667
  button: '0 4px 12px rgba(235, 47, 150, 0.35)'
2976
2668
  }
2977
2669
  };
2978
-
2979
2670
  /**
2980
2671
  * 紫色主题(优雅神秘)
2981
2672
  */
@@ -3026,7 +2717,6 @@ const PURPLE_THEME = {
3026
2717
  button: '0 4px 12px rgba(114, 46, 209, 0.35)'
3027
2718
  }
3028
2719
  };
3029
-
3030
2720
  /**
3031
2721
  * 海洋主题(深蓝深海)
3032
2722
  */
@@ -3077,7 +2767,6 @@ const OCEAN_THEME = {
3077
2767
  button: '0 4px 12px rgba(0, 119, 182, 0.35)'
3078
2768
  }
3079
2769
  };
3080
-
3081
2770
  /**
3082
2771
  * 暮光主题(紫罗兰渐变)
3083
2772
  */
@@ -3128,7 +2817,6 @@ const TWILIGHT_THEME = {
3128
2817
  button: '0 4px 12px rgba(147, 51, 234, 0.35)'
3129
2818
  }
3130
2819
  };
3131
-
3132
2820
  /**
3133
2821
  * 薄荷主题(青绿色)
3134
2822
  */
@@ -3179,7 +2867,6 @@ const MINT_THEME = {
3179
2867
  button: '0 4px 12px rgba(20, 184, 166, 0.35)'
3180
2868
  }
3181
2869
  };
3182
-
3183
2870
  /**
3184
2871
  * 玫瑰主题(深红色)
3185
2872
  */
@@ -3230,7 +2917,6 @@ const ROSE_THEME = {
3230
2917
  button: '0 4px 12px rgba(225, 29, 72, 0.35)'
3231
2918
  }
3232
2919
  };
3233
-
3234
2920
  /**
3235
2921
  * 极光主题(蓝绿渐变)
3236
2922
  */
@@ -3281,7 +2967,6 @@ const AURORA_THEME = {
3281
2967
  button: '0 4px 12px rgba(14, 165, 233, 0.35)'
3282
2968
  }
3283
2969
  };
3284
-
3285
2970
  /**
3286
2971
  * 薰衣草主题(淡紫色)
3287
2972
  */
@@ -3332,7 +3017,6 @@ const LAVENDER_THEME = {
3332
3017
  button: '0 4px 12px rgba(139, 92, 246, 0.35)'
3333
3018
  }
3334
3019
  };
3335
-
3336
3020
  /**
3337
3021
  * 珊瑚主题(粉橙色)
3338
3022
  */
@@ -3383,7 +3067,6 @@ const CORAL_THEME = {
3383
3067
  button: '0 4px 12px rgba(249, 115, 22, 0.35)'
3384
3068
  }
3385
3069
  };
3386
-
3387
3070
  /**
3388
3071
  * 翡翠主题(深绿色)
3389
3072
  */
@@ -3434,7 +3117,6 @@ const JADE_THEME = {
3434
3117
  button: '0 4px 12px rgba(5, 150, 105, 0.35)'
3435
3118
  }
3436
3119
  };
3437
-
3438
3120
  /**
3439
3121
  * 星空主题(深蓝紫色)
3440
3122
  */
@@ -3485,7 +3167,6 @@ const STARSKY_THEME = {
3485
3167
  button: '0 4px 12px rgba(99, 102, 241, 0.4)'
3486
3168
  }
3487
3169
  };
3488
-
3489
3170
  /**
3490
3171
  * 日落主题(暖色调)
3491
3172
  */
@@ -3536,7 +3217,6 @@ const SUNSET_THEME = {
3536
3217
  button: '0 4px 12px rgba(234, 88, 12, 0.35)'
3537
3218
  }
3538
3219
  };
3539
-
3540
3220
  /**
3541
3221
  * 所有预设主题列表
3542
3222
  */
@@ -3562,27 +3242,21 @@ const PRESET_THEMES = {
3562
3242
  /**
3563
3243
  * AIChatDialog - 纯JavaScript实现的AI对话组件 (Web Components)
3564
3244
  * 样式与功能完全对齐 Vue 版本(1:1 复刻)
3565
- *
3245
+ *
3566
3246
  * @author IBC AI Team
3567
3247
  * @version 2.1.0
3568
3248
  */
3569
-
3570
-
3249
+ // 导入 marked Markdown 解析库 + DOMPurify XSS防护 + 主题配置
3571
3250
  // 运行时占位符(对齐 portal)
3572
3251
  const RUNTIME_PLACEHOLDERS = ['请求已受理', '任务已受理', '正在思考', '正在执行', '结果处理中', '已进入助手运行时', '任务运行时', 'SSE 连接已建立'];
3573
3252
  const DEFAULT_DIALOG_TOP = '96px';
3574
-
3575
3253
  // ========== marked 配置(安全且功能完整) ==========
3254
+ // marked v18 移除了 headerIds/mangle,仅保留 breaks 和 gfm
3576
3255
  g.setOptions({
3577
3256
  breaks: true,
3578
3257
  // 支持GFM换行(单换行变<br>)
3579
- gfm: true,
3580
- // GitHub Flavored Markdown
3581
- headerIds: false,
3582
- // 不生成标题id
3583
- mangle: false // 不转义邮箱
3584
- });
3585
-
3258
+ gfm: true // GitHub Flavored Markdown
3259
+ } /* marked v18 types are strict */);
3586
3260
  // Vue themes.js 的 camelCase key → JS _themeVars CSS变量名 映射表
3587
3261
  const THEME_COLOR_KEY_MAP = {
3588
3262
  primary: '--ai-primary',
@@ -3611,14 +3285,82 @@ const THEME_COLOR_KEY_MAP = {
3611
3285
  error: '--ai-error',
3612
3286
  warning: '--ai-warning'
3613
3287
  };
3614
-
3615
3288
  // ========== 16种预设主题(与Vue版themes.js完全一致) ==========
3616
3289
  class AIChatDialog extends HTMLElement {
3290
+ // ====== 类型声明(HTMLElement 子类必需) ======
3617
3291
  static get observedAttributes() {
3618
3292
  return ['visible'];
3619
3293
  }
3620
3294
  constructor() {
3621
3295
  super();
3296
+ // 核心状态
3297
+ this._messages = [];
3298
+ this._isLoading = false;
3299
+ this._config = null;
3300
+ this._mockMode = false;
3301
+ this._isDragging = false;
3302
+ this._isExpanded = false;
3303
+ this._chatClient = null;
3304
+ this._attachments = [];
3305
+ this._dragStartX = 0;
3306
+ this._dragStartY = 0;
3307
+ this._dialogX = 0;
3308
+ this._dialogY = 0;
3309
+ this._appDetail = null;
3310
+ this._historyVisible = false;
3311
+ this._historyRecords = [];
3312
+ this._historyLoading = false;
3313
+ this._historyLoaded = false;
3314
+ this._historyPageIndex = 1;
3315
+ this._historyHasMore = false;
3316
+ this._isMobile = false;
3317
+ // 流式渲染
3318
+ this._streamTextEl = null;
3319
+ this._streamInitDone = false;
3320
+ this._streamFullText = '';
3321
+ this._streamVisibleLength = 0;
3322
+ this._streamTypeRaf = null;
3323
+ this._streaming = false;
3324
+ // 运行时面板
3325
+ this._runtimePanelEl = null;
3326
+ this._runtimeEventsContainerEl = null;
3327
+ this._runtimeStatusEl = null;
3328
+ this._runtimeCountEl = null;
3329
+ // 页面上下文
3330
+ this._context = {};
3331
+ // 主题
3332
+ this._themeVars = {};
3333
+ // 事件处理器引用(用于清理)
3334
+ this._handleOnline = null;
3335
+ this._handleOffline = null;
3336
+ this._handleResize = null;
3337
+ // DOM 缓存引用
3338
+ this._dialog = null;
3339
+ this._body = null;
3340
+ this._input = null;
3341
+ this._sendBtn = null;
3342
+ this._attachBtn = null;
3343
+ this._attachmentInput = null;
3344
+ this._closeBtn = null;
3345
+ this._expandBtn = null;
3346
+ this._newChatBtn = null;
3347
+ this._historyBtn = null;
3348
+ this._floatBtn = null;
3349
+ this._inputContainer = null;
3350
+ // 会话
3351
+ this._conversationId = null;
3352
+ // 防抖
3353
+ this._lastSendTime = 0;
3354
+ // 拖拽处理器引用
3355
+ this._dragMouseDownHandler = null;
3356
+ this._dragMouseMoveHandler = null;
3357
+ this._dragMouseUpHandler = null;
3358
+ this._dragTouchStartHandler = null;
3359
+ this._dragTouchMoveHandler = null;
3360
+ this._dragTouchEndHandler = null;
3361
+ this._dragInitialized = false;
3362
+ // 错误标记
3363
+ this._ERROR_CONTENT_PATTERNS = ['(请求超时', '(等待AI处理', '(无回复)', '(已停止)', '(AI 处理超时', '错误:', '网络错误:', '抱歉,'];
3622
3364
  this.attachShadow({
3623
3365
  mode: 'open'
3624
3366
  });
@@ -3655,7 +3397,8 @@ class AIChatDialog extends HTMLElement {
3655
3397
  this._runtimeEventsContainerEl = null;
3656
3398
  this._runtimeStatusEl = null;
3657
3399
  this._runtimeCountEl = null;
3658
-
3400
+ // P3: 页面上下文数据(宿主页面选中的数据)
3401
+ this._context = {};
3659
3402
  // ====== 默认主题配置(与 themes.js DEFAULT_THEME 完全一致) ======
3660
3403
  this._themeVars = {
3661
3404
  '--ai-primary': '#1890ff',
@@ -3698,9 +3441,7 @@ class AIChatDialog extends HTMLElement {
3698
3441
  this.render();
3699
3442
  this.bindEvents();
3700
3443
  }
3701
-
3702
3444
  // ==================== 生命周期 ====================
3703
-
3704
3445
  connectedCallback() {
3705
3446
  // P1-8: 网络状态监控(与Vue版一致)
3706
3447
  this._handleOnline = () => {
@@ -3713,12 +3454,11 @@ class AIChatDialog extends HTMLElement {
3713
3454
  tip.className = 'network-tip';
3714
3455
  tip.textContent = '网络连接已断开,请检查网络后重试';
3715
3456
  this._dialog?.prepend(tip);
3716
- setTimeout(() => tip.remove(), 5000);
3457
+ window.setTimeout(() => tip.remove(), 5000);
3717
3458
  }
3718
3459
  };
3719
3460
  window.addEventListener('online', this._handleOnline);
3720
3461
  window.addEventListener('offline', this._handleOffline);
3721
-
3722
3462
  // P2-17: 移动端环境检测(与Vue版 detectEnvironment 一致)
3723
3463
  this._detectMobile();
3724
3464
  // P2-17: 窗口resize时重新检测移动端
@@ -3731,7 +3471,6 @@ class AIChatDialog extends HTMLElement {
3731
3471
  }
3732
3472
  };
3733
3473
  window.addEventListener('resize', this._handleResize);
3734
-
3735
3474
  // 恢复后台Token刷新定时器(SPA路由切换后 re-attach 场景)
3736
3475
  if (this._chatClient) this._chatClient.startBackgroundRefresh();
3737
3476
  }
@@ -3741,13 +3480,14 @@ class AIChatDialog extends HTMLElement {
3741
3480
  if (this._handleOffline) window.removeEventListener('offline', this._handleOffline);
3742
3481
  // P2-17: 清理resize监听
3743
3482
  if (this._handleResize) window.removeEventListener('resize', this._handleResize);
3483
+ // P0: 清理拖拽事件监听
3484
+ this._cleanupDragListeners();
3744
3485
  // 暂停后台Token刷新定时器(detach时停止,re-attach时由connectedCallback恢复)
3745
3486
  if (this._chatClient) {
3746
3487
  this._chatClient.stopBackgroundRefresh();
3747
3488
  this._chatClient.cancelCurrentRequest();
3748
3489
  }
3749
3490
  }
3750
-
3751
3491
  // P2-17: 移动端4维检测(与Vue版 isMobileDevice 计算属性完全一致)
3752
3492
  _detectMobile() {
3753
3493
  // 1. 优先使用显式配置
@@ -3755,31 +3495,25 @@ class AIChatDialog extends HTMLElement {
3755
3495
  this._isMobile = !!this._config.mobileMode;
3756
3496
  return;
3757
3497
  }
3758
-
3759
3498
  // 2. 微信小程序环境检测
3760
3499
  if (typeof wx !== 'undefined' && wx.getSystemInfoSync) {
3761
3500
  this._isMobile = true;
3762
3501
  return;
3763
3502
  }
3764
-
3765
3503
  // 3. 浏览器环境
3766
3504
  if (typeof window === 'undefined') {
3767
3505
  this._isMobile = false;
3768
3506
  return;
3769
3507
  }
3770
-
3771
3508
  // 4. User Agent 正则匹配
3772
3509
  const ua = navigator.userAgent || '';
3773
3510
  const isMobileUA = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua);
3774
-
3775
3511
  // 5. 屏幕宽度 < 768px + 触摸支持
3776
3512
  const isSmallScreen = window.innerWidth < 768;
3777
3513
  const hasTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
3778
-
3779
3514
  // 综合判断:UA匹配 或 (小屏幕+触摸)
3780
3515
  this._isMobile = isMobileUA || isSmallScreen && hasTouch;
3781
3516
  }
3782
-
3783
3517
  // P2-17: 应用移动端/桌面端布局(自动全屏或恢复浮动气泡)
3784
3518
  _applyMobileLayout() {
3785
3519
  if (!this._dialog) return;
@@ -3824,9 +3558,7 @@ class AIChatDialog extends HTMLElement {
3824
3558
  if (visible) this.showDialog();else this.hideDialog();
3825
3559
  }
3826
3560
  }
3827
-
3828
3561
  // ==================== 属性访问器 ====================
3829
-
3830
3562
  get visible() {
3831
3563
  return this.hasAttribute('visible');
3832
3564
  }
@@ -3842,9 +3574,7 @@ class AIChatDialog extends HTMLElement {
3842
3574
  get config() {
3843
3575
  return this._config;
3844
3576
  }
3845
-
3846
3577
  // ==================== 公共API ====================
3847
-
3848
3578
  init(config = {}) {
3849
3579
  this._config = {
3850
3580
  apiBaseUrl: '',
@@ -3892,6 +3622,14 @@ class AIChatDialog extends HTMLElement {
3892
3622
  authFn: null,
3893
3623
  onLoad: null,
3894
3624
  onError: null,
3625
+ // P3: 发送前回调 - 每发消息前调用,可返回最新页面上下文(与 setContext 合并,此回调结果优先)
3626
+ onBeforeSend: null,
3627
+ // P3: 上下文注入方式 — 'prompt'=拼到用户消息前面(默认), 'bizParams'=注入到 bizParams JSON 中
3628
+ contextMode: 'prompt',
3629
+ // P4: 调试模式 - 开启后 console 打印请求/响应/SSE/上下文合并全过程
3630
+ debug: false,
3631
+ // P4: 自定义消息操作按钮 — 返回数组 [{label, className?, onClick}] 在 AI 消息下方渲染
3632
+ onMessageActions: null,
3895
3633
  suggestions: [{
3896
3634
  label: '帮我购买一台轻量应用服务器用于部署应用',
3897
3635
  value: '帮我购买一台轻量应用服务器用于部署应用'
@@ -3905,6 +3643,11 @@ class AIChatDialog extends HTMLElement {
3905
3643
  this._chatClient = new AIChatClient(this._config);
3906
3644
  if (this._conversationId) this._chatClient.setConversationId(this._conversationId);
3907
3645
  this.applyConfig();
3646
+ // P1-2 fix: 在 _config 就绪后初始化拖拽,以正确读取 enableDrag
3647
+ if (this._config?.enableDrag !== false && this.getAttribute('mode') !== 'inline' && !this._dragInitialized) {
3648
+ this.initDraggable();
3649
+ }
3650
+ this._debugLog('初始化完成', 'appId=' + this._config.appId, 'userId=' + this._config.userId, 'baseUrl=' + this._config.apiBaseUrl, 'debug=' + !!this._config.debug, 'contextMode=' + (this._config.contextMode || 'prompt'));
3908
3651
  this.loadAppDetail();
3909
3652
  // 触发 onLoad 回调(与Vue版一致)
3910
3653
  if (this._config?.onLoad) this._config.onLoad(this);
@@ -3990,9 +3733,42 @@ class AIChatDialog extends HTMLElement {
3990
3733
  this._mockMode = false;
3991
3734
  return this;
3992
3735
  }
3993
-
3736
+ /**
3737
+ * 设置页面上下文数据(宿主页面选中的数据,随每次请求发送)
3738
+ * @param {Object} context - 上下文数据对象,传 null 清空
3739
+ * @returns {this}
3740
+ */
3741
+ setContext(context) {
3742
+ this._context = context && typeof context === 'object' ? {
3743
+ ...context
3744
+ } : {};
3745
+ return this;
3746
+ }
3747
+ /**
3748
+ * 获取当前上下文数据
3749
+ * @returns {Object}
3750
+ */
3751
+ getContext() {
3752
+ return {
3753
+ ...this._context
3754
+ };
3755
+ }
3756
+ /**
3757
+ * 外部触发表态发送(业务层主动调用,如点击外部按钮触发 AI 请求)
3758
+ * @param {string} text - 要发送的消息内容
3759
+ * @returns {this}
3760
+ */
3761
+ send(text) {
3762
+ const content = String(text || '').trim();
3763
+ if (!content) return this;
3764
+ if (this._input) this._input.value = content;
3765
+ this._autoResizeInput();
3766
+ this._updateSendButtonState();
3767
+ this._lastSendTime = 0; // 跳过防抖,外部触发视为独立操作
3768
+ this.handleSend();
3769
+ return this;
3770
+ }
3994
3771
  // ==================== 显示/隐藏 ====================
3995
-
3996
3772
  showDialog() {
3997
3773
  const dialog = this.shadowRoot.querySelector('.ai-chat-dialog');
3998
3774
  const btn = this.shadowRoot.querySelector('.float-button');
@@ -4007,9 +3783,7 @@ class AIChatDialog extends HTMLElement {
4007
3783
  if (dialog) dialog.classList.remove('dialog-visible');
4008
3784
  if (btn) btn.style.display = 'flex';
4009
3785
  }
4010
-
4011
3786
  // ==================== 渲染(完整CSS对齐theme.css) ====================
4012
-
4013
3787
  render() {
4014
3788
  const cssVarsStr = Object.entries(this._themeVars).map(([k, v]) => `${k}:${v};`).join('\n ');
4015
3789
  this.shadowRoot.innerHTML = `
@@ -4626,6 +4400,19 @@ class AIChatDialog extends HTMLElement {
4626
4400
  color: var(--ai-success);
4627
4401
  background: rgba(16, 185, 129, 0.08);
4628
4402
  }
4403
+ /* P4: 自定义操作按钮(文本标签型,宽度自适应) */
4404
+ .action-icon.custom-action-btn {
4405
+ width: auto;
4406
+ padding: 4px 10px;
4407
+ font-size: 12px;
4408
+ font-weight: 500;
4409
+ white-space: nowrap;
4410
+ }
4411
+ .action-icon.custom-action-btn:hover {
4412
+ color: #fff;
4413
+ background: var(--ai-primary);
4414
+ transform: translateY(-1px);
4415
+ }
4629
4416
 
4630
4417
  /* ========== 底部输入框(与Vue .dialog-footer 一致) ========== */
4631
4418
  .dialog-footer {
@@ -5087,16 +4874,43 @@ class AIChatDialog extends HTMLElement {
5087
4874
  :host(.dark-theme) blockquote { background: rgba(110, 168, 254, 0.08); }
5088
4875
  :host(.dark-theme) th { background: rgba(110, 168, 254, 0.12); }
5089
4876
  :host(.dark-theme) hr { border-top-color: var(--ai-border); }
4877
+
4878
+ /* ========== 插槽样式(自定义内容区域) ========== */
4879
+ /* header-title 插槽 */
4880
+ ::slotted([slot="header-title"]) {
4881
+ font-size: var(--ai-font-title, 15px);
4882
+ font-weight: 650;
4883
+ color: var(--ai-text);
4884
+ overflow: hidden;
4885
+ text-overflow: ellipsis;
4886
+ white-space: nowrap;
4887
+ }
4888
+ /* input-prepend 插槽 — 输入区上方附加内容 */
4889
+ ::slotted([slot="input-prepend"]) {
4890
+ display: block;
4891
+ padding: 0 4px 8px;
4892
+ }
4893
+ /* footer 插槽 */
4894
+ ::slotted([slot="footer"]) {
4895
+ display: flex;
4896
+ justify-content: space-between;
4897
+ gap: 12px;
4898
+ color: #b5bbc5;
4899
+ font-size: 12px;
4900
+ line-height: 1;
4901
+ }
5090
4902
  </style>
5091
4903
 
5092
4904
  <div class="ai-float-container">
5093
4905
  <!-- 对话框 -->
5094
4906
  <div class="ai-chat-dialog">
5095
- <!-- 头部(含展开/关闭按钮) -->
5096
- <div class="dialog-header">
5097
- <div class="header-left">
5098
- <span class="header-title">${this.escapeHtml(this._config?.title || 'AI 助手')}</span>
5099
- </div>
4907
+ <!-- 头部(含展开/关闭按钮) -->
4908
+ <div class="dialog-header">
4909
+ <div class="header-left">
4910
+ <slot name="header-title">
4911
+ <span class="header-title">${this.escapeHtml(this._config?.title || 'AI 助手')}</span>
4912
+ </slot>
4913
+ </div>
5100
4914
  <div class="header-right">
5101
4915
  <button class="new-chat-btn history-btn" type="button" title="历史记录" aria-label="历史记录">
5102
4916
  <svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7"/><path d="M3 4v5h5"/><path d="M12 7v5l3 2"/></svg>
@@ -5120,9 +4934,10 @@ class AIChatDialog extends HTMLElement {
5120
4934
  <!-- 消息区域 -->
5121
4935
  <div class="dialog-body" id="messagesContainer"></div>
5122
4936
 
5123
- <!-- 输入区域 -->
5124
- <div class="dialog-footer">
5125
- <div class="input-container" id="inputContainer">
4937
+ <!-- 输入区域 -->
4938
+ <div class="dialog-footer">
4939
+ <slot name="input-prepend"></slot>
4940
+ <div class="input-container" id="inputContainer">
5126
4941
  <textarea class="message-input" id="msgInput"
5127
4942
  placeholder="请输入您的问题..." autocomplete="off" rows="2"></textarea>
5128
4943
  <div class="input-tools">
@@ -5135,10 +4950,12 @@ class AIChatDialog extends HTMLElement {
5135
4950
  </button>
5136
4951
  </div>
5137
4952
  </div>
5138
- <div class="footer-note">
5139
- <span class="footer-note-left">${this.escapeHtml(this._config?.footerDisclaimer || '')}</span>
5140
- <span class="footer-note-right">${this.escapeHtml(this._config?.footerIdentity || '')}</span>
5141
- </div>
4953
+ <div class="footer-note">
4954
+ <slot name="footer">
4955
+ <span class="footer-note-left">${this.escapeHtml(this._config?.footerDisclaimer || '')}</span>
4956
+ <span class="footer-note-right">${this.escapeHtml(this._config?.footerIdentity || '')}</span>
4957
+ </slot>
4958
+ </div>
5142
4959
  </div>
5143
4960
  </div>
5144
4961
 
@@ -5146,7 +4963,6 @@ class AIChatDialog extends HTMLElement {
5146
4963
  <div class="float-button" id="floatBtn" title="打开AI助手"></div>
5147
4964
  </div>
5148
4965
  `;
5149
-
5150
4966
  // 缓存DOM引用
5151
4967
  this._dialog = this.shadowRoot.querySelector('.ai-chat-dialog');
5152
4968
  this._body = this.shadowRoot.querySelector('#messagesContainer');
@@ -5168,28 +4984,21 @@ class AIChatDialog extends HTMLElement {
5168
4984
  requestAnimationFrame(() => {
5169
4985
  // 关闭按钮
5170
4986
  if (this._closeBtn) this._closeBtn.addEventListener('click', () => this.close());
5171
-
5172
4987
  // 展开/收起按钮
5173
4988
  if (this._expandBtn) this._expandBtn.addEventListener('click', () => this.toggleExpand());
5174
-
5175
4989
  // 新会话按钮
5176
4990
  if (this._newChatBtn) this._newChatBtn.addEventListener('click', () => this.clearChat());
5177
-
5178
4991
  // 历史记录按钮
5179
4992
  if (this._historyBtn) this._historyBtn.addEventListener('click', () => this.toggleHistory());
5180
-
5181
4993
  // 悬浮按钮打开
5182
4994
  if (this._floatBtn) this._floatBtn.addEventListener('click', () => this.open());
5183
-
5184
4995
  // 发送按钮
5185
4996
  if (this._sendBtn) this._sendBtn.addEventListener('click', () => this.handleSend());
5186
-
5187
4997
  // 附件选择
5188
4998
  if (this._attachBtn && this._attachmentInput) {
5189
4999
  this._attachBtn.addEventListener('click', () => this._attachmentInput.click());
5190
5000
  this._attachmentInput.addEventListener('change', () => this._handleAttachmentSelect());
5191
5001
  }
5192
-
5193
5002
  // 输入回车发送
5194
5003
  if (this._input) {
5195
5004
  this._autoResizeInput();
@@ -5205,19 +5014,15 @@ class AIChatDialog extends HTMLElement {
5205
5014
  }
5206
5015
  });
5207
5016
  }
5208
-
5209
- // 拖拽(内嵌模式禁用)
5210
- if (this._dialog && this._config?.enableDrag !== false && this.getAttribute('mode') !== 'inline') this.initDraggable();
5017
+ // 拖拽(内嵌模式禁用)— 由 init() 在 _config 就绪后触发
5018
+ // initDraggable 延迟到 init() 中执行以免 _config 为空
5211
5019
  });
5212
5020
  }
5213
-
5214
5021
  // ==================== 展开/收起 ====================
5215
-
5216
5022
  toggleExpand() {
5217
5023
  this._isExpanded = !this._isExpanded;
5218
5024
  const dlg = this._dialog;
5219
5025
  if (!dlg) return;
5220
-
5221
5026
  // P2-17: 移动端始终全屏,展开/收起无意义(与Vue版 dialogStyle 一致)
5222
5027
  if (this._isMobile) {
5223
5028
  this._isExpanded = false; // 移动端不记录展开状态
@@ -5254,77 +5059,107 @@ class AIChatDialog extends HTMLElement {
5254
5059
  detail: this._isExpanded
5255
5060
  }));
5256
5061
  }
5257
-
5258
5062
  // ==================== 拖拽(与Vue startDrag/onDrag/stopDrag 一致) ====================
5259
-
5260
5063
  initDraggable() {
5261
5064
  const header = this.shadowRoot?.querySelector('.dialog-header');
5262
5065
  if (!header) return;
5066
+ // 清理上一次遗留的 document 级监听(SPA 路由切换场景)
5067
+ this._cleanupDragListeners();
5068
+ const self = this;
5263
5069
  const startDrag = (clientX, clientY) => {
5264
5070
  // P2-17: 移动端禁用拖拽(与Vue版 startTouchDrag: if(isExpanded || isMobile) return 一致)
5265
- if (this._isExpanded || this._isMobile) return;
5266
- this._isDragging = true;
5267
- this._dialog.classList.add('dragging');
5268
- const rect = this._dialog.getBoundingClientRect();
5269
- this._dragStartX = clientX - rect.left;
5270
- this._dragStartY = clientY - rect.top;
5071
+ if (self._isExpanded || self._isMobile) return;
5072
+ self._isDragging = true;
5073
+ self._dialog.classList.add('dragging');
5074
+ const rect = self._dialog.getBoundingClientRect();
5075
+ self._dragStartX = clientX - rect.left;
5076
+ self._dragStartY = clientY - rect.top;
5271
5077
  };
5272
5078
  const onDrag = (clientX, clientY) => {
5273
- if (!this._isDragging) return;
5274
- this._dialogX = clientX - this._dragStartX;
5275
- this._dialogY = clientY - this._dragStartY;
5276
- this._dialog.style.left = this._dialogX + 'px';
5277
- this._dialog.style.right = 'auto';
5278
- this._dialog.style.top = this._dialogY + 'px';
5279
- this._dialog.style.bottom = 'auto';
5079
+ if (!self._isDragging) return;
5080
+ self._dialogX = clientX - self._dragStartX;
5081
+ self._dialogY = clientY - self._dragStartY;
5082
+ self._dialog.style.left = self._dialogX + 'px';
5083
+ self._dialog.style.right = 'auto';
5084
+ self._dialog.style.top = self._dialogY + 'px';
5085
+ self._dialog.style.bottom = 'auto';
5280
5086
  };
5281
5087
  const stopDrag = () => {
5282
- if (this._isDragging) {
5283
- this._isDragging = false;
5284
- this._dialog.classList.remove('dragging');
5088
+ if (self._isDragging) {
5089
+ self._isDragging = false;
5090
+ self._dialog.classList.remove('dragging');
5285
5091
  }
5286
5092
  };
5287
-
5288
- // 鼠标事件(桌面端)
5289
- header.addEventListener('mousedown', e => {
5093
+ // 鼠标事件(桌面端)— 保存引用以便清理
5094
+ this._dragMouseDownHandler = e => {
5290
5095
  if (e.target.closest('button, .header-icon')) return;
5291
5096
  startDrag(e.clientX, e.clientY);
5292
5097
  e.preventDefault();
5293
- });
5294
- document.addEventListener('mousemove', e => {
5098
+ };
5099
+ this._dragMouseMoveHandler = e => {
5295
5100
  onDrag(e.clientX, e.clientY);
5296
- });
5297
- document.addEventListener('mouseup', stopDrag);
5298
-
5101
+ };
5102
+ this._dragMouseUpHandler = stopDrag;
5103
+ header.addEventListener('mousedown', this._dragMouseDownHandler);
5104
+ document.addEventListener('mousemove', this._dragMouseMoveHandler);
5105
+ document.addEventListener('mouseup', this._dragMouseUpHandler);
5299
5106
  // P1-7: 触摸事件(移动端,与Vue版一致)
5300
- header.addEventListener('touchstart', e => {
5301
- if (this._isExpanded) return;
5107
+ this._dragTouchStartHandler = e => {
5108
+ if (self._isExpanded) return;
5302
5109
  if (e.target.closest('button, .header-icon')) return;
5303
5110
  const touch = e.touches[0];
5304
5111
  startDrag(touch.clientX, touch.clientY);
5305
- }, {
5306
- passive: true
5307
- });
5308
- document.addEventListener('touchmove', e => {
5309
- if (!this._isDragging) return;
5112
+ };
5113
+ this._dragTouchMoveHandler = e => {
5114
+ if (!self._isDragging) return;
5310
5115
  const touch = e.touches[0];
5311
5116
  onDrag(touch.clientX, touch.clientY);
5312
- }, {
5117
+ };
5118
+ this._dragTouchEndHandler = stopDrag;
5119
+ header.addEventListener('touchstart', this._dragTouchStartHandler, {
5120
+ passive: true
5121
+ });
5122
+ document.addEventListener('touchmove', this._dragTouchMoveHandler, {
5313
5123
  passive: true
5314
5124
  });
5315
- document.addEventListener('touchend', stopDrag);
5125
+ document.addEventListener('touchend', this._dragTouchEndHandler);
5126
+ this._dragInitialized = true;
5127
+ }
5128
+ // P0: 清理拖拽事件监听(SPA disconnectedCallback / re-init 调用)
5129
+ _cleanupDragListeners() {
5130
+ if (this._dragMouseDownHandler) {
5131
+ const header = this.shadowRoot?.querySelector('.dialog-header');
5132
+ if (header) {
5133
+ header.removeEventListener('mousedown', this._dragMouseDownHandler);
5134
+ header.removeEventListener('touchstart', this._dragTouchStartHandler, {
5135
+ passive: true
5136
+ });
5137
+ }
5138
+ this._dragMouseDownHandler = null;
5139
+ this._dragTouchStartHandler = null;
5140
+ }
5141
+ if (this._dragMouseMoveHandler) {
5142
+ document.removeEventListener('mousemove', this._dragMouseMoveHandler);
5143
+ document.removeEventListener('touchmove', this._dragTouchMoveHandler, {
5144
+ passive: true
5145
+ });
5146
+ document.removeEventListener('mouseup', this._dragMouseUpHandler);
5147
+ document.removeEventListener('touchend', this._dragTouchEndHandler);
5148
+ this._dragMouseMoveHandler = null;
5149
+ this._dragTouchMoveHandler = null;
5150
+ this._dragMouseUpHandler = null;
5151
+ this._dragTouchEndHandler = null;
5152
+ }
5316
5153
  }
5317
5154
  applyConfig() {
5318
5155
  if (!this._config) return;
5319
5156
  // 更新标题
5320
5157
  const titleEl = this.shadowRoot.querySelector('.header-title');
5321
5158
  if (titleEl && this._config.title) titleEl.textContent = this._config.title;
5322
-
5323
5159
  // 更新placeholder
5324
5160
  if (this._input && this._config.placeholder) this._input.placeholder = this._config.placeholder;
5325
5161
  // P1-11: 动态设置输入框最大长度
5326
5162
  if (this._input && this._config.maxLength) this._input.maxLength = this._config.maxLength;
5327
-
5328
5163
  // ====== 主题处理:16种字符串预设 + 对象自定义 ======
5329
5164
  const t = this._config.theme;
5330
5165
  const host = this.shadowRoot.host;
@@ -5353,7 +5188,6 @@ class AIChatDialog extends HTMLElement {
5353
5188
  }
5354
5189
  host.classList.toggle('dark-theme', ['dark', 'starsky'].includes(t.toLowerCase()));
5355
5190
  }
5356
-
5357
5191
  // 对象形式自定义主题 - 也先重置再合并
5358
5192
  if (t && typeof t === 'object') {
5359
5193
  this._resetThemeVars();
@@ -5368,7 +5202,6 @@ class AIChatDialog extends HTMLElement {
5368
5202
  });
5369
5203
  host.classList.remove('dark-theme');
5370
5204
  }
5371
-
5372
5205
  // 应用所有CSS变量到host
5373
5206
  Object.entries(this._themeVars).forEach(([k, v]) => host.style.setProperty(k, v));
5374
5207
  }
@@ -5423,9 +5256,7 @@ class AIChatDialog extends HTMLElement {
5423
5256
  questions
5424
5257
  };
5425
5258
  }
5426
-
5427
5259
  // ==================== 渲染消息(与Vue模板结构一致) ====================
5428
-
5429
5260
  renderMessages(options = {}) {
5430
5261
  if (!this._body) return;
5431
5262
  if (this._historyVisible) {
@@ -5477,23 +5308,22 @@ class AIChatDialog extends HTMLElement {
5477
5308
  <div class="message-content">
5478
5309
  ${hasRuntimeEvents ? this._buildRuntimePanel(msg, idx) : ''}
5479
5310
  ${bubbleContent ? `<div class="${bubbleClass}">${bubbleContent}</div>` : ''}
5480
- ${!msg._isStreaming ? `<div class="message-actions-bar">
5481
- ${msg.type === 'ai' ? `<div class="action-icons">
5482
- <span class="action-icon copy-btn${msg.copied ? ' copied' : ''}" data-idx="${idx}" title="${msg.copied ? '已复制' : '复制'}">${msg.copied ? '<svg viewBox="0 0 24 24" fill="none" stroke-width="2"><path d="m20 6-11 11-5-5"/></svg>' : '<svg viewBox="0 0 24 24" fill="none" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>'}</span>
5483
- <span class="action-icon regenerate-btn" data-idx="${idx}" title="重新回答"><svg viewBox="0 0 24 24" fill="none" stroke-width="2"><path d="M21 12a9 9 0 1 1-2.64-6.36"/><path d="M21 3v6h-6"/></svg></span>
5484
- </div>` : ''}
5311
+ ${!msg._isStreaming ? `<div class="message-actions-bar">
5312
+ ${msg.type === 'ai' ? `<div class="action-icons">
5313
+ <span class="action-icon copy-btn${msg.copied ? ' copied' : ''}" data-idx="${idx}" title="${msg.copied ? '已复制' : '复制'}">${msg.copied ? '<svg viewBox="0 0 24 24" fill="none" stroke-width="2"><path d="m20 6-11 11-5-5"/></svg>' : '<svg viewBox="0 0 24 24" fill="none" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>'}</span>
5314
+ <span class="action-icon regenerate-btn" data-idx="${idx}" title="重新回答"><svg viewBox="0 0 24 24" fill="none" stroke-width="2"><path d="M21 12a9 9 0 1 1-2.64-6.36"/><path d="M21 3v6h-6"/></svg></span>
5315
+ ${this._buildCustomActions(msg, idx)}
5316
+ </div>` : ''}
5485
5317
  </div>` : ''}
5486
5318
  </div>
5487
5319
  </div>`;
5488
5320
  });
5489
-
5490
5321
  // 加载状态 — 有执行过程时不展示思考中
5491
5322
  if (this._isLoading && !runtimeExists) {
5492
5323
  html += '<div class="message-item ai">' + '<div class="message-content">' + '<div class="message-bubble loading"><span class="thinking-text">思考中</span><span class="typing-indicator"><span class="typing-dot"></span><span class="typing-dot"></span><span class="typing-dot"></span></span></div>' + '</div>' + '</div>';
5493
5324
  }
5494
5325
  html += '</div>';
5495
5326
  this._body.innerHTML = html;
5496
-
5497
5327
  // 绑定复制事件
5498
5328
  this._body.querySelectorAll('.copy-btn').forEach(btn => {
5499
5329
  btn.addEventListener('click', () => {
@@ -5502,7 +5332,6 @@ class AIChatDialog extends HTMLElement {
5502
5332
  if (msg) this.copyMessage(msg.content, idx);
5503
5333
  });
5504
5334
  });
5505
-
5506
5335
  // 绑定重新生成事件
5507
5336
  this._body.querySelectorAll('.regenerate-btn').forEach(btn => {
5508
5337
  btn.addEventListener('click', () => {
@@ -5510,7 +5339,23 @@ class AIChatDialog extends HTMLElement {
5510
5339
  this.regenerate(idx);
5511
5340
  });
5512
5341
  });
5513
-
5342
+ // P4: 绑定自定义操作按钮
5343
+ this._body.querySelectorAll('.custom-action-btn').forEach(btn => {
5344
+ btn.addEventListener('click', () => {
5345
+ const idx = parseInt(btn.dataset.idx);
5346
+ const actionIdx = parseInt(btn.dataset.action);
5347
+ const msg = this._messages[idx];
5348
+ if (!msg) return;
5349
+ try {
5350
+ const actions = this._getCustomActions(msg, idx);
5351
+ if (actions && actions[actionIdx]) {
5352
+ actions[actionIdx].onClick(msg.content);
5353
+ }
5354
+ } catch (e) {
5355
+ console.warn('[AIChatDialog] 自定义操作按钮执行失败:', e);
5356
+ }
5357
+ });
5358
+ });
5514
5359
  // 绑定执行过程面板折叠/展开(Shadow DOM 下 inline onclick 不可靠)
5515
5360
  this._body.querySelectorAll('.runtime-header').forEach(header => {
5516
5361
  header.addEventListener('click', () => {
@@ -5753,9 +5598,7 @@ class AIChatDialog extends HTMLElement {
5753
5598
  }
5754
5599
  this._updateSendButtonState();
5755
5600
  }
5756
-
5757
5601
  // ==================== 发送消息(与Vue sendMessage 一致) ====================
5758
-
5759
5602
  async handleSend() {
5760
5603
  const content = this._input ? this._input.value.trim() : '';
5761
5604
  const attachments = [...(this._attachments || [])];
@@ -5763,15 +5606,13 @@ class AIChatDialog extends HTMLElement {
5763
5606
  this.showToast(this._config?.emptyMessageError || '请输入消息内容');
5764
5607
  return;
5765
5608
  }
5766
- if (this._isLoading) return;
5767
-
5609
+ if (this._isLoading || this._streaming) return;
5768
5610
  // P1-11: 字数限制检查
5769
5611
  const maxLen = this._config?.maxLength ?? 500;
5770
5612
  if (content.length > maxLen) {
5771
5613
  this.showToast(`输入内容不能超过${maxLen}个字符(当前${content.length}字)`);
5772
5614
  return;
5773
5615
  }
5774
-
5775
5616
  // 防抖:500ms内不允许重复发送
5776
5617
  const now = Date.now();
5777
5618
  if (this._lastSendTime && now - this._lastSendTime < 500) return;
@@ -5819,8 +5660,46 @@ class AIChatDialog extends HTMLElement {
5819
5660
  attachmentIds.push(res.data.attachmentId);
5820
5661
  }
5821
5662
  }
5822
- await this.sendMessageToAI(content || attachmentText, {
5823
- attachmentIds
5663
+ // P3: 收集页面上下文(setContext + onBeforeSend)
5664
+ let context = {
5665
+ ...(this._context || {})
5666
+ };
5667
+ if (typeof this._config?.onBeforeSend === 'function') {
5668
+ try {
5669
+ const dynamicCtx = await this._config.onBeforeSend();
5670
+ if (dynamicCtx && typeof dynamicCtx === 'object') {
5671
+ context = {
5672
+ ...context,
5673
+ ...dynamicCtx
5674
+ };
5675
+ }
5676
+ } catch (e) {
5677
+ console.warn('[AIChatDialog] onBeforeSend 执行失败:', e);
5678
+ }
5679
+ }
5680
+ const hasContext = context && Object.keys(context).length > 0;
5681
+ const rawMode = this._config?.contextMode;
5682
+ const VALID_CONTEXT_MODES = ['prompt', 'bizParams'];
5683
+ const contextMode = VALID_CONTEXT_MODES.includes(rawMode) ? rawMode : rawMode ? (console.warn('[AIChatDialog] 无效的 contextMode: "' + rawMode + '",已回退为 "prompt"(有效值: ' + VALID_CONTEXT_MODES.join(', ') + ')'), 'prompt') : 'prompt';
5684
+ let finalPrompt = content || attachmentText;
5685
+ let contextForBizParams = null;
5686
+ if (hasContext) {
5687
+ this._debugLog('上下文合并', 'keys=', Object.keys(context), 'mode=', contextMode);
5688
+ if (contextMode === 'bizParams') {
5689
+ // 注入到 bizParams
5690
+ contextForBizParams = context;
5691
+ } else {
5692
+ // 默认:拼到 prompt 前面
5693
+ const ctxText = this._formatContextText(context);
5694
+ if (ctxText) {
5695
+ finalPrompt = ctxText + '\n---\n' + finalPrompt;
5696
+ }
5697
+ }
5698
+ }
5699
+ this._debugLog('发送', 'prompt=' + (finalPrompt || '').substring(0, 150) + (finalPrompt && finalPrompt.length > 150 ? '...' : ''), 'ctxKeys=' + Object.keys(contextForBizParams || context || {}).join(','), 'mode=' + contextMode);
5700
+ await this.sendMessageToAI(finalPrompt, {
5701
+ attachmentIds,
5702
+ context: contextForBizParams
5824
5703
  });
5825
5704
  } catch (err) {
5826
5705
  console.error('[AIChatDialog] Error:', err);
@@ -5854,14 +5733,14 @@ class AIChatDialog extends HTMLElement {
5854
5733
  ...(options.streamOptions || {})
5855
5734
  };
5856
5735
  if (options.attachmentIds?.length) streamOpts.attachmentIds = options.attachmentIds;
5736
+ if (options.context) streamOpts.context = options.context;
5857
5737
  await this._directApiCallStream(msgId, content, streamOpts);
5858
5738
  }
5859
5739
  }
5860
5740
  async mockResponse(userContent) {
5861
- await new Promise(r => setTimeout(r, 600 + Math.random() * 800));
5741
+ await new Promise(r => window.setTimeout(r, 600 + Math.random() * 800));
5862
5742
  const responses = [`关于"${(userContent || '').substring(0, 20)}"这个问题,我来为您详细解答...`, `这是一个很好的问题!根据我的理解:\n\n1. 首先,我们需要分析需求\n2. 其次,设计实现方案\n3. 最后,进行测试验证`, `收到您的问题。让我来帮您分析一下...\n\n根据您的描述,我建议您可以按照以下步骤操作:`, `感谢您的提问!以下是我的看法:\n\n• 第一点很关键,需要注意细节\n• 第二点值得关注\n• 第三点是核心所在`];
5863
5743
  const mockContent = responses[Math.floor(Math.random() * responses.length)];
5864
-
5865
5744
  // 流式效果
5866
5745
  const tempId = this.generateId();
5867
5746
  this._messages.push({
@@ -5872,7 +5751,7 @@ class AIChatDialog extends HTMLElement {
5872
5751
  });
5873
5752
  this.renderMessages();
5874
5753
  for (let i = 0; i < mockContent.length; i++) {
5875
- await new Promise(r => setTimeout(r, 12 + Math.random() * 20));
5754
+ await new Promise(r => window.setTimeout(r, 12 + Math.random() * 20));
5876
5755
  const msgIdx = this._messages.findIndex(m => m.id === tempId);
5877
5756
  if (msgIdx >= 0) {
5878
5757
  this._messages[msgIdx].content = mockContent.substring(0, i + 1);
@@ -5904,13 +5783,15 @@ class AIChatDialog extends HTMLElement {
5904
5783
  if (idx >= 0) delete this._messages[idx]._isStreaming;
5905
5784
  this.renderMessages();
5906
5785
  }
5907
-
5908
5786
  // P0: 会话ID管理
5909
- _conversationId = null;
5910
5787
  async _directApiCallStream(msgId, content, requestOptions = {}) {
5911
5788
  if (!this._chatClient) {
5912
5789
  this._chatClient = new AIChatClient(this._config || {});
5913
5790
  }
5791
+ if (this._config?.debug) {
5792
+ this._chatClient.config.debug = true;
5793
+ }
5794
+ this._debugLog('Stream开始', 'msgId=' + msgId, 'content=' + (content || '').substring(0, 80), 'opts=' + JSON.stringify(requestOptions));
5914
5795
  if (Object.prototype.hasOwnProperty.call(requestOptions, 'conversationId')) {
5915
5796
  this._chatClient.setConversationId(requestOptions.conversationId || null);
5916
5797
  } else if (this._conversationId) {
@@ -6029,6 +5910,7 @@ class AIChatDialog extends HTMLElement {
6029
5910
  }
6030
5911
  }, requestOptions);
6031
5912
  if (response?.success) {
5913
+ this._debugLog('Stream完成', 'ok, conversationId=' + (response.data?.conversationId || this._conversationId), 'textLen=' + streamText.length);
6032
5914
  if (response.data?.conversationId) {
6033
5915
  this._conversationId = response.data.conversationId;
6034
5916
  } else if (this._chatClient.conversationId) {
@@ -6041,6 +5923,7 @@ class AIChatDialog extends HTMLElement {
6041
5923
  streamText = result;
6042
5924
  }
6043
5925
  } else {
5926
+ this._finalizeMsg(msgId, streamText || '(无回复)');
6044
5927
  return;
6045
5928
  }
6046
5929
  this._finalizeMsg(msgId, streamText || '(无回复)');
@@ -6051,12 +5934,14 @@ class AIChatDialog extends HTMLElement {
6051
5934
  }));
6052
5935
  if (this._config?.onMessageReceived) this._config.onMessageReceived(streamText);
6053
5936
  } catch (e) {
5937
+ this._debugWarn('Stream异常', e.name + ': ' + (e.message || ''));
6054
5938
  if (e.name === 'AbortError') {
6055
5939
  this._updateMsg(msgId, '(请求超时或已取消)');
6056
5940
  } else {
6057
5941
  console.error('[AIChatDialog] 流式失败:', e);
6058
5942
  this._updateMsg(msgId, '网络错误: ' + (e.message || '请检查连接'));
6059
5943
  }
5944
+ this._finalizeMsg(msgId, this._messages.find(m => m.id === msgId)?.content || '(无回复)');
6060
5945
  }
6061
5946
  }
6062
5947
  _getStreamTextEl() {
@@ -6089,10 +5974,8 @@ class AIChatDialog extends HTMLElement {
6089
5974
  const idx = this._messages.findIndex(m => m.id === msgId);
6090
5975
  if (idx < 0) return;
6091
5976
  this._messages[idx].content = content;
6092
-
6093
5977
  // Detect if there are runtime events (for typewriter mode check)
6094
5978
  const hasRuntime = !!(this._messages[idx]._runtimeEvents && this._messages[idx]._runtimeEvents.length > 0);
6095
-
6096
5979
  // Accumulate full content
6097
5980
  if (content.startsWith(this._streamFullText)) {
6098
5981
  this._streamFullText = content;
@@ -6153,7 +6036,6 @@ class AIChatDialog extends HTMLElement {
6153
6036
  this.renderMessages();
6154
6037
  }
6155
6038
  }
6156
-
6157
6039
  // 运行时占位符过滤(对齐 portal)
6158
6040
  _isPlaceholder(text) {
6159
6041
  if (!text || typeof text !== 'string') return false;
@@ -6172,14 +6054,31 @@ class AIChatDialog extends HTMLElement {
6172
6054
  } catch (e) {}
6173
6055
  return false;
6174
6056
  }
6175
-
6176
6057
  // 判断错误标记内容(替换脆弱的前缀检查 startsWith('('))
6177
- _ERROR_CONTENT_PATTERNS = ['(请求超时', '(等待AI处理', '(无回复)', '(已停止)', '(AI 处理超时', '错误:', '网络错误:', '抱歉,'];
6178
6058
  _isErrorContent(content) {
6179
6059
  if (!content) return true;
6180
6060
  return this._ERROR_CONTENT_PATTERNS.some(p => content.startsWith(p));
6181
6061
  }
6182
-
6062
+ // P3: 将上下文对象格式化为可读文本(拼入 prompt 前缀)
6063
+ _formatContextText(context) {
6064
+ if (!context || typeof context !== 'object') return '';
6065
+ const lines = ['[页面上下文]'];
6066
+ for (const key in context) {
6067
+ if (!Object.prototype.hasOwnProperty.call(context, key)) continue;
6068
+ const val = context[key];
6069
+ if (Array.isArray(val) && val.length > 0 && typeof val[0] === 'object') {
6070
+ lines.push(key + ':');
6071
+ for (const item of val) {
6072
+ lines.push(' - ' + Object.values(item).join(' | '));
6073
+ }
6074
+ } else if (typeof val === 'object' && val !== null) {
6075
+ lines.push(key + ': ' + JSON.stringify(val));
6076
+ } else {
6077
+ lines.push(key + ': ' + val);
6078
+ }
6079
+ }
6080
+ return lines.join('\n');
6081
+ }
6183
6082
  // 运行时事件管理 – incremental DOM, no renderMessages
6184
6083
  _addRuntimeEvent(msgId, event) {
6185
6084
  const idx = this._messages.findIndex(m => m.id === msgId);
@@ -6207,7 +6106,6 @@ class AIChatDialog extends HTMLElement {
6207
6106
  if (this._shouldAutoScroll()) this.scrollToBottom();
6208
6107
  return;
6209
6108
  }
6210
-
6211
6109
  // Path 2: first event – inject runtime panel DOM next to the streaming bubble
6212
6110
  const msgContent = this._findStreamingMessageContent();
6213
6111
  if (msgContent) {
@@ -6274,6 +6172,28 @@ class AIChatDialog extends HTMLElement {
6274
6172
  panel.appendChild(eventsContainer);
6275
6173
  return panel;
6276
6174
  }
6175
+ // P4: 获取自定义操作按钮列表(缓存结果避免重复调用 onMessageActions)
6176
+ _getCustomActions(msg, idx) {
6177
+ const key = '_customActions_' + idx;
6178
+ if (!msg[key] && typeof this._config?.onMessageActions === 'function') {
6179
+ try {
6180
+ msg[key] = this._config.onMessageActions(msg, idx) || [];
6181
+ } catch (e) {
6182
+ console.warn('[AIChatDialog] onMessageActions 执行失败:', e);
6183
+ msg[key] = [];
6184
+ }
6185
+ }
6186
+ return msg[key] || [];
6187
+ }
6188
+ // P4: 生成自定义操作按钮 HTML
6189
+ _buildCustomActions(msg, idx) {
6190
+ const actions = this._getCustomActions(msg, idx);
6191
+ if (!actions.length) return '';
6192
+ return actions.map((a, i) => {
6193
+ const cls = a.className || '';
6194
+ return '<span class="action-icon custom-action-btn' + (cls ? ' ' + this.escapeAttr(cls) : '') + '" data-idx="' + idx + '" data-action="' + i + '" title="' + this.escapeAttr(a.label) + '">' + this.escapeHtml(a.label) + '</span>';
6195
+ }).join('');
6196
+ }
6277
6197
  _buildRuntimePanel(msg, msgIdx) {
6278
6198
  const events = msg._runtimeEvents || [];
6279
6199
  if (events.length === 0) return '';
@@ -6290,7 +6210,7 @@ class AIChatDialog extends HTMLElement {
6290
6210
  }
6291
6211
  async _fetchConversationResult(conversationId) {
6292
6212
  for (let i = 0; i < 8; i++) {
6293
- await new Promise(r => setTimeout(r, 1000));
6213
+ await new Promise(r => window.setTimeout(r, 1000));
6294
6214
  try {
6295
6215
  const response = await this._chatClient.queryConversation({
6296
6216
  conversationId,
@@ -6306,11 +6226,9 @@ class AIChatDialog extends HTMLElement {
6306
6226
  }
6307
6227
  return '(AI 处理超时,请稍后查看对话记录)';
6308
6228
  }
6309
-
6310
6229
  // ==================== 重新生成(与Vue regenerate 一致) ====================
6311
-
6312
6230
  async regenerate(index) {
6313
- if (this._isLoading) return;
6231
+ if (this._isLoading || this._streaming) return;
6314
6232
  const aiMessage = this._messages[index];
6315
6233
  if (!aiMessage || aiMessage.type !== 'ai') return;
6316
6234
  let userQuestion = '';
@@ -6353,14 +6271,12 @@ class AIChatDialog extends HTMLElement {
6353
6271
  toast.className = 'error-toast';
6354
6272
  toast.textContent = msg;
6355
6273
  this._dialog?.appendChild(toast);
6356
- setTimeout(() => toast.remove(), 3000);
6274
+ window.setTimeout(() => toast.remove(), 3000);
6357
6275
  }
6358
-
6359
6276
  // P1-6: 精细化错误处理(与Vue版 handleErrorMsg 一致,按HTTP状态码+业务错误码分类)
6360
6277
  handleError(err) {
6361
6278
  let displayMsg = '抱歉,网络请求失败,请稍后重试';
6362
6279
  const errMsg = err?.message || '';
6363
-
6364
6280
  // 按错误类型分类
6365
6281
  if (errMsg.includes('Failed to fetch') || errMsg.includes('NetworkError') || errMsg.includes('网络')) {
6366
6282
  displayMsg = '网络连接失败,请检查网络后重试';
@@ -6394,9 +6310,7 @@ class AIChatDialog extends HTMLElement {
6394
6310
  detail: err
6395
6311
  }));
6396
6312
  }
6397
-
6398
6313
  // ==================== 复制(与Vue copyMessage 一致) ====================
6399
-
6400
6314
  async copyContent(text) {
6401
6315
  // P1-10: 微信环境优先使用 wx.setClipboardData(与Vue版一致)
6402
6316
  if (typeof wx !== 'undefined' && wx.setClipboardData) {
@@ -6439,7 +6353,7 @@ class AIChatDialog extends HTMLElement {
6439
6353
  await this.copyContent(content);
6440
6354
  if (this._messages[idx]) this._messages[idx].copied = true;
6441
6355
  this.renderMessages();
6442
- setTimeout(() => {
6356
+ window.setTimeout(() => {
6443
6357
  if (this._messages[idx]) {
6444
6358
  this._messages[idx].copied = false;
6445
6359
  this.renderMessages();
@@ -6488,9 +6402,7 @@ class AIChatDialog extends HTMLElement {
6488
6402
  }
6489
6403
  return response;
6490
6404
  }
6491
-
6492
6405
  // ==================== 工具函数 ====================
6493
-
6494
6406
  generateId() {
6495
6407
  return `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
6496
6408
  }
@@ -6498,6 +6410,19 @@ class AIChatDialog extends HTMLElement {
6498
6410
  const n = new Date();
6499
6411
  return `${String(n.getHours()).padStart(2, '0')}:${String(n.getMinutes()).padStart(2, '0')}`;
6500
6412
  }
6413
+ /**
6414
+ * 调试日志(仅在 config.debug === true 时输出)
6415
+ */
6416
+ _debugLog(tag, ...args) {
6417
+ if (this._config?.debug) {
6418
+ console.log('%c[AI-SDK]%c ' + tag, 'color:#2563eb;font-weight:600', 'color:inherit', ...args);
6419
+ }
6420
+ }
6421
+ _debugWarn(tag, ...args) {
6422
+ if (this._config?.debug) {
6423
+ console.warn('%c[AI-SDK]%c ' + tag, 'color:#f59e0b;font-weight:600', 'color:inherit', ...args);
6424
+ }
6425
+ }
6501
6426
  escapeHtml(s) {
6502
6427
  if (!s) return '';
6503
6428
  const d = document.createElement('div');
@@ -6508,7 +6433,6 @@ class AIChatDialog extends HTMLElement {
6508
6433
  if (!s) return '';
6509
6434
  return s.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&#39;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
6510
6435
  }
6511
-
6512
6436
  /**
6513
6437
  * 重置 _themeVars 为默认值(主题切换时调用,防止残留)
6514
6438
  */
@@ -6550,7 +6474,6 @@ class AIChatDialog extends HTMLElement {
6550
6474
  '--ai-font-small': '11px'
6551
6475
  });
6552
6476
  }
6553
-
6554
6477
  /**
6555
6478
  * Markdown → HTML 解析(仅用于AI回复,用户消息保持纯文本)
6556
6479
  * 使用 marked + DOMPurify 双重保障安全
@@ -6574,7 +6497,6 @@ class AIChatDialog extends HTMLElement {
6574
6497
  }
6575
6498
  }
6576
6499
  }
6577
-
6578
6500
  // 注册自定义元素
6579
6501
  if (!customElements.get('ai-chat-dialog')) {
6580
6502
  customElements.define('ai-chat-dialog', AIChatDialog);
@@ -6586,17 +6508,15 @@ if (typeof window !== 'undefined') {
6586
6508
  /**
6587
6509
  * IBC AI Web SDK - 纯JavaScript版本
6588
6510
  * 支持任意前端框架:Vue, React, Angular, 原生HTML等
6589
- *
6511
+ *
6590
6512
  * @author IBC AI Team
6591
- * @version 2.0.4
6513
+ * @version 2.1.0
6592
6514
  */
6593
-
6594
-
6515
+ // 导出组件
6595
6516
  // 快速初始化函数
6596
6517
  function createAIChatDialog(options = {}) {
6597
6518
  // 创建自定义元素实例
6598
6519
  const dialog = document.createElement('ai-chat-dialog');
6599
-
6600
6520
  // 设置属性
6601
6521
  if (options.title) dialog.setAttribute('title', options.title);
6602
6522
  if (options.placeholder) dialog.setAttribute('placeholder', options.placeholder);
@@ -6605,7 +6525,6 @@ function createAIChatDialog(options = {}) {
6605
6525
  if (options.height) dialog.style.setProperty('--ai-dialog-height', typeof options.height === 'number' ? `${options.height}px` : options.height);
6606
6526
  if (options.top != null) dialog.style.setProperty('--ai-dialog-top', typeof options.top === 'number' ? `${options.top}px` : options.top);
6607
6527
  if (options.right != null) dialog.style.setProperty('--ai-dialog-right', typeof options.right === 'number' ? `${options.right}px` : options.right);
6608
-
6609
6528
  // 挂载到指定容器或 body
6610
6529
  if (options.target) {
6611
6530
  const container = typeof options.target === 'string' ? document.querySelector(options.target) : options.target;
@@ -6619,12 +6538,10 @@ function createAIChatDialog(options = {}) {
6619
6538
  } else {
6620
6539
  document.body.appendChild(dialog);
6621
6540
  }
6622
-
6623
6541
  // 初始化配置
6624
6542
  if (Object.keys(options).length > 0) {
6625
6543
  dialog.init(options);
6626
6544
  }
6627
-
6628
6545
  // 行内模式:挂载到 DOM 后直接展开
6629
6546
  if (options.target) {
6630
6547
  requestAnimationFrame(() => {
@@ -6649,14 +6566,12 @@ function createAIChatDialog(options = {}) {
6649
6566
  }
6650
6567
  return dialog;
6651
6568
  }
6652
-
6653
6569
  // Vue插件安装方式(向后兼容)
6654
6570
  function installVuePlugin(Vue) {
6655
6571
  if (!Vue) {
6656
6572
  console.warn('[AI Web SDK] Vue instance not provided');
6657
6573
  return;
6658
6574
  }
6659
-
6660
6575
  // 注册全局组件包装器
6661
6576
  Vue.component('AiChatWrapper', {
6662
6577
  props: {
@@ -6712,7 +6627,6 @@ function installVuePlugin(Vue) {
6712
6627
  methods: {
6713
6628
  initDialog() {
6714
6629
  this.dialogInstance = createAIChatDialog(this.config || {});
6715
-
6716
6630
  // 监听事件并转发
6717
6631
  const events = ['open', 'close', 'message-send', 'message-received', 'error'];
6718
6632
  events.forEach(event => {
@@ -6740,9 +6654,6 @@ function installVuePlugin(Vue) {
6740
6654
  }
6741
6655
  });
6742
6656
  }
6743
-
6744
- // React Hook(可选) — 通过 window.React 获取 hooks,兼容 CDN 全局引入
6745
- /* global React */
6746
6657
  function useAIChat(options = {}) {
6747
6658
  if (typeof React === 'undefined') {
6748
6659
  console.warn('[AI Web SDK] React is not loaded, useAIChat skipped');
@@ -6766,7 +6677,6 @@ function useAIChat(options = {}) {
6766
6677
  useEffect(() => {
6767
6678
  if (!dialogRef.current) {
6768
6679
  dialogRef.current = createAIChatDialog(options);
6769
-
6770
6680
  // 监听事件
6771
6681
  dialogRef.current.addEventListener('message-send', e => {
6772
6682
  setMessages(prev => [...prev, e.detail]);
@@ -6805,12 +6715,10 @@ function useAIChat(options = {}) {
6805
6715
  },
6806
6716
  sendMessage: content => {
6807
6717
  if (dialogRef.current) {
6808
- const input = dialogRef.current.shadowRoot?.querySelector('.ai-textarea');
6718
+ const input = dialogRef.current.shadowRoot?.querySelector('.message-input');
6809
6719
  if (input) {
6810
- input.value = content;
6811
- input.dispatchEvent(new Event('input'));
6720
+ dialogRef.current.send?.(content) || (input.value = content, input.dispatchEvent(new Event('input')), dialogRef.current.shadowRoot?.querySelector('.send-btn')?.click());
6812
6721
  }
6813
- dialogRef.current.handleSend?.() || dialogRef.current.shadowRoot?.querySelector('.ai-send-btn')?.click();
6814
6722
  }
6815
6723
  },
6816
6724
  clearMessages: () => {
@@ -6823,7 +6731,6 @@ function useAIChat(options = {}) {
6823
6731
  ref: dialogRef
6824
6732
  };
6825
6733
  }
6826
-
6827
6734
  // 默认导出
6828
6735
  var index = {
6829
6736
  AIChatDialog,
@@ -6831,14 +6738,13 @@ var index = {
6831
6738
  createAIChatDialog,
6832
6739
  installVuePlugin,
6833
6740
  useAIChat,
6834
- version: '2.0.4'
6741
+ version: '2.1.0'
6835
6742
  };
6836
-
6837
6743
  // 全局暴露(UMD/浏览器环境)
6838
6744
  if (typeof window !== 'undefined') {
6839
6745
  window.AICreateChatDialog = createAIChatDialog;
6840
6746
  window.AIWebSDK = {
6841
- version: '2.0.4',
6747
+ version: '2.1.0',
6842
6748
  create: createAIChatDialog,
6843
6749
  AIChatDialog,
6844
6750
  AIChatClient,