@vectojs/markdown 0.14.0 → 0.15.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.js CHANGED
@@ -52,7 +52,7 @@ __export(index_exports, {
52
52
  module.exports = __toCommonJS(index_exports);
53
53
 
54
54
  // src/Markdown.ts
55
- var import_core = require("@vectojs/core");
55
+ var import_core4 = require("@vectojs/core");
56
56
  var import_marked = require("marked");
57
57
 
58
58
  // src/StreamController.ts
@@ -464,746 +464,109 @@ function createStreamController(host, options = {}) {
464
464
  return new StreamControllerImpl(host, options);
465
465
  }
466
466
 
467
- // src/Markdown.ts
468
- var import_ui2 = require("@vectojs/ui");
469
-
470
- // src/blockAffordances.ts
471
- var import_ui = require("@vectojs/ui");
472
- var LANGUAGE_EXTENSIONS = {
473
- bash: "sh",
474
- c: "c",
475
- cpp: "cpp",
476
- cs: "cs",
477
- css: "css",
478
- diff: "diff",
479
- dockerfile: "dockerfile",
480
- go: "go",
481
- graphql: "graphql",
482
- haskell: "hs",
483
- html: "html",
484
- java: "java",
485
- javascript: "js",
486
- js: "js",
487
- json: "json",
488
- jsonc: "jsonc",
489
- jsx: "jsx",
490
- kotlin: "kt",
491
- latex: "tex",
492
- lua: "lua",
493
- make: "mk",
494
- markdown: "md",
495
- md: "md",
496
- nix: "nix",
497
- php: "php",
498
- python: "py",
499
- py: "py",
500
- ruby: "rb",
501
- rust: "rs",
502
- rs: "rs",
503
- scss: "scss",
504
- sh: "sh",
505
- shell: "sh",
506
- sql: "sql",
507
- svelte: "svelte",
508
- swift: "swift",
509
- tex: "tex",
510
- toml: "toml",
511
- ts: "ts",
512
- tsx: "tsx",
513
- typescript: "ts",
514
- vue: "vue",
515
- xml: "xml",
516
- yaml: "yaml",
517
- yml: "yaml",
518
- zig: "zig",
519
- zsh: "sh"
520
- };
521
- function extensionForLanguage(lang) {
522
- const first = lang.trim().toLowerCase().split(/[\s:,{]/)[0] ?? "";
523
- return LANGUAGE_EXTENSIONS[first] ?? "txt";
524
- }
525
- function mimeForLanguage(lang) {
526
- const ext = extensionForLanguage(lang);
527
- if (ext === "json" || ext === "jsonc") return "application/json";
528
- if (ext === "html") return "text/html";
529
- if (ext === "css") return "text/css";
530
- if (ext === "xml" || ext === "svelte" || ext === "vue") return "text/plain";
531
- return "text/plain";
532
- }
533
- function escapeCsvField(value) {
534
- let needsQuoting = false;
535
- let hasQuote = false;
536
- for (const char of value) {
537
- if (char === '"') {
538
- hasQuote = true;
539
- needsQuoting = true;
540
- break;
541
- }
542
- if (char === "," || char === "\n" || char === "\r") needsQuoting = true;
543
- }
544
- if (!needsQuoting) return value;
545
- return hasQuote ? `"${value.replace(/"/g, '""')}"` : `"${value}"`;
546
- }
547
- function escapeMarkdownTableCell(cell) {
548
- let needsEscaping = false;
549
- for (const char of cell) {
550
- if (char === "\\" || char === "|") {
551
- needsEscaping = true;
552
- break;
553
- }
554
- }
555
- if (!needsEscaping) return cell;
556
- return cell.replace(/\\/g, "\\\\").replace(/\|/g, "\\|");
557
- }
558
- function tableToCsv(table) {
559
- const lines = [table.headers.map(escapeCsvField).join(",")];
560
- for (const row of table.rows) lines.push(row.map(escapeCsvField).join(","));
561
- return `\uFEFF${lines.join("\r\n")}`;
562
- }
563
- function tableToMarkdown(table) {
564
- const header = `| ${table.headers.map(escapeMarkdownTableCell).join(" | ")} |`;
565
- const divider = `| ${table.headers.map((_cell, index) => {
566
- switch (table.align[index]) {
567
- case "left":
568
- return ":---";
569
- case "center":
570
- return ":---:";
571
- case "right":
572
- return "---:";
573
- default:
574
- return "---";
575
- }
576
- }).join(" | ")} |`;
577
- const body = table.rows.map(
578
- (row) => `| ${table.headers.map((_cell, index) => escapeMarkdownTableCell(row[index] ?? "")).join(" | ")} |`
579
- );
580
- return [header, divider, ...body].join("\n");
581
- }
582
- function defaultWriteClipboard(text) {
583
- const clipboard = globalThis.navigator?.clipboard;
584
- clipboard?.writeText?.(text);
585
- }
586
- function defaultSaveFile(filename, content, mimeType) {
587
- const doc = globalThis.document;
588
- if (!doc?.body) return;
589
- const blob = new Blob([content], { type: mimeType });
590
- const url = URL.createObjectURL(blob);
591
- const anchor = doc.createElement("a");
592
- anchor.href = url;
593
- anchor.download = filename;
594
- doc.body.appendChild(anchor);
595
- anchor.click();
596
- doc.body.removeChild(anchor);
597
- URL.revokeObjectURL(url);
598
- }
599
- var BlockAffordanceButton = class _BlockAffordanceButton extends import_ui.Button {
600
- constructor(label, successLabel, act, opts = {}) {
601
- super(label, { ...opts, onClick: () => this.run() });
602
- this.act = act;
603
- this.restingLabel = label;
604
- this.successLabel = successLabel;
605
- this.width = Math.max(this.width, (0, import_ui.measureText)(successLabel, this.font) + 24);
606
- }
607
- act;
608
- /** How long the confirmation label stays up, in ms. */
609
- static FEEDBACK_MS = 1600;
610
- restingLabel;
611
- successLabel;
612
- feedbackTimer;
613
- /**
614
- * Runs the action, then shows the confirmation.
615
- *
616
- * The action runs first and a throw propagates: a clipboard write the browser
617
- * rejected must not be reported as a success.
618
- */
619
- run() {
620
- this.act();
621
- this.setTransientLabel(this.successLabel);
622
- if (this.feedbackTimer !== void 0) clearTimeout(this.feedbackTimer);
623
- this.feedbackTimer = setTimeout(() => {
624
- this.setTransientLabel(this.restingLabel);
625
- this.feedbackTimer = void 0;
626
- }, _BlockAffordanceButton.FEEDBACK_MS);
627
- }
628
- setTransientLabel(label) {
629
- this.label = label;
630
- this.textWidth = (0, import_ui.measureText)(label, this.font);
631
- this.scene?.markDirty();
467
+ // src/markdown-entities.ts
468
+ var import_core = require("@vectojs/core");
469
+ var HorizontalRule = class extends import_core.Entity {
470
+ color;
471
+ constructor(w, color) {
472
+ super();
473
+ this.width = w;
474
+ this.height = 1;
475
+ this.color = color;
632
476
  }
633
- /**
634
- * The label a reader hears is the one they see, transient confirmation
635
- * included, so an AT user gets the same feedback a sighted user does.
636
- */
637
- getA11yAttributes() {
638
- return { ...super.getA11yAttributes(), label: this.label };
477
+ isPointInside() {
478
+ return false;
639
479
  }
640
- /** Clears the pending revert so a destroyed block leaves no timer behind. */
641
- destroy() {
642
- if (this.feedbackTimer !== void 0) {
643
- clearTimeout(this.feedbackTimer);
644
- this.feedbackTimer = void 0;
645
- }
646
- super.destroy();
480
+ render(r) {
481
+ r.beginPath();
482
+ r.moveTo(0, 0);
483
+ r.lineTo(this.width, 0);
484
+ r.stroke(this.color, 1);
647
485
  }
648
486
  };
649
- var BlockWithAffordances = class _BlockWithAffordances extends import_ui.UIComponent {
650
- constructor(block, controls) {
487
+ var QuoteBorder = class extends import_core.Entity {
488
+ color;
489
+ constructor(height, color, width = 4) {
651
490
  super();
652
- this.block = block;
653
- this.controls = controls;
654
- this.add(block);
655
- for (const control of controls) this.add(control);
656
- this.layoutAffordances();
657
- }
658
- block;
659
- controls;
660
- /** Gap between the block's edges and the controls, in px. */
661
- static INSET = 8;
662
- /** Gap between adjacent controls, in px. */
663
- static GAP = 6;
664
- /**
665
- * Places the controls right-aligned along the block's top edge.
666
- *
667
- * Laid out right-to-left from the block's right edge so the first control in
668
- * the list ends up leftmost, which keeps DOM order (and therefore tab order and
669
- * the a11y reading order) matching the visual order.
670
- */
671
- layoutAffordances() {
672
- this.width = this.block.width;
673
- this.height = this.block.height;
674
- let right = this.block.width - _BlockWithAffordances.INSET;
675
- for (let i = this.controls.length - 1; i >= 0; i--) {
676
- const control = this.controls[i];
677
- control.x = right - control.width;
678
- control.y = _BlockWithAffordances.INSET;
679
- right = control.x - _BlockWithAffordances.GAP;
680
- }
491
+ this.width = width;
492
+ this.height = height;
493
+ this.color = color;
681
494
  }
682
- /**
683
- * Re-places the controls after the block's own box changed.
684
- *
685
- * Called by the owner when a block is resized or its content grew; the controls
686
- * are anchored to the right edge, so a width change moves them.
687
- */
688
- refreshAffordances() {
689
- this.layoutAffordances();
690
- this.scene?.markDirty();
495
+ isPointInside() {
496
+ return false;
691
497
  }
692
- /** The wrapper is a pass-through: its size is the block's size. */
693
- getLayoutControlledProperties() {
694
- return ["x", "y"];
498
+ render(r) {
499
+ r.beginPath();
500
+ r.roundRect(0, 0, this.width, this.height, this.width / 2);
501
+ r.fill(this.color);
695
502
  }
696
- /**
697
- * Projected as a group so assistive technology reports one labelled region
698
- * containing the block and its controls, rather than two unrelated siblings.
699
- */
700
- getA11yAttributes() {
701
- return { role: "group", pointerEvents: "none" };
503
+ };
504
+ var MarkdownContainer = class extends import_core.Entity {
505
+ isPointInside(_globalX, _globalY) {
506
+ return false;
702
507
  }
703
- render() {
508
+ render(_r) {
704
509
  }
705
510
  };
706
- function tableContentOf(token) {
707
- return {
708
- headers: token.header.map((cell) => cell.text),
709
- rows: token.rows.map((row) => row.map((cell) => cell.text)),
710
- align: token.align
711
- };
712
- }
713
-
714
- // src/frontMatter.ts
715
- var OPEN_RE = /^---[ \t]*\r?\n/;
716
- var OPENER_PREFIX_RE = /^(?:-|--|---[ \t]*\r?)$/;
717
- var KEY_RE = /^[^\s:#][^:]*:(?:[ \t].*)?$/;
718
- var CLOSE_RE = /^(?:---|\.\.\.)[ \t]*$/;
719
- var MAX_PENDING_CHARS = 4096;
720
- var NONE = { kind: "none" };
721
- var PENDING = { kind: "pending" };
722
- function scanFrontMatter(text, complete) {
723
- if (text.length === 0) return PENDING;
724
- const open = OPEN_RE.exec(text);
725
- if (!open) {
726
- return !complete && OPENER_PREFIX_RE.test(text) ? PENDING : NONE;
727
- }
728
- const decide = complete || text.length > MAX_PENDING_CHARS;
729
- const contentStart = open[0].length;
730
- let cursor = contentStart;
731
- let keyChecked = false;
732
- while (cursor < text.length) {
733
- const nl = text.indexOf("\n", cursor);
734
- if (nl === -1 && !decide) return PENDING;
735
- const line = text.slice(cursor, nl === -1 ? text.length : nl).replace(/\r$/, "");
736
- if (!keyChecked) {
737
- if (!KEY_RE.test(line)) return NONE;
738
- keyChecked = true;
739
- } else if (CLOSE_RE.test(line)) {
740
- return {
741
- kind: "found",
742
- raw: text.slice(contentStart, cursor),
743
- // A closer with no trailing newline ends the document, so the body is
744
- // empty rather than starting one character past the end.
745
- bodyStart: nl === -1 ? text.length : nl + 1
746
- };
747
- }
748
- if (nl === -1) break;
749
- cursor = nl + 1;
750
- }
751
- return decide ? NONE : PENDING;
752
- }
753
- function parseFrontMatterFields(raw) {
754
- const out = {};
755
- for (const rawLine of raw.split("\n")) {
756
- const line = rawLine.replace(/\r$/, "");
757
- if (line.length === 0 || /^[\s#]/.test(line)) continue;
758
- const sep = line.indexOf(":");
759
- if (sep <= 0) continue;
760
- const value = line.slice(sep + 1);
761
- if (value.length > 0 && value[0] !== " " && value[0] !== " ") continue;
762
- out[line.slice(0, sep).trim()] = unquote(value.trim());
763
- }
764
- return out;
765
- }
766
- function unquote(value) {
767
- if (value.length < 2) return value;
768
- const first = value[0];
769
- if ((first === '"' || first === "'") && value.endsWith(first)) {
770
- return value.slice(1, -1);
771
- }
772
- return value;
773
- }
774
511
 
775
- // src/MarkdownWorkerSource.ts
776
- var WORKER_SOURCE_STRING = '"use strict";(()=>{function V(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}var _=V();function ke(t){_=t}var C={exec:()=>null};function P(t){let e=[];return n=>{let s=Math.max(0,Math.min(3,n-1)),r=e[s];return r||(r=t(s),e[s]=r),r}}function k(t,e=""){let n=typeof t=="string"?t:t.source,s={replace:(r,l)=>{let a=typeof l=="string"?l:l.source;return a=a.replace(x.caret,"$1"),n=n.replace(r,a),s},getRegex:()=>new RegExp(n,e)};return s}var _e=((t="")=>{try{return!!new RegExp("(?<=1)(?<!1)"+t)}catch{return!1}})(),x={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:t=>new RegExp(`^( {0,3}${t})((?:[ ][^\\\\n]*)?(?:\\\\n|$))`),nextBulletRegex:P(t=>new RegExp(`^ {0,${t}}(?:[*+-]|\\\\d{1,9}[.)])((?:[ ][^\\\\n]*)?(?:\\\\n|$))`)),hrRegex:P(t=>new RegExp(`^ {0,${t}}((?:- *){3,}|(?:_ *){3,}|(?:\\\\* *){3,})(?:\\\\n+|$)`)),fencesBeginRegex:P(t=>new RegExp(`^ {0,${t}}(?:\\`\\`\\`|~~~)`)),headingBeginRegex:P(t=>new RegExp(`^ {0,${t}}#`)),htmlBeginRegex:P(t=>new RegExp(`^ {0,${t}}<(?:[a-z].*>|!--)`,"i")),blockquoteBeginRegex:P(t=>new RegExp(`^ {0,${t}}>`))},Pe=/^(?:[ \\t]*(?:\\n|$))+/,Me=/^((?: {4}| {0,3}\\t)[^\\n]+(?:\\n(?:[ \\t]*(?:\\n|$))*)?)+/,Ee=/^ {0,3}(`{3,}(?=[^`\\n]*(?:\\n|$))|~{3,})([^\\n]*)(?:\\n|$)(?:|([\\s\\S]*?)(?:\\n|$))(?: {0,3}\\1[~`]* *(?=\\n|$)|$)/,v=/^ {0,3}((?:-[\\t ]*){3,}|(?:_[ \\t]*){3,}|(?:\\*[ \\t]*){3,})(?:\\n+|$)/,Be=/^ {0,3}(#{1,6})(?=\\s|$)(.*)(?:\\n+|$)/,K=/ {0,3}(?:[*+-]|\\d{1,9}[.)])/,fe=/^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\\n(?!\\s*?\\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\\n {0,3}(=+|-+) *(?:\\n+|$)/,de=k(fe).replace(/bull/g,K).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}(?:\\s|$)/).replace(/html/g,/ {0,3}<[^\\n>]+>\\n/).replace(/\\|table/g,"").getRegex(),qe=k(fe).replace(/bull/g,K).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}(?:\\s|$)/).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|[ \\t]+\\n)[^\\n]+)*)/,ve=/^[^\\n]+/,Y=/(?!\\s*\\])(?:\\\\[\\s\\S]|[^\\[\\]\\\\])+/,De=k(/^ {0,3}\\[(label)\\]: *(?:\\n[ \\t]*)?([^<\\s][^\\s]*|<.*?>)(?:(?: +(?:\\n[ \\t]*)?| *\\n[ \\t]*)(title))? *(?:\\n+|$)/).replace("label",Y).replace("title",/(?:"(?:\\\\"?|[^"\\\\])*"|\'[^\'\\n]*(?:\\n[^\'\\n]+)*\\n?\'|\\([^()]*\\))/).getRegex(),Ze=k(/^(bull)([ \\t][^\\n]*?)?(?:\\n|$)/).replace(/bull/g,K).getRegex(),N="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",ee=/<!--(?:-?>|[\\s\\S]*?(?:-->|$))/,Oe=k("^ {0,3}(?:<(script|pre|style|textarea)[\\\\s>][\\\\s\\\\S]*?(?:</\\\\1>[^\\\\n]*\\\\n*|$)|comment[^\\\\n]*(\\\\n+|$)|<\\\\?[\\\\s\\\\S]*?(?:\\\\?>[^\\\\n]*\\\\n*|$)|<![A-Z][\\\\s\\\\S]*?(?:>[^\\\\n]*\\\\n*|$)|<!\\\\[CDATA\\\\[[\\\\s\\\\S]*?(?:\\\\]\\\\]>[^\\\\n]*\\\\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",ee).replace("tag",N).replace("attribute",/ +[a-zA-Z:_][\\w.:-]*(?: *= *"[^"\\n]*"| *= *\'[^\'\\n]*\'| *= *[^\\s"\'=<>`]+)?/).getRegex(),xe=t=>k(J).replace("hr",v).replace("heading"," {0,3}#{1,6}(?:\\\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\\\n]*\\\\n)|~~~)[^\\\\n]*\\\\n").replace("list",t).replace("html","</?(?:tag)(?: +|\\\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",N).getRegex(),Qe=xe(/ {0,3}(?:[*+-]|1[.)])[ \\t]+[^ \\t\\n]/),Ne=xe(/ {0,3}(?:[*+-]|\\d{1,9}[.)])(?:[ \\t]|\\n|$)/),He=k(/^( {0,3}> ?(paragraph|[^\\n]*)(?:\\n|$))+/).replace("paragraph",Ne).getRegex(),te={blockquote:He,code:Me,def:De,fences:Ee,heading:Be,hr:v,html:Oe,lheading:de,list:Ze,newline:Pe,paragraph:Qe,table:C,text:ve},ae=k("^ *([^\\\\n ].*)\\\\n {0,3}((?:\\\\| *)?:?-+:? *(?:\\\\| *:?-+:? *)*(?:\\\\| *)?)(?:\\\\n((?:(?! *\\\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\\\n|$))*)\\\\n*|$)").replace("hr",v).replace("heading"," {0,3}#{1,6}(?:\\\\s|$)").replace("blockquote"," {0,3}>").replace("code","(?: {4}| {0,3} )[^\\\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\\\n]*\\\\n)|~~~)[^\\\\n]*\\\\n").replace("list"," {0,3}(?:[*+-]|1[.)])[ \\\\t]").replace("html","</?(?:tag)(?: +|\\\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",N).getRegex(),je={...te,lheading:qe,table:ae,paragraph:k(J).replace("hr",v).replace("heading"," {0,3}#{1,6}(?:\\\\s|$)").replace("|lheading","").replace("table",ae).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\\\n]*\\\\n)|~~~)[^\\\\n]*\\\\n").replace("list"," {0,3}(?:[*+-]|1[.)])[ \\\\t]+[^ \\\\t\\\\n]").replace("html","</?(?:tag)(?: +|\\\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",N).getRegex()},Ge={...te,html:k(`^ *(?:comment *(?:\\\\n|\\\\s*$)|<(tag)[\\\\s\\\\S]+?</\\\\1> *(?:\\\\n{2,}|\\\\s*$)|<tag(?:"[^"]*"|\'[^\']*\'|\\\\s[^\'"/>\\\\s]*)*?/?> *(?:\\\\n{2,}|\\\\s*$))`).replace("comment",ee).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:C,lheading:/^(.+?)\\n {0,3}(=+|-+) *(?:\\n+|$)/,paragraph:k(J).replace("hr",v).replace("heading",` *#{1,6} *[^\n]`).replace("lheading",de).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},We=/^\\\\([!"#$%&\'()*+,\\-./:;<=>?@\\[\\]\\\\^_`{|}~])/,Fe=/^(`+)([^`]|[^`][\\s\\S]*?[^`])\\1(?!`)/,be=/^( {2,}|\\\\)\\n(?!\\s*$)/,Xe=/^(`+|[^`])(?:(?= {2,}\\n)|[\\s\\S]*?(?:(?=[\\\\<!\\[`*_]|\\b_|$)|[^ ](?= {2,}\\n)))/,M=/[\\p{P}\\p{S}]/u,H=/[\\s\\p{P}\\p{S}]/u,ne=/[^\\s\\p{P}\\p{S}]/u,Ue=k(/^((?![*_])punctSpace)/,"u").replace(/punctSpace/g,H).getRegex(),me=/(?!~)[\\p{P}\\p{S}]/u,Ve=/(?!~)[\\s\\p{P}\\p{S}]/u,Ke=/(?:[^\\s\\p{P}\\p{S}]|~)/u,Je=k(/link|precode-code|html/,"g").replace("link",/\\[(?:[^\\[\\]`]|(?<a>`+)[^`]+\\k<a>(?!`))*?\\]\\((?:\\\\[\\s\\S]|[^\\\\\\(\\)]|\\((?:\\\\[\\s\\S]|[^\\\\\\(\\)])*\\))*\\)/).replace("precode-",_e?"(?<!`)()":"(^^|[^`])").replace("code",/(?<b>`+)[^`]+\\k<b>(?!`)/).replace("html",/<(?! )[^<>]*?>/).getRegex(),we=/^(?:\\*+(?:((?!\\*)punct)|([^\\s*]))?)|^_+(?:((?!_)punct)|([^\\s_]))?/,Ye=k(we,"u").replace(/punct/g,M).getRegex(),et=k(we,"u").replace(/punct/g,me).getRegex(),ye="^[^_*]*?__[^_*]*?\\\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\\\*)punct(\\\\*+)(?=[\\\\s]|$)|notPunctSpace(\\\\*+)(?!\\\\*)(?=punctSpace|$)|(?!\\\\*)punctSpace(\\\\*+)(?=notPunctSpace)|[\\\\s](\\\\*+)(?!\\\\*)(?=punct)|(?!\\\\*)punct(\\\\*+)(?!\\\\*)(?=punct)|notPunctSpace(\\\\*+)(?=notPunctSpace)",tt=k(ye,"gu").replace(/notPunctSpace/g,ne).replace(/punctSpace/g,H).replace(/punct/g,M).getRegex(),nt=k(ye,"gu").replace(/notPunctSpace/g,Ke).replace(/punctSpace/g,Ve).replace(/punct/g,me).getRegex(),rt=k("^[^_*]*?\\\\*\\\\*[^_*]*?_[^_*]*?(?=\\\\*\\\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)","gu").replace(/notPunctSpace/g,ne).replace(/punctSpace/g,H).replace(/punct/g,M).getRegex(),st=k(/^~~?(?:((?!~)punct)|[^\\s~])/,"u").replace(/punct/g,M).getRegex(),lt="^[^~]+(?=[^~])|(?!~)punct(~~?)(?=[\\\\s]|$)|notPunctSpace(~~?)(?!~)(?=punctSpace|$)|(?!~)punctSpace(~~?)(?=notPunctSpace)|[\\\\s](~~?)(?!~)(?=punct)|(?!~)punct(~~?)(?!~)(?=punct)|notPunctSpace(~~?)(?=notPunctSpace)",it=k(lt,"gu").replace(/notPunctSpace/g,ne).replace(/punctSpace/g,H).replace(/punct/g,M).getRegex(),at=k(/\\\\(punct)/,"gu").replace(/punct/g,M).getRegex(),ot=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(),ct=k(ee).replace("(?:-->|$)","-->").getRegex(),ht=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",ct).replace("attribute",/\\s+[a-zA-Z:_][\\w.:-]*(?:\\s*=\\s*"[^"]*"|\\s*=\\s*\'[^\']*\'|\\s*=\\s*[^\\s"\'=<>`]+)?/).getRegex(),Z=/(?:\\[(?:\\\\[\\s\\S]|[^\\[\\]\\\\])*\\]|\\\\[\\s\\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\\])|[^\\[\\]\\\\`])*?/,ut=k(/^!?\\[(label)\\]\\(\\s*(href)(?:(?:[ \\t]+(?:\\n[ \\t]*)?|\\n[ \\t]*)(title))?\\s*\\)/).replace("label",Z).replace("href",/<(?:\\\\.|[^\\n<>\\\\])+>|[^ \\t\\n\\x00-\\x1f]+|(?=\\))/).replace("title",/"(?:\\\\"?|[^"\\\\])*"|\'(?:\\\\\'?|[^\'\\\\])*\'|\\((?:\\\\\\)?|[^)\\\\])*\\)/).getRegex(),Re=k(/^!?\\[(label)\\]\\[(ref)\\]/).replace("label",Z).replace("ref",Y).getRegex(),$e=k(/^!?\\[(ref)\\](?:\\[\\])?/).replace("ref",Y).getRegex(),pt=k("reflink|nolink(?!\\\\()","g").replace("reflink",Re).replace("nolink",$e).getRegex(),oe=/[hH][tT][tT][pP][sS]?|[fF][tT][pP]/,re={_backpedal:C,anyPunctuation:at,autolink:ot,blockSkip:Je,br:be,code:Fe,del:C,delLDelim:C,delRDelim:C,emStrongLDelim:Ye,emStrongRDelimAst:tt,emStrongRDelimUnd:rt,escape:We,link:ut,nolink:$e,punctuation:Ue,reflink:Re,reflinkSearch:pt,tag:ht,text:Xe,url:C},gt={...re,link:k(/^!?\\[(label)\\]\\((.*?)\\)/).replace("label",Z).getRegex(),reflink:k(/^!?\\[(label)\\]\\s*\\[([^\\]]*)\\]/).replace("label",Z).getRegex()},F={...re,emStrongRDelimAst:nt,emStrongLDelim:et,delLDelim:st,delRDelim:it,url:k(/^((?:protocol):\\/\\/|www\\.)(?:[a-zA-Z0-9\\-]+\\.?)+[^\\s<]*|^email/).replace("protocol",oe).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",oe).getRegex()},kt={...F,br:k(be).replace("{2,}","*").getRegex(),text:k(F.text).replace("\\\\b_","\\\\b_| {2,}\\\\n").replace(/\\{2,\\}/g,"*").getRegex()},D={normal:te,gfm:je,pedantic:Ge},B={normal:re,gfm:F,breaks:kt,pedantic:gt},ft={"&":"&amp;","<":"&lt;",">":"&gt;",\'"\':"&quot;","\'":"&#39;"},ce=t=>ft[t];function S(t,e){if(e){if(x.escapeTest.test(t))return t.replace(x.escapeReplace,ce)}else if(x.escapeTestNoEncode.test(t))return t.replace(x.escapeReplaceNoEncode,ce);return t}function he(t){try{t=encodeURI(t).replace(x.percentDecode,"%")}catch{return null}return t}function ue(t,e){let n=t.replace(x.findPipe,(l,a,i)=>{let o=!1,c=a;for(;--c>=0&&i[c]==="\\\\";)o=!o;return o?"|":" |"}),s=n.split(x.splitPipe),r=0;if(s[0].trim()||s.shift(),s.length>0&&!s.at(-1)?.trim()&&s.pop(),e)if(s.length>e)s.splice(e);else for(;s.length<e;)s.push("");for(;r<s.length;r++)s[r]=s[r].trim().replace(x.slashPipe,"|");return s}function z(t,e,n){let s=t.length;if(s===0)return"";let r=0;for(;r<s;){let l=t.charAt(s-r-1);if(l===e&&!n)r++;else if(l!==e&&n)r++;else break}return t.slice(0,s-r)}function pe(t){let e=t.split(`\n`),n=e.length-1;for(;n>=0&&x.blankLine.test(e[n]);)n--;return e.length-n<=2?t:e.slice(0,n+1).join(`\n`)}function dt(t,e){if(t.indexOf(e[1])===-1)return-1;let n=0;for(let s=0;s<t.length;s++)if(t[s]==="\\\\")s++;else if(t[s]===e[0])n++;else if(t[s]===e[1]&&(n--,n<0))return s;return n>0?-2:-1}function xt(t,e=0){let n=e,s="";for(let r of t)if(r===" "){let l=4-n%4;s+=" ".repeat(l),n+=l}else s+=r,n++;return s}function ge(t,e,n,s,r){let l=e.href,a=e.title||null,i=t[1].replace(r.other.outputLinkReplace,"$1");s.state.inLink=!0;let o={type:t[0].charAt(0)==="!"?"image":"link",raw:n,href:l,title:a,text:i,tokens:s.inlineTokens(i)};return s.state.inLink=!1,o}function bt(t,e,n){let s=t.match(n.other.indentCodeCompensation);if(s===null)return e;let r=s[1];return e.split(`\n`).map(l=>{let a=l.match(n.other.beginningSpace);if(a===null)return l;let[i]=a;return i.length>=r.length?l.slice(r.length):l}).join(`\n`)}var O=class{options;rules;lexer;constructor(t){this.options=t||_}space(t){let e=this.rules.block.newline.exec(t);if(e&&e[0].length>0)return{type:"space",raw:e[0]}}code(t){let e=this.rules.block.code.exec(t);if(e){let n=this.options.pedantic?e[0]:pe(e[0]),s=n.replace(this.rules.other.codeRemoveIndent,"");return{type:"code",raw:n,codeBlockStyle:"indented",text:s}}}fences(t){let e=this.rules.block.fences.exec(t);if(e){let n=e[0],s=bt(n,e[3]||"",this.rules);return{type:"code",raw:n,lang:e[2]?e[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):e[2],text:s}}}heading(t){let e=this.rules.block.heading.exec(t);if(e){let n=e[2].trim();if(this.rules.other.endingHash.test(n)){let s=z(n,"#");(this.options.pedantic||!s||this.rules.other.endingSpaceChar.test(s))&&(n=s.trim())}return{type:"heading",raw:z(e[0],`\n`),depth:e[1].length,text:n,tokens:this.lexer.inline(n)}}}hr(t){let e=this.rules.block.hr.exec(t);if(e)return{type:"hr",raw:z(e[0],`\n`)}}blockquote(t){let e=this.rules.block.blockquote.exec(t);if(e){let n=z(e[0],`\n`).split(`\n`),s="",r="",l=[];for(;n.length>0;){let a=!1,i=[],o;for(o=0;o<n.length;o++)if(this.rules.other.blockquoteStart.test(n[o]))i.push(n[o]),a=!0;else if(!a)i.push(n[o]);else break;n=n.slice(o);let c=i.join(`\n`),u=c.replace(this.rules.other.blockquoteSetextReplace,`\n $1`).replace(this.rules.other.blockquoteSetextReplace2,"");s=s?`${s}\n${c}`:c,r=r?`${r}\n${u}`:u;let h=this.lexer.state.top;if(this.lexer.state.top=!0,this.lexer.blockTokens(u,l,!0),this.lexer.state.top=h,n.length===0)break;let p=l.at(-1);if(p?.type==="code")break;if(p?.type==="blockquote"){let d=p,f=d.raw+`\n`+n.join(`\n`),m=this.blockquote(f);l[l.length-1]=m,s=s.substring(0,s.length-d.raw.length)+m.raw,r=r.substring(0,r.length-d.text.length)+m.text;break}else if(p?.type==="list"){let d=p,f=d.raw+`\n`+n.join(`\n`),m=this.list(f);l[l.length-1]=m,s=s.substring(0,s.length-p.raw.length)+m.raw,r=r.substring(0,r.length-d.raw.length)+m.raw,n=f.substring(l.at(-1).raw.length).split(`\n`);continue}}return{type:"blockquote",raw:s,tokens:l,text:r}}}list(t){let e=this.rules.block.list.exec(t);if(e){let n=e[1].trim(),s=n.length>1,r={type:"list",raw:"",ordered:s,start:s?+n.slice(0,-1):"",loose:!1,items:[]};n=s?`\\\\d{1,9}\\\\${n.slice(-1)}`:`\\\\${n}`,this.options.pedantic&&(n=s?n:"[*+-]");let l=this.rules.other.listItemRegex(n),a=!1;for(;t;){let o=!1,c="",u="";if(!(e=l.exec(t))||this.rules.block.hr.test(t))break;c=e[0],t=t.substring(c.length);let h=xt(e[2].split(`\n`,1)[0],e[1].length),p=t.split(`\n`,1)[0],d=!h.trim(),f=0;if(this.options.pedantic?(f=2,u=h.trimStart()):d?f=e[1].length+1:(f=h.search(this.rules.other.nonSpaceChar),f=f>4?1:f,u=h.slice(f),f+=e[1].length),d&&this.rules.other.blankLine.test(p)&&(c+=p+`\n`,t=t.substring(p.length+1),o=!0),!o){let m=this.rules.other.nextBulletRegex(f),w=this.rules.other.hrRegex(f),y=this.rules.other.fencesBeginRegex(f),L=this.rules.other.headingBeginRegex(f),W=this.rules.other.htmlBeginRegex(f),A=this.rules.other.blockquoteBeginRegex(f);for(;t;){let b=t.split(`\n`,1)[0],T;if(p=b,this.options.pedantic?(p=p.replace(this.rules.other.listReplaceNesting," "),T=p):T=p.replace(this.rules.other.tabCharGlobal," "),y.test(p)||L.test(p)||W.test(p)||A.test(p)||m.test(p)||w.test(p))break;if(T.search(this.rules.other.nonSpaceChar)>=f||!p.trim())u+=`\n`+T.slice(f);else{if(d||h.replace(this.rules.other.tabCharGlobal," ").search(this.rules.other.nonSpaceChar)>=4||y.test(h)||L.test(h)||w.test(h))break;u+=`\n`+p}d=!p.trim(),c+=b+`\n`,t=t.substring(b.length+1),h=T.slice(f)}}r.loose||(a?r.loose=!0:this.rules.other.doubleBlankLine.test(c)&&(a=!0)),r.items.push({type:"list_item",raw:c,task:!!this.options.gfm&&this.rules.other.listIsTask.test(u),loose:!1,text:u,tokens:[]}),r.raw+=c}let i=r.items.at(-1);if(i)i.raw=i.raw.trimEnd(),i.text=i.text.trimEnd();else return;r.raw=r.raw.trimEnd();for(let o of r.items){this.lexer.state.top=!1,o.tokens=this.lexer.blockTokens(o.text,[]);let c=o.tokens[0];if(o.task&&(c?.type==="text"||c?.type==="paragraph")){o.text=o.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 h=this.lexer.inlineQueue.length-1;h>=0;h--)if(this.rules.other.listIsTask.test(this.lexer.inlineQueue[h].src)){this.lexer.inlineQueue[h].src=this.lexer.inlineQueue[h].src.replace(this.rules.other.listReplaceTask,"");break}let u=this.rules.other.listTaskCheckbox.exec(o.raw);if(u){let h={type:"checkbox",raw:u[0]+" ",checked:u[0]!=="[ ]"};o.checked=h.checked,r.loose?o.tokens[0]&&["paragraph","text"].includes(o.tokens[0].type)&&"tokens"in o.tokens[0]&&o.tokens[0].tokens?(o.tokens[0].raw=h.raw+o.tokens[0].raw,o.tokens[0].text=h.raw+o.tokens[0].text,o.tokens[0].tokens.unshift(h)):o.tokens.unshift({type:"paragraph",raw:h.raw,text:h.raw,tokens:[h]}):o.tokens.unshift(h)}}else o.task&&(o.task=!1);if(!r.loose){let u=o.tokens.filter(p=>p.type==="space"),h=u.length>0&&u.some(p=>this.rules.other.anyLine.test(p.raw));r.loose=h}}if(r.loose)for(let o of r.items){o.loose=!0;for(let c of o.tokens)c.type==="text"&&(c.type="paragraph")}return r}}html(t){let e=this.rules.block.html.exec(t);if(e){let n=pe(e[0]);return{type:"html",block:!0,raw:n,pre:e[1]==="pre"||e[1]==="script"||e[1]==="style",text:n}}}def(t){let e=this.rules.block.def.exec(t);if(e){let n=e[1].toLowerCase().replace(this.rules.other.multipleSpaceGlobal," "),s=e[2]?e[2].replace(this.rules.other.hrefBrackets,"$1").replace(this.rules.inline.anyPunctuation,"$1"):"",r=e[3]?e[3].substring(1,e[3].length-1).replace(this.rules.inline.anyPunctuation,"$1"):e[3];return{type:"def",tag:n,raw:z(e[0],`\n`),href:s,title:r}}}table(t){let e=this.rules.block.table.exec(t);if(!e||!this.rules.other.tableDelimiter.test(e[2]))return;let n=ue(e[1]),s=e[2].replace(this.rules.other.tableAlignChars,"").split("|"),r=e[3]?.trim()?e[3].replace(this.rules.other.tableRowBlankLine,"").split(`\n`):[],l={type:"table",raw:z(e[0],`\n`),header:[],align:[],rows:[]};if(n.length===s.length){for(let a of s)this.rules.other.tableAlignRight.test(a)?l.align.push("right"):this.rules.other.tableAlignCenter.test(a)?l.align.push("center"):this.rules.other.tableAlignLeft.test(a)?l.align.push("left"):l.align.push(null);for(let a=0;a<n.length;a++)l.header.push({text:n[a],tokens:this.lexer.inline(n[a]),header:!0,align:l.align[a]});for(let a of r)l.rows.push(ue(a,l.header.length).map((i,o)=>({text:i,tokens:this.lexer.inline(i),header:!1,align:l.align[o]})));return l}}lheading(t){let e=this.rules.block.lheading.exec(t);if(e){let n=e[1].trim();return{type:"heading",raw:z(e[0],`\n`),depth:e[2].charAt(0)==="="?1:2,text:n,tokens:this.lexer.inline(n)}}}paragraph(t){let e=this.rules.block.paragraph.exec(t);if(e){let n=e[1].charAt(e[1].length-1)===`\n`?e[1].slice(0,-1):e[1];return{type:"paragraph",raw:e[0],text:n,tokens:this.lexer.inline(n)}}}text(t){let e=this.rules.block.text.exec(t);if(e)return{type:"text",raw:e[0],text:e[0],tokens:this.lexer.inline(e[0])}}escape(t){let e=this.rules.inline.escape.exec(t);if(e)return{type:"escape",raw:e[0],text:e[1]}}tag(t){let e=this.rules.inline.tag.exec(t);if(e)return!this.lexer.state.inLink&&this.rules.other.startATag.test(e[0])?this.lexer.state.inLink=!0:this.lexer.state.inLink&&this.rules.other.endATag.test(e[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&this.rules.other.startPreScriptTag.test(e[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&this.rules.other.endPreScriptTag.test(e[0])&&(this.lexer.state.inRawBlock=!1),{type:"html",raw:e[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:!1,text:e[0]}}link(t){let e=this.rules.inline.link.exec(t);if(e){let n=e[2].trim();if(!this.options.pedantic&&this.rules.other.startAngleBracket.test(n)){if(!this.rules.other.endAngleBracket.test(n))return;let l=z(n.slice(0,-1),"\\\\");if((n.length-l.length)%2===0)return}else{let l=dt(e[2],"()");if(l===-2)return;if(l>-1){let a=(e[0].indexOf("!")===0?5:4)+e[1].length+l;e[2]=e[2].substring(0,l),e[0]=e[0].substring(0,a).trim(),e[3]=""}}let s=e[2],r="";if(this.options.pedantic){let l=this.rules.other.pedanticHrefTitle.exec(s);l&&(s=l[1],r=l[3])}else r=e[3]?e[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)),ge(e,{href:s&&s.replace(this.rules.inline.anyPunctuation,"$1"),title:r&&r.replace(this.rules.inline.anyPunctuation,"$1")},e[0],this.lexer,this.rules)}}reflink(t,e){let n;if((n=this.rules.inline.reflink.exec(t))||(n=this.rules.inline.nolink.exec(t))){let s=(n[2]||n[1]).replace(this.rules.other.multipleSpaceGlobal," "),r=e[s.toLowerCase()];if(!r){let l=n[0].charAt(0);return{type:"text",raw:l,text:l}}return ge(n,r,n[0],this.lexer,this.rules)}}emStrong(t,e,n=""){let s=this.rules.inline.emStrongLDelim.exec(t);if(!(!s||!s[1]&&!s[2]&&!s[3]&&!s[4]||s[4]&&n.match(this.rules.other.unicodeAlphaNumeric))&&(!(s[1]||s[3])||!n||this.rules.inline.punctuation.exec(n))){let r=[...s[0]].length-1,l,a,i=r,o=0,c=s[0][0]==="*"?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(c.lastIndex=0,e=e.slice(-1*t.length+r);(s=c.exec(e))!==null;){if(l=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!l)continue;if(a=[...l].length,s[3]||s[4]){i+=a;continue}else if((s[5]||s[6])&&r%3&&!((r+a)%3)){o+=a;continue}if(i-=a,i>0)continue;a=Math.min(a,a+i+o);let u=[...s[0]][0].length,h=t.slice(0,r+s.index+u+a);if(Math.min(r,a)%2){let d=h.slice(1,-1);return{type:"em",raw:h,text:d,tokens:this.lexer.inlineTokens(d)}}let p=h.slice(2,-2);return{type:"strong",raw:h,text:p,tokens:this.lexer.inlineTokens(p)}}}}codespan(t){let e=this.rules.inline.code.exec(t);if(e){let n=e[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:e[0],text:n}}}br(t){let e=this.rules.inline.br.exec(t);if(e)return{type:"br",raw:e[0]}}del(t,e,n=""){let s=this.rules.inline.delLDelim.exec(t);if(s&&(!s[1]||!n||this.rules.inline.punctuation.exec(n))){let r=[...s[0]].length-1,l,a,i=r,o=this.rules.inline.delRDelim;for(o.lastIndex=0,e=e.slice(-1*t.length+r);(s=o.exec(e))!==null;){if(l=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!l||(a=[...l].length,a!==r))continue;if(s[3]||s[4]){i+=a;continue}if(i-=a,i>0)continue;a=Math.min(a,a+i);let c=[...s[0]][0].length,u=t.slice(0,r+s.index+c+a),h=u.slice(r,-r);return{type:"del",raw:u,text:h,tokens:this.lexer.inlineTokens(h)}}}}autolink(t){let e=this.rules.inline.autolink.exec(t);if(e){let n,s;return e[2]==="@"?(n=e[1],s="mailto:"+n):(n=e[1],s=n),{type:"link",raw:e[0],text:n,href:s,tokens:[{type:"text",raw:n,text:n}]}}}url(t){let e;if(e=this.rules.inline.url.exec(t)){let n,s;if(e[2]==="@")n=e[0],s="mailto:"+n;else{let r;do r=e[0],e[0]=this.rules.inline._backpedal.exec(e[0])?.[0]??"";while(r!==e[0]);n=e[0],e[1]==="www."?s="http://"+e[0]:s=e[0]}return{type:"link",raw:e[0],text:n,href:s,tokens:[{type:"text",raw:n,text:n}]}}}inlineText(t){let e=this.rules.inline.text.exec(t);if(e){let n=this.lexer.state.inRawBlock;return{type:"text",raw:e[0],text:e[0],escaped:n}}}},R=class X{tokens;options;state;inlineQueue;tokenizer;constructor(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||_,this.options.tokenizer=this.options.tokenizer||new O,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options,this.tokenizer.lexer=this,this.inlineQueue=[],this.state={inLink:!1,inRawBlock:!1,top:!0};let n={other:x,block:D.normal,inline:B.normal};this.options.pedantic?(n.block=D.pedantic,n.inline=B.pedantic):this.options.gfm&&(n.block=D.gfm,this.options.breaks?n.inline=B.breaks:n.inline=B.gfm),this.tokenizer.rules=n}static get rules(){return{block:D,inline:B}}static lex(e,n){return new X(n).lex(e)}static lexInline(e,n){return new X(n).inlineTokens(e)}lex(e){e=e.replace(x.carriageReturn,`\n`),this.blockTokens(e,this.tokens);for(let n=0;n<this.inlineQueue.length;n++){let s=this.inlineQueue[n];this.inlineTokens(s.src,s.tokens)}return this.inlineQueue=[],this.tokens}blockTokens(e,n=[],s=!1){this.tokenizer.lexer=this,this.options.pedantic&&(e=e.replace(x.tabCharGlobal," ").replace(x.spaceLine,""));let r=1/0;for(;e;){if(e.length<r)r=e.length;else{this.infiniteLoopError(e.charCodeAt(0));break}let l;if(this.options.extensions?.block?.some(i=>(l=i.call({lexer:this},e,n))?(e=e.substring(l.raw.length),n.push(l),!0):!1))continue;if(l=this.tokenizer.space(e)){e=e.substring(l.raw.length);let i=n.at(-1);l.raw.length===1&&i!==void 0?i.raw+=`\n`:n.push(l);continue}if(l=this.tokenizer.code(e)){e=e.substring(l.raw.length);let i=n.at(-1);i?.type==="paragraph"||i?.type==="text"?(i.raw+=(i.raw.endsWith(`\n`)?"":`\n`)+l.raw,i.text+=`\n`+l.text,this.inlineQueue.at(-1).src=i.text):n.push(l);continue}if(l=this.tokenizer.fences(e)){e=e.substring(l.raw.length),n.push(l);continue}if(l=this.tokenizer.heading(e)){e=e.substring(l.raw.length),n.push(l);continue}if(l=this.tokenizer.hr(e)){e=e.substring(l.raw.length),n.push(l);continue}if(l=this.tokenizer.blockquote(e)){e=e.substring(l.raw.length),n.push(l);continue}if(l=this.tokenizer.list(e)){e=e.substring(l.raw.length),n.push(l);continue}if(l=this.tokenizer.html(e)){e=e.substring(l.raw.length),n.push(l);continue}if(l=this.tokenizer.def(e)){e=e.substring(l.raw.length);let i=n.at(-1);i?.type==="paragraph"||i?.type==="text"?(i.raw+=(i.raw.endsWith(`\n`)?"":`\n`)+l.raw,i.text+=`\n`+l.raw,this.inlineQueue.at(-1).src=i.text):this.tokens.links[l.tag]||(this.tokens.links[l.tag]={href:l.href,title:l.title},n.push(l));continue}if(l=this.tokenizer.table(e)){e=e.substring(l.raw.length),n.push(l);continue}if(l=this.tokenizer.lheading(e)){e=e.substring(l.raw.length),n.push(l);continue}let a=e;if(this.options.extensions?.startBlock){let i=1/0,o=e.slice(1),c;this.options.extensions.startBlock.forEach(u=>{c=u.call({lexer:this},o),typeof c=="number"&&c>=0&&(i=Math.min(i,c))}),i<1/0&&i>=0&&(a=e.substring(0,i+1))}if(this.state.top&&(l=this.tokenizer.paragraph(a))){let i=n.at(-1);s&&i?.type==="paragraph"?(i.raw+=(i.raw.endsWith(`\n`)?"":`\n`)+l.raw,i.text+=`\n`+l.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=i.text):n.push(l),s=a.length!==e.length,e=e.substring(l.raw.length);continue}if(l=this.tokenizer.text(e)){e=e.substring(l.raw.length);let i=n.at(-1);i?.type==="text"?(i.raw+=(i.raw.endsWith(`\n`)?"":`\n`)+l.raw,i.text+=`\n`+l.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=i.text):n.push(l);continue}if(e){this.infiniteLoopError(e.charCodeAt(0));break}}return this.state.top=!0,n}inline(e,n=[]){return this.inlineQueue.push({src:e,tokens:n}),n}inlineTokens(e,n=[]){this.tokenizer.lexer=this;let s=e;if(this.tokens.links){let i=Object.keys(this.tokens.links);i.length>0&&(s=s.replace(this.tokenizer.rules.inline.reflinkSearch,o=>i.includes(o.slice(o.lastIndexOf("[")+1,-1))?"["+"a".repeat(o.length-2)+"]":o))}s=s.replace(this.tokenizer.rules.inline.anyPunctuation,"++"),s=s.replace(this.tokenizer.rules.inline.blockSkip,(i,o,c)=>{let u=c?c.length:0;return i.slice(0,u)+"["+"a".repeat(i.length-u-2)+"]"}),s=this.options.hooks?.emStrongMask?.call({lexer:this},s)??s;let r=!1,l="",a=1/0;for(;e;){if(e.length<a)a=e.length;else{this.infiniteLoopError(e.charCodeAt(0));break}r||(l=""),r=!1;let i;if(this.options.extensions?.inline?.some(c=>(i=c.call({lexer:this},e,n))?(e=e.substring(i.raw.length),n.push(i),!0):!1))continue;if(i=this.tokenizer.escape(e)){e=e.substring(i.raw.length),n.push(i);continue}if(i=this.tokenizer.tag(e)){e=e.substring(i.raw.length),n.push(i);continue}if(i=this.tokenizer.link(e)){e=e.substring(i.raw.length),n.push(i);continue}if(i=this.tokenizer.reflink(e,this.tokens.links)){e=e.substring(i.raw.length);let c=n.at(-1);i.type==="text"&&c?.type==="text"?(c.raw+=i.raw,c.text+=i.text):n.push(i);continue}if(i=this.tokenizer.emStrong(e,s,l)){e=e.substring(i.raw.length),n.push(i);continue}if(i=this.tokenizer.codespan(e)){e=e.substring(i.raw.length),n.push(i);continue}if(i=this.tokenizer.br(e)){e=e.substring(i.raw.length),n.push(i);continue}if(i=this.tokenizer.del(e,s,l)){e=e.substring(i.raw.length),n.push(i);continue}if(i=this.tokenizer.autolink(e)){e=e.substring(i.raw.length),n.push(i);continue}if(!this.state.inLink&&(i=this.tokenizer.url(e))){e=e.substring(i.raw.length),n.push(i);continue}let o=e;if(this.options.extensions?.startInline){let c=1/0,u=e.slice(1),h;this.options.extensions.startInline.forEach(p=>{h=p.call({lexer:this},u),typeof h=="number"&&h>=0&&(c=Math.min(c,h))}),c<1/0&&c>=0&&(o=e.substring(0,c+1))}if(i=this.tokenizer.inlineText(o)){e=e.substring(i.raw.length),i.raw.slice(-1)!=="_"&&(l=i.raw.slice(-1)),r=!0;let c=n.at(-1);c?.type==="text"?(c.raw+=i.raw,c.text+=i.text):n.push(i);continue}if(e){this.infiniteLoopError(e.charCodeAt(0));break}}return n}infiniteLoopError(e){let n="Infinite loop on byte: "+e;if(this.options.silent)console.error(n);else throw new Error(n)}},Q=class{options;parser;constructor(t){this.options=t||_}space(t){return""}code({text:t,lang:e,escaped:n}){let s=(e||"").match(x.notSpaceStart)?.[0],r=t.replace(x.endingNewline,"")+`\n`;return s?\'<pre><code class="language-\'+S(s)+\'">\'+(n?r:S(r,!0))+`</code></pre>\n`:"<pre><code>"+(n?r:S(r,!0))+`</code></pre>\n`}blockquote({tokens:t}){return`<blockquote>\n${this.parser.parse(t)}</blockquote>\n`}html({text:t}){return t}def(t){return""}heading({tokens:t,depth:e}){return`<h${e}>${this.parser.parseInline(t)}</h${e}>\n`}hr(t){return`<hr>\n`}list(t){let e=t.ordered,n=t.start,s="";for(let a=0;a<t.items.length;a++){let i=t.items[a];s+=this.listitem(i)}let r=e?"ol":"ul",l=e&&n!==1?\' start="\'+n+\'"\':"";return"<"+r+l+`>\n`+s+"</"+r+`>\n`}listitem(t){return`<li>${this.parser.parse(t.tokens)}</li>\n`}checkbox({checked:t}){return"<input "+(t?\'checked="" \':"")+\'disabled="" type="checkbox"> \'}paragraph({tokens:t}){return`<p>${this.parser.parseInline(t)}</p>\n`}table(t){let e="",n="";for(let r=0;r<t.header.length;r++)n+=this.tablecell(t.header[r]);e+=this.tablerow({text:n});let s="";for(let r=0;r<t.rows.length;r++){let l=t.rows[r];n="";for(let a=0;a<l.length;a++)n+=this.tablecell(l[a]);s+=this.tablerow({text:n})}return s&&(s=`<tbody>${s}</tbody>`),`<table>\n<thead>\n`+e+`</thead>\n`+s+`</table>\n`}tablerow({text:t}){return`<tr>\n${t}</tr>\n`}tablecell(t){let e=this.parser.parseInline(t.tokens),n=t.header?"th":"td";return(t.align?`<${n} align="${t.align}">`:`<${n}>`)+e+`</${n}>\n`}strong({tokens:t}){return`<strong>${this.parser.parseInline(t)}</strong>`}em({tokens:t}){return`<em>${this.parser.parseInline(t)}</em>`}codespan({text:t}){return`<code>${S(t,!0)}</code>`}br(t){return"<br>"}del({tokens:t}){return`<del>${this.parser.parseInline(t)}</del>`}link({href:t,title:e,tokens:n}){let s=this.parser.parseInline(n),r=he(t);if(r===null)return s;t=r;let l=\'<a href="\'+t+\'"\';return e&&(l+=\' title="\'+S(e)+\'"\'),l+=">"+s+"</a>",l}image({href:t,title:e,text:n,tokens:s}){s&&(n=this.parser.parseInline(s,this.parser.textRenderer));let r=he(t);if(r===null)return S(n);t=r;let l=`<img src="${t}" alt="${S(n)}"`;return e&&(l+=` title="${S(e)}"`),l+=">",l}text(t){return"tokens"in t&&t.tokens?this.parser.parseInline(t.tokens):"escaped"in t&&t.escaped?t.text:S(t.text)}},se=class{strong({text:t}){return t}em({text:t}){return t}codespan({text:t}){return t}del({text:t}){return t}html({text:t}){return t}text({text:t}){return t}link({text:t}){return""+t}image({text:t}){return""+t}br(){return""}checkbox({raw:t}){return t}},$=class U{options;renderer;textRenderer;constructor(e){this.options=e||_,this.options.renderer=this.options.renderer||new Q,this.renderer=this.options.renderer,this.renderer.options=this.options,this.renderer.parser=this,this.textRenderer=new se}static parse(e,n){return new U(n).parse(e)}static parseInline(e,n){return new U(n).parseInline(e)}parse(e){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 a=r,i=this.options.extensions.renderers[a.type].call({parser:this},a);if(i!==!1||!["space","hr","heading","code","table","blockquote","list","html","def","paragraph","text"].includes(a.type)){n+=i||"";continue}}let l=r;switch(l.type){case"space":{n+=this.renderer.space(l);break}case"hr":{n+=this.renderer.hr(l);break}case"heading":{n+=this.renderer.heading(l);break}case"code":{n+=this.renderer.code(l);break}case"table":{n+=this.renderer.table(l);break}case"blockquote":{n+=this.renderer.blockquote(l);break}case"list":{n+=this.renderer.list(l);break}case"checkbox":{n+=this.renderer.checkbox(l);break}case"html":{n+=this.renderer.html(l);break}case"def":{n+=this.renderer.def(l);break}case"paragraph":{n+=this.renderer.paragraph(l);break}case"text":{n+=this.renderer.text(l);break}default:{let a=\'Token with "\'+l.type+\'" type was not found.\';if(this.options.silent)return console.error(a),"";throw new Error(a)}}}return n}parseInline(e,n=this.renderer){this.renderer.parser=this;let s="";for(let r=0;r<e.length;r++){let l=e[r];if(this.options.extensions?.renderers?.[l.type]){let i=this.options.extensions.renderers[l.type].call({parser:this},l);if(i!==!1||!["escape","html","link","image","strong","em","codespan","br","del","text"].includes(l.type)){s+=i||"";continue}}let a=l;switch(a.type){case"escape":{s+=n.text(a);break}case"html":{s+=n.html(a);break}case"link":{s+=n.link(a);break}case"image":{s+=n.image(a);break}case"checkbox":{s+=n.checkbox(a);break}case"strong":{s+=n.strong(a);break}case"em":{s+=n.em(a);break}case"codespan":{s+=n.codespan(a);break}case"br":{s+=n.br(a);break}case"del":{s+=n.del(a);break}case"text":{s+=n.text(a);break}default:{let i=\'Token with "\'+a.type+\'" type was not found.\';if(this.options.silent)return console.error(i),"";throw new Error(i)}}}return s}},q=class{options;block;constructor(t){this.options=t||_}static passThroughHooks=new Set(["preprocess","postprocess","processAllTokens","emStrongMask"]);static passThroughHooksRespectAsync=new Set(["preprocess","postprocess","processAllTokens"]);preprocess(t){return t}postprocess(t){return t}processAllTokens(t){return t}emStrongMask(t){return t}provideLexer(t=this.block){return t?R.lex:R.lexInline}provideParser(t=this.block){return t?$.parse:$.parseInline}},mt=class{defaults=V();options=this.setOptions;parse=this.parseMarkdown(!0);parseInline=this.parseMarkdown(!1);Parser=$;Renderer=Q;TextRenderer=se;Lexer=R;Tokenizer=O;Hooks=q;constructor(...t){this.use(...t)}walkTokens(t,e){let n=[];for(let s of t)switch(n=n.concat(e.call(this,s)),s.type){case"table":{let r=s;for(let l of r.header)n=n.concat(this.walkTokens(l.tokens,e));for(let l of r.rows)for(let a of l)n=n.concat(this.walkTokens(a.tokens,e));break}case"list":{let r=s;n=n.concat(this.walkTokens(r.items,e));break}default:{let r=s;this.defaults.extensions?.childTokens?.[r.type]?this.defaults.extensions.childTokens[r.type].forEach(l=>{let a=r[l].flat(1/0);n=n.concat(this.walkTokens(a,e))}):r.tokens&&(n=n.concat(this.walkTokens(r.tokens,e)))}}return n}use(...t){let e=this.defaults.extensions||{renderers:{},childTokens:{}};return t.forEach(n=>{let s={...n};if(s.async=this.defaults.async||s.async||!1,n.extensions&&(n.extensions.forEach(r=>{if(!r.name)throw new Error("extension name required");if("renderer"in r){let l=e.renderers[r.name];l?e.renderers[r.name]=function(...a){let i=r.renderer.apply(this,a);return i===!1&&(i=l.apply(this,a)),i}:e.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 l=e[r.level];l?l.unshift(r.tokenizer):e[r.level]=[r.tokenizer],r.start&&(r.level==="block"?e.startBlock?e.startBlock.push(r.start):e.startBlock=[r.start]:r.level==="inline"&&(e.startInline?e.startInline.push(r.start):e.startInline=[r.start]))}"childTokens"in r&&r.childTokens&&(e.childTokens[r.name]=r.childTokens)}),s.extensions=e),n.renderer){let r=this.defaults.renderer||new Q(this.defaults);for(let l in n.renderer){if(!(l in r))throw new Error(`renderer \'${l}\' does not exist`);if(["options","parser"].includes(l))continue;let a=l,i=n.renderer[a],o=r[a];r[a]=(...c)=>{let u=i.apply(r,c);return u===!1&&(u=o.apply(r,c)),u||""}}s.renderer=r}if(n.tokenizer){let r=this.defaults.tokenizer||new O(this.defaults);for(let l in n.tokenizer){if(!(l in r))throw new Error(`tokenizer \'${l}\' does not exist`);if(["options","rules","lexer"].includes(l))continue;let a=l,i=n.tokenizer[a],o=r[a];r[a]=(...c)=>{let u=i.apply(r,c);return u===!1&&(u=o.apply(r,c)),u}}s.tokenizer=r}if(n.hooks){let r=this.defaults.hooks||new q;for(let l in n.hooks){if(!(l in r))throw new Error(`hook \'${l}\' does not exist`);if(["options","block"].includes(l))continue;let a=l,i=n.hooks[a],o=r[a];q.passThroughHooks.has(l)?r[a]=c=>{if(this.defaults.async&&q.passThroughHooksRespectAsync.has(l))return(async()=>{let h=await i.call(r,c);return o.call(r,h)})();let u=i.call(r,c);return o.call(r,u)}:r[a]=(...c)=>{if(this.defaults.async)return(async()=>{let h=await i.apply(r,c);return h===!1&&(h=await o.apply(r,c)),h})();let u=i.apply(r,c);return u===!1&&(u=o.apply(r,c)),u}}s.hooks=r}if(n.walkTokens){let r=this.defaults.walkTokens,l=n.walkTokens;s.walkTokens=function(a){let i=[];return i.push(l.call(this,a)),r&&(i=i.concat(r.call(this,a))),i}}this.defaults={...this.defaults,...s}}),this}setOptions(t){return this.defaults={...this.defaults,...t},this}lexer(t,e){return R.lex(t,e??this.defaults)}parser(t,e){return $.parse(t,e??this.defaults)}parseMarkdown(t){return(e,n)=>{let s={...n},r={...this.defaults,...s},l=this.onError(!!r.silent,!!r.async);if(this.defaults.async===!0&&s.async===!1)return l(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 e>"u"||e===null)return l(new Error("marked(): input parameter is undefined or null"));if(typeof e!="string")return l(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(e)+", string expected"));if(r.hooks&&(r.hooks.options=r,r.hooks.block=t),r.async)return(async()=>{let a=r.hooks?await r.hooks.preprocess(e):e,i=await(r.hooks?await r.hooks.provideLexer(t):t?R.lex:R.lexInline)(a,r),o=r.hooks?await r.hooks.processAllTokens(i):i;r.walkTokens&&await Promise.all(this.walkTokens(o,r.walkTokens));let c=await(r.hooks?await r.hooks.provideParser(t):t?$.parse:$.parseInline)(o,r);return r.hooks?await r.hooks.postprocess(c):c})().catch(l);try{r.hooks&&(e=r.hooks.preprocess(e));let a=(r.hooks?r.hooks.provideLexer(t):t?R.lex:R.lexInline)(e,r);r.hooks&&(a=r.hooks.processAllTokens(a)),r.walkTokens&&this.walkTokens(a,r.walkTokens);let i=(r.hooks?r.hooks.provideParser(t):t?$.parse:$.parseInline)(a,r);return r.hooks&&(i=r.hooks.postprocess(i)),i}catch(a){return l(a)}}}onError(t,e){return n=>{if(n.message+=`\nPlease report this to https://github.com/markedjs/marked.`,t){let s="<p>An error occurred:</p><pre>"+S(n.message+"",!0)+"</pre>";return e?Promise.resolve(s):s}if(e)return Promise.reject(n);throw n}}},I=new mt;function g(t,e){return I.parse(t,e)}g.options=g.setOptions=function(t){return I.setOptions(t),g.defaults=I.defaults,ke(g.defaults),g};g.getDefaults=V;g.defaults=_;g.use=function(...t){return I.use(...t),g.defaults=I.defaults,ke(g.defaults),g};g.walkTokens=function(t,e){return I.walkTokens(t,e)};g.parseInline=I.parseInline;g.Parser=$;g.parser=$.parse;g.Renderer=Q;g.TextRenderer=se;g.Lexer=R;g.lexer=R.lex;g.Tokenizer=O;g.Hooks=q;g.parse=g;var zt=g.options,At=g.setOptions,Ct=g.use,It=g.walkTokens,_t=g.parseInline;var Pt=$.parse,Mt=R.lex;function Se(t,e,n){let s=0;for(let r=e;r<n;r++)s+=t[r].raw.length;return s}function wt(t,e){let n=t;return n.links=e,n}var yt=/^ {0,3}\\$\\$/m;function Le(t){return t.includes("$$")===!1?!1:yt.test(t)}function Rt(t,e){return t[e-2]?.type!=="list"?!0:e+1<t.length}function ze(t,e){for(let n=t.length-2;n>=e;n--)if(t[n].type==="space"&&Rt(t,n+1)!==!1)return n+1;return-1}function Ae(t){let e=t.links;if(!e)return!1;for(let n in e)return!0;return!1}function Ce(t,e,n,s,r){let l=r;for(let a=e;a<n;a++){let i=t[a].raw;if(s.startsWith(i,l)===!1)return!1;l+=i.length}return!0}function G(t,e,n){return{source:t,tail:t,tokens:e,stableCount:0,stableOffset:0,degraded:!0,degradedReason:n}}function Te(t,e){return{source:t,tail:t,tokens:e,stableCount:0,stableOffset:0,degraded:!1,degradedReason:null}}function $t(t,e){if(Ae(e))return G(t,e,"link-definition");if(t.includes("\\r"))return G(t,e,"carriage-return");if(Le(t))return G(t,e,"block-math");let n=ze(e,1);if(n<0||Ce(e,0,n,t,0)===!1)return Te(t,e);let s=Se(e,0,n);return{source:t,tail:t.slice(s),tokens:e,stableCount:n,stableOffset:s,degraded:!1,degradedReason:null}}function le(t){let e=g.lexer(t);return{tokens:e,cache:$t(t,e),charsLexed:t.length,reusedTokens:0}}function j(t,e){let n=g.lexer(t);return{tokens:n,cache:G(t,n,e),charsLexed:t.length,reusedTokens:0}}function Ie(t,e){let n=t.source+e;if(t.degraded)return j(n,t.degradedReason??"link-definition");if(e.includes("\\r"))return j(n,"carriage-return");if(t.stableCount===0)return le(n);let s=t.tail+e;if(Le(s))return j(n,"block-math");let r=g.lexer(s);if(Ae(r))return j(n,"link-definition");let l=t.tokens.slice(0,t.stableCount),a=wt([...l,...r],r.links),i=t.stableCount,o=t.stableOffset,c=s,u=ze(a,t.stableCount+1);if(u>t.stableCount&&Ce(a,t.stableCount,u,s,0)){let h=Se(a,t.stableCount,u);i=u,o=t.stableOffset+h,c=s.slice(h)}return{tokens:a,cache:{source:n,tail:c,tokens:a,stableCount:i,stableOffset:o,degraded:!1,degradedReason:null},charsLexed:s.length,reusedTokens:t.stableCount}}var Tt=0;function St(t){if(typeof t!="string"||typeof performance.mark!="function"||typeof performance.measure!="function")return null;let e=Tt++,n={name:t,startMark:`${t}:start:${e}`,endMark:`${t}:end:${e}`};try{return performance.mark(n.startMark),n}catch{return null}}function Lt(t){if(t)try{performance.mark(t.endMark),performance.measure(t.name,t.startMark,t.endMark)}catch{}finally{try{performance.clearMarks?.(t.startMark),performance.clearMarks?.(t.endMark)}catch{}}}g.use({extensions:[{name:"blockMath",level:"block",start(t){return t.match(/^ {0,3}\\$\\$/m)?.index},tokenizer(t){let e=/^ {0,3}\\$\\$([\\s\\S]+?)\\$\\$[ \\t]*(?:\\n|$)/.exec(t);if(e)return{type:"blockMath",raw:e[0],text:e[1].trim()}},renderer(t){return t.raw}},{name:"inlineMath",level:"inline",start(t){return t.match(/(?<![\\\\$])\\$(?![$\\s])/)?.index},tokenizer(t){let e=/^\\$(?![$\\s\\d])((?:\\\\\\$|[^$\\n])*?)(?<!\\s)\\$(?!\\d)/.exec(t);if(e)return{type:"inlineMath",raw:e[0],text:e[1].trim()}},renderer(t){return t.raw}}]});var E=new Map;self.onmessage=t=>{let e=t.data;if(typeof e!="object"||e===null)return;let{id:n,text:s,append:r,expectedLength:l,oldRaws:a,instance:i,baseVersion:o,dispose:c,userTimingName:u}=e;if(c===!0){typeof i=="string"&&E.delete(i);return}let h=typeof i=="string"?i:null,p=typeof o=="number"?o:null,d,f=null,m=null;if(typeof r=="string"){if(h===null||p===null){self.postMessage({id:n,needResync:!0});return}let w=E.get(h);if(!w||w.version!==p){self.postMessage({id:n,needResync:!0});return}if(typeof l=="number"&&w.lex.source.length+r.length!==l){E.delete(h),self.postMessage({id:n,needResync:!0});return}let y=w.lex;d=()=>Ie(y,r),m=y.tokens}else if(typeof s=="string"){let w=s;if(d=()=>le(w),Array.isArray(a))f=a;else if(h!==null&&p!==null){let y=E.get(h);if(y&&y.version===p)m=y.lex.tokens;else{self.postMessage({id:n,needResync:!0});return}}}else return;try{let w=typeof u=="string"?St(u):null,y=performance.now(),L;try{L=d()}finally{w&&Lt(w)}let W=performance.now()-y,A=L.tokens,b=0;if(f!==null){let T=Math.min(f.length,A.length);for(;b<T&&f[b]===A[b].raw;b++);}else if(m!==null){let T=m,ie=Math.min(T.length,A.length);for(b=Math.min(L.reusedTokens,ie);b<ie&&T[b].raw===A[b].raw;b++);}h!==null&&p!==null&&E.set(h,{version:p+1,lex:L.cache}),self.postMessage({id:n,matchLen:b,tail:A.slice(b),lexerMs:W,sourceCharsLexed:L.charsLexed})}catch(w){h!==null&&E.delete(h),self.postMessage({id:n,error:String(w)})}};})();\n';
512
+ // src/markdown-code.ts
513
+ var import_core2 = require("@vectojs/core");
514
+ var import_ui = require("@vectojs/ui");
777
515
 
778
- // src/Markdown.ts
779
- var now = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
780
- function lexMarkdown(text, userTiming) {
781
- if (!userTiming) return import_marked.marked.lexer(text);
782
- const timing = (0, import_core.beginVectoUserTiming)(import_core.VECTO_USER_TIMING.markdown.parse);
783
- try {
784
- return import_marked.marked.lexer(text);
785
- } finally {
786
- if (timing) (0, import_core.endVectoUserTiming)(timing);
787
- }
788
- }
789
- import_marked.marked.use({
790
- extensions: [
791
- {
792
- name: "blockMath",
793
- level: "block",
794
- start(src) {
795
- return src.match(/^ {0,3}\$\$/m)?.index;
796
- },
797
- tokenizer(src) {
798
- const match = /^ {0,3}\$\$([\s\S]+?)\$\$[ \t]*(?:\n|$)/.exec(src);
799
- if (match) {
800
- return {
801
- type: "blockMath",
802
- raw: match[0],
803
- text: match[1].trim()
804
- };
805
- }
806
- return void 0;
807
- },
808
- renderer(token) {
809
- return token.raw;
810
- }
811
- },
812
- {
813
- name: "inlineMath",
814
- level: "inline",
815
- start(src) {
816
- return src.match(/(?<![\\$])\$(?![$\s])/)?.index;
817
- },
818
- tokenizer(src) {
819
- const match = /^\$(?![$\s\d])((?:\\\$|[^$\n])*?)(?<!\s)\$(?!\d)/.exec(src);
820
- if (match) {
821
- return {
822
- type: "inlineMath",
823
- raw: match[0],
824
- text: match[1].trim()
825
- };
826
- }
827
- return void 0;
828
- },
829
- renderer(token) {
830
- return token.raw;
831
- }
832
- }
833
- ]
834
- });
835
- var mathConverter = null;
836
- var mathLoad = null;
837
- function interop(mod, key) {
838
- const ns = mod;
839
- if (typeof ns?.[key] !== "undefined") return ns;
840
- const fallback = ns?.default;
841
- if (fallback && typeof fallback[key] !== "undefined") return fallback;
842
- throw new Error(`mathjax-full module is missing export "${key}"`);
843
- }
844
- function preloadMathJax() {
845
- if (mathLoad) return mathLoad;
846
- mathLoad = (async () => {
847
- const [mathjaxMod, texMod, svgMod, adaptorMod, handlerMod, packagesMod] = await Promise.all([
848
- import("mathjax-full/js/mathjax.js"),
849
- import("mathjax-full/js/input/tex.js"),
850
- import("mathjax-full/js/output/svg.js"),
851
- import("mathjax-full/js/adaptors/liteAdaptor.js"),
852
- import("mathjax-full/js/handlers/html.js"),
853
- import("mathjax-full/js/input/tex/AllPackages.js")
854
- ]);
855
- const { mathjax } = interop(mathjaxMod, "mathjax");
856
- const { TeX } = interop(texMod, "TeX");
857
- const { SVG } = interop(svgMod, "SVG");
858
- const { liteAdaptor } = interop(adaptorMod, "liteAdaptor");
859
- const { RegisterHTMLHandler } = interop(handlerMod, "RegisterHTMLHandler");
860
- const { AllPackages } = interop(packagesMod, "AllPackages");
861
- const adaptor = liteAdaptor();
862
- RegisterHTMLHandler(adaptor);
863
- const tex = new TeX({ packages: AllPackages });
864
- const svg = new SVG({ fontCache: "local" });
865
- const htmlMathJax = mathjax.document("", { InputJax: tex, OutputJax: svg });
866
- mathConverter = (formula, displayMode, color) => convertMathToSVGDataURI(
867
- formula,
868
- displayMode,
869
- (f, d) => adaptor.innerHTML(htmlMathJax.convert(f, { display: d })),
870
- color
871
- );
872
- })().catch((e) => {
873
- console.error("MathJax failed to load; formulas will render as TeX source", e);
874
- });
875
- return mathLoad;
876
- }
877
- function isMathJaxReady() {
878
- return mathConverter !== null;
879
- }
880
- var EX_PER_EM = 0.4421;
881
- function exToPx(ex, fontSize) {
882
- return ex * fontSize * EX_PER_EM;
883
- }
884
- function fontSizeFromFont(font) {
885
- const pxIndex = font.indexOf("px");
886
- if (pxIndex <= 0) return void 0;
887
- let start = pxIndex;
888
- while (start > 0) {
889
- const ch = font[start - 1];
890
- if (ch >= "0" && ch <= "9" || ch === ".") start--;
891
- else break;
892
- }
893
- if (start === pxIndex) return void 0;
894
- const size = parseFloat(font.slice(start, pxIndex));
895
- return Number.isFinite(size) ? size : void 0;
896
- }
897
- var mathCache = /* @__PURE__ */ new Map();
898
- var MATH_CACHE_LIMIT = 256;
899
- var inlineMathRasters = /* @__PURE__ */ new Map();
900
- var inlineMathRasterWaiters = /* @__PURE__ */ new Set();
901
- function ensureInlineMathRaster(uri) {
902
- const existing = inlineMathRasters.get(uri);
903
- if (existing) return existing;
904
- const entry = { decoded: false };
905
- inlineMathRasters.set(uri, entry);
906
- if (typeof globalThis.Image !== "undefined") {
907
- const bitmap = new globalThis.Image();
908
- bitmap.onload = () => {
909
- entry.decoded = true;
910
- for (const notify of inlineMathRasterWaiters) notify();
911
- };
912
- bitmap.src = uri;
913
- entry.bitmap = bitmap;
914
- }
915
- return entry;
916
- }
917
- function paintInlineMath(uri, surface, box) {
918
- const raster = ensureInlineMathRaster(uri);
919
- if (!raster.decoded || !raster.bitmap) return;
920
- surface.drawImage(raster.bitmap, box.x, box.y, box.width, box.height);
921
- }
922
- var MATH_LANGS = /* @__PURE__ */ new Set(["math", "latex", "tex"]);
923
- function containsInlineMath(token) {
924
- if (token.type === "inlineMath") return true;
925
- const anyToken = token;
926
- if (Array.isArray(anyToken.tokens) && anyToken.tokens.some(containsInlineMath)) {
927
- return true;
928
- }
929
- if (Array.isArray(anyToken.items) && anyToken.items.some(containsInlineMath)) {
930
- return true;
931
- }
932
- if (Array.isArray(anyToken.header) && anyToken.header.some(containsInlineMath)) {
933
- return true;
934
- }
935
- if (Array.isArray(anyToken.rows)) {
936
- for (const row of anyToken.rows) {
937
- if (Array.isArray(row) && row.some(containsInlineMath)) return true;
938
- }
939
- }
940
- return false;
941
- }
942
- var FENCE_OPEN_RE = /^ {0,3}(`{3,}|~{3,})/;
943
- var FENCE_CLOSE_RE = /^ {0,3}(`+|~+)[ \t]*$/;
944
- function isFenceClosed(raw) {
945
- const lines = raw.split("\n");
946
- const open = FENCE_OPEN_RE.exec(lines[0]);
947
- if (!open) return false;
948
- const marker = open[1][0];
949
- const minLen = open[1].length;
950
- for (let i = 1; i < lines.length; i++) {
951
- const close = FENCE_CLOSE_RE.exec(lines[i]);
952
- if (close && close[1][0] === marker && close[1].length >= minLen) return true;
516
+ // src/theme.ts
517
+ var DEFAULT_THEME = {
518
+ textColor: "#e2e8f0",
519
+ headingColor: "#f8fafc",
520
+ codeColor: "#a5f3fc",
521
+ codeBgColor: "rgba(30, 41, 59, 0.85)",
522
+ quoteBorderColor: "#6366f1",
523
+ quoteTextColor: "#e2e8f0",
524
+ hrColor: "rgba(148, 163, 184, 0.3)",
525
+ tableBgColor: "rgba(15, 15, 25, 0.4)",
526
+ tableHeaderBgColor: "rgba(255, 255, 255, 0.08)",
527
+ linkColor: "#38bdf8",
528
+ mathFallbackColor: "#fcd34d",
529
+ syntaxKeywordColor: "#c084fc",
530
+ syntaxStringColor: "#86efac",
531
+ syntaxCommentColor: "#64748b",
532
+ syntaxNumberColor: "#fbbf24",
533
+ bodyFont: "Inter, system-ui, sans-serif",
534
+ codeFont: 'ui-monospace, "JetBrains Mono", "Fira Code", monospace',
535
+ fontSize: 16,
536
+ headingSizes: [32, 28, 24, 20, 18, 16],
537
+ codeFontSize: 15,
538
+ tableFontSize: 14,
539
+ codeLineHeight: 24,
540
+ bodyLineHeight: 24,
541
+ blockGap: 16,
542
+ codePadding: 18,
543
+ codeRadius: 8,
544
+ listGap: 6,
545
+ listItemGap: 4,
546
+ quoteIndent: 16,
547
+ quoteBorderWidth: 4,
548
+ quoteInnerGap: 8,
549
+ imageRadius: 8,
550
+ inlineImageScale: 1.15
551
+ };
552
+ function resolveTheme(theme) {
553
+ const merged = { ...DEFAULT_THEME, ...theme };
554
+ if (theme?.tableFontSize === void 0) {
555
+ merged.tableFontSize = Math.max(1, merged.fontSize - 2);
953
556
  }
954
- return false;
955
- }
956
- function paragraphHasImage(token) {
957
- return containsImage(token.tokens);
958
- }
959
- function containsImage(tokens) {
960
- if (!tokens) return false;
961
- for (const token of tokens) {
962
- if (token.type === "image") return true;
963
- if (containsImage(token.tokens)) return true;
557
+ if (theme?.quoteTextColor === void 0) {
558
+ merged.quoteTextColor = merged.textColor;
964
559
  }
965
- return false;
560
+ return merged;
966
561
  }
967
- function imagesOf(tokens) {
968
- const images = [];
969
- for (const token of tokens ?? []) {
970
- if (token.type === "image") {
971
- images.push(token);
972
- continue;
973
- }
974
- images.push(...imagesOf(token.tokens));
975
- }
976
- return images;
562
+ function headingSize(theme, depth) {
563
+ const sizes = theme.headingSizes;
564
+ if (sizes.length === 0) return theme.fontSize;
565
+ const idx = Math.min(Math.max(depth, 1) - 1, sizes.length - 1);
566
+ return sizes[idx] ?? theme.fontSize;
977
567
  }
978
- function stripImages(token) {
979
- const children = token.tokens;
980
- if (!children) return token;
981
- const kept = [];
982
- for (const child of children) {
983
- if (child.type === "image") continue;
984
- const grandchildren = child.tokens;
985
- if (grandchildren && containsImage(grandchildren)) {
986
- const stripped = stripImages(child);
987
- const remaining = stripped.tokens;
988
- if (remaining && remaining.length > 0) kept.push(stripped);
989
- continue;
990
- }
991
- kept.push(child);
992
- }
993
- return { ...token, tokens: kept };
994
- }
995
- function liftNestedImages(tokens) {
996
- const lifted = [];
997
- for (const token of tokens) {
998
- if (token.type === "image") {
999
- lifted.push(token);
1000
- continue;
1001
- }
1002
- const children = token.tokens;
1003
- if (children && containsImage(children)) {
1004
- lifted.push(...liftNestedImages(children));
1005
- continue;
1006
- }
1007
- lifted.push(token);
1008
- }
1009
- return lifted;
1010
- }
1011
- function lastIndexOfImage(tokens) {
1012
- for (let i = tokens.length - 1; i >= 0; i--) {
1013
- if (tokens[i].type === "image") return i;
1014
- }
1015
- return -1;
1016
- }
1017
- function expectedImageParagraphChildren(tokens) {
1018
- let children = 0;
1019
- let inTextRun = false;
1020
- for (const token of liftNestedImages(tokens)) {
1021
- if (token.type === "image") {
1022
- children++;
1023
- inTextRun = false;
1024
- } else if (!inTextRun) {
1025
- children++;
1026
- inTextRun = true;
1027
- }
1028
- }
1029
- return children;
1030
- }
1031
- function rendersAsMath(token) {
1032
- return MATH_LANGS.has((token.lang ?? "").toLowerCase()) && token.text.trim() !== "" && isFenceClosed(token.raw);
1033
- }
1034
- function renderMathToSVGDataURI(formula, displayMode, color) {
1035
- const key = `${displayMode ? 1 : 0}\0${color}\0${formula}`;
1036
- const hit = mathCache.get(key);
1037
- if (hit) return hit;
1038
- if (!mathConverter) return null;
1039
- const converted = mathConverter(formula, displayMode, color);
1040
- if (converted) {
1041
- if (mathCache.size >= MATH_CACHE_LIMIT) {
1042
- const oldest = mathCache.keys().next().value;
1043
- if (oldest !== void 0) mathCache.delete(oldest);
1044
- }
1045
- mathCache.set(key, converted);
1046
- }
1047
- return converted;
1048
- }
1049
- function applyMathColor(svg, color) {
1050
- const openTag = svg.match(/<svg\b[^>]*>/);
1051
- if (!openTag) return svg;
1052
- const tag = openTag[0];
1053
- const colored = /\bstyle="/.test(tag) ? tag.replace(/\bstyle="/, `style="color:${color};`) : tag.replace(/^<svg\b/, `<svg style="color:${color}"`);
1054
- return svg.replace(tag, colored);
1055
- }
1056
- function convertMathToSVGDataURI(formula, displayMode, typeset, color) {
1057
- try {
1058
- const svgString = applyMathColor(typeset(formula, displayMode), color);
1059
- const wMatch = svgString.match(/width="([^"]+)ex"/);
1060
- const hMatch = svgString.match(/height="([^"]+)ex"/);
1061
- const wEx = wMatch ? parseFloat(wMatch[1]) : 10;
1062
- const hEx = hMatch ? parseFloat(hMatch[1]) : 2;
1063
- const vMatch = svgString.match(/vertical-align:\s*(-?[\d.]+)ex/);
1064
- const depthEx = vMatch ? Math.max(0, -parseFloat(vMatch[1])) : 0;
1065
- const base64 = btoa(unescape(encodeURIComponent(svgString)));
1066
- return {
1067
- uri: `data:image/svg+xml;base64,${base64}`,
1068
- widthEx: wEx,
1069
- heightEx: hEx,
1070
- depthEx
1071
- };
1072
- } catch (e) {
1073
- console.error("MathJax error", e);
1074
- return null;
1075
- }
1076
- }
1077
- var markdownWorker = null;
1078
- var workerIdCounter = 0;
1079
- var workerInstanceCounter = 0;
1080
- var workerCallbacks = /* @__PURE__ */ new Map();
1081
- function runSyncFallback(entry) {
1082
- try {
1083
- entry.cb(0, lexMarkdown(entry.text, entry.userTiming), true);
1084
- } catch (err) {
1085
- console.warn("Markdown sync fallback parse failed", err);
1086
- entry.onDropped?.();
1087
- }
1088
- }
1089
- if (typeof Worker !== "undefined") {
1090
- try {
1091
- const blob = new Blob([WORKER_SOURCE_STRING], {
1092
- type: "application/javascript"
1093
- });
1094
- markdownWorker = new Worker(URL.createObjectURL(blob));
1095
- markdownWorker.onmessage = (e) => {
1096
- const { id, matchLen, tail, error, needResync, lexerMs, sourceCharsLexed } = e.data;
1097
- const entry = workerCallbacks.get(id);
1098
- if (entry) {
1099
- workerCallbacks.delete(id);
1100
- if (needResync && entry.onNeedResync) {
1101
- entry.onNeedResync();
1102
- } else if (needResync) {
1103
- runSyncFallback(entry);
1104
- } else if (!error) {
1105
- entry.cb(matchLen, tail, false, {
1106
- lexerMs: typeof lexerMs === "number" ? lexerMs : 0,
1107
- sourceCharsLexed: typeof sourceCharsLexed === "number" ? sourceCharsLexed : 0
1108
- });
1109
- } else {
1110
- runSyncFallback(entry);
1111
- }
1112
- }
1113
- };
1114
- markdownWorker.onerror = () => {
1115
- const pending = [...workerCallbacks.values()];
1116
- workerCallbacks.clear();
1117
- markdownWorker = null;
1118
- for (const entry of pending) runSyncFallback(entry);
1119
- };
1120
- } catch (err) {
1121
- console.warn("Failed to initialize MarkdownWorker", err);
1122
- }
1123
- }
1124
- var DEFAULT_THEME = {
1125
- textColor: "#e2e8f0",
1126
- headingColor: "#f8fafc",
1127
- codeColor: "#a5f3fc",
1128
- codeBgColor: "rgba(30, 41, 59, 0.85)",
1129
- quoteBorderColor: "#6366f1",
1130
- quoteTextColor: "#94a3b8",
1131
- hrColor: "rgba(148, 163, 184, 0.3)",
1132
- tableBgColor: "rgba(15, 15, 25, 0.4)",
1133
- tableHeaderBgColor: "rgba(255, 255, 255, 0.08)",
1134
- bodyFont: "Inter, system-ui, sans-serif",
1135
- codeFont: 'ui-monospace, "JetBrains Mono", "Fira Code", monospace',
1136
- fontSize: 16
1137
- };
1138
- var HorizontalRule = class extends import_core.Entity {
1139
- color;
1140
- constructor(w, color) {
1141
- super();
1142
- this.width = w;
1143
- this.height = 1;
1144
- this.color = color;
1145
- }
1146
- isPointInside() {
1147
- return false;
1148
- }
1149
- render(r) {
1150
- r.beginPath();
1151
- r.moveTo(0, 0);
1152
- r.lineTo(this.width, 0);
1153
- r.stroke(this.color, 1);
1154
- }
1155
- };
1156
- var QuoteBorder = class extends import_core.Entity {
1157
- color;
1158
- constructor(height, color) {
1159
- super();
1160
- this.width = 4;
1161
- this.height = height;
1162
- this.color = color;
1163
- }
1164
- isPointInside() {
1165
- return false;
1166
- }
1167
- render(r) {
1168
- r.beginPath();
1169
- r.roundRect(0, 0, this.width, this.height, 2);
1170
- r.fill(this.color);
1171
- }
1172
- };
1173
- var MarkdownContainer = class extends import_core.Entity {
1174
- isPointInside(_globalX, _globalY) {
1175
- return false;
1176
- }
1177
- render(_r) {
1178
- }
1179
- };
1180
- var MathBlock = class extends MarkdownContainer {
1181
- /**
1182
- * The TeX source, exactly as written between the delimiters.
1183
- *
1184
- * Also the projected text and the accessible name, so this is the one string a
1185
- * reader can find, select, and copy.
1186
- */
1187
- formula;
1188
- /** The `data:image/svg+xml` URI of the typeset glyphs. */
1189
- svgUri;
1190
- constructor(formula, svgUri) {
1191
- super();
1192
- this.formula = formula;
1193
- this.svgUri = svgUri;
1194
- }
1195
- getDevtoolsDescriptor() {
1196
- return {
1197
- kind: "MathBlock",
1198
- groups: [
1199
- {
1200
- label: "Math",
1201
- fields: [{ label: "formula", value: this.formula, readOnly: true }]
1202
- }
1203
- ]
1204
- };
1205
- }
1206
- };
568
+
569
+ // src/markdown-code.ts
1207
570
  var KEYWORD_SETS = {
1208
571
  js: /* @__PURE__ */ new Set([
1209
572
  "const",
@@ -1378,10 +741,10 @@ function highlightLine(line, lang, theme) {
1378
741
  return [{ text: line, color: theme.codeColor }];
1379
742
  }
1380
743
  const segments = [];
1381
- const KEYWORD_COLOR = "#c084fc";
1382
- const STRING_COLOR = "#86efac";
1383
- const COMMENT_COLOR = "#64748b";
1384
- const NUMBER_COLOR = "#fbbf24";
744
+ const KEYWORD_COLOR = theme.syntaxKeywordColor;
745
+ const STRING_COLOR = theme.syntaxStringColor;
746
+ const COMMENT_COLOR = theme.syntaxCommentColor;
747
+ const NUMBER_COLOR = theme.syntaxNumberColor;
1385
748
  let i = 0;
1386
749
  let buf = "";
1387
750
  const flush = (color) => {
@@ -1402,469 +765,1230 @@ function highlightLine(line, lang, theme) {
1402
765
  segments.push({ text: line.slice(i), color: COMMENT_COLOR });
1403
766
  return segments;
1404
767
  }
1405
- if (ch === '"' || ch === "'" || ch === "`") {
1406
- const quote = ch;
1407
- let j = i + 1;
1408
- let closed = false;
1409
- while (j < line.length) {
1410
- if (line[j] === "\\") {
1411
- j += 2;
1412
- continue;
768
+ if (ch === '"' || ch === "'" || ch === "`") {
769
+ const quote = ch;
770
+ let j = i + 1;
771
+ let closed = false;
772
+ while (j < line.length) {
773
+ if (line[j] === "\\") {
774
+ j += 2;
775
+ continue;
776
+ }
777
+ if (line[j] === quote) {
778
+ closed = true;
779
+ break;
780
+ }
781
+ j++;
782
+ }
783
+ if (closed) {
784
+ flush(theme.codeColor);
785
+ segments.push({ text: line.slice(i, j + 1), color: STRING_COLOR });
786
+ i = j + 1;
787
+ continue;
788
+ }
789
+ buf += ch;
790
+ i++;
791
+ continue;
792
+ }
793
+ if (/\d/.test(ch) && (i === 0 || /[\s(,=+\-*/<>[\]{}:;]/.test(line[i - 1]))) {
794
+ flush(theme.codeColor);
795
+ let j = i;
796
+ while (j < line.length && /[\d._xXa-fA-F]/.test(line[j])) j++;
797
+ segments.push({ text: line.slice(i, j), color: NUMBER_COLOR });
798
+ i = j;
799
+ continue;
800
+ }
801
+ if (/[a-zA-Z_]/.test(ch)) {
802
+ flush(theme.codeColor);
803
+ let j = i;
804
+ while (j < line.length && /[a-zA-Z0-9_]/.test(line[j])) j++;
805
+ const word = line.slice(i, j);
806
+ segments.push({
807
+ text: word,
808
+ color: keywords.has(word) ? KEYWORD_COLOR : theme.codeColor
809
+ });
810
+ i = j;
811
+ continue;
812
+ }
813
+ buf += ch;
814
+ i++;
815
+ }
816
+ flush(theme.codeColor);
817
+ return segments;
818
+ }
819
+ var CodeBlock = class extends import_ui.UIComponent {
820
+ lines;
821
+ grid = null;
822
+ /** Raw (unhighlighted) lines of the last build, for prefix reuse in buildLines. */
823
+ rawLines = null;
824
+ cellWidth = 0;
825
+ source;
826
+ /** Bumped by {@link buildLines} and {@link setSelectable}; read by `Scene`. */
827
+ contentEpoch = 0;
828
+ lang;
829
+ theme;
830
+ /**
831
+ * Assigned in the constructor rather than as a field initializer: both come
832
+ * from `theme`, and a field initializer runs before the constructor body has
833
+ * a `theme` to read.
834
+ */
835
+ lineH;
836
+ pad;
837
+ codeFont;
838
+ selectable;
839
+ /**
840
+ * @param theme Any subset of {@link MarkdownTheme}; missing keys fall back to
841
+ * `DEFAULT_THEME` in `./theme`. Accepting a partial theme keeps callers that were
842
+ * written against an earlier, smaller `MarkdownTheme` working — this class
843
+ * is public API, and a hand-built theme literal would otherwise start
844
+ * throwing `lineHeight must be a positive finite number` the moment a new
845
+ * size key was added.
846
+ */
847
+ constructor(code, lang, maxWidth, theme, selectable = true) {
848
+ super();
849
+ const resolved = resolveTheme(theme);
850
+ this.source = code;
851
+ this.lang = lang;
852
+ this.theme = resolved;
853
+ this.lineH = resolved.codeLineHeight;
854
+ this.pad = resolved.codePadding;
855
+ this.codeFont = `${resolved.codeFontSize}px ${resolved.codeFont}`;
856
+ this.selectable = selectable;
857
+ this.lines = [];
858
+ this.width = maxWidth;
859
+ this.buildLines(code);
860
+ }
861
+ /** Re-parse code content (e.g. for live editing). */
862
+ setCode(code, lang) {
863
+ if (lang !== void 0) this.lang = lang;
864
+ this.source = code;
865
+ this.buildLines(code);
866
+ this.scene?.markDirty();
867
+ return this;
868
+ }
869
+ /** Enable or disable browser-native selection for this code block. */
870
+ setSelectable(selectable) {
871
+ this.selectable = selectable;
872
+ this.contentEpoch++;
873
+ this.scene?.markDirty();
874
+ return this;
875
+ }
876
+ getContentEpoch() {
877
+ return this.contentEpoch;
878
+ }
879
+ /**
880
+ * Change the block's box width.
881
+ *
882
+ * Deliberately does **not** rebuild the grid or the highlight, because code does
883
+ * not reflow: lines are placed on a fixed monospace grid at `col × cellWidth` and
884
+ * a long line overflows rather than wrapping, so `height` is a function of line
885
+ * *count* alone. The width only sizes the rounded background. Anything that would
886
+ * change the glyph geometry — the source, the language, the font — goes through
887
+ * {@link setCode} and invalidates the grid there.
888
+ *
889
+ * @returns `this` for chaining.
890
+ */
891
+ setWidth(width) {
892
+ const next = Math.max(0, width);
893
+ if (next === this.width) return this;
894
+ this.width = next;
895
+ this.scene?.markDirty();
896
+ return this;
897
+ }
898
+ getContentProjection(hint) {
899
+ if (!this.source) return null;
900
+ const grid = this.ensureGrid();
901
+ const rows = [];
902
+ rows.length = grid.lines.length;
903
+ for (let row = 0; row < grid.lines.length; row++) {
904
+ const line = grid.lines[row];
905
+ const y = this.pad + row * this.lineH;
906
+ if (!(0, import_core2.contentLineInHint)(hint, y, this.lineH)) continue;
907
+ rows[row] = {
908
+ text: this.source.slice(line.sourceStart, line.sourceEnd),
909
+ separatorAfter: this.source.slice(line.sourceEnd, line.nextSourceStart) || void 0,
910
+ x: this.pad,
911
+ y,
912
+ baseline: this.lineH * 0.75,
913
+ font: this.codeFont,
914
+ lineHeight: this.lineH
915
+ };
916
+ }
917
+ return {
918
+ text: this.source,
919
+ font: this.codeFont,
920
+ lineHeight: this.lineH,
921
+ // Every row is absolutely positioned from the same local coordinates as
922
+ // render(). A single pre-wrap DOM text node would introduce browser
923
+ // wrapping for long source lines that canvas intentionally keeps intact.
924
+ //
925
+ lines: rows,
926
+ selectable: this.selectable,
927
+ // render() draws cell-by-cell (no ligatures can form); the DOM copy
928
+ // must not ligate either or Firefox selection geometry drifts.
929
+ ligatures: "none",
930
+ grid
931
+ };
932
+ }
933
+ /**
934
+ * Re-highlight the code, reusing the highlight of any unchanged line prefix.
935
+ *
936
+ * Streaming appends to the END of a block, so all but the last line or two are
937
+ * byte-identical to the previous call — yet this used to re-highlight every
938
+ * line on every chunk, making a streamed block O(N) per append and O(N^2)
939
+ * overall. Reusing the stable prefix makes an append proportional to what
940
+ * actually changed.
941
+ *
942
+ * The last previously-seen line is deliberately NOT reused: a chunk usually
943
+ * lands mid-line, so that line's text (and therefore its tokenization) changes.
944
+ */
945
+ buildLines(code) {
946
+ this.contentEpoch++;
947
+ const rawLines = code.split(/\r\n|\r|\n/);
948
+ const previous = this.rawLines;
949
+ let reusable = 0;
950
+ if (previous && this.lines.length === previous.length) {
951
+ const limit = Math.min(previous.length - 1, rawLines.length);
952
+ while (reusable < limit && previous[reusable] === rawLines[reusable]) reusable++;
953
+ }
954
+ if (reusable > 0) {
955
+ const next = this.lines.slice(0, reusable);
956
+ for (let i = reusable; i < rawLines.length; i++) {
957
+ next.push(highlightLine(rawLines[i], this.lang, this.theme));
958
+ }
959
+ this.lines = next;
960
+ } else {
961
+ this.lines = rawLines.map((l) => highlightLine(l, this.lang, this.theme));
962
+ }
963
+ this.rawLines = rawLines;
964
+ this.grid = null;
965
+ this.height = this.pad * 2 + rawLines.length * this.lineH;
966
+ }
967
+ ensureGrid() {
968
+ const cellWidth = this.cellWidth || Math.max(1, (0, import_ui.measureText)("M", this.codeFont));
969
+ if (!this.grid || this.grid.source !== this.source || this.grid.font !== this.codeFont || this.grid.cellWidth !== cellWidth) {
970
+ this.grid = (0, import_core2.prepareContentGrid)(this.source, {
971
+ font: this.codeFont,
972
+ cellWidth,
973
+ lineHeight: this.lineH,
974
+ baseline: this.lineH * 0.75
975
+ });
976
+ }
977
+ return this.grid;
978
+ }
979
+ /** Code blocks are decorative — not interactive. */
980
+ isPointInside() {
981
+ return false;
982
+ }
983
+ render(r) {
984
+ r.beginPath();
985
+ r.roundRect(0, 0, this.width, this.height, this.theme.codeRadius);
986
+ r.fill(this.theme.codeBgColor);
987
+ const grid = this.ensureGrid();
988
+ const atlas = codeGlyphAtlas(r);
989
+ const atlasSource = atlas?.source ?? null;
990
+ const blit = atlas ? r.drawImageRect : void 0;
991
+ for (let row = 0; row < grid.lines.length; row++) {
992
+ const yBaseline = this.pad + row * this.lineH + this.lineH * 0.75;
993
+ const segments = this.lines[row];
994
+ let segmentIndex = 0;
995
+ let segmentEnd = segments[0]?.text.length ?? 0;
996
+ const lineStart = grid.lines[row].sourceStart;
997
+ for (const cell of grid.lines[row].cells) {
998
+ const localSourceStart = cell.sourceStart - lineStart;
999
+ while (segmentIndex < segments.length - 1 && localSourceStart >= segmentEnd) {
1000
+ segmentIndex++;
1001
+ segmentEnd += segments[segmentIndex].text.length;
1002
+ }
1003
+ const sourceText = this.source.slice(cell.sourceStart, cell.sourceEnd);
1004
+ if (cell.advance <= 0 || sourceText === " " || sourceText === " ") continue;
1005
+ const color = segments[segmentIndex]?.color ?? this.theme.codeColor;
1006
+ const x = this.pad + cell.x;
1007
+ if (blit && atlas) {
1008
+ const slot = atlas.get(this.codeFont, color, cell.glyph);
1009
+ const src = atlasSource ?? atlas.source;
1010
+ if (slot && src) {
1011
+ blit.call(
1012
+ r,
1013
+ src,
1014
+ slot.sx,
1015
+ slot.sy,
1016
+ slot.sw,
1017
+ slot.sh,
1018
+ x - slot.offsetX,
1019
+ yBaseline - slot.offsetY,
1020
+ slot.w,
1021
+ slot.h
1022
+ );
1023
+ continue;
1024
+ }
1025
+ }
1026
+ r.fillText(cell.glyph, x, yBaseline, this.codeFont, color);
1027
+ }
1028
+ }
1029
+ }
1030
+ };
1031
+ var codeAtlases = /* @__PURE__ */ new Map();
1032
+ var MAX_CODE_ATLASES = 2;
1033
+ var lastCodeAtlas = null;
1034
+ function codeGlyphAtlas(r) {
1035
+ if (typeof r.drawImageRect !== "function") return void 0;
1036
+ if (typeof document === "undefined") return void 0;
1037
+ const dpr = Math.max(
1038
+ 1,
1039
+ r.pixelRatio ?? (typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1)
1040
+ );
1041
+ const existing = codeAtlases.get(dpr);
1042
+ if (existing) {
1043
+ codeAtlases.delete(dpr);
1044
+ codeAtlases.set(dpr, existing);
1045
+ lastCodeAtlas = existing;
1046
+ return existing;
1047
+ }
1048
+ const atlas = new import_core2.GlyphRasterAtlas({ dpr, maxSize: 2048 });
1049
+ codeAtlases.set(dpr, atlas);
1050
+ if (codeAtlases.size > MAX_CODE_ATLASES) {
1051
+ const oldestKey = codeAtlases.keys().next().value;
1052
+ const oldest = codeAtlases.get(oldestKey);
1053
+ codeAtlases.delete(oldestKey);
1054
+ if (oldest && oldest !== atlas) oldest.destroy();
1055
+ }
1056
+ lastCodeAtlas = atlas;
1057
+ return atlas;
1058
+ }
1059
+ function codeAtlasStats() {
1060
+ return lastCodeAtlas ? lastCodeAtlas.stats : null;
1061
+ }
1062
+ function codeAtlas() {
1063
+ return lastCodeAtlas;
1064
+ }
1065
+
1066
+ // src/markdown-math.ts
1067
+ var mathConverter = null;
1068
+ var mathLoad = null;
1069
+ function preloadMathJax() {
1070
+ if (mathLoad) return mathLoad;
1071
+ mathLoad = (async () => {
1072
+ const { emitSVG, layout } = await import("@vectojs/tex");
1073
+ mathConverter = (formula, displayMode, color) => convertMathToSVGDataURI(formula, displayMode, color, layout, emitSVG);
1074
+ })().catch((e) => {
1075
+ console.error("Math engine failed to load; formulas will render as TeX source", e);
1076
+ });
1077
+ return mathLoad;
1078
+ }
1079
+ function isMathJaxReady() {
1080
+ return mathConverter !== null;
1081
+ }
1082
+ var EX_PER_EM = 0.4421;
1083
+ function exToPx(ex, fontSize) {
1084
+ return ex * fontSize * EX_PER_EM;
1085
+ }
1086
+ function fontSizeFromFont(font) {
1087
+ const pxIndex = font.indexOf("px");
1088
+ if (pxIndex <= 0) return void 0;
1089
+ let start = pxIndex;
1090
+ while (start > 0) {
1091
+ const ch = font[start - 1];
1092
+ if (ch >= "0" && ch <= "9" || ch === ".") start--;
1093
+ else break;
1094
+ }
1095
+ if (start === pxIndex) return void 0;
1096
+ const size = parseFloat(font.slice(start, pxIndex));
1097
+ return Number.isFinite(size) ? size : void 0;
1098
+ }
1099
+ var mathCache = /* @__PURE__ */ new Map();
1100
+ var MATH_CACHE_LIMIT = 256;
1101
+ var inlineMathRasters = /* @__PURE__ */ new Map();
1102
+ var inlineMathRasterWaiters = /* @__PURE__ */ new Set();
1103
+ function subscribeInlineMathRaster(notify) {
1104
+ inlineMathRasterWaiters.add(notify);
1105
+ }
1106
+ function unsubscribeInlineMathRaster(notify) {
1107
+ inlineMathRasterWaiters.delete(notify);
1108
+ }
1109
+ function ensureInlineMathRaster(uri) {
1110
+ const existing = inlineMathRasters.get(uri);
1111
+ if (existing) return existing;
1112
+ const entry = { decoded: false };
1113
+ inlineMathRasters.set(uri, entry);
1114
+ if (typeof globalThis.Image !== "undefined") {
1115
+ const bitmap = new globalThis.Image();
1116
+ bitmap.onload = () => {
1117
+ entry.decoded = true;
1118
+ for (const notify of inlineMathRasterWaiters) notify();
1119
+ };
1120
+ bitmap.src = uri;
1121
+ entry.bitmap = bitmap;
1122
+ }
1123
+ return entry;
1124
+ }
1125
+ function paintInlineMath(uri, surface, box) {
1126
+ const raster = ensureInlineMathRaster(uri);
1127
+ if (!raster.decoded || !raster.bitmap) return;
1128
+ surface.drawImage(raster.bitmap, box.x, box.y, box.width, box.height);
1129
+ }
1130
+ var MATH_LANGS = /* @__PURE__ */ new Set(["math", "latex", "tex"]);
1131
+ function containsInlineMath(token) {
1132
+ if (token.type === "inlineMath") return true;
1133
+ const anyToken = token;
1134
+ if (Array.isArray(anyToken.tokens) && anyToken.tokens.some(containsInlineMath)) {
1135
+ return true;
1136
+ }
1137
+ if (Array.isArray(anyToken.items) && anyToken.items.some(containsInlineMath)) {
1138
+ return true;
1139
+ }
1140
+ if (Array.isArray(anyToken.header) && anyToken.header.some(containsInlineMath)) {
1141
+ return true;
1142
+ }
1143
+ if (Array.isArray(anyToken.rows)) {
1144
+ for (const row of anyToken.rows) {
1145
+ if (Array.isArray(row) && row.some(containsInlineMath)) return true;
1146
+ }
1147
+ }
1148
+ return false;
1149
+ }
1150
+ var FENCE_OPEN_RE = /^ {0,3}(`{3,}|~{3,})/;
1151
+ var FENCE_CLOSE_RE = /^ {0,3}(`+|~+)[ \t]*$/;
1152
+ function isFenceClosed(raw) {
1153
+ const lines = raw.split("\n");
1154
+ const open = FENCE_OPEN_RE.exec(lines[0]);
1155
+ if (!open) return false;
1156
+ const marker = open[1][0];
1157
+ const minLen = open[1].length;
1158
+ for (let i = 1; i < lines.length; i++) {
1159
+ const close = FENCE_CLOSE_RE.exec(lines[i]);
1160
+ if (close && close[1][0] === marker && close[1].length >= minLen) return true;
1161
+ }
1162
+ return false;
1163
+ }
1164
+ function rendersAsMath(token) {
1165
+ return MATH_LANGS.has((token.lang ?? "").toLowerCase()) && token.text.trim() !== "" && isFenceClosed(token.raw);
1166
+ }
1167
+ function renderMathToSVGDataURI(formula, displayMode, color) {
1168
+ const key = `${displayMode ? 1 : 0}\0${color}\0${formula}`;
1169
+ const hit = mathCache.get(key);
1170
+ if (hit) return hit;
1171
+ if (!mathConverter) return null;
1172
+ const converted = mathConverter(formula, displayMode, color);
1173
+ if (converted) {
1174
+ if (mathCache.size >= MATH_CACHE_LIMIT) {
1175
+ const oldest = mathCache.keys().next().value;
1176
+ if (oldest !== void 0) mathCache.delete(oldest);
1177
+ }
1178
+ mathCache.set(key, converted);
1179
+ }
1180
+ return converted;
1181
+ }
1182
+ var MATH_PAD_EM = 0.05;
1183
+ var KATEX_FONT_SCALE = 1.21;
1184
+ var EX_PER_KATEX_EM = KATEX_FONT_SCALE / EX_PER_EM;
1185
+ function convertMathToSVGDataURI(formula, displayMode, color, layout, emitSVG) {
1186
+ try {
1187
+ const emitted = emitSVG(layout(formula, { displayMode }), {
1188
+ color,
1189
+ padEm: MATH_PAD_EM
1190
+ });
1191
+ if (emitted.missing.length > 0) return null;
1192
+ const pad2 = MATH_PAD_EM * 2;
1193
+ const base64 = btoa(unescape(encodeURIComponent(emitted.svg)));
1194
+ return {
1195
+ uri: `data:image/svg+xml;base64,${base64}`,
1196
+ widthEx: (emitted.width + pad2) * EX_PER_KATEX_EM,
1197
+ heightEx: (emitted.height + emitted.depth + pad2) * EX_PER_KATEX_EM,
1198
+ depthEx: (emitted.depth + MATH_PAD_EM) * EX_PER_KATEX_EM
1199
+ };
1200
+ } catch (e) {
1201
+ console.error("Math typesetting error", e);
1202
+ return null;
1203
+ }
1204
+ }
1205
+ var MathBlock = class extends MarkdownContainer {
1206
+ /**
1207
+ * The TeX source, exactly as written between the delimiters.
1208
+ *
1209
+ * Also the projected text and the accessible name, so this is the one string a
1210
+ * reader can find, select, and copy.
1211
+ */
1212
+ formula;
1213
+ /** The `data:image/svg+xml` URI of the typeset glyphs. */
1214
+ svgUri;
1215
+ constructor(formula, svgUri) {
1216
+ super();
1217
+ this.formula = formula;
1218
+ this.svgUri = svgUri;
1219
+ }
1220
+ getDevtoolsDescriptor() {
1221
+ return {
1222
+ kind: "MathBlock",
1223
+ groups: [
1224
+ {
1225
+ label: "Math",
1226
+ fields: [{ label: "formula", value: this.formula, readOnly: true }]
1227
+ }
1228
+ ]
1229
+ };
1230
+ }
1231
+ };
1232
+
1233
+ // src/markdown-inline.ts
1234
+ var import_core3 = require("@vectojs/core");
1235
+ var import_ui2 = require("@vectojs/ui");
1236
+
1237
+ // src/markdown-image.ts
1238
+ function paragraphHasImage(token) {
1239
+ return containsImage(token.tokens);
1240
+ }
1241
+ function containsImage(tokens) {
1242
+ if (!tokens) return false;
1243
+ for (const token of tokens) {
1244
+ if (token.type === "image") return true;
1245
+ const anyToken = token;
1246
+ if (containsImage(anyToken.tokens)) return true;
1247
+ if (Array.isArray(anyToken.items) && containsImage(anyToken.items)) {
1248
+ return true;
1249
+ }
1250
+ const table = token;
1251
+ if (Array.isArray(table.header) && table.header.some((cell) => containsImage(cell.tokens))) {
1252
+ return true;
1253
+ }
1254
+ if (Array.isArray(table.rows) && table.rows.some((row) => row.some((cell) => containsImage(cell.tokens)))) {
1255
+ return true;
1256
+ }
1257
+ }
1258
+ return false;
1259
+ }
1260
+ function imagesOf(tokens) {
1261
+ const images = [];
1262
+ for (const token of tokens ?? []) {
1263
+ if (token.type === "image") {
1264
+ images.push(token);
1265
+ continue;
1266
+ }
1267
+ images.push(...imagesOf(token.tokens));
1268
+ }
1269
+ return images;
1270
+ }
1271
+ function stripImages(token) {
1272
+ const children = token.tokens;
1273
+ if (!children) return token;
1274
+ const kept = [];
1275
+ for (const child of children) {
1276
+ if (child.type === "image") continue;
1277
+ const grandchildren = child.tokens;
1278
+ if (grandchildren && containsImage(grandchildren)) {
1279
+ const stripped = stripImages(child);
1280
+ const remaining = stripped.tokens;
1281
+ if (remaining && remaining.length > 0) kept.push(stripped);
1282
+ continue;
1283
+ }
1284
+ kept.push(child);
1285
+ }
1286
+ return { ...token, tokens: kept };
1287
+ }
1288
+ function liftNestedImages(tokens) {
1289
+ const lifted = [];
1290
+ for (const token of tokens) {
1291
+ if (token.type === "image") {
1292
+ lifted.push(token);
1293
+ continue;
1294
+ }
1295
+ const children = token.tokens;
1296
+ if (children && containsImage(children)) {
1297
+ lifted.push(...liftNestedImages(children));
1298
+ continue;
1299
+ }
1300
+ lifted.push(token);
1301
+ }
1302
+ return lifted;
1303
+ }
1304
+ function lastIndexOfImage(tokens) {
1305
+ for (let i = tokens.length - 1; i >= 0; i--) {
1306
+ if (tokens[i].type === "image") return i;
1307
+ }
1308
+ return -1;
1309
+ }
1310
+ var inlineImageRasters = /* @__PURE__ */ new Map();
1311
+ var inlineImageRasterWaiters = /* @__PURE__ */ new Set();
1312
+ function subscribeInlineImageRaster(notify) {
1313
+ inlineImageRasterWaiters.add(notify);
1314
+ }
1315
+ function unsubscribeInlineImageRaster(notify) {
1316
+ inlineImageRasterWaiters.delete(notify);
1317
+ }
1318
+ function ensureInlineImageRaster(src) {
1319
+ const existing = inlineImageRasters.get(src);
1320
+ if (existing) return existing;
1321
+ const entry = { decoded: false };
1322
+ inlineImageRasters.set(src, entry);
1323
+ if (typeof globalThis.Image !== "undefined") {
1324
+ const bitmap = new globalThis.Image();
1325
+ bitmap.onload = () => {
1326
+ entry.decoded = true;
1327
+ entry.naturalWidth = bitmap.naturalWidth || void 0;
1328
+ entry.naturalHeight = bitmap.naturalHeight || void 0;
1329
+ for (const notify of inlineImageRasterWaiters) notify();
1330
+ };
1331
+ bitmap.onerror = () => {
1332
+ entry.failed = true;
1333
+ for (const notify of inlineImageRasterWaiters) notify();
1334
+ };
1335
+ bitmap.src = src;
1336
+ entry.bitmap = bitmap;
1337
+ }
1338
+ return entry;
1339
+ }
1340
+ function paintInlineImage(src, surface, box) {
1341
+ const raster = ensureInlineImageRaster(src);
1342
+ if (!raster.decoded || !raster.bitmap) return;
1343
+ surface.drawImage(raster.bitmap, box.x, box.y, box.width, box.height);
1344
+ }
1345
+ function expectedImageParagraphChildren(tokens) {
1346
+ let children = 0;
1347
+ let inTextRun = false;
1348
+ for (const token of liftNestedImages(tokens)) {
1349
+ if (token.type === "image") {
1350
+ children++;
1351
+ inTextRun = false;
1352
+ } else if (!inTextRun) {
1353
+ children++;
1354
+ inTextRun = true;
1355
+ }
1356
+ }
1357
+ return children;
1358
+ }
1359
+
1360
+ // src/markdown-inline.ts
1361
+ function decodeEntities(text) {
1362
+ return text.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&amp;/g, "&");
1363
+ }
1364
+ function collectSpans(tokens, inherited, theme, out, blockFontSize) {
1365
+ for (const token of tokens) {
1366
+ switch (token.type) {
1367
+ case "strong": {
1368
+ const t = token;
1369
+ if (t.tokens) {
1370
+ collectSpans(t.tokens, { ...inherited, bold: true }, theme, out, blockFontSize);
1371
+ } else {
1372
+ out.push({
1373
+ text: decodeEntities(t.text),
1374
+ style: { ...inherited, bold: true }
1375
+ });
1413
1376
  }
1414
- if (line[j] === quote) {
1415
- closed = true;
1377
+ break;
1378
+ }
1379
+ case "em": {
1380
+ const t = token;
1381
+ if (t.tokens) {
1382
+ collectSpans(t.tokens, { ...inherited, italic: true }, theme, out, blockFontSize);
1383
+ } else {
1384
+ out.push({
1385
+ text: decodeEntities(t.text),
1386
+ style: { ...inherited, italic: true }
1387
+ });
1388
+ }
1389
+ break;
1390
+ }
1391
+ case "del": {
1392
+ const t = token;
1393
+ if (t.tokens) {
1394
+ collectSpans(t.tokens, { ...inherited, lineThrough: true }, theme, out, blockFontSize);
1395
+ } else {
1396
+ out.push({
1397
+ text: decodeEntities(t.text),
1398
+ style: { ...inherited, lineThrough: true }
1399
+ });
1400
+ }
1401
+ break;
1402
+ }
1403
+ case "codespan": {
1404
+ const t = token;
1405
+ out.push({
1406
+ text: decodeEntities(t.text),
1407
+ // Inline code renders in the theme's monospace family (not just tinted
1408
+ // prose) — TextStyle.fontFamily drives both measurement and drawing.
1409
+ style: {
1410
+ ...inherited,
1411
+ color: theme.codeColor,
1412
+ fontFamily: theme.codeFont
1413
+ }
1414
+ });
1415
+ break;
1416
+ }
1417
+ case "br": {
1418
+ out.push({ text: "\n" });
1419
+ break;
1420
+ }
1421
+ case "html": {
1422
+ const t = token;
1423
+ const raw = t.raw ?? t.text ?? "";
1424
+ const brCount = (raw.match(/<br\s*\/?>/gi) ?? []).length;
1425
+ for (let i = 0; i < brCount; i++) out.push({ text: "\n" });
1426
+ break;
1427
+ }
1428
+ case "inlineMath": {
1429
+ const t = token;
1430
+ const runSize = inherited.fontSize ?? blockFontSize ?? theme.fontSize;
1431
+ const runColor = inherited.color ?? theme.textColor;
1432
+ const rendered = renderMathToSVGDataURI(t.text, false, runColor);
1433
+ if (rendered) {
1434
+ const uri = rendered.uri;
1435
+ out.push({
1436
+ text: import_core3.OBJECT_REPLACEMENT,
1437
+ style: inherited,
1438
+ object: {
1439
+ width: exToPx(rendered.widthEx, runSize),
1440
+ height: exToPx(rendered.heightEx, runSize),
1441
+ depth: exToPx(rendered.depthEx, runSize),
1442
+ // The TeX source is the accessible name: without it a screen reader
1443
+ // receives only the invisible U+FFFC sentinel.
1444
+ alt: t.text,
1445
+ // Without this the box is reserved and stays empty. The engine does
1446
+ // not draw objects, and nothing else in the tree holds the raster.
1447
+ paint: (surface, box) => paintInlineMath(uri, surface, box)
1448
+ }
1449
+ });
1450
+ } else {
1451
+ out.push({
1452
+ text: decodeEntities(t.raw),
1453
+ style: { ...inherited, color: theme.mathFallbackColor }
1454
+ });
1455
+ }
1456
+ break;
1457
+ }
1458
+ case "image": {
1459
+ const t = token;
1460
+ const runSize = inherited.fontSize ?? blockFontSize ?? theme.fontSize;
1461
+ const raster = ensureInlineImageRaster(t.href);
1462
+ if (raster.failed) {
1463
+ out.push({ text: decodeEntities(t.text), style: inherited });
1416
1464
  break;
1417
1465
  }
1418
- j++;
1466
+ const height = runSize * theme.inlineImageScale;
1467
+ const aspect = raster.naturalWidth && raster.naturalHeight ? raster.naturalWidth / raster.naturalHeight : 1;
1468
+ const src = t.href;
1469
+ out.push({
1470
+ text: import_core3.OBJECT_REPLACEMENT,
1471
+ style: inherited,
1472
+ object: {
1473
+ width: height * aspect,
1474
+ height,
1475
+ // Sits on the baseline like a cap-height glyph rather than hanging
1476
+ // below it; an image has no descender to align.
1477
+ depth: 0,
1478
+ // The accessible name, and what a copy yields. Without it the
1479
+ // invisible U+FFFC sentinel is all a screen reader receives.
1480
+ alt: t.text,
1481
+ // What this object PAINTS, which `alt` does not determine: two badges
1482
+ // can share alt text and differ in URL. Without it the paragraph memo
1483
+ // serves the first one's painter to the second and every row of a badge
1484
+ // column draws the first row's badge.
1485
+ key: src,
1486
+ paint: (surface, box) => paintInlineImage(src, surface, box)
1487
+ }
1488
+ });
1489
+ break;
1419
1490
  }
1420
- if (closed) {
1421
- flush(theme.codeColor);
1422
- segments.push({ text: line.slice(i, j + 1), color: STRING_COLOR });
1423
- i = j + 1;
1424
- continue;
1491
+ case "link": {
1492
+ const t = token;
1493
+ const linkStyle = {
1494
+ ...inherited,
1495
+ href: t.href,
1496
+ color: theme.linkColor
1497
+ };
1498
+ if (t.tokens && t.tokens.length > 0) {
1499
+ collectSpans(t.tokens, linkStyle, theme, out, blockFontSize);
1500
+ } else {
1501
+ out.push({ text: decodeEntities(t.text), style: linkStyle });
1502
+ }
1503
+ break;
1504
+ }
1505
+ case "text": {
1506
+ const t = token;
1507
+ if ("tokens" in t && t.tokens?.length) {
1508
+ collectSpans(t.tokens, inherited, theme, out, blockFontSize);
1509
+ } else {
1510
+ const decoded = decodeEntities(t.text);
1511
+ if (decoded) {
1512
+ const style = Object.keys(inherited).length > 0 ? inherited : void 0;
1513
+ out.push({ text: decoded, style });
1514
+ }
1515
+ }
1516
+ break;
1517
+ }
1518
+ default: {
1519
+ if ("text" in token) {
1520
+ const decoded = decodeEntities(token.text);
1521
+ if (decoded) {
1522
+ const style = Object.keys(inherited).length > 0 ? inherited : void 0;
1523
+ out.push({ text: decoded, style });
1524
+ }
1525
+ }
1526
+ break;
1425
1527
  }
1426
- buf += ch;
1427
- i++;
1428
- continue;
1429
1528
  }
1430
- if (/\d/.test(ch) && (i === 0 || /[\s(,=+\-*/<>[\]{}:;]/.test(line[i - 1]))) {
1431
- flush(theme.codeColor);
1432
- let j = i;
1433
- while (j < line.length && /[\d._xXa-fA-F]/.test(line[j])) j++;
1434
- segments.push({ text: line.slice(i, j), color: NUMBER_COLOR });
1435
- i = j;
1436
- continue;
1529
+ }
1530
+ }
1531
+ function findUnclosedInline(text) {
1532
+ let best = null;
1533
+ const tick = text.lastIndexOf("`");
1534
+ if (tick !== -1 && tick < text.length - 1) {
1535
+ return { kind: "codespan", at: tick, contentAt: tick + 1 };
1536
+ }
1537
+ if (tick !== -1) return null;
1538
+ const emphasis = /(\*{1,2}(?!\*)|_{1,2}(?!_))(?=[^\s])/g;
1539
+ for (let match = emphasis.exec(text); match !== null; match = emphasis.exec(text)) {
1540
+ const marker = match[1];
1541
+ const at = match.index;
1542
+ if (marker[0] === "_" && at > 0 && /[\w]/.test(text[at - 1])) continue;
1543
+ best = {
1544
+ kind: marker.length === 2 ? "strong" : "em",
1545
+ at,
1546
+ contentAt: at + marker.length
1547
+ };
1548
+ }
1549
+ const bracket = text.lastIndexOf("[");
1550
+ if (bracket !== -1 && bracket < text.length - 1 && (best === null || bracket > best.at)) {
1551
+ const closed = /\]\([^)]*\)/.test(text.slice(bracket));
1552
+ if (!closed) {
1553
+ best = { kind: "link", at: bracket, contentAt: bracket + 1 };
1554
+ }
1555
+ }
1556
+ return best;
1557
+ }
1558
+ function renderInlineToRichText(tokens, fallbackText, font, color, maxWidth, theme, selectable, onLinkClick) {
1559
+ const spans = [];
1560
+ if (tokens && tokens.length > 0) {
1561
+ collectSpans(tokens, {}, theme, spans, fontSizeFromFont(font));
1562
+ }
1563
+ if (spans.length === 0) {
1564
+ spans.push({ text: decodeEntities(fallbackText) });
1565
+ }
1566
+ return new import_ui2.RichText(spans, {
1567
+ font,
1568
+ color,
1569
+ maxWidth,
1570
+ linkColor: theme.linkColor,
1571
+ selectable,
1572
+ onLinkClick
1573
+ });
1574
+ }
1575
+
1576
+ // src/Markdown.ts
1577
+ var import_ui4 = require("@vectojs/ui");
1578
+
1579
+ // src/blockAffordances.ts
1580
+ var import_ui3 = require("@vectojs/ui");
1581
+ var LANGUAGE_EXTENSIONS = {
1582
+ bash: "sh",
1583
+ c: "c",
1584
+ cpp: "cpp",
1585
+ cs: "cs",
1586
+ css: "css",
1587
+ diff: "diff",
1588
+ dockerfile: "dockerfile",
1589
+ go: "go",
1590
+ graphql: "graphql",
1591
+ haskell: "hs",
1592
+ html: "html",
1593
+ java: "java",
1594
+ javascript: "js",
1595
+ js: "js",
1596
+ json: "json",
1597
+ jsonc: "jsonc",
1598
+ jsx: "jsx",
1599
+ kotlin: "kt",
1600
+ latex: "tex",
1601
+ lua: "lua",
1602
+ make: "mk",
1603
+ markdown: "md",
1604
+ md: "md",
1605
+ nix: "nix",
1606
+ php: "php",
1607
+ python: "py",
1608
+ py: "py",
1609
+ ruby: "rb",
1610
+ rust: "rs",
1611
+ rs: "rs",
1612
+ scss: "scss",
1613
+ sh: "sh",
1614
+ shell: "sh",
1615
+ sql: "sql",
1616
+ svelte: "svelte",
1617
+ swift: "swift",
1618
+ tex: "tex",
1619
+ toml: "toml",
1620
+ ts: "ts",
1621
+ tsx: "tsx",
1622
+ typescript: "ts",
1623
+ vue: "vue",
1624
+ xml: "xml",
1625
+ yaml: "yaml",
1626
+ yml: "yaml",
1627
+ zig: "zig",
1628
+ zsh: "sh"
1629
+ };
1630
+ function extensionForLanguage(lang) {
1631
+ const first = lang.trim().toLowerCase().split(/[\s:,{]/)[0] ?? "";
1632
+ return LANGUAGE_EXTENSIONS[first] ?? "txt";
1633
+ }
1634
+ function mimeForLanguage(lang) {
1635
+ const ext = extensionForLanguage(lang);
1636
+ if (ext === "json" || ext === "jsonc") return "application/json";
1637
+ if (ext === "html") return "text/html";
1638
+ if (ext === "css") return "text/css";
1639
+ if (ext === "xml" || ext === "svelte" || ext === "vue") return "text/plain";
1640
+ return "text/plain";
1641
+ }
1642
+ function escapeCsvField(value) {
1643
+ let needsQuoting = false;
1644
+ let hasQuote = false;
1645
+ for (const char of value) {
1646
+ if (char === '"') {
1647
+ hasQuote = true;
1648
+ needsQuoting = true;
1649
+ break;
1437
1650
  }
1438
- if (/[a-zA-Z_]/.test(ch)) {
1439
- flush(theme.codeColor);
1440
- let j = i;
1441
- while (j < line.length && /[a-zA-Z0-9_]/.test(line[j])) j++;
1442
- const word = line.slice(i, j);
1443
- segments.push({
1444
- text: word,
1445
- color: keywords.has(word) ? KEYWORD_COLOR : theme.codeColor
1446
- });
1447
- i = j;
1448
- continue;
1651
+ if (char === "," || char === "\n" || char === "\r") needsQuoting = true;
1652
+ }
1653
+ if (!needsQuoting) return value;
1654
+ return hasQuote ? `"${value.replace(/"/g, '""')}"` : `"${value}"`;
1655
+ }
1656
+ function escapeMarkdownTableCell(cell) {
1657
+ let needsEscaping = false;
1658
+ for (const char of cell) {
1659
+ if (char === "\\" || char === "|") {
1660
+ needsEscaping = true;
1661
+ break;
1449
1662
  }
1450
- buf += ch;
1451
- i++;
1452
1663
  }
1453
- flush(theme.codeColor);
1454
- return segments;
1664
+ if (!needsEscaping) return cell;
1665
+ return cell.replace(/\\/g, "\\\\").replace(/\|/g, "\\|");
1455
1666
  }
1456
- var CodeBlock = class extends import_ui2.UIComponent {
1457
- lines;
1458
- grid = null;
1459
- /** Raw (unhighlighted) lines of the last build, for prefix reuse in buildLines. */
1460
- rawLines = null;
1461
- cellWidth = 0;
1462
- source;
1463
- /** Bumped by {@link buildLines} and {@link setSelectable}; read by `Scene`. */
1464
- contentEpoch = 0;
1465
- lang;
1466
- theme;
1467
- lineH = 24;
1468
- pad = 18;
1469
- codeFont;
1470
- selectable;
1471
- constructor(code, lang, maxWidth, theme, selectable = true) {
1472
- super();
1473
- this.source = code;
1474
- this.lang = lang;
1475
- this.theme = theme;
1476
- this.codeFont = `15px ${theme.codeFont}`;
1477
- this.selectable = selectable;
1478
- this.lines = [];
1479
- this.width = maxWidth;
1480
- this.buildLines(code);
1667
+ function tableToCsv(table) {
1668
+ const lines = [table.headers.map(escapeCsvField).join(",")];
1669
+ for (const row of table.rows) lines.push(row.map(escapeCsvField).join(","));
1670
+ return `\uFEFF${lines.join("\r\n")}`;
1671
+ }
1672
+ function tableToMarkdown(table) {
1673
+ const header = `| ${table.headers.map(escapeMarkdownTableCell).join(" | ")} |`;
1674
+ const divider = `| ${table.headers.map((_cell, index) => {
1675
+ switch (table.align[index]) {
1676
+ case "left":
1677
+ return ":---";
1678
+ case "center":
1679
+ return ":---:";
1680
+ case "right":
1681
+ return "---:";
1682
+ default:
1683
+ return "---";
1684
+ }
1685
+ }).join(" | ")} |`;
1686
+ const body = table.rows.map(
1687
+ (row) => `| ${table.headers.map((_cell, index) => escapeMarkdownTableCell(row[index] ?? "")).join(" | ")} |`
1688
+ );
1689
+ return [header, divider, ...body].join("\n");
1690
+ }
1691
+ function defaultWriteClipboard(text) {
1692
+ const clipboard = globalThis.navigator?.clipboard;
1693
+ clipboard?.writeText?.(text);
1694
+ }
1695
+ function defaultSaveFile(filename, content, mimeType) {
1696
+ const doc = globalThis.document;
1697
+ if (!doc?.body) return;
1698
+ const blob = new Blob([content], { type: mimeType });
1699
+ const url = URL.createObjectURL(blob);
1700
+ const anchor = doc.createElement("a");
1701
+ anchor.href = url;
1702
+ anchor.download = filename;
1703
+ doc.body.appendChild(anchor);
1704
+ anchor.click();
1705
+ doc.body.removeChild(anchor);
1706
+ URL.revokeObjectURL(url);
1707
+ }
1708
+ var BlockAffordanceButton = class _BlockAffordanceButton extends import_ui3.Button {
1709
+ constructor(label, successLabel, act, opts = {}) {
1710
+ super(label, { ...opts, onClick: () => this.run() });
1711
+ this.act = act;
1712
+ this.restingLabel = label;
1713
+ this.successLabel = successLabel;
1714
+ this.width = Math.max(this.width, (0, import_ui3.measureText)(successLabel, this.font) + 24);
1481
1715
  }
1482
- /** Re-parse code content (e.g. for live editing). */
1483
- setCode(code, lang) {
1484
- if (lang !== void 0) this.lang = lang;
1485
- this.source = code;
1486
- this.buildLines(code);
1487
- this.scene?.markDirty();
1488
- return this;
1716
+ act;
1717
+ /** How long the confirmation label stays up, in ms. */
1718
+ static FEEDBACK_MS = 1600;
1719
+ restingLabel;
1720
+ successLabel;
1721
+ feedbackTimer;
1722
+ /**
1723
+ * Runs the action, then shows the confirmation.
1724
+ *
1725
+ * The action runs first and a throw propagates: a clipboard write the browser
1726
+ * rejected must not be reported as a success.
1727
+ */
1728
+ run() {
1729
+ this.act();
1730
+ this.setTransientLabel(this.successLabel);
1731
+ if (this.feedbackTimer !== void 0) clearTimeout(this.feedbackTimer);
1732
+ this.feedbackTimer = setTimeout(() => {
1733
+ this.setTransientLabel(this.restingLabel);
1734
+ this.feedbackTimer = void 0;
1735
+ }, _BlockAffordanceButton.FEEDBACK_MS);
1489
1736
  }
1490
- /** Enable or disable browser-native selection for this code block. */
1491
- setSelectable(selectable) {
1492
- this.selectable = selectable;
1493
- this.contentEpoch++;
1737
+ setTransientLabel(label) {
1738
+ this.label = label;
1739
+ this.textWidth = (0, import_ui3.measureText)(label, this.font);
1494
1740
  this.scene?.markDirty();
1495
- return this;
1496
1741
  }
1497
- getContentEpoch() {
1498
- return this.contentEpoch;
1742
+ /**
1743
+ * The label a reader hears is the one they see, transient confirmation
1744
+ * included, so an AT user gets the same feedback a sighted user does.
1745
+ */
1746
+ getA11yAttributes() {
1747
+ return { ...super.getA11yAttributes(), label: this.label };
1748
+ }
1749
+ /** Clears the pending revert so a destroyed block leaves no timer behind. */
1750
+ destroy() {
1751
+ if (this.feedbackTimer !== void 0) {
1752
+ clearTimeout(this.feedbackTimer);
1753
+ this.feedbackTimer = void 0;
1754
+ }
1755
+ super.destroy();
1756
+ }
1757
+ };
1758
+ var BlockWithAffordances = class _BlockWithAffordances extends import_ui3.UIComponent {
1759
+ constructor(block, controls) {
1760
+ super();
1761
+ this.block = block;
1762
+ this.controls = controls;
1763
+ this.add(block);
1764
+ for (const control of controls) this.add(control);
1765
+ this.layoutAffordances();
1499
1766
  }
1767
+ block;
1768
+ controls;
1769
+ /** Gap between the block's edges and the controls, in px. */
1770
+ static INSET = 8;
1771
+ /** Gap between adjacent controls, in px. */
1772
+ static GAP = 6;
1500
1773
  /**
1501
- * Change the block's box width.
1502
- *
1503
- * Deliberately does **not** rebuild the grid or the highlight, because code does
1504
- * not reflow: lines are placed on a fixed monospace grid at `col × cellWidth` and
1505
- * a long line overflows rather than wrapping, so `height` is a function of line
1506
- * *count* alone. The width only sizes the rounded background. Anything that would
1507
- * change the glyph geometry — the source, the language, the font — goes through
1508
- * {@link setCode} and invalidates the grid there.
1774
+ * Places the controls right-aligned along the block's top edge.
1509
1775
  *
1510
- * @returns `this` for chaining.
1776
+ * Laid out right-to-left from the block's right edge so the first control in
1777
+ * the list ends up leftmost, which keeps DOM order (and therefore tab order and
1778
+ * the a11y reading order) matching the visual order.
1511
1779
  */
1512
- setWidth(width) {
1513
- const next = Math.max(0, width);
1514
- if (next === this.width) return this;
1515
- this.width = next;
1516
- this.scene?.markDirty();
1517
- return this;
1518
- }
1519
- getContentProjection(hint) {
1520
- if (!this.source) return null;
1521
- const grid = this.ensureGrid();
1522
- const rows = [];
1523
- rows.length = grid.lines.length;
1524
- for (let row = 0; row < grid.lines.length; row++) {
1525
- const line = grid.lines[row];
1526
- const y = this.pad + row * this.lineH;
1527
- if (!(0, import_core.contentLineInHint)(hint, y, this.lineH)) continue;
1528
- rows[row] = {
1529
- text: this.source.slice(line.sourceStart, line.sourceEnd),
1530
- separatorAfter: this.source.slice(line.sourceEnd, line.nextSourceStart) || void 0,
1531
- x: this.pad,
1532
- y,
1533
- baseline: this.lineH * 0.75,
1534
- font: this.codeFont,
1535
- lineHeight: this.lineH
1536
- };
1780
+ layoutAffordances() {
1781
+ this.width = this.block.width;
1782
+ this.height = this.block.height;
1783
+ let right = this.block.width - _BlockWithAffordances.INSET;
1784
+ for (let i = this.controls.length - 1; i >= 0; i--) {
1785
+ const control = this.controls[i];
1786
+ control.x = right - control.width;
1787
+ control.y = _BlockWithAffordances.INSET;
1788
+ right = control.x - _BlockWithAffordances.GAP;
1537
1789
  }
1538
- return {
1539
- text: this.source,
1540
- font: this.codeFont,
1541
- lineHeight: this.lineH,
1542
- // Every row is absolutely positioned from the same local coordinates as
1543
- // render(). A single pre-wrap DOM text node would introduce browser
1544
- // wrapping for long source lines that canvas intentionally keeps intact.
1545
- //
1546
- lines: rows,
1547
- selectable: this.selectable,
1548
- // render() draws cell-by-cell (no ligatures can form); the DOM copy
1549
- // must not ligate either or Firefox selection geometry drifts.
1550
- ligatures: "none",
1551
- grid
1552
- };
1553
1790
  }
1554
1791
  /**
1555
- * Re-highlight the code, reusing the highlight of any unchanged line prefix.
1556
- *
1557
- * Streaming appends to the END of a block, so all but the last line or two are
1558
- * byte-identical to the previous call — yet this used to re-highlight every
1559
- * line on every chunk, making a streamed block O(N) per append and O(N^2)
1560
- * overall. Reusing the stable prefix makes an append proportional to what
1561
- * actually changed.
1792
+ * Re-places the controls after the block's own box changed.
1562
1793
  *
1563
- * The last previously-seen line is deliberately NOT reused: a chunk usually
1564
- * lands mid-line, so that line's text (and therefore its tokenization) changes.
1794
+ * Called by the owner when a block is resized or its content grew; the controls
1795
+ * are anchored to the right edge, so a width change moves them.
1565
1796
  */
1566
- buildLines(code) {
1567
- this.contentEpoch++;
1568
- const rawLines = code.split(/\r\n|\r|\n/);
1569
- const previous = this.rawLines;
1570
- let reusable = 0;
1571
- if (previous && this.lines.length === previous.length) {
1572
- const limit = Math.min(previous.length - 1, rawLines.length);
1573
- while (reusable < limit && previous[reusable] === rawLines[reusable]) reusable++;
1574
- }
1575
- if (reusable > 0) {
1576
- const next = this.lines.slice(0, reusable);
1577
- for (let i = reusable; i < rawLines.length; i++) {
1578
- next.push(highlightLine(rawLines[i], this.lang, this.theme));
1579
- }
1580
- this.lines = next;
1581
- } else {
1582
- this.lines = rawLines.map((l) => highlightLine(l, this.lang, this.theme));
1583
- }
1584
- this.rawLines = rawLines;
1585
- this.grid = null;
1586
- this.height = this.pad * 2 + rawLines.length * this.lineH;
1797
+ refreshAffordances() {
1798
+ this.layoutAffordances();
1799
+ this.scene?.markDirty();
1587
1800
  }
1588
- ensureGrid() {
1589
- const cellWidth = this.cellWidth || Math.max(1, (0, import_ui2.measureText)("M", this.codeFont));
1590
- if (!this.grid || this.grid.source !== this.source || this.grid.font !== this.codeFont || this.grid.cellWidth !== cellWidth) {
1591
- this.grid = (0, import_core.prepareContentGrid)(this.source, {
1592
- font: this.codeFont,
1593
- cellWidth,
1594
- lineHeight: this.lineH,
1595
- baseline: this.lineH * 0.75
1596
- });
1597
- }
1598
- return this.grid;
1801
+ /** The wrapper is a pass-through: its size is the block's size. */
1802
+ getLayoutControlledProperties() {
1803
+ return ["x", "y"];
1599
1804
  }
1600
- /** Code blocks are decorative — not interactive. */
1601
- isPointInside() {
1602
- return false;
1805
+ /**
1806
+ * Projected as a group so assistive technology reports one labelled region
1807
+ * containing the block and its controls, rather than two unrelated siblings.
1808
+ */
1809
+ getA11yAttributes() {
1810
+ return { role: "group", pointerEvents: "none" };
1603
1811
  }
1604
- render(r) {
1605
- r.beginPath();
1606
- r.roundRect(0, 0, this.width, this.height, 8);
1607
- r.fill(this.theme.codeBgColor);
1608
- const grid = this.ensureGrid();
1609
- const atlas = codeGlyphAtlas(r);
1610
- const atlasSource = atlas?.source ?? null;
1611
- const blit = atlas ? r.drawImageRect : void 0;
1612
- for (let row = 0; row < grid.lines.length; row++) {
1613
- const yBaseline = this.pad + row * this.lineH + this.lineH * 0.75;
1614
- const segments = this.lines[row];
1615
- let segmentIndex = 0;
1616
- let segmentEnd = segments[0]?.text.length ?? 0;
1617
- const lineStart = grid.lines[row].sourceStart;
1618
- for (const cell of grid.lines[row].cells) {
1619
- const localSourceStart = cell.sourceStart - lineStart;
1620
- while (segmentIndex < segments.length - 1 && localSourceStart >= segmentEnd) {
1621
- segmentIndex++;
1622
- segmentEnd += segments[segmentIndex].text.length;
1623
- }
1624
- const sourceText = this.source.slice(cell.sourceStart, cell.sourceEnd);
1625
- if (cell.advance <= 0 || sourceText === " " || sourceText === " ") continue;
1626
- const color = segments[segmentIndex]?.color ?? this.theme.codeColor;
1627
- const x = this.pad + cell.x;
1628
- if (blit && atlas) {
1629
- const slot = atlas.get(this.codeFont, color, cell.glyph);
1630
- const src = atlasSource ?? atlas.source;
1631
- if (slot && src) {
1632
- blit.call(
1633
- r,
1634
- src,
1635
- slot.sx,
1636
- slot.sy,
1637
- slot.sw,
1638
- slot.sh,
1639
- x - slot.offsetX,
1640
- yBaseline - slot.offsetY,
1641
- slot.w,
1642
- slot.h
1643
- );
1644
- continue;
1645
- }
1646
- }
1647
- r.fillText(cell.glyph, x, yBaseline, this.codeFont, color);
1648
- }
1649
- }
1812
+ render() {
1650
1813
  }
1651
1814
  };
1652
- var codeAtlases = /* @__PURE__ */ new Map();
1653
- var MAX_CODE_ATLASES = 2;
1654
- var lastCodeAtlas = null;
1655
- function codeGlyphAtlas(r) {
1656
- if (typeof r.drawImageRect !== "function") return void 0;
1657
- if (typeof document === "undefined") return void 0;
1658
- const dpr = Math.max(
1659
- 1,
1660
- r.pixelRatio ?? (typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1)
1661
- );
1662
- const existing = codeAtlases.get(dpr);
1663
- if (existing) {
1664
- codeAtlases.delete(dpr);
1665
- codeAtlases.set(dpr, existing);
1666
- lastCodeAtlas = existing;
1667
- return existing;
1815
+ function tableContentOf(token) {
1816
+ return {
1817
+ headers: token.header.map((cell) => cell.text),
1818
+ rows: token.rows.map((row) => row.map((cell) => cell.text)),
1819
+ align: token.align
1820
+ };
1821
+ }
1822
+
1823
+ // src/frontMatter.ts
1824
+ var OPEN_RE = /^---[ \t]*\r?\n/;
1825
+ var OPENER_PREFIX_RE = /^(?:-|--|---[ \t]*\r?)$/;
1826
+ var KEY_RE = /^[^\s:#][^:]*:(?:[ \t].*)?$/;
1827
+ var CLOSE_RE = /^(?:---|\.\.\.)[ \t]*$/;
1828
+ var MAX_PENDING_CHARS = 4096;
1829
+ var NONE = { kind: "none" };
1830
+ var PENDING = { kind: "pending" };
1831
+ function scanFrontMatter(text, complete) {
1832
+ if (text.length === 0) return PENDING;
1833
+ const open = OPEN_RE.exec(text);
1834
+ if (!open) {
1835
+ return !complete && OPENER_PREFIX_RE.test(text) ? PENDING : NONE;
1668
1836
  }
1669
- const atlas = new import_core.GlyphRasterAtlas({ dpr, maxSize: 2048 });
1670
- codeAtlases.set(dpr, atlas);
1671
- if (codeAtlases.size > MAX_CODE_ATLASES) {
1672
- const oldestKey = codeAtlases.keys().next().value;
1673
- const oldest = codeAtlases.get(oldestKey);
1674
- codeAtlases.delete(oldestKey);
1675
- if (oldest && oldest !== atlas) oldest.destroy();
1837
+ const decide = complete || text.length > MAX_PENDING_CHARS;
1838
+ const contentStart = open[0].length;
1839
+ let cursor = contentStart;
1840
+ let keyChecked = false;
1841
+ while (cursor < text.length) {
1842
+ const nl = text.indexOf("\n", cursor);
1843
+ if (nl === -1 && !decide) return PENDING;
1844
+ const line = text.slice(cursor, nl === -1 ? text.length : nl).replace(/\r$/, "");
1845
+ if (!keyChecked) {
1846
+ if (!KEY_RE.test(line)) return NONE;
1847
+ keyChecked = true;
1848
+ } else if (CLOSE_RE.test(line)) {
1849
+ return {
1850
+ kind: "found",
1851
+ raw: text.slice(contentStart, cursor),
1852
+ // A closer with no trailing newline ends the document, so the body is
1853
+ // empty rather than starting one character past the end.
1854
+ bodyStart: nl === -1 ? text.length : nl + 1
1855
+ };
1856
+ }
1857
+ if (nl === -1) break;
1858
+ cursor = nl + 1;
1676
1859
  }
1677
- lastCodeAtlas = atlas;
1678
- return atlas;
1860
+ return decide ? NONE : PENDING;
1679
1861
  }
1680
- function codeAtlasStats() {
1681
- return lastCodeAtlas ? lastCodeAtlas.stats : null;
1862
+ function parseFrontMatterFields(raw) {
1863
+ const out = {};
1864
+ for (const rawLine of raw.split("\n")) {
1865
+ const line = rawLine.replace(/\r$/, "");
1866
+ if (line.length === 0 || /^[\s#]/.test(line)) continue;
1867
+ const sep = line.indexOf(":");
1868
+ if (sep <= 0) continue;
1869
+ const value = line.slice(sep + 1);
1870
+ if (value.length > 0 && value[0] !== " " && value[0] !== " ") continue;
1871
+ out[line.slice(0, sep).trim()] = unquote(value.trim());
1872
+ }
1873
+ return out;
1682
1874
  }
1683
- function codeAtlas() {
1684
- return lastCodeAtlas;
1875
+ function unquote(value) {
1876
+ if (value.length < 2) return value;
1877
+ const first = value[0];
1878
+ if ((first === '"' || first === "'") && value.endsWith(first)) {
1879
+ return value.slice(1, -1);
1880
+ }
1881
+ return value;
1685
1882
  }
1686
- function decodeEntities(text) {
1687
- return text.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&amp;/g, "&");
1883
+
1884
+ // src/MarkdownWorkerSource.ts
1885
+ var WORKER_SOURCE_STRING = '"use strict";(()=>{function V(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}var _=V();function ke(t){_=t}var C={exec:()=>null};function P(t){let e=[];return n=>{let s=Math.max(0,Math.min(3,n-1)),r=e[s];return r||(r=t(s),e[s]=r),r}}function k(t,e=""){let n=typeof t=="string"?t:t.source,s={replace:(r,l)=>{let a=typeof l=="string"?l:l.source;return a=a.replace(x.caret,"$1"),n=n.replace(r,a),s},getRegex:()=>new RegExp(n,e)};return s}var _e=((t="")=>{try{return!!new RegExp("(?<=1)(?<!1)"+t)}catch{return!1}})(),x={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:t=>new RegExp(`^( {0,3}${t})((?:[ ][^\\\\n]*)?(?:\\\\n|$))`),nextBulletRegex:P(t=>new RegExp(`^ {0,${t}}(?:[*+-]|\\\\d{1,9}[.)])((?:[ ][^\\\\n]*)?(?:\\\\n|$))`)),hrRegex:P(t=>new RegExp(`^ {0,${t}}((?:- *){3,}|(?:_ *){3,}|(?:\\\\* *){3,})(?:\\\\n+|$)`)),fencesBeginRegex:P(t=>new RegExp(`^ {0,${t}}(?:\\`\\`\\`|~~~)`)),headingBeginRegex:P(t=>new RegExp(`^ {0,${t}}#`)),htmlBeginRegex:P(t=>new RegExp(`^ {0,${t}}<(?:[a-z].*>|!--)`,"i")),blockquoteBeginRegex:P(t=>new RegExp(`^ {0,${t}}>`))},Pe=/^(?:[ \\t]*(?:\\n|$))+/,Me=/^((?: {4}| {0,3}\\t)[^\\n]+(?:\\n(?:[ \\t]*(?:\\n|$))*)?)+/,Ee=/^ {0,3}(`{3,}(?=[^`\\n]*(?:\\n|$))|~{3,})([^\\n]*)(?:\\n|$)(?:|([\\s\\S]*?)(?:\\n|$))(?: {0,3}\\1[~`]* *(?=\\n|$)|$)/,v=/^ {0,3}((?:-[\\t ]*){3,}|(?:_[ \\t]*){3,}|(?:\\*[ \\t]*){3,})(?:\\n+|$)/,Be=/^ {0,3}(#{1,6})(?=\\s|$)(.*)(?:\\n+|$)/,K=/ {0,3}(?:[*+-]|\\d{1,9}[.)])/,fe=/^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\\n(?!\\s*?\\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\\n {0,3}(=+|-+) *(?:\\n+|$)/,de=k(fe).replace(/bull/g,K).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}(?:\\s|$)/).replace(/html/g,/ {0,3}<[^\\n>]+>\\n/).replace(/\\|table/g,"").getRegex(),qe=k(fe).replace(/bull/g,K).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}(?:\\s|$)/).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|[ \\t]+\\n)[^\\n]+)*)/,ve=/^[^\\n]+/,Y=/(?!\\s*\\])(?:\\\\[\\s\\S]|[^\\[\\]\\\\])+/,De=k(/^ {0,3}\\[(label)\\]: *(?:\\n[ \\t]*)?([^<\\s][^\\s]*|<.*?>)(?:(?: +(?:\\n[ \\t]*)?| *\\n[ \\t]*)(title))? *(?:\\n+|$)/).replace("label",Y).replace("title",/(?:"(?:\\\\"?|[^"\\\\])*"|\'[^\'\\n]*(?:\\n[^\'\\n]+)*\\n?\'|\\([^()]*\\))/).getRegex(),Ze=k(/^(bull)([ \\t][^\\n]*?)?(?:\\n|$)/).replace(/bull/g,K).getRegex(),N="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",ee=/<!--(?:-?>|[\\s\\S]*?(?:-->|$))/,Oe=k("^ {0,3}(?:<(script|pre|style|textarea)[\\\\s>][\\\\s\\\\S]*?(?:</\\\\1>[^\\\\n]*\\\\n*|$)|comment[^\\\\n]*(\\\\n+|$)|<\\\\?[\\\\s\\\\S]*?(?:\\\\?>[^\\\\n]*\\\\n*|$)|<![A-Z][\\\\s\\\\S]*?(?:>[^\\\\n]*\\\\n*|$)|<!\\\\[CDATA\\\\[[\\\\s\\\\S]*?(?:\\\\]\\\\]>[^\\\\n]*\\\\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",ee).replace("tag",N).replace("attribute",/ +[a-zA-Z:_][\\w.:-]*(?: *= *"[^"\\n]*"| *= *\'[^\'\\n]*\'| *= *[^\\s"\'=<>`]+)?/).getRegex(),xe=t=>k(J).replace("hr",v).replace("heading"," {0,3}#{1,6}(?:\\\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\\\n]*\\\\n)|~~~)[^\\\\n]*\\\\n").replace("list",t).replace("html","</?(?:tag)(?: +|\\\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",N).getRegex(),Qe=xe(/ {0,3}(?:[*+-]|1[.)])[ \\t]+[^ \\t\\n]/),Ne=xe(/ {0,3}(?:[*+-]|\\d{1,9}[.)])(?:[ \\t]|\\n|$)/),He=k(/^( {0,3}> ?(paragraph|[^\\n]*)(?:\\n|$))+/).replace("paragraph",Ne).getRegex(),te={blockquote:He,code:Me,def:De,fences:Ee,heading:Be,hr:v,html:Oe,lheading:de,list:Ze,newline:Pe,paragraph:Qe,table:C,text:ve},ae=k("^ *([^\\\\n ].*)\\\\n {0,3}((?:\\\\| *)?:?-+:? *(?:\\\\| *:?-+:? *)*(?:\\\\| *)?)(?:\\\\n((?:(?! *\\\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\\\n|$))*)\\\\n*|$)").replace("hr",v).replace("heading"," {0,3}#{1,6}(?:\\\\s|$)").replace("blockquote"," {0,3}>").replace("code","(?: {4}| {0,3} )[^\\\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\\\n]*\\\\n)|~~~)[^\\\\n]*\\\\n").replace("list"," {0,3}(?:[*+-]|1[.)])[ \\\\t]").replace("html","</?(?:tag)(?: +|\\\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",N).getRegex(),je={...te,lheading:qe,table:ae,paragraph:k(J).replace("hr",v).replace("heading"," {0,3}#{1,6}(?:\\\\s|$)").replace("|lheading","").replace("table",ae).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\\\n]*\\\\n)|~~~)[^\\\\n]*\\\\n").replace("list"," {0,3}(?:[*+-]|1[.)])[ \\\\t]+[^ \\\\t\\\\n]").replace("html","</?(?:tag)(?: +|\\\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",N).getRegex()},Ge={...te,html:k(`^ *(?:comment *(?:\\\\n|\\\\s*$)|<(tag)[\\\\s\\\\S]+?</\\\\1> *(?:\\\\n{2,}|\\\\s*$)|<tag(?:"[^"]*"|\'[^\']*\'|\\\\s[^\'"/>\\\\s]*)*?/?> *(?:\\\\n{2,}|\\\\s*$))`).replace("comment",ee).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:C,lheading:/^(.+?)\\n {0,3}(=+|-+) *(?:\\n+|$)/,paragraph:k(J).replace("hr",v).replace("heading",` *#{1,6} *[^\n]`).replace("lheading",de).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},We=/^\\\\([!"#$%&\'()*+,\\-./:;<=>?@\\[\\]\\\\^_`{|}~])/,Fe=/^(`+)([^`]|[^`][\\s\\S]*?[^`])\\1(?!`)/,be=/^( {2,}|\\\\)\\n(?!\\s*$)/,Xe=/^(`+|[^`])(?:(?= {2,}\\n)|[\\s\\S]*?(?:(?=[\\\\<!\\[`*_]|\\b_|$)|[^ ](?= {2,}\\n)))/,M=/[\\p{P}\\p{S}]/u,H=/[\\s\\p{P}\\p{S}]/u,ne=/[^\\s\\p{P}\\p{S}]/u,Ue=k(/^((?![*_])punctSpace)/,"u").replace(/punctSpace/g,H).getRegex(),me=/(?!~)[\\p{P}\\p{S}]/u,Ve=/(?!~)[\\s\\p{P}\\p{S}]/u,Ke=/(?:[^\\s\\p{P}\\p{S}]|~)/u,Je=k(/link|precode-code|html/,"g").replace("link",/\\[(?:[^\\[\\]`]|(?<a>`+)[^`]+\\k<a>(?!`))*?\\]\\((?:\\\\[\\s\\S]|[^\\\\\\(\\)]|\\((?:\\\\[\\s\\S]|[^\\\\\\(\\)])*\\))*\\)/).replace("precode-",_e?"(?<!`)()":"(^^|[^`])").replace("code",/(?<b>`+)[^`]+\\k<b>(?!`)/).replace("html",/<(?! )[^<>]*?>/).getRegex(),we=/^(?:\\*+(?:((?!\\*)punct)|([^\\s*]))?)|^_+(?:((?!_)punct)|([^\\s_]))?/,Ye=k(we,"u").replace(/punct/g,M).getRegex(),et=k(we,"u").replace(/punct/g,me).getRegex(),ye="^[^_*]*?__[^_*]*?\\\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\\\*)punct(\\\\*+)(?=[\\\\s]|$)|notPunctSpace(\\\\*+)(?!\\\\*)(?=punctSpace|$)|(?!\\\\*)punctSpace(\\\\*+)(?=notPunctSpace)|[\\\\s](\\\\*+)(?!\\\\*)(?=punct)|(?!\\\\*)punct(\\\\*+)(?!\\\\*)(?=punct)|notPunctSpace(\\\\*+)(?=notPunctSpace)",tt=k(ye,"gu").replace(/notPunctSpace/g,ne).replace(/punctSpace/g,H).replace(/punct/g,M).getRegex(),nt=k(ye,"gu").replace(/notPunctSpace/g,Ke).replace(/punctSpace/g,Ve).replace(/punct/g,me).getRegex(),rt=k("^[^_*]*?\\\\*\\\\*[^_*]*?_[^_*]*?(?=\\\\*\\\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)","gu").replace(/notPunctSpace/g,ne).replace(/punctSpace/g,H).replace(/punct/g,M).getRegex(),st=k(/^~~?(?:((?!~)punct)|[^\\s~])/,"u").replace(/punct/g,M).getRegex(),lt="^[^~]+(?=[^~])|(?!~)punct(~~?)(?=[\\\\s]|$)|notPunctSpace(~~?)(?!~)(?=punctSpace|$)|(?!~)punctSpace(~~?)(?=notPunctSpace)|[\\\\s](~~?)(?!~)(?=punct)|(?!~)punct(~~?)(?!~)(?=punct)|notPunctSpace(~~?)(?=notPunctSpace)",it=k(lt,"gu").replace(/notPunctSpace/g,ne).replace(/punctSpace/g,H).replace(/punct/g,M).getRegex(),at=k(/\\\\(punct)/,"gu").replace(/punct/g,M).getRegex(),ot=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(),ct=k(ee).replace("(?:-->|$)","-->").getRegex(),ht=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",ct).replace("attribute",/\\s+[a-zA-Z:_][\\w.:-]*(?:\\s*=\\s*"[^"]*"|\\s*=\\s*\'[^\']*\'|\\s*=\\s*[^\\s"\'=<>`]+)?/).getRegex(),Z=/(?:\\[(?:\\\\[\\s\\S]|[^\\[\\]\\\\])*\\]|\\\\[\\s\\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\\])|[^\\[\\]\\\\`])*?/,ut=k(/^!?\\[(label)\\]\\(\\s*(href)(?:(?:[ \\t]+(?:\\n[ \\t]*)?|\\n[ \\t]*)(title))?\\s*\\)/).replace("label",Z).replace("href",/<(?:\\\\.|[^\\n<>\\\\])+>|[^ \\t\\n\\x00-\\x1f]+|(?=\\))/).replace("title",/"(?:\\\\"?|[^"\\\\])*"|\'(?:\\\\\'?|[^\'\\\\])*\'|\\((?:\\\\\\)?|[^)\\\\])*\\)/).getRegex(),Re=k(/^!?\\[(label)\\]\\[(ref)\\]/).replace("label",Z).replace("ref",Y).getRegex(),$e=k(/^!?\\[(ref)\\](?:\\[\\])?/).replace("ref",Y).getRegex(),pt=k("reflink|nolink(?!\\\\()","g").replace("reflink",Re).replace("nolink",$e).getRegex(),oe=/[hH][tT][tT][pP][sS]?|[fF][tT][pP]/,re={_backpedal:C,anyPunctuation:at,autolink:ot,blockSkip:Je,br:be,code:Fe,del:C,delLDelim:C,delRDelim:C,emStrongLDelim:Ye,emStrongRDelimAst:tt,emStrongRDelimUnd:rt,escape:We,link:ut,nolink:$e,punctuation:Ue,reflink:Re,reflinkSearch:pt,tag:ht,text:Xe,url:C},gt={...re,link:k(/^!?\\[(label)\\]\\((.*?)\\)/).replace("label",Z).getRegex(),reflink:k(/^!?\\[(label)\\]\\s*\\[([^\\]]*)\\]/).replace("label",Z).getRegex()},F={...re,emStrongRDelimAst:nt,emStrongLDelim:et,delLDelim:st,delRDelim:it,url:k(/^((?:protocol):\\/\\/|www\\.)(?:[a-zA-Z0-9\\-]+\\.?)+[^\\s<]*|^email/).replace("protocol",oe).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",oe).getRegex()},kt={...F,br:k(be).replace("{2,}","*").getRegex(),text:k(F.text).replace("\\\\b_","\\\\b_| {2,}\\\\n").replace(/\\{2,\\}/g,"*").getRegex()},D={normal:te,gfm:je,pedantic:Ge},B={normal:re,gfm:F,breaks:kt,pedantic:gt},ft={"&":"&amp;","<":"&lt;",">":"&gt;",\'"\':"&quot;","\'":"&#39;"},ce=t=>ft[t];function S(t,e){if(e){if(x.escapeTest.test(t))return t.replace(x.escapeReplace,ce)}else if(x.escapeTestNoEncode.test(t))return t.replace(x.escapeReplaceNoEncode,ce);return t}function he(t){try{t=encodeURI(t).replace(x.percentDecode,"%")}catch{return null}return t}function ue(t,e){let n=t.replace(x.findPipe,(l,a,i)=>{let o=!1,c=a;for(;--c>=0&&i[c]==="\\\\";)o=!o;return o?"|":" |"}),s=n.split(x.splitPipe),r=0;if(s[0].trim()||s.shift(),s.length>0&&!s.at(-1)?.trim()&&s.pop(),e)if(s.length>e)s.splice(e);else for(;s.length<e;)s.push("");for(;r<s.length;r++)s[r]=s[r].trim().replace(x.slashPipe,"|");return s}function z(t,e,n){let s=t.length;if(s===0)return"";let r=0;for(;r<s;){let l=t.charAt(s-r-1);if(l===e&&!n)r++;else if(l!==e&&n)r++;else break}return t.slice(0,s-r)}function pe(t){let e=t.split(`\n`),n=e.length-1;for(;n>=0&&x.blankLine.test(e[n]);)n--;return e.length-n<=2?t:e.slice(0,n+1).join(`\n`)}function dt(t,e){if(t.indexOf(e[1])===-1)return-1;let n=0;for(let s=0;s<t.length;s++)if(t[s]==="\\\\")s++;else if(t[s]===e[0])n++;else if(t[s]===e[1]&&(n--,n<0))return s;return n>0?-2:-1}function xt(t,e=0){let n=e,s="";for(let r of t)if(r===" "){let l=4-n%4;s+=" ".repeat(l),n+=l}else s+=r,n++;return s}function ge(t,e,n,s,r){let l=e.href,a=e.title||null,i=t[1].replace(r.other.outputLinkReplace,"$1");s.state.inLink=!0;let o={type:t[0].charAt(0)==="!"?"image":"link",raw:n,href:l,title:a,text:i,tokens:s.inlineTokens(i)};return s.state.inLink=!1,o}function bt(t,e,n){let s=t.match(n.other.indentCodeCompensation);if(s===null)return e;let r=s[1];return e.split(`\n`).map(l=>{let a=l.match(n.other.beginningSpace);if(a===null)return l;let[i]=a;return i.length>=r.length?l.slice(r.length):l}).join(`\n`)}var O=class{options;rules;lexer;constructor(t){this.options=t||_}space(t){let e=this.rules.block.newline.exec(t);if(e&&e[0].length>0)return{type:"space",raw:e[0]}}code(t){let e=this.rules.block.code.exec(t);if(e){let n=this.options.pedantic?e[0]:pe(e[0]),s=n.replace(this.rules.other.codeRemoveIndent,"");return{type:"code",raw:n,codeBlockStyle:"indented",text:s}}}fences(t){let e=this.rules.block.fences.exec(t);if(e){let n=e[0],s=bt(n,e[3]||"",this.rules);return{type:"code",raw:n,lang:e[2]?e[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):e[2],text:s}}}heading(t){let e=this.rules.block.heading.exec(t);if(e){let n=e[2].trim();if(this.rules.other.endingHash.test(n)){let s=z(n,"#");(this.options.pedantic||!s||this.rules.other.endingSpaceChar.test(s))&&(n=s.trim())}return{type:"heading",raw:z(e[0],`\n`),depth:e[1].length,text:n,tokens:this.lexer.inline(n)}}}hr(t){let e=this.rules.block.hr.exec(t);if(e)return{type:"hr",raw:z(e[0],`\n`)}}blockquote(t){let e=this.rules.block.blockquote.exec(t);if(e){let n=z(e[0],`\n`).split(`\n`),s="",r="",l=[];for(;n.length>0;){let a=!1,i=[],o;for(o=0;o<n.length;o++)if(this.rules.other.blockquoteStart.test(n[o]))i.push(n[o]),a=!0;else if(!a)i.push(n[o]);else break;n=n.slice(o);let c=i.join(`\n`),u=c.replace(this.rules.other.blockquoteSetextReplace,`\n $1`).replace(this.rules.other.blockquoteSetextReplace2,"");s=s?`${s}\n${c}`:c,r=r?`${r}\n${u}`:u;let h=this.lexer.state.top;if(this.lexer.state.top=!0,this.lexer.blockTokens(u,l,!0),this.lexer.state.top=h,n.length===0)break;let p=l.at(-1);if(p?.type==="code")break;if(p?.type==="blockquote"){let d=p,f=d.raw+`\n`+n.join(`\n`),m=this.blockquote(f);l[l.length-1]=m,s=s.substring(0,s.length-d.raw.length)+m.raw,r=r.substring(0,r.length-d.text.length)+m.text;break}else if(p?.type==="list"){let d=p,f=d.raw+`\n`+n.join(`\n`),m=this.list(f);l[l.length-1]=m,s=s.substring(0,s.length-p.raw.length)+m.raw,r=r.substring(0,r.length-d.raw.length)+m.raw,n=f.substring(l.at(-1).raw.length).split(`\n`);continue}}return{type:"blockquote",raw:s,tokens:l,text:r}}}list(t){let e=this.rules.block.list.exec(t);if(e){let n=e[1].trim(),s=n.length>1,r={type:"list",raw:"",ordered:s,start:s?+n.slice(0,-1):"",loose:!1,items:[]};n=s?`\\\\d{1,9}\\\\${n.slice(-1)}`:`\\\\${n}`,this.options.pedantic&&(n=s?n:"[*+-]");let l=this.rules.other.listItemRegex(n),a=!1;for(;t;){let o=!1,c="",u="";if(!(e=l.exec(t))||this.rules.block.hr.test(t))break;c=e[0],t=t.substring(c.length);let h=xt(e[2].split(`\n`,1)[0],e[1].length),p=t.split(`\n`,1)[0],d=!h.trim(),f=0;if(this.options.pedantic?(f=2,u=h.trimStart()):d?f=e[1].length+1:(f=h.search(this.rules.other.nonSpaceChar),f=f>4?1:f,u=h.slice(f),f+=e[1].length),d&&this.rules.other.blankLine.test(p)&&(c+=p+`\n`,t=t.substring(p.length+1),o=!0),!o){let m=this.rules.other.nextBulletRegex(f),w=this.rules.other.hrRegex(f),y=this.rules.other.fencesBeginRegex(f),L=this.rules.other.headingBeginRegex(f),W=this.rules.other.htmlBeginRegex(f),A=this.rules.other.blockquoteBeginRegex(f);for(;t;){let b=t.split(`\n`,1)[0],T;if(p=b,this.options.pedantic?(p=p.replace(this.rules.other.listReplaceNesting," "),T=p):T=p.replace(this.rules.other.tabCharGlobal," "),y.test(p)||L.test(p)||W.test(p)||A.test(p)||m.test(p)||w.test(p))break;if(T.search(this.rules.other.nonSpaceChar)>=f||!p.trim())u+=`\n`+T.slice(f);else{if(d||h.replace(this.rules.other.tabCharGlobal," ").search(this.rules.other.nonSpaceChar)>=4||y.test(h)||L.test(h)||w.test(h))break;u+=`\n`+p}d=!p.trim(),c+=b+`\n`,t=t.substring(b.length+1),h=T.slice(f)}}r.loose||(a?r.loose=!0:this.rules.other.doubleBlankLine.test(c)&&(a=!0)),r.items.push({type:"list_item",raw:c,task:!!this.options.gfm&&this.rules.other.listIsTask.test(u),loose:!1,text:u,tokens:[]}),r.raw+=c}let i=r.items.at(-1);if(i)i.raw=i.raw.trimEnd(),i.text=i.text.trimEnd();else return;r.raw=r.raw.trimEnd();for(let o of r.items){this.lexer.state.top=!1,o.tokens=this.lexer.blockTokens(o.text,[]);let c=o.tokens[0];if(o.task&&(c?.type==="text"||c?.type==="paragraph")){o.text=o.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 h=this.lexer.inlineQueue.length-1;h>=0;h--)if(this.rules.other.listIsTask.test(this.lexer.inlineQueue[h].src)){this.lexer.inlineQueue[h].src=this.lexer.inlineQueue[h].src.replace(this.rules.other.listReplaceTask,"");break}let u=this.rules.other.listTaskCheckbox.exec(o.raw);if(u){let h={type:"checkbox",raw:u[0]+" ",checked:u[0]!=="[ ]"};o.checked=h.checked,r.loose?o.tokens[0]&&["paragraph","text"].includes(o.tokens[0].type)&&"tokens"in o.tokens[0]&&o.tokens[0].tokens?(o.tokens[0].raw=h.raw+o.tokens[0].raw,o.tokens[0].text=h.raw+o.tokens[0].text,o.tokens[0].tokens.unshift(h)):o.tokens.unshift({type:"paragraph",raw:h.raw,text:h.raw,tokens:[h]}):o.tokens.unshift(h)}}else o.task&&(o.task=!1);if(!r.loose){let u=o.tokens.filter(p=>p.type==="space"),h=u.length>0&&u.some(p=>this.rules.other.anyLine.test(p.raw));r.loose=h}}if(r.loose)for(let o of r.items){o.loose=!0;for(let c of o.tokens)c.type==="text"&&(c.type="paragraph")}return r}}html(t){let e=this.rules.block.html.exec(t);if(e){let n=pe(e[0]);return{type:"html",block:!0,raw:n,pre:e[1]==="pre"||e[1]==="script"||e[1]==="style",text:n}}}def(t){let e=this.rules.block.def.exec(t);if(e){let n=e[1].toLowerCase().replace(this.rules.other.multipleSpaceGlobal," "),s=e[2]?e[2].replace(this.rules.other.hrefBrackets,"$1").replace(this.rules.inline.anyPunctuation,"$1"):"",r=e[3]?e[3].substring(1,e[3].length-1).replace(this.rules.inline.anyPunctuation,"$1"):e[3];return{type:"def",tag:n,raw:z(e[0],`\n`),href:s,title:r}}}table(t){let e=this.rules.block.table.exec(t);if(!e||!this.rules.other.tableDelimiter.test(e[2]))return;let n=ue(e[1]),s=e[2].replace(this.rules.other.tableAlignChars,"").split("|"),r=e[3]?.trim()?e[3].replace(this.rules.other.tableRowBlankLine,"").split(`\n`):[],l={type:"table",raw:z(e[0],`\n`),header:[],align:[],rows:[]};if(n.length===s.length){for(let a of s)this.rules.other.tableAlignRight.test(a)?l.align.push("right"):this.rules.other.tableAlignCenter.test(a)?l.align.push("center"):this.rules.other.tableAlignLeft.test(a)?l.align.push("left"):l.align.push(null);for(let a=0;a<n.length;a++)l.header.push({text:n[a],tokens:this.lexer.inline(n[a]),header:!0,align:l.align[a]});for(let a of r)l.rows.push(ue(a,l.header.length).map((i,o)=>({text:i,tokens:this.lexer.inline(i),header:!1,align:l.align[o]})));return l}}lheading(t){let e=this.rules.block.lheading.exec(t);if(e){let n=e[1].trim();return{type:"heading",raw:z(e[0],`\n`),depth:e[2].charAt(0)==="="?1:2,text:n,tokens:this.lexer.inline(n)}}}paragraph(t){let e=this.rules.block.paragraph.exec(t);if(e){let n=e[1].charAt(e[1].length-1)===`\n`?e[1].slice(0,-1):e[1];return{type:"paragraph",raw:e[0],text:n,tokens:this.lexer.inline(n)}}}text(t){let e=this.rules.block.text.exec(t);if(e)return{type:"text",raw:e[0],text:e[0],tokens:this.lexer.inline(e[0])}}escape(t){let e=this.rules.inline.escape.exec(t);if(e)return{type:"escape",raw:e[0],text:e[1]}}tag(t){let e=this.rules.inline.tag.exec(t);if(e)return!this.lexer.state.inLink&&this.rules.other.startATag.test(e[0])?this.lexer.state.inLink=!0:this.lexer.state.inLink&&this.rules.other.endATag.test(e[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&this.rules.other.startPreScriptTag.test(e[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&this.rules.other.endPreScriptTag.test(e[0])&&(this.lexer.state.inRawBlock=!1),{type:"html",raw:e[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:!1,text:e[0]}}link(t){let e=this.rules.inline.link.exec(t);if(e){let n=e[2].trim();if(!this.options.pedantic&&this.rules.other.startAngleBracket.test(n)){if(!this.rules.other.endAngleBracket.test(n))return;let l=z(n.slice(0,-1),"\\\\");if((n.length-l.length)%2===0)return}else{let l=dt(e[2],"()");if(l===-2)return;if(l>-1){let a=(e[0].indexOf("!")===0?5:4)+e[1].length+l;e[2]=e[2].substring(0,l),e[0]=e[0].substring(0,a).trim(),e[3]=""}}let s=e[2],r="";if(this.options.pedantic){let l=this.rules.other.pedanticHrefTitle.exec(s);l&&(s=l[1],r=l[3])}else r=e[3]?e[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)),ge(e,{href:s&&s.replace(this.rules.inline.anyPunctuation,"$1"),title:r&&r.replace(this.rules.inline.anyPunctuation,"$1")},e[0],this.lexer,this.rules)}}reflink(t,e){let n;if((n=this.rules.inline.reflink.exec(t))||(n=this.rules.inline.nolink.exec(t))){let s=(n[2]||n[1]).replace(this.rules.other.multipleSpaceGlobal," "),r=e[s.toLowerCase()];if(!r){let l=n[0].charAt(0);return{type:"text",raw:l,text:l}}return ge(n,r,n[0],this.lexer,this.rules)}}emStrong(t,e,n=""){let s=this.rules.inline.emStrongLDelim.exec(t);if(!(!s||!s[1]&&!s[2]&&!s[3]&&!s[4]||s[4]&&n.match(this.rules.other.unicodeAlphaNumeric))&&(!(s[1]||s[3])||!n||this.rules.inline.punctuation.exec(n))){let r=[...s[0]].length-1,l,a,i=r,o=0,c=s[0][0]==="*"?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(c.lastIndex=0,e=e.slice(-1*t.length+r);(s=c.exec(e))!==null;){if(l=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!l)continue;if(a=[...l].length,s[3]||s[4]){i+=a;continue}else if((s[5]||s[6])&&r%3&&!((r+a)%3)){o+=a;continue}if(i-=a,i>0)continue;a=Math.min(a,a+i+o);let u=[...s[0]][0].length,h=t.slice(0,r+s.index+u+a);if(Math.min(r,a)%2){let d=h.slice(1,-1);return{type:"em",raw:h,text:d,tokens:this.lexer.inlineTokens(d)}}let p=h.slice(2,-2);return{type:"strong",raw:h,text:p,tokens:this.lexer.inlineTokens(p)}}}}codespan(t){let e=this.rules.inline.code.exec(t);if(e){let n=e[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:e[0],text:n}}}br(t){let e=this.rules.inline.br.exec(t);if(e)return{type:"br",raw:e[0]}}del(t,e,n=""){let s=this.rules.inline.delLDelim.exec(t);if(s&&(!s[1]||!n||this.rules.inline.punctuation.exec(n))){let r=[...s[0]].length-1,l,a,i=r,o=this.rules.inline.delRDelim;for(o.lastIndex=0,e=e.slice(-1*t.length+r);(s=o.exec(e))!==null;){if(l=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!l||(a=[...l].length,a!==r))continue;if(s[3]||s[4]){i+=a;continue}if(i-=a,i>0)continue;a=Math.min(a,a+i);let c=[...s[0]][0].length,u=t.slice(0,r+s.index+c+a),h=u.slice(r,-r);return{type:"del",raw:u,text:h,tokens:this.lexer.inlineTokens(h)}}}}autolink(t){let e=this.rules.inline.autolink.exec(t);if(e){let n,s;return e[2]==="@"?(n=e[1],s="mailto:"+n):(n=e[1],s=n),{type:"link",raw:e[0],text:n,href:s,tokens:[{type:"text",raw:n,text:n}]}}}url(t){let e;if(e=this.rules.inline.url.exec(t)){let n,s;if(e[2]==="@")n=e[0],s="mailto:"+n;else{let r;do r=e[0],e[0]=this.rules.inline._backpedal.exec(e[0])?.[0]??"";while(r!==e[0]);n=e[0],e[1]==="www."?s="http://"+e[0]:s=e[0]}return{type:"link",raw:e[0],text:n,href:s,tokens:[{type:"text",raw:n,text:n}]}}}inlineText(t){let e=this.rules.inline.text.exec(t);if(e){let n=this.lexer.state.inRawBlock;return{type:"text",raw:e[0],text:e[0],escaped:n}}}},R=class X{tokens;options;state;inlineQueue;tokenizer;constructor(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||_,this.options.tokenizer=this.options.tokenizer||new O,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options,this.tokenizer.lexer=this,this.inlineQueue=[],this.state={inLink:!1,inRawBlock:!1,top:!0};let n={other:x,block:D.normal,inline:B.normal};this.options.pedantic?(n.block=D.pedantic,n.inline=B.pedantic):this.options.gfm&&(n.block=D.gfm,this.options.breaks?n.inline=B.breaks:n.inline=B.gfm),this.tokenizer.rules=n}static get rules(){return{block:D,inline:B}}static lex(e,n){return new X(n).lex(e)}static lexInline(e,n){return new X(n).inlineTokens(e)}lex(e){e=e.replace(x.carriageReturn,`\n`),this.blockTokens(e,this.tokens);for(let n=0;n<this.inlineQueue.length;n++){let s=this.inlineQueue[n];this.inlineTokens(s.src,s.tokens)}return this.inlineQueue=[],this.tokens}blockTokens(e,n=[],s=!1){this.tokenizer.lexer=this,this.options.pedantic&&(e=e.replace(x.tabCharGlobal," ").replace(x.spaceLine,""));let r=1/0;for(;e;){if(e.length<r)r=e.length;else{this.infiniteLoopError(e.charCodeAt(0));break}let l;if(this.options.extensions?.block?.some(i=>(l=i.call({lexer:this},e,n))?(e=e.substring(l.raw.length),n.push(l),!0):!1))continue;if(l=this.tokenizer.space(e)){e=e.substring(l.raw.length);let i=n.at(-1);l.raw.length===1&&i!==void 0?i.raw+=`\n`:n.push(l);continue}if(l=this.tokenizer.code(e)){e=e.substring(l.raw.length);let i=n.at(-1);i?.type==="paragraph"||i?.type==="text"?(i.raw+=(i.raw.endsWith(`\n`)?"":`\n`)+l.raw,i.text+=`\n`+l.text,this.inlineQueue.at(-1).src=i.text):n.push(l);continue}if(l=this.tokenizer.fences(e)){e=e.substring(l.raw.length),n.push(l);continue}if(l=this.tokenizer.heading(e)){e=e.substring(l.raw.length),n.push(l);continue}if(l=this.tokenizer.hr(e)){e=e.substring(l.raw.length),n.push(l);continue}if(l=this.tokenizer.blockquote(e)){e=e.substring(l.raw.length),n.push(l);continue}if(l=this.tokenizer.list(e)){e=e.substring(l.raw.length),n.push(l);continue}if(l=this.tokenizer.html(e)){e=e.substring(l.raw.length),n.push(l);continue}if(l=this.tokenizer.def(e)){e=e.substring(l.raw.length);let i=n.at(-1);i?.type==="paragraph"||i?.type==="text"?(i.raw+=(i.raw.endsWith(`\n`)?"":`\n`)+l.raw,i.text+=`\n`+l.raw,this.inlineQueue.at(-1).src=i.text):this.tokens.links[l.tag]||(this.tokens.links[l.tag]={href:l.href,title:l.title},n.push(l));continue}if(l=this.tokenizer.table(e)){e=e.substring(l.raw.length),n.push(l);continue}if(l=this.tokenizer.lheading(e)){e=e.substring(l.raw.length),n.push(l);continue}let a=e;if(this.options.extensions?.startBlock){let i=1/0,o=e.slice(1),c;this.options.extensions.startBlock.forEach(u=>{c=u.call({lexer:this},o),typeof c=="number"&&c>=0&&(i=Math.min(i,c))}),i<1/0&&i>=0&&(a=e.substring(0,i+1))}if(this.state.top&&(l=this.tokenizer.paragraph(a))){let i=n.at(-1);s&&i?.type==="paragraph"?(i.raw+=(i.raw.endsWith(`\n`)?"":`\n`)+l.raw,i.text+=`\n`+l.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=i.text):n.push(l),s=a.length!==e.length,e=e.substring(l.raw.length);continue}if(l=this.tokenizer.text(e)){e=e.substring(l.raw.length);let i=n.at(-1);i?.type==="text"?(i.raw+=(i.raw.endsWith(`\n`)?"":`\n`)+l.raw,i.text+=`\n`+l.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=i.text):n.push(l);continue}if(e){this.infiniteLoopError(e.charCodeAt(0));break}}return this.state.top=!0,n}inline(e,n=[]){return this.inlineQueue.push({src:e,tokens:n}),n}inlineTokens(e,n=[]){this.tokenizer.lexer=this;let s=e;if(this.tokens.links){let i=Object.keys(this.tokens.links);i.length>0&&(s=s.replace(this.tokenizer.rules.inline.reflinkSearch,o=>i.includes(o.slice(o.lastIndexOf("[")+1,-1))?"["+"a".repeat(o.length-2)+"]":o))}s=s.replace(this.tokenizer.rules.inline.anyPunctuation,"++"),s=s.replace(this.tokenizer.rules.inline.blockSkip,(i,o,c)=>{let u=c?c.length:0;return i.slice(0,u)+"["+"a".repeat(i.length-u-2)+"]"}),s=this.options.hooks?.emStrongMask?.call({lexer:this},s)??s;let r=!1,l="",a=1/0;for(;e;){if(e.length<a)a=e.length;else{this.infiniteLoopError(e.charCodeAt(0));break}r||(l=""),r=!1;let i;if(this.options.extensions?.inline?.some(c=>(i=c.call({lexer:this},e,n))?(e=e.substring(i.raw.length),n.push(i),!0):!1))continue;if(i=this.tokenizer.escape(e)){e=e.substring(i.raw.length),n.push(i);continue}if(i=this.tokenizer.tag(e)){e=e.substring(i.raw.length),n.push(i);continue}if(i=this.tokenizer.link(e)){e=e.substring(i.raw.length),n.push(i);continue}if(i=this.tokenizer.reflink(e,this.tokens.links)){e=e.substring(i.raw.length);let c=n.at(-1);i.type==="text"&&c?.type==="text"?(c.raw+=i.raw,c.text+=i.text):n.push(i);continue}if(i=this.tokenizer.emStrong(e,s,l)){e=e.substring(i.raw.length),n.push(i);continue}if(i=this.tokenizer.codespan(e)){e=e.substring(i.raw.length),n.push(i);continue}if(i=this.tokenizer.br(e)){e=e.substring(i.raw.length),n.push(i);continue}if(i=this.tokenizer.del(e,s,l)){e=e.substring(i.raw.length),n.push(i);continue}if(i=this.tokenizer.autolink(e)){e=e.substring(i.raw.length),n.push(i);continue}if(!this.state.inLink&&(i=this.tokenizer.url(e))){e=e.substring(i.raw.length),n.push(i);continue}let o=e;if(this.options.extensions?.startInline){let c=1/0,u=e.slice(1),h;this.options.extensions.startInline.forEach(p=>{h=p.call({lexer:this},u),typeof h=="number"&&h>=0&&(c=Math.min(c,h))}),c<1/0&&c>=0&&(o=e.substring(0,c+1))}if(i=this.tokenizer.inlineText(o)){e=e.substring(i.raw.length),i.raw.slice(-1)!=="_"&&(l=i.raw.slice(-1)),r=!0;let c=n.at(-1);c?.type==="text"?(c.raw+=i.raw,c.text+=i.text):n.push(i);continue}if(e){this.infiniteLoopError(e.charCodeAt(0));break}}return n}infiniteLoopError(e){let n="Infinite loop on byte: "+e;if(this.options.silent)console.error(n);else throw new Error(n)}},Q=class{options;parser;constructor(t){this.options=t||_}space(t){return""}code({text:t,lang:e,escaped:n}){let s=(e||"").match(x.notSpaceStart)?.[0],r=t.replace(x.endingNewline,"")+`\n`;return s?\'<pre><code class="language-\'+S(s)+\'">\'+(n?r:S(r,!0))+`</code></pre>\n`:"<pre><code>"+(n?r:S(r,!0))+`</code></pre>\n`}blockquote({tokens:t}){return`<blockquote>\n${this.parser.parse(t)}</blockquote>\n`}html({text:t}){return t}def(t){return""}heading({tokens:t,depth:e}){return`<h${e}>${this.parser.parseInline(t)}</h${e}>\n`}hr(t){return`<hr>\n`}list(t){let e=t.ordered,n=t.start,s="";for(let a=0;a<t.items.length;a++){let i=t.items[a];s+=this.listitem(i)}let r=e?"ol":"ul",l=e&&n!==1?\' start="\'+n+\'"\':"";return"<"+r+l+`>\n`+s+"</"+r+`>\n`}listitem(t){return`<li>${this.parser.parse(t.tokens)}</li>\n`}checkbox({checked:t}){return"<input "+(t?\'checked="" \':"")+\'disabled="" type="checkbox"> \'}paragraph({tokens:t}){return`<p>${this.parser.parseInline(t)}</p>\n`}table(t){let e="",n="";for(let r=0;r<t.header.length;r++)n+=this.tablecell(t.header[r]);e+=this.tablerow({text:n});let s="";for(let r=0;r<t.rows.length;r++){let l=t.rows[r];n="";for(let a=0;a<l.length;a++)n+=this.tablecell(l[a]);s+=this.tablerow({text:n})}return s&&(s=`<tbody>${s}</tbody>`),`<table>\n<thead>\n`+e+`</thead>\n`+s+`</table>\n`}tablerow({text:t}){return`<tr>\n${t}</tr>\n`}tablecell(t){let e=this.parser.parseInline(t.tokens),n=t.header?"th":"td";return(t.align?`<${n} align="${t.align}">`:`<${n}>`)+e+`</${n}>\n`}strong({tokens:t}){return`<strong>${this.parser.parseInline(t)}</strong>`}em({tokens:t}){return`<em>${this.parser.parseInline(t)}</em>`}codespan({text:t}){return`<code>${S(t,!0)}</code>`}br(t){return"<br>"}del({tokens:t}){return`<del>${this.parser.parseInline(t)}</del>`}link({href:t,title:e,tokens:n}){let s=this.parser.parseInline(n),r=he(t);if(r===null)return s;t=r;let l=\'<a href="\'+t+\'"\';return e&&(l+=\' title="\'+S(e)+\'"\'),l+=">"+s+"</a>",l}image({href:t,title:e,text:n,tokens:s}){s&&(n=this.parser.parseInline(s,this.parser.textRenderer));let r=he(t);if(r===null)return S(n);t=r;let l=`<img src="${t}" alt="${S(n)}"`;return e&&(l+=` title="${S(e)}"`),l+=">",l}text(t){return"tokens"in t&&t.tokens?this.parser.parseInline(t.tokens):"escaped"in t&&t.escaped?t.text:S(t.text)}},se=class{strong({text:t}){return t}em({text:t}){return t}codespan({text:t}){return t}del({text:t}){return t}html({text:t}){return t}text({text:t}){return t}link({text:t}){return""+t}image({text:t}){return""+t}br(){return""}checkbox({raw:t}){return t}},$=class U{options;renderer;textRenderer;constructor(e){this.options=e||_,this.options.renderer=this.options.renderer||new Q,this.renderer=this.options.renderer,this.renderer.options=this.options,this.renderer.parser=this,this.textRenderer=new se}static parse(e,n){return new U(n).parse(e)}static parseInline(e,n){return new U(n).parseInline(e)}parse(e){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 a=r,i=this.options.extensions.renderers[a.type].call({parser:this},a);if(i!==!1||!["space","hr","heading","code","table","blockquote","list","html","def","paragraph","text"].includes(a.type)){n+=i||"";continue}}let l=r;switch(l.type){case"space":{n+=this.renderer.space(l);break}case"hr":{n+=this.renderer.hr(l);break}case"heading":{n+=this.renderer.heading(l);break}case"code":{n+=this.renderer.code(l);break}case"table":{n+=this.renderer.table(l);break}case"blockquote":{n+=this.renderer.blockquote(l);break}case"list":{n+=this.renderer.list(l);break}case"checkbox":{n+=this.renderer.checkbox(l);break}case"html":{n+=this.renderer.html(l);break}case"def":{n+=this.renderer.def(l);break}case"paragraph":{n+=this.renderer.paragraph(l);break}case"text":{n+=this.renderer.text(l);break}default:{let a=\'Token with "\'+l.type+\'" type was not found.\';if(this.options.silent)return console.error(a),"";throw new Error(a)}}}return n}parseInline(e,n=this.renderer){this.renderer.parser=this;let s="";for(let r=0;r<e.length;r++){let l=e[r];if(this.options.extensions?.renderers?.[l.type]){let i=this.options.extensions.renderers[l.type].call({parser:this},l);if(i!==!1||!["escape","html","link","image","strong","em","codespan","br","del","text"].includes(l.type)){s+=i||"";continue}}let a=l;switch(a.type){case"escape":{s+=n.text(a);break}case"html":{s+=n.html(a);break}case"link":{s+=n.link(a);break}case"image":{s+=n.image(a);break}case"checkbox":{s+=n.checkbox(a);break}case"strong":{s+=n.strong(a);break}case"em":{s+=n.em(a);break}case"codespan":{s+=n.codespan(a);break}case"br":{s+=n.br(a);break}case"del":{s+=n.del(a);break}case"text":{s+=n.text(a);break}default:{let i=\'Token with "\'+a.type+\'" type was not found.\';if(this.options.silent)return console.error(i),"";throw new Error(i)}}}return s}},q=class{options;block;constructor(t){this.options=t||_}static passThroughHooks=new Set(["preprocess","postprocess","processAllTokens","emStrongMask"]);static passThroughHooksRespectAsync=new Set(["preprocess","postprocess","processAllTokens"]);preprocess(t){return t}postprocess(t){return t}processAllTokens(t){return t}emStrongMask(t){return t}provideLexer(t=this.block){return t?R.lex:R.lexInline}provideParser(t=this.block){return t?$.parse:$.parseInline}},mt=class{defaults=V();options=this.setOptions;parse=this.parseMarkdown(!0);parseInline=this.parseMarkdown(!1);Parser=$;Renderer=Q;TextRenderer=se;Lexer=R;Tokenizer=O;Hooks=q;constructor(...t){this.use(...t)}walkTokens(t,e){let n=[];for(let s of t)switch(n=n.concat(e.call(this,s)),s.type){case"table":{let r=s;for(let l of r.header)n=n.concat(this.walkTokens(l.tokens,e));for(let l of r.rows)for(let a of l)n=n.concat(this.walkTokens(a.tokens,e));break}case"list":{let r=s;n=n.concat(this.walkTokens(r.items,e));break}default:{let r=s;this.defaults.extensions?.childTokens?.[r.type]?this.defaults.extensions.childTokens[r.type].forEach(l=>{let a=r[l].flat(1/0);n=n.concat(this.walkTokens(a,e))}):r.tokens&&(n=n.concat(this.walkTokens(r.tokens,e)))}}return n}use(...t){let e=this.defaults.extensions||{renderers:{},childTokens:{}};return t.forEach(n=>{let s={...n};if(s.async=this.defaults.async||s.async||!1,n.extensions&&(n.extensions.forEach(r=>{if(!r.name)throw new Error("extension name required");if("renderer"in r){let l=e.renderers[r.name];l?e.renderers[r.name]=function(...a){let i=r.renderer.apply(this,a);return i===!1&&(i=l.apply(this,a)),i}:e.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 l=e[r.level];l?l.unshift(r.tokenizer):e[r.level]=[r.tokenizer],r.start&&(r.level==="block"?e.startBlock?e.startBlock.push(r.start):e.startBlock=[r.start]:r.level==="inline"&&(e.startInline?e.startInline.push(r.start):e.startInline=[r.start]))}"childTokens"in r&&r.childTokens&&(e.childTokens[r.name]=r.childTokens)}),s.extensions=e),n.renderer){let r=this.defaults.renderer||new Q(this.defaults);for(let l in n.renderer){if(!(l in r))throw new Error(`renderer \'${l}\' does not exist`);if(["options","parser"].includes(l))continue;let a=l,i=n.renderer[a],o=r[a];r[a]=(...c)=>{let u=i.apply(r,c);return u===!1&&(u=o.apply(r,c)),u||""}}s.renderer=r}if(n.tokenizer){let r=this.defaults.tokenizer||new O(this.defaults);for(let l in n.tokenizer){if(!(l in r))throw new Error(`tokenizer \'${l}\' does not exist`);if(["options","rules","lexer"].includes(l))continue;let a=l,i=n.tokenizer[a],o=r[a];r[a]=(...c)=>{let u=i.apply(r,c);return u===!1&&(u=o.apply(r,c)),u}}s.tokenizer=r}if(n.hooks){let r=this.defaults.hooks||new q;for(let l in n.hooks){if(!(l in r))throw new Error(`hook \'${l}\' does not exist`);if(["options","block"].includes(l))continue;let a=l,i=n.hooks[a],o=r[a];q.passThroughHooks.has(l)?r[a]=c=>{if(this.defaults.async&&q.passThroughHooksRespectAsync.has(l))return(async()=>{let h=await i.call(r,c);return o.call(r,h)})();let u=i.call(r,c);return o.call(r,u)}:r[a]=(...c)=>{if(this.defaults.async)return(async()=>{let h=await i.apply(r,c);return h===!1&&(h=await o.apply(r,c)),h})();let u=i.apply(r,c);return u===!1&&(u=o.apply(r,c)),u}}s.hooks=r}if(n.walkTokens){let r=this.defaults.walkTokens,l=n.walkTokens;s.walkTokens=function(a){let i=[];return i.push(l.call(this,a)),r&&(i=i.concat(r.call(this,a))),i}}this.defaults={...this.defaults,...s}}),this}setOptions(t){return this.defaults={...this.defaults,...t},this}lexer(t,e){return R.lex(t,e??this.defaults)}parser(t,e){return $.parse(t,e??this.defaults)}parseMarkdown(t){return(e,n)=>{let s={...n},r={...this.defaults,...s},l=this.onError(!!r.silent,!!r.async);if(this.defaults.async===!0&&s.async===!1)return l(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 e>"u"||e===null)return l(new Error("marked(): input parameter is undefined or null"));if(typeof e!="string")return l(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(e)+", string expected"));if(r.hooks&&(r.hooks.options=r,r.hooks.block=t),r.async)return(async()=>{let a=r.hooks?await r.hooks.preprocess(e):e,i=await(r.hooks?await r.hooks.provideLexer(t):t?R.lex:R.lexInline)(a,r),o=r.hooks?await r.hooks.processAllTokens(i):i;r.walkTokens&&await Promise.all(this.walkTokens(o,r.walkTokens));let c=await(r.hooks?await r.hooks.provideParser(t):t?$.parse:$.parseInline)(o,r);return r.hooks?await r.hooks.postprocess(c):c})().catch(l);try{r.hooks&&(e=r.hooks.preprocess(e));let a=(r.hooks?r.hooks.provideLexer(t):t?R.lex:R.lexInline)(e,r);r.hooks&&(a=r.hooks.processAllTokens(a)),r.walkTokens&&this.walkTokens(a,r.walkTokens);let i=(r.hooks?r.hooks.provideParser(t):t?$.parse:$.parseInline)(a,r);return r.hooks&&(i=r.hooks.postprocess(i)),i}catch(a){return l(a)}}}onError(t,e){return n=>{if(n.message+=`\nPlease report this to https://github.com/markedjs/marked.`,t){let s="<p>An error occurred:</p><pre>"+S(n.message+"",!0)+"</pre>";return e?Promise.resolve(s):s}if(e)return Promise.reject(n);throw n}}},I=new mt;function g(t,e){return I.parse(t,e)}g.options=g.setOptions=function(t){return I.setOptions(t),g.defaults=I.defaults,ke(g.defaults),g};g.getDefaults=V;g.defaults=_;g.use=function(...t){return I.use(...t),g.defaults=I.defaults,ke(g.defaults),g};g.walkTokens=function(t,e){return I.walkTokens(t,e)};g.parseInline=I.parseInline;g.Parser=$;g.parser=$.parse;g.Renderer=Q;g.TextRenderer=se;g.Lexer=R;g.lexer=R.lex;g.Tokenizer=O;g.Hooks=q;g.parse=g;var zt=g.options,At=g.setOptions,Ct=g.use,It=g.walkTokens,_t=g.parseInline;var Pt=$.parse,Mt=R.lex;function Se(t,e,n){let s=0;for(let r=e;r<n;r++)s+=t[r].raw.length;return s}function wt(t,e){let n=t;return n.links=e,n}var yt=/^ {0,3}\\$\\$/m;function Le(t){return t.includes("$$")===!1?!1:yt.test(t)}function Rt(t,e){return t[e-2]?.type!=="list"?!0:e+1<t.length}function ze(t,e){for(let n=t.length-2;n>=e;n--)if(t[n].type==="space"&&Rt(t,n+1)!==!1)return n+1;return-1}function Ae(t){let e=t.links;if(!e)return!1;for(let n in e)return!0;return!1}function Ce(t,e,n,s,r){let l=r;for(let a=e;a<n;a++){let i=t[a].raw;if(s.startsWith(i,l)===!1)return!1;l+=i.length}return!0}function G(t,e,n){return{source:t,tail:t,tokens:e,stableCount:0,stableOffset:0,degraded:!0,degradedReason:n}}function Te(t,e){return{source:t,tail:t,tokens:e,stableCount:0,stableOffset:0,degraded:!1,degradedReason:null}}function $t(t,e){if(Ae(e))return G(t,e,"link-definition");if(t.includes("\\r"))return G(t,e,"carriage-return");if(Le(t))return G(t,e,"block-math");let n=ze(e,1);if(n<0||Ce(e,0,n,t,0)===!1)return Te(t,e);let s=Se(e,0,n);return{source:t,tail:t.slice(s),tokens:e,stableCount:n,stableOffset:s,degraded:!1,degradedReason:null}}function le(t){let e=g.lexer(t);return{tokens:e,cache:$t(t,e),charsLexed:t.length,reusedTokens:0}}function j(t,e){let n=g.lexer(t);return{tokens:n,cache:G(t,n,e),charsLexed:t.length,reusedTokens:0}}function Ie(t,e){let n=t.source+e;if(t.degraded)return j(n,t.degradedReason??"link-definition");if(e.includes("\\r"))return j(n,"carriage-return");if(t.stableCount===0)return le(n);let s=t.tail+e;if(Le(s))return j(n,"block-math");let r=g.lexer(s);if(Ae(r))return j(n,"link-definition");let l=t.tokens.slice(0,t.stableCount),a=wt([...l,...r],r.links),i=t.stableCount,o=t.stableOffset,c=s,u=ze(a,t.stableCount+1);if(u>t.stableCount&&Ce(a,t.stableCount,u,s,0)){let h=Se(a,t.stableCount,u);i=u,o=t.stableOffset+h,c=s.slice(h)}return{tokens:a,cache:{source:n,tail:c,tokens:a,stableCount:i,stableOffset:o,degraded:!1,degradedReason:null},charsLexed:s.length,reusedTokens:t.stableCount}}var Tt=0;function St(t){if(typeof t!="string"||typeof performance.mark!="function"||typeof performance.measure!="function")return null;let e=Tt++,n={name:t,startMark:`${t}:start:${e}`,endMark:`${t}:end:${e}`};try{return performance.mark(n.startMark),n}catch{return null}}function Lt(t){if(t)try{performance.mark(t.endMark),performance.measure(t.name,t.startMark,t.endMark)}catch{}finally{try{performance.clearMarks?.(t.startMark),performance.clearMarks?.(t.endMark)}catch{}}}g.use({extensions:[{name:"blockMath",level:"block",start(t){return t.match(/^ {0,3}\\$\\$/m)?.index},tokenizer(t){let e=/^ {0,3}\\$\\$([\\s\\S]+?)\\$\\$[ \\t]*(?:\\n|$)/.exec(t);if(e)return{type:"blockMath",raw:e[0],text:e[1].trim()}},renderer(t){return t.raw}},{name:"inlineMath",level:"inline",start(t){return t.match(/(?<![\\\\$])\\$(?![$\\s])/)?.index},tokenizer(t){let e=/^\\$(?![$\\s\\d])((?:\\\\\\$|[^$\\n])*?)(?<!\\s)\\$(?!\\d)/.exec(t);if(e)return{type:"inlineMath",raw:e[0],text:e[1].trim()}},renderer(t){return t.raw}}]});var E=new Map;self.onmessage=t=>{let e=t.data;if(typeof e!="object"||e===null)return;let{id:n,text:s,append:r,expectedLength:l,oldRaws:a,instance:i,baseVersion:o,dispose:c,userTimingName:u}=e;if(c===!0){typeof i=="string"&&E.delete(i);return}let h=typeof i=="string"?i:null,p=typeof o=="number"?o:null,d,f=null,m=null;if(typeof r=="string"){if(h===null||p===null){self.postMessage({id:n,needResync:!0});return}let w=E.get(h);if(!w||w.version!==p){self.postMessage({id:n,needResync:!0});return}if(typeof l=="number"&&w.lex.source.length+r.length!==l){E.delete(h),self.postMessage({id:n,needResync:!0});return}let y=w.lex;d=()=>Ie(y,r),m=y.tokens}else if(typeof s=="string"){let w=s;if(d=()=>le(w),Array.isArray(a))f=a;else if(h!==null&&p!==null){let y=E.get(h);if(y&&y.version===p)m=y.lex.tokens;else{self.postMessage({id:n,needResync:!0});return}}}else return;try{let w=typeof u=="string"?St(u):null,y=performance.now(),L;try{L=d()}finally{w&&Lt(w)}let W=performance.now()-y,A=L.tokens,b=0;if(f!==null){let T=Math.min(f.length,A.length);for(;b<T&&f[b]===A[b].raw;b++);}else if(m!==null){let T=m,ie=Math.min(T.length,A.length);for(b=Math.min(L.reusedTokens,ie);b<ie&&T[b].raw===A[b].raw;b++);}h!==null&&p!==null&&E.set(h,{version:p+1,lex:L.cache}),self.postMessage({id:n,matchLen:b,tail:A.slice(b),lexerMs:W,sourceCharsLexed:L.charsLexed})}catch(w){h!==null&&E.delete(h),self.postMessage({id:n,error:String(w)})}};})();\n';
1886
+
1887
+ // src/Markdown.ts
1888
+ var now = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
1889
+ function lexMarkdown(text, userTiming) {
1890
+ if (!userTiming) return import_marked.marked.lexer(text);
1891
+ const timing = (0, import_core4.beginVectoUserTiming)(import_core4.VECTO_USER_TIMING.markdown.parse);
1892
+ try {
1893
+ return import_marked.marked.lexer(text);
1894
+ } finally {
1895
+ if (timing) (0, import_core4.endVectoUserTiming)(timing);
1896
+ }
1688
1897
  }
1689
- function collectSpans(tokens, inherited, theme, out, blockFontSize) {
1690
- for (const token of tokens) {
1691
- switch (token.type) {
1692
- case "strong": {
1693
- const t = token;
1694
- if (t.tokens) {
1695
- collectSpans(t.tokens, { ...inherited, bold: true }, theme, out, blockFontSize);
1696
- } else {
1697
- out.push({
1698
- text: decodeEntities(t.text),
1699
- style: { ...inherited, bold: true }
1700
- });
1701
- }
1702
- break;
1703
- }
1704
- case "em": {
1705
- const t = token;
1706
- if (t.tokens) {
1707
- collectSpans(t.tokens, { ...inherited, italic: true }, theme, out, blockFontSize);
1708
- } else {
1709
- out.push({
1710
- text: decodeEntities(t.text),
1711
- style: { ...inherited, italic: true }
1712
- });
1898
+ import_marked.marked.use({
1899
+ extensions: [
1900
+ {
1901
+ name: "blockMath",
1902
+ level: "block",
1903
+ start(src) {
1904
+ return src.match(/^ {0,3}\$\$/m)?.index;
1905
+ },
1906
+ tokenizer(src) {
1907
+ const match = /^ {0,3}\$\$([\s\S]+?)\$\$[ \t]*(?:\n|$)/.exec(src);
1908
+ if (match) {
1909
+ return {
1910
+ type: "blockMath",
1911
+ raw: match[0],
1912
+ text: match[1].trim()
1913
+ };
1713
1914
  }
1714
- break;
1915
+ return void 0;
1916
+ },
1917
+ renderer(token) {
1918
+ return token.raw;
1715
1919
  }
1716
- case "del": {
1717
- const t = token;
1718
- if (t.tokens) {
1719
- collectSpans(t.tokens, { ...inherited, lineThrough: true }, theme, out, blockFontSize);
1720
- } else {
1721
- out.push({
1722
- text: decodeEntities(t.text),
1723
- style: { ...inherited, lineThrough: true }
1724
- });
1920
+ },
1921
+ {
1922
+ name: "inlineMath",
1923
+ level: "inline",
1924
+ start(src) {
1925
+ return src.match(/(?<![\\$])\$(?![$\s])/)?.index;
1926
+ },
1927
+ tokenizer(src) {
1928
+ const match = /^\$(?![$\s\d])((?:\\\$|[^$\n])*?)(?<!\s)\$(?!\d)/.exec(src);
1929
+ if (match) {
1930
+ return {
1931
+ type: "inlineMath",
1932
+ raw: match[0],
1933
+ text: match[1].trim()
1934
+ };
1725
1935
  }
1726
- break;
1727
- }
1728
- case "codespan": {
1729
- const t = token;
1730
- out.push({
1731
- text: decodeEntities(t.text),
1732
- // Inline code renders in the theme's monospace family (not just tinted
1733
- // prose) — TextStyle.fontFamily drives both measurement and drawing.
1734
- style: {
1735
- ...inherited,
1736
- color: theme.codeColor,
1737
- fontFamily: theme.codeFont
1738
- }
1739
- });
1740
- break;
1741
- }
1742
- case "br": {
1743
- out.push({ text: "\n" });
1744
- break;
1745
- }
1746
- case "html": {
1747
- const t = token;
1748
- const raw = t.raw ?? t.text ?? "";
1749
- const brCount = (raw.match(/<br\s*\/?>/gi) ?? []).length;
1750
- for (let i = 0; i < brCount; i++) out.push({ text: "\n" });
1751
- break;
1936
+ return void 0;
1937
+ },
1938
+ renderer(token) {
1939
+ return token.raw;
1752
1940
  }
1753
- case "inlineMath": {
1754
- const t = token;
1755
- const runSize = inherited.fontSize ?? blockFontSize ?? theme.fontSize;
1756
- const runColor = inherited.color ?? theme.textColor;
1757
- const rendered = renderMathToSVGDataURI(t.text, false, runColor);
1758
- if (rendered) {
1759
- const uri = rendered.uri;
1760
- out.push({
1761
- text: import_core.OBJECT_REPLACEMENT,
1762
- style: inherited,
1763
- object: {
1764
- width: exToPx(rendered.widthEx, runSize),
1765
- height: exToPx(rendered.heightEx, runSize),
1766
- depth: exToPx(rendered.depthEx, runSize),
1767
- // The TeX source is the accessible name: without it a screen reader
1768
- // receives only the invisible U+FFFC sentinel.
1769
- alt: t.text,
1770
- // Without this the box is reserved and stays empty. The engine does
1771
- // not draw objects, and nothing else in the tree holds the raster.
1772
- paint: (surface, box) => paintInlineMath(uri, surface, box)
1773
- }
1774
- });
1775
- } else {
1776
- out.push({
1777
- text: decodeEntities(t.raw),
1778
- style: { ...inherited, color: "#fcd34d" }
1941
+ }
1942
+ ]
1943
+ });
1944
+ var markdownWorker = null;
1945
+ var workerIdCounter = 0;
1946
+ var workerInstanceCounter = 0;
1947
+ var workerCallbacks = /* @__PURE__ */ new Map();
1948
+ function runSyncFallback(entry) {
1949
+ try {
1950
+ entry.cb(0, lexMarkdown(entry.text, entry.userTiming), true);
1951
+ } catch (err) {
1952
+ console.warn("Markdown sync fallback parse failed", err);
1953
+ entry.onDropped?.();
1954
+ }
1955
+ }
1956
+ if (typeof Worker !== "undefined") {
1957
+ try {
1958
+ const blob = new Blob([WORKER_SOURCE_STRING], {
1959
+ type: "application/javascript"
1960
+ });
1961
+ markdownWorker = new Worker(URL.createObjectURL(blob));
1962
+ markdownWorker.onmessage = (e) => {
1963
+ const { id, matchLen, tail, error, needResync, lexerMs, sourceCharsLexed } = e.data;
1964
+ const entry = workerCallbacks.get(id);
1965
+ if (entry) {
1966
+ workerCallbacks.delete(id);
1967
+ if (needResync && entry.onNeedResync) {
1968
+ entry.onNeedResync();
1969
+ } else if (needResync) {
1970
+ runSyncFallback(entry);
1971
+ } else if (!error) {
1972
+ entry.cb(matchLen, tail, false, {
1973
+ lexerMs: typeof lexerMs === "number" ? lexerMs : 0,
1974
+ sourceCharsLexed: typeof sourceCharsLexed === "number" ? sourceCharsLexed : 0
1779
1975
  });
1780
- }
1781
- break;
1782
- }
1783
- case "link": {
1784
- const t = token;
1785
- const linkStyle = {
1786
- ...inherited,
1787
- href: t.href,
1788
- color: "#38bdf8"
1789
- };
1790
- if (t.tokens && t.tokens.length > 0) {
1791
- collectSpans(t.tokens, linkStyle, theme, out, blockFontSize);
1792
- } else {
1793
- out.push({ text: decodeEntities(t.text), style: linkStyle });
1794
- }
1795
- break;
1796
- }
1797
- case "text": {
1798
- const t = token;
1799
- if ("tokens" in t && t.tokens?.length) {
1800
- collectSpans(t.tokens, inherited, theme, out, blockFontSize);
1801
1976
  } else {
1802
- const decoded = decodeEntities(t.text);
1803
- if (decoded) {
1804
- const style = Object.keys(inherited).length > 0 ? inherited : void 0;
1805
- out.push({ text: decoded, style });
1806
- }
1807
- }
1808
- break;
1809
- }
1810
- default: {
1811
- if ("text" in token) {
1812
- const decoded = decodeEntities(token.text);
1813
- if (decoded) {
1814
- const style = Object.keys(inherited).length > 0 ? inherited : void 0;
1815
- out.push({ text: decoded, style });
1816
- }
1977
+ runSyncFallback(entry);
1817
1978
  }
1818
- break;
1819
1979
  }
1820
- }
1821
- }
1822
- }
1823
- function findUnclosedInline(text) {
1824
- let best = null;
1825
- const tick = text.lastIndexOf("`");
1826
- if (tick !== -1 && tick < text.length - 1) {
1827
- return { kind: "codespan", at: tick, contentAt: tick + 1 };
1828
- }
1829
- if (tick !== -1) return null;
1830
- const emphasis = /(\*{1,2}(?!\*)|_{1,2}(?!_))(?=[^\s])/g;
1831
- for (let match = emphasis.exec(text); match !== null; match = emphasis.exec(text)) {
1832
- const marker = match[1];
1833
- const at = match.index;
1834
- if (marker[0] === "_" && at > 0 && /[\w]/.test(text[at - 1])) continue;
1835
- best = {
1836
- kind: marker.length === 2 ? "strong" : "em",
1837
- at,
1838
- contentAt: at + marker.length
1839
1980
  };
1981
+ markdownWorker.onerror = () => {
1982
+ const pending = [...workerCallbacks.values()];
1983
+ workerCallbacks.clear();
1984
+ markdownWorker = null;
1985
+ for (const entry of pending) runSyncFallback(entry);
1986
+ };
1987
+ } catch (err) {
1988
+ console.warn("Failed to initialize MarkdownWorker", err);
1840
1989
  }
1841
- const bracket = text.lastIndexOf("[");
1842
- if (bracket !== -1 && bracket < text.length - 1 && (best === null || bracket > best.at)) {
1843
- const closed = /\]\([^)]*\)/.test(text.slice(bracket));
1844
- if (!closed) {
1845
- best = { kind: "link", at: bracket, contentAt: bracket + 1 };
1846
- }
1847
- }
1848
- return best;
1849
- }
1850
- function renderInlineToRichText(tokens, fallbackText, font, color, maxWidth, theme, selectable, onLinkClick) {
1851
- const spans = [];
1852
- if (tokens && tokens.length > 0) {
1853
- collectSpans(tokens, {}, theme, spans, fontSizeFromFont(font));
1854
- }
1855
- if (spans.length === 0) {
1856
- spans.push({ text: decodeEntities(fallbackText) });
1857
- }
1858
- return new import_ui2.RichText(spans, {
1859
- font,
1860
- color,
1861
- maxWidth,
1862
- linkColor: "#38bdf8",
1863
- selectable,
1864
- onLinkClick
1865
- });
1866
1990
  }
1867
- var Markdown = class _Markdown extends import_ui2.UIComponent {
1991
+ var Markdown = class _Markdown extends import_ui4.UIComponent {
1868
1992
  content;
1869
1993
  maxWidth;
1870
1994
  theme;
@@ -1957,6 +2081,20 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
1957
2081
  * field only so {@link destroy} can remove the exact closure it added.
1958
2082
  */
1959
2083
  inlineMathRepaint;
2084
+ /**
2085
+ * This instance's entry in the inline-image decode waiters, or `undefined` if it
2086
+ * has never rendered an image. Held as a field only so {@link destroy} can remove
2087
+ * the exact closure it added.
2088
+ */
2089
+ inlineImageRemeasure;
2090
+ /**
2091
+ * URLs whose decoded aspect ratio this document has already reserved a box for.
2092
+ *
2093
+ * The guard that makes the re-measure fire once per image rather than once per
2094
+ * decode-notification-per-image: the waiter set is module-level, so a page of
2095
+ * many documents tells all of them about all decodes.
2096
+ */
2097
+ inlineImagesMeasured = /* @__PURE__ */ new Set();
1960
2098
  /**
1961
2099
  * True while this document is waiting on the lazy MathJax load.
1962
2100
  *
@@ -2102,14 +2240,17 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
2102
2240
  constructor(markdownText, opts = {}) {
2103
2241
  super();
2104
2242
  this.maxWidth = opts.maxWidth ?? 800;
2105
- this.theme = { ...DEFAULT_THEME, ...opts.theme };
2243
+ this.theme = resolveTheme(opts.theme);
2106
2244
  this.onLinkClick = opts.onLinkClick;
2107
2245
  this.selectable = opts.selectable ?? true;
2108
2246
  this._userTiming = opts.userTiming ?? false;
2109
2247
  this.blockAffordances = opts.blockAffordances ?? false;
2110
2248
  this.writeClipboard = opts.writeClipboard ?? defaultWriteClipboard;
2111
2249
  this.saveFile = opts.saveFile ?? defaultSaveFile;
2112
- this.content = new import_ui2.Stack({ direction: "vertical", gap: 16 });
2250
+ this.content = new import_ui4.Stack({
2251
+ direction: "vertical",
2252
+ gap: this.theme.blockGap
2253
+ });
2113
2254
  this.add(this.content);
2114
2255
  this.rawMarkdown = "";
2115
2256
  this.setTokens([]);
@@ -2328,15 +2469,15 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
2328
2469
  switch (token.type) {
2329
2470
  case "heading":
2330
2471
  case "paragraph": {
2331
- if (entity instanceof import_ui2.RichText) {
2472
+ if (entity instanceof import_ui4.RichText) {
2332
2473
  entity.setMaxWidth(availableWidth);
2333
2474
  return;
2334
2475
  }
2335
- if (entity instanceof import_ui2.Stack) {
2476
+ if (entity instanceof import_ui4.Stack) {
2336
2477
  entity.maxWidth = availableWidth;
2337
2478
  for (const run of entity.children) {
2338
- if (run instanceof import_ui2.RichText) run.setMaxWidth(availableWidth);
2339
- else if (run instanceof import_ui2.Image) this.refitParagraphImage(run, availableWidth);
2479
+ if (run instanceof import_ui4.RichText) run.setMaxWidth(availableWidth);
2480
+ else if (run instanceof import_ui4.Image) this.refitParagraphImage(run, availableWidth);
2340
2481
  }
2341
2482
  entity.layout();
2342
2483
  }
@@ -2349,11 +2490,11 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
2349
2490
  }
2350
2491
  case "blockquote": {
2351
2492
  const bqToken = token;
2352
- const innerStack = entity.children.find((c) => c instanceof import_ui2.Stack);
2493
+ const innerStack = entity.children.find((c) => c instanceof import_ui4.Stack);
2353
2494
  const border = entity.children.find((c) => c instanceof QuoteBorder);
2354
- const indentStart = Math.min(16, availableWidth);
2495
+ const indentStart = Math.min(this.theme.quoteIndent, availableWidth);
2355
2496
  const childWidth = Math.max(0, availableWidth - indentStart);
2356
- if (innerStack instanceof import_ui2.Stack && bqToken.tokens) {
2497
+ if (innerStack instanceof import_ui4.Stack && bqToken.tokens) {
2357
2498
  let index = 0;
2358
2499
  for (const inner of bqToken.tokens) {
2359
2500
  if (!this.producesEntity(inner)) continue;
@@ -2376,15 +2517,15 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
2376
2517
  return;
2377
2518
  }
2378
2519
  case "list": {
2379
- if (!(entity instanceof import_ui2.Stack)) return;
2520
+ if (!(entity instanceof import_ui4.Stack)) return;
2380
2521
  for (const item of entity.children) {
2381
- if (item instanceof import_ui2.RichText) item.setMaxWidth(availableWidth);
2522
+ if (item instanceof import_ui4.RichText) item.setMaxWidth(availableWidth);
2382
2523
  }
2383
2524
  entity.layout();
2384
2525
  return;
2385
2526
  }
2386
2527
  case "table": {
2387
- if (entity instanceof import_ui2.Table) entity.setWidth(availableWidth);
2528
+ if (entity instanceof import_ui4.Table) entity.setWidth(availableWidth);
2388
2529
  return;
2389
2530
  }
2390
2531
  case "hr": {
@@ -2392,7 +2533,7 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
2392
2533
  return;
2393
2534
  }
2394
2535
  default: {
2395
- if (entity instanceof import_ui2.Text) entity.setMaxWidth(availableWidth);
2536
+ if (entity instanceof import_ui4.Text) entity.setMaxWidth(availableWidth);
2396
2537
  return;
2397
2538
  }
2398
2539
  }
@@ -2454,7 +2595,98 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
2454
2595
  this.scene?.markDirty();
2455
2596
  };
2456
2597
  this.inlineMathRepaint = repaint;
2457
- inlineMathRasterWaiters.add(repaint);
2598
+ subscribeInlineMathRaster(repaint);
2599
+ }
2600
+ /**
2601
+ * Re-measure this document when an inline image's raster finishes decoding.
2602
+ *
2603
+ * Inline images differ from inline formulas in one way that matters: a formula's
2604
+ * box is known synchronously the moment it typesets, while an image's aspect
2605
+ * ratio arrives only with the decode. The span reserved a square until then, so a
2606
+ * decode that reports anything else has invalidated a WIDTH, and a repaint into
2607
+ * the old box would letterbox or stretch the picture.
2608
+ *
2609
+ * So this rebuilds through {@link retypesetFromTokens} — the same late-arrival
2610
+ * path MathJax uses — but only when a reserved width actually changed. Every live
2611
+ * document is notified for every decode, including images it does not contain, so
2612
+ * an unconditional rebuild here would be O(documents x images) full re-renders
2613
+ * for a page of many blocks.
2614
+ *
2615
+ * Subscribed lazily and held as a field for the same two reasons as its math
2616
+ * counterpart: a document with no images costs nothing, and `destroy` must remove
2617
+ * the exact closure it added.
2618
+ */
2619
+ subscribeInlineImageRemeasure() {
2620
+ if (this.inlineImageRemeasure || this.isDestroyed) return;
2621
+ const remeasure = () => {
2622
+ if (this.isDestroyed) return;
2623
+ if (this.inlineImageBoxesStale()) this.retypesetFromTokens();
2624
+ else this.scene?.markDirty();
2625
+ };
2626
+ this.inlineImageRemeasure = remeasure;
2627
+ subscribeInlineImageRaster(remeasure);
2628
+ }
2629
+ /**
2630
+ * Whether any inline image in this document has just learned it is not square.
2631
+ *
2632
+ * An inline image's span reserves a square box before its raster decodes, because
2633
+ * that is the only shape available without a natural size. The decode supplies the
2634
+ * real aspect ratio, so a non-square image needs one rebuild to reserve the right
2635
+ * width — and exactly one. Every live document is notified of every decode on the
2636
+ * page, including images it does not contain, so this has to answer "did MY
2637
+ * geometry just change" and not merely "did something decode".
2638
+ *
2639
+ * Walks the tokens rather than the entity tree: the reserved box is a function of
2640
+ * the raster's aspect ratio, which is available here, and a token walk cannot be
2641
+ * confused by an entity a previous rebuild already corrected.
2642
+ *
2643
+ * Only headings and table cells are inspected. Every other context splits an image
2644
+ * into its own block whose `Image` entity resizes itself in `onLoad`, so a rebuild
2645
+ * for one of those would be pure cost.
2646
+ */
2647
+ inlineImageBoxesStale() {
2648
+ const stale = (tokens) => {
2649
+ let changed2 = false;
2650
+ for (const token of tokens ?? []) {
2651
+ if (token.type === "image") {
2652
+ const href = token.href;
2653
+ if (this.inlineImagesMeasured.has(href)) continue;
2654
+ const raster = ensureInlineImageRaster(href);
2655
+ if (raster.failed) {
2656
+ this.inlineImagesMeasured.add(href);
2657
+ changed2 = true;
2658
+ continue;
2659
+ }
2660
+ if (!raster.decoded || !raster.naturalWidth || !raster.naturalHeight) {
2661
+ continue;
2662
+ }
2663
+ this.inlineImagesMeasured.add(href);
2664
+ if (raster.naturalWidth !== raster.naturalHeight) changed2 = true;
2665
+ continue;
2666
+ }
2667
+ if (stale(token.tokens)) {
2668
+ changed2 = true;
2669
+ }
2670
+ }
2671
+ return changed2;
2672
+ };
2673
+ let changed = false;
2674
+ for (const token of this.tokens) {
2675
+ if (token.type === "heading") {
2676
+ if (stale(token.tokens)) changed = true;
2677
+ } else if (token.type === "table") {
2678
+ const table = token;
2679
+ for (const cell of table.header) {
2680
+ if (stale(cell.tokens)) changed = true;
2681
+ }
2682
+ for (const row of table.rows) {
2683
+ for (const cell of row) {
2684
+ if (stale(cell.tokens)) changed = true;
2685
+ }
2686
+ }
2687
+ }
2688
+ }
2689
+ return changed;
2458
2690
  }
2459
2691
  destroy() {
2460
2692
  this.isDestroyed = true;
@@ -2467,9 +2699,13 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
2467
2699
  this.mathLoadPending = false;
2468
2700
  this.flushAppendSettledWaiters();
2469
2701
  if (this.inlineMathRepaint) {
2470
- inlineMathRasterWaiters.delete(this.inlineMathRepaint);
2702
+ unsubscribeInlineMathRaster(this.inlineMathRepaint);
2471
2703
  this.inlineMathRepaint = void 0;
2472
2704
  }
2705
+ if (this.inlineImageRemeasure) {
2706
+ unsubscribeInlineImageRaster(this.inlineImageRemeasure);
2707
+ this.inlineImageRemeasure = void 0;
2708
+ }
2473
2709
  markdownWorker?.postMessage({
2474
2710
  instance: this.workerInstanceId,
2475
2711
  dispose: true
@@ -2771,7 +3007,7 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
2771
3007
  id,
2772
3008
  instance: this.workerInstanceId,
2773
3009
  baseVersion,
2774
- userTimingName: this._userTiming ? import_core.VECTO_USER_TIMING.markdown.parse : void 0,
3010
+ userTimingName: this._userTiming ? import_core4.VECTO_USER_TIMING.markdown.parse : void 0,
2775
3011
  ...canSendDelta ? {
2776
3012
  append: this.rawMarkdown.slice(this.workerSourceLen),
2777
3013
  // What the worker's source must total once it applies this append. It
@@ -2863,11 +3099,11 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
2863
3099
  }
2864
3100
  /** One text run of an image-bearing paragraph, as both paths build it. */
2865
3101
  inlineRunRichText(tokens, availableWidth, t) {
2866
- return new import_ui2.RichText(this.inlineRunSpans(tokens, t), {
3102
+ return new import_ui4.RichText(this.inlineRunSpans(tokens, t), {
2867
3103
  font: `${t.fontSize}px ${t.bodyFont}`,
2868
3104
  color: t.textColor,
2869
3105
  maxWidth: availableWidth,
2870
- linkColor: "#38bdf8",
3106
+ linkColor: t.linkColor,
2871
3107
  selectable: this.selectable,
2872
3108
  onLinkClick: this.onLinkClick
2873
3109
  });
@@ -2967,11 +3203,11 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
2967
3203
  paragraphImage(imgToken, availableWidth) {
2968
3204
  const initialWidth = Math.min(800, availableWidth);
2969
3205
  const initialHeight = Math.round(initialWidth * 0.6);
2970
- const img = new import_ui2.Image(imgToken.href, {
3206
+ const img = new import_ui4.Image(imgToken.href, {
2971
3207
  width: initialWidth,
2972
3208
  height: initialHeight,
2973
3209
  alt: imgToken.text,
2974
- radius: 8,
3210
+ radius: this.theme.imageRadius,
2975
3211
  onLoad: () => {
2976
3212
  const bmp = img.bitmap;
2977
3213
  if (bmp && bmp.naturalWidth && bmp.naturalHeight) {
@@ -2986,11 +3222,11 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
2986
3222
  }
2987
3223
  /** One table cell entity, shared by the render arm and the streamed-table path. */
2988
3224
  tableCellRichText(cell, header, t) {
2989
- return new import_ui2.RichText(this.tableCellSpans(cell, t), {
2990
- font: `${t.fontSize - 2}px ${t.bodyFont}`,
3225
+ return new import_ui4.RichText(this.tableCellSpans(cell, t), {
3226
+ font: `${t.tableFontSize}px ${t.bodyFont}`,
2991
3227
  color: header ? t.headingColor : t.textColor,
2992
3228
  baseStyle: header ? { bold: true } : void 0,
2993
- linkColor: "#38bdf8",
3229
+ linkColor: t.linkColor,
2994
3230
  selectable: this.selectable,
2995
3231
  onLinkClick: this.onLinkClick
2996
3232
  });
@@ -3072,7 +3308,7 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
3072
3308
  listItemBlockStack(token, index, availableWidth, t) {
3073
3309
  const item = token.items[index];
3074
3310
  const children = item.tokens ?? [];
3075
- const stack = new import_ui2.Stack({ direction: "vertical", gap: 4 });
3311
+ const stack = new import_ui4.Stack({ direction: "vertical", gap: t.listItemGap });
3076
3312
  const first = children[0];
3077
3313
  const firstIsInline = Boolean(first) && (first.type === "text" || first.type === "paragraph");
3078
3314
  const leadHasImage = firstIsInline && containsImage(first.tokens);
@@ -3139,16 +3375,16 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
3139
3375
  const box = item.task ? item.checked ? "\u2611 " : "\u2610 " : "";
3140
3376
  const leadingMarker = token.ordered ? `${num}. ${box}` : box || "\u2022 ";
3141
3377
  const trailingMarker = token.ordered ? ` ${box}.${num}` : box ? ` ${box.trimEnd()}` : " \u2022";
3142
- const itemIsRtl = import_core.BidiResolver.getBaseLevel(contentSpans.map((s) => s.text).join("")) % 2 === 1;
3378
+ const itemIsRtl = import_core4.BidiResolver.getBaseLevel(contentSpans.map((s) => s.text).join("")) % 2 === 1;
3143
3379
  return itemIsRtl ? [...contentSpans, { text: trailingMarker }] : [{ text: leadingMarker }, ...contentSpans];
3144
3380
  }
3145
3381
  /** Construct the `RichText` for one list item. */
3146
3382
  listItemRichText(token, index, availableWidth, t) {
3147
- return new import_ui2.RichText(this.listItemSpans(token, index), {
3383
+ return new import_ui4.RichText(this.listItemSpans(token, index), {
3148
3384
  font: `${t.fontSize}px ${t.bodyFont}`,
3149
3385
  color: t.textColor,
3150
3386
  maxWidth: availableWidth,
3151
- linkColor: "#38bdf8",
3387
+ linkColor: t.linkColor,
3152
3388
  selectable: this.selectable,
3153
3389
  onLinkClick: this.onLinkClick
3154
3390
  });
@@ -3179,7 +3415,7 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
3179
3415
  * and keep stale spans. Bail when `loose` flips.
3180
3416
  */
3181
3417
  updateStreamedList(stack, oldToken, newToken) {
3182
- if (!(stack instanceof import_ui2.Stack)) return false;
3418
+ if (!(stack instanceof import_ui4.Stack)) return false;
3183
3419
  if (newToken.items.length < oldToken.items.length || oldToken.items.length === 0) return false;
3184
3420
  if (oldToken.ordered !== newToken.ordered) return false;
3185
3421
  if ((oldToken.start ?? 1) !== (newToken.start ?? 1)) return false;
@@ -3188,7 +3424,7 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
3188
3424
  const lastRetained = oldToken.items.length - 1;
3189
3425
  for (let i = 0; i < lastRetained; i++) {
3190
3426
  if (oldToken.items[i].text !== newToken.items[i].text) return false;
3191
- const isStack = stack.children[i] instanceof import_ui2.Stack;
3427
+ const isStack = stack.children[i] instanceof import_ui4.Stack;
3192
3428
  if (isStack !== !this.itemIsInlineOnly(newToken.items[i])) return false;
3193
3429
  }
3194
3430
  const availableWidth = this.activeBlockMetrics?.availableWidth ?? this.maxWidth;
@@ -3247,7 +3483,7 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
3247
3483
  * *token runs* split at the last image, never token index against child index.
3248
3484
  */
3249
3485
  updateImageParagraph(entity, oldToken, newToken) {
3250
- if (!(entity instanceof import_ui2.Stack)) return false;
3486
+ if (!(entity instanceof import_ui4.Stack)) return false;
3251
3487
  const oldTokens = oldToken.tokens;
3252
3488
  const newTokens = newToken.tokens;
3253
3489
  if (!oldTokens || !newTokens) return false;
@@ -3272,7 +3508,7 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
3272
3508
  entity.add(this.inlineRunRichText(newTail, availableWidth, t));
3273
3509
  } else {
3274
3510
  const tailEntity = entity.children[entity.children.length - 1];
3275
- if (!(tailEntity instanceof import_ui2.RichText)) return false;
3511
+ if (!(tailEntity instanceof import_ui4.RichText)) return false;
3276
3512
  tailEntity.setSpans(this.inlineRunSpans(newTail, t));
3277
3513
  }
3278
3514
  const last = entity.children[entity.children.length - 1];
@@ -3304,7 +3540,7 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
3304
3540
  * (its keys are `text`/`tokens`/`header`/`align`).
3305
3541
  */
3306
3542
  updateStreamedTable(entity, oldToken, newToken) {
3307
- if (!(entity instanceof import_ui2.Table)) return false;
3543
+ if (!(entity instanceof import_ui4.Table)) return false;
3308
3544
  if (oldToken.header.length !== newToken.header.length) return false;
3309
3545
  for (let c = 0; c < oldToken.header.length; c++) {
3310
3546
  if (oldToken.header[c].text !== newToken.header[c].text) return false;
@@ -3325,7 +3561,7 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
3325
3561
  if (lastRetained >= 0) {
3326
3562
  for (let c = 0; c < oldToken.header.length; c++) {
3327
3563
  const cell = entity.rows[lastRetained]?.[c];
3328
- if (!(cell instanceof import_ui2.RichText)) return false;
3564
+ if (!(cell instanceof import_ui4.RichText)) return false;
3329
3565
  }
3330
3566
  }
3331
3567
  const t = this.theme;
@@ -3358,7 +3594,7 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
3358
3594
  const newTail = newInner[tail];
3359
3595
  if (oldTail.type !== newTail.type) return false;
3360
3596
  const innerStack = container.children[1];
3361
- if (!(innerStack instanceof import_ui2.Stack)) return false;
3597
+ if (!(innerStack instanceof import_ui4.Stack)) return false;
3362
3598
  const wrapper = innerStack.children.at(-1);
3363
3599
  if (!wrapper || wrapper.children.length !== 1) return false;
3364
3600
  const entity = wrapper.children[0];
@@ -3498,12 +3734,12 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
3498
3734
  * queued while the first is outstanding.
3499
3735
  */
3500
3736
  ensureMathJax() {
3501
- if (mathConverter || this.mathLoadPending || this.isDestroyed) return;
3737
+ if (isMathJaxReady() || this.mathLoadPending || this.isDestroyed) return;
3502
3738
  this.mathLoadPending = true;
3503
3739
  void preloadMathJax().then(() => {
3504
3740
  this.mathLoadPending = false;
3505
3741
  if (this.isDestroyed) return;
3506
- if (mathConverter) this.retypesetFromTokens();
3742
+ if (isMathJaxReady()) this.retypesetFromTokens();
3507
3743
  this.flushAppendSettledWaiters();
3508
3744
  });
3509
3745
  }
@@ -3823,10 +4059,10 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
3823
4059
  const width = intrinsicW * scale;
3824
4060
  const height = intrinsicH * scale;
3825
4061
  const uri = mathData.uri;
3826
- const math = new import_ui2.RichText(
4062
+ const math = new import_ui4.RichText(
3827
4063
  [
3828
4064
  {
3829
- text: import_core.OBJECT_REPLACEMENT,
4065
+ text: import_core4.OBJECT_REPLACEMENT,
3830
4066
  object: {
3831
4067
  width,
3832
4068
  height,
@@ -3866,15 +4102,15 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
3866
4102
  };
3867
4103
  const availableWidth = metrics.availableWidth;
3868
4104
  if (containsInlineMath(token)) {
3869
- if (!mathConverter) this.ensureMathJax();
4105
+ if (!isMathJaxReady()) this.ensureMathJax();
3870
4106
  this.subscribeInlineMathRepaint();
3871
4107
  }
4108
+ if (containsImage([token])) this.subscribeInlineImageRemeasure();
3872
4109
  switch (token.type) {
3873
4110
  // ── Headings ─────────────────────────────────────────────────────
3874
4111
  case "heading": {
3875
4112
  const hToken = token;
3876
- const sizes = [32, 28, 24, 20, 18, 16];
3877
- const size = sizes[Math.min(hToken.depth - 1, 5)];
4113
+ const size = headingSize(t, hToken.depth);
3878
4114
  const headingFont = `bold ${size}px ${t.bodyFont}`;
3879
4115
  return renderInlineToRichText(
3880
4116
  hToken.tokens,
@@ -3902,9 +4138,9 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
3902
4138
  this.onLinkClick
3903
4139
  );
3904
4140
  }
3905
- const stack = new import_ui2.Stack({
4141
+ const stack = new import_ui4.Stack({
3906
4142
  direction: "vertical",
3907
- gap: 16,
4143
+ gap: this.theme.blockGap,
3908
4144
  maxWidth: availableWidth
3909
4145
  });
3910
4146
  let currentTokens = [];
@@ -3950,28 +4186,43 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
3950
4186
  // ── Blockquotes ──────────────────────────────────────────────────
3951
4187
  case "blockquote": {
3952
4188
  const bqToken = token;
3953
- const innerStack = new import_ui2.Stack({ direction: "vertical", gap: 8 });
3954
- const indentStart = Math.min(16, availableWidth);
4189
+ const innerStack = new import_ui4.Stack({
4190
+ direction: "vertical",
4191
+ gap: this.theme.quoteInnerGap
4192
+ });
4193
+ const indentStart = Math.min(this.theme.quoteIndent, availableWidth);
3955
4194
  const childMetrics = {
3956
4195
  marginBefore: 0,
3957
4196
  marginAfter: 0,
3958
4197
  indentStart,
3959
4198
  availableWidth: Math.max(0, availableWidth - indentStart)
3960
4199
  };
3961
- if (bqToken.tokens) {
3962
- for (const inner of bqToken.tokens) {
3963
- const el = this.renderTokenWithMetrics(inner, childMetrics);
3964
- if (el) {
3965
- const wrapper = new MarkdownContainer();
3966
- el.x = childMetrics.indentStart;
3967
- wrapper.add(el);
3968
- wrapper.width = el.width + childMetrics.indentStart;
3969
- wrapper.height = el.height;
3970
- innerStack.add(wrapper);
4200
+ const outerTheme = this.theme;
4201
+ if (t.quoteTextColor !== t.textColor) {
4202
+ this.theme = { ...outerTheme, textColor: t.quoteTextColor };
4203
+ }
4204
+ try {
4205
+ if (bqToken.tokens) {
4206
+ for (const inner of bqToken.tokens) {
4207
+ const el = this.renderTokenWithMetrics(inner, childMetrics);
4208
+ if (el) {
4209
+ const wrapper = new MarkdownContainer();
4210
+ el.x = childMetrics.indentStart;
4211
+ wrapper.add(el);
4212
+ wrapper.width = el.width + childMetrics.indentStart;
4213
+ wrapper.height = el.height;
4214
+ innerStack.add(wrapper);
4215
+ }
3971
4216
  }
3972
4217
  }
4218
+ } finally {
4219
+ this.theme = outerTheme;
3973
4220
  }
3974
- const border = new QuoteBorder(innerStack.height || 20, t.quoteBorderColor);
4221
+ const border = new QuoteBorder(
4222
+ innerStack.height || 20,
4223
+ t.quoteBorderColor,
4224
+ t.quoteBorderWidth
4225
+ );
3975
4226
  const container = new MarkdownContainer();
3976
4227
  border.x = 0;
3977
4228
  border.y = 0;
@@ -3986,7 +4237,10 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
3986
4237
  // ── Lists ────────────────────────────────────────────────
3987
4238
  case "list": {
3988
4239
  const listToken = token;
3989
- const listStack = new import_ui2.Stack({ direction: "vertical", gap: 6 });
4240
+ const listStack = new import_ui4.Stack({
4241
+ direction: "vertical",
4242
+ gap: this.theme.listGap
4243
+ });
3990
4244
  for (let i = 0; i < listToken.items.length; i++) {
3991
4245
  listStack.add(
3992
4246
  this.itemIsInlineOnly(listToken.items[i]) ? this.listItemRichText(listToken, i, availableWidth, t) : this.listItemBlockStack(listToken, i, availableWidth, t)
@@ -4002,7 +4256,7 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
4002
4256
  (row) => row.map((cell) => this.tableCellRichText(cell, false, t))
4003
4257
  );
4004
4258
  return this.withBlockAffordances(
4005
- new import_ui2.Table({
4259
+ new import_ui4.Table({
4006
4260
  headers,
4007
4261
  rows,
4008
4262
  // `| :--- | :---: | ---: |` already resolves to this on the token; it
@@ -4011,7 +4265,7 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
4011
4265
  width: availableWidth,
4012
4266
  textColor: t.textColor,
4013
4267
  headerTextColor: t.headingColor,
4014
- font: `${t.fontSize - 2}px ${t.bodyFont}`,
4268
+ font: `${t.tableFontSize}px ${t.bodyFont}`,
4015
4269
  borderColor: t.hrColor,
4016
4270
  bg: t.tableBgColor,
4017
4271
  headerBg: t.tableHeaderBgColor,
@@ -4030,18 +4284,18 @@ var Markdown = class _Markdown extends import_ui2.UIComponent {
4030
4284
  case "html": {
4031
4285
  const htmlToken = token;
4032
4286
  if (htmlToken.text.toLowerCase().includes("<svg") && htmlToken.text.toLowerCase().includes("</svg>")) {
4033
- return new import_core.SVGEntity(htmlToken.text);
4287
+ return new import_core4.SVGEntity(htmlToken.text);
4034
4288
  }
4035
4289
  return null;
4036
4290
  }
4037
4291
  // ── Fallback ─────────────────────────────────────────────────────
4038
4292
  default:
4039
4293
  if ("text" in token) {
4040
- return new import_ui2.Text(token.text, {
4294
+ return new import_ui4.Text(token.text, {
4041
4295
  font: bodyFont,
4042
4296
  color: t.textColor,
4043
4297
  maxWidth: availableWidth,
4044
- lineHeight: 24,
4298
+ lineHeight: t.bodyLineHeight,
4045
4299
  selectable: this.selectable
4046
4300
  });
4047
4301
  }