@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.mjs CHANGED
@@ -1,11 +1,7 @@
1
1
  // src/Markdown.ts
2
2
  import {
3
- contentLineInHint,
4
3
  BidiResolver,
5
- Entity,
6
- GlyphRasterAtlas,
7
- OBJECT_REPLACEMENT,
8
- prepareContentGrid,
4
+ OBJECT_REPLACEMENT as OBJECT_REPLACEMENT2,
9
5
  SVGEntity,
10
6
  beginVectoUserTiming,
11
7
  endVectoUserTiming,
@@ -422,754 +418,113 @@ function createStreamController(host, options = {}) {
422
418
  return new StreamControllerImpl(host, options);
423
419
  }
424
420
 
425
- // src/Markdown.ts
426
- import {
427
- measureText as measureText2,
428
- RichText,
429
- Stack,
430
- Table,
431
- Text,
432
- Image,
433
- UIComponent as UIComponent2
434
- } from "@vectojs/ui";
435
-
436
- // src/blockAffordances.ts
437
- import { Button, measureText, UIComponent } from "@vectojs/ui";
438
- var LANGUAGE_EXTENSIONS = {
439
- bash: "sh",
440
- c: "c",
441
- cpp: "cpp",
442
- cs: "cs",
443
- css: "css",
444
- diff: "diff",
445
- dockerfile: "dockerfile",
446
- go: "go",
447
- graphql: "graphql",
448
- haskell: "hs",
449
- html: "html",
450
- java: "java",
451
- javascript: "js",
452
- js: "js",
453
- json: "json",
454
- jsonc: "jsonc",
455
- jsx: "jsx",
456
- kotlin: "kt",
457
- latex: "tex",
458
- lua: "lua",
459
- make: "mk",
460
- markdown: "md",
461
- md: "md",
462
- nix: "nix",
463
- php: "php",
464
- python: "py",
465
- py: "py",
466
- ruby: "rb",
467
- rust: "rs",
468
- rs: "rs",
469
- scss: "scss",
470
- sh: "sh",
471
- shell: "sh",
472
- sql: "sql",
473
- svelte: "svelte",
474
- swift: "swift",
475
- tex: "tex",
476
- toml: "toml",
477
- ts: "ts",
478
- tsx: "tsx",
479
- typescript: "ts",
480
- vue: "vue",
481
- xml: "xml",
482
- yaml: "yaml",
483
- yml: "yaml",
484
- zig: "zig",
485
- zsh: "sh"
486
- };
487
- function extensionForLanguage(lang) {
488
- const first = lang.trim().toLowerCase().split(/[\s:,{]/)[0] ?? "";
489
- return LANGUAGE_EXTENSIONS[first] ?? "txt";
490
- }
491
- function mimeForLanguage(lang) {
492
- const ext = extensionForLanguage(lang);
493
- if (ext === "json" || ext === "jsonc") return "application/json";
494
- if (ext === "html") return "text/html";
495
- if (ext === "css") return "text/css";
496
- if (ext === "xml" || ext === "svelte" || ext === "vue") return "text/plain";
497
- return "text/plain";
498
- }
499
- function escapeCsvField(value) {
500
- let needsQuoting = false;
501
- let hasQuote = false;
502
- for (const char of value) {
503
- if (char === '"') {
504
- hasQuote = true;
505
- needsQuoting = true;
506
- break;
507
- }
508
- if (char === "," || char === "\n" || char === "\r") needsQuoting = true;
509
- }
510
- if (!needsQuoting) return value;
511
- return hasQuote ? `"${value.replace(/"/g, '""')}"` : `"${value}"`;
512
- }
513
- function escapeMarkdownTableCell(cell) {
514
- let needsEscaping = false;
515
- for (const char of cell) {
516
- if (char === "\\" || char === "|") {
517
- needsEscaping = true;
518
- break;
519
- }
520
- }
521
- if (!needsEscaping) return cell;
522
- return cell.replace(/\\/g, "\\\\").replace(/\|/g, "\\|");
523
- }
524
- function tableToCsv(table) {
525
- const lines = [table.headers.map(escapeCsvField).join(",")];
526
- for (const row of table.rows) lines.push(row.map(escapeCsvField).join(","));
527
- return `\uFEFF${lines.join("\r\n")}`;
528
- }
529
- function tableToMarkdown(table) {
530
- const header = `| ${table.headers.map(escapeMarkdownTableCell).join(" | ")} |`;
531
- const divider = `| ${table.headers.map((_cell, index) => {
532
- switch (table.align[index]) {
533
- case "left":
534
- return ":---";
535
- case "center":
536
- return ":---:";
537
- case "right":
538
- return "---:";
539
- default:
540
- return "---";
541
- }
542
- }).join(" | ")} |`;
543
- const body = table.rows.map(
544
- (row) => `| ${table.headers.map((_cell, index) => escapeMarkdownTableCell(row[index] ?? "")).join(" | ")} |`
545
- );
546
- return [header, divider, ...body].join("\n");
547
- }
548
- function defaultWriteClipboard(text) {
549
- const clipboard = globalThis.navigator?.clipboard;
550
- clipboard?.writeText?.(text);
551
- }
552
- function defaultSaveFile(filename, content, mimeType) {
553
- const doc = globalThis.document;
554
- if (!doc?.body) return;
555
- const blob = new Blob([content], { type: mimeType });
556
- const url = URL.createObjectURL(blob);
557
- const anchor = doc.createElement("a");
558
- anchor.href = url;
559
- anchor.download = filename;
560
- doc.body.appendChild(anchor);
561
- anchor.click();
562
- doc.body.removeChild(anchor);
563
- URL.revokeObjectURL(url);
564
- }
565
- var BlockAffordanceButton = class _BlockAffordanceButton extends Button {
566
- constructor(label, successLabel, act, opts = {}) {
567
- super(label, { ...opts, onClick: () => this.run() });
568
- this.act = act;
569
- this.restingLabel = label;
570
- this.successLabel = successLabel;
571
- this.width = Math.max(this.width, measureText(successLabel, this.font) + 24);
572
- }
573
- act;
574
- /** How long the confirmation label stays up, in ms. */
575
- static FEEDBACK_MS = 1600;
576
- restingLabel;
577
- successLabel;
578
- feedbackTimer;
579
- /**
580
- * Runs the action, then shows the confirmation.
581
- *
582
- * The action runs first and a throw propagates: a clipboard write the browser
583
- * rejected must not be reported as a success.
584
- */
585
- run() {
586
- this.act();
587
- this.setTransientLabel(this.successLabel);
588
- if (this.feedbackTimer !== void 0) clearTimeout(this.feedbackTimer);
589
- this.feedbackTimer = setTimeout(() => {
590
- this.setTransientLabel(this.restingLabel);
591
- this.feedbackTimer = void 0;
592
- }, _BlockAffordanceButton.FEEDBACK_MS);
593
- }
594
- setTransientLabel(label) {
595
- this.label = label;
596
- this.textWidth = measureText(label, this.font);
597
- this.scene?.markDirty();
421
+ // src/markdown-entities.ts
422
+ import { Entity } from "@vectojs/core";
423
+ var HorizontalRule = class extends Entity {
424
+ color;
425
+ constructor(w, color) {
426
+ super();
427
+ this.width = w;
428
+ this.height = 1;
429
+ this.color = color;
598
430
  }
599
- /**
600
- * The label a reader hears is the one they see, transient confirmation
601
- * included, so an AT user gets the same feedback a sighted user does.
602
- */
603
- getA11yAttributes() {
604
- return { ...super.getA11yAttributes(), label: this.label };
431
+ isPointInside() {
432
+ return false;
605
433
  }
606
- /** Clears the pending revert so a destroyed block leaves no timer behind. */
607
- destroy() {
608
- if (this.feedbackTimer !== void 0) {
609
- clearTimeout(this.feedbackTimer);
610
- this.feedbackTimer = void 0;
611
- }
612
- super.destroy();
434
+ render(r) {
435
+ r.beginPath();
436
+ r.moveTo(0, 0);
437
+ r.lineTo(this.width, 0);
438
+ r.stroke(this.color, 1);
613
439
  }
614
440
  };
615
- var BlockWithAffordances = class _BlockWithAffordances extends UIComponent {
616
- constructor(block, controls) {
441
+ var QuoteBorder = class extends Entity {
442
+ color;
443
+ constructor(height, color, width = 4) {
617
444
  super();
618
- this.block = block;
619
- this.controls = controls;
620
- this.add(block);
621
- for (const control of controls) this.add(control);
622
- this.layoutAffordances();
623
- }
624
- block;
625
- controls;
626
- /** Gap between the block's edges and the controls, in px. */
627
- static INSET = 8;
628
- /** Gap between adjacent controls, in px. */
629
- static GAP = 6;
630
- /**
631
- * Places the controls right-aligned along the block's top edge.
632
- *
633
- * Laid out right-to-left from the block's right edge so the first control in
634
- * the list ends up leftmost, which keeps DOM order (and therefore tab order and
635
- * the a11y reading order) matching the visual order.
636
- */
637
- layoutAffordances() {
638
- this.width = this.block.width;
639
- this.height = this.block.height;
640
- let right = this.block.width - _BlockWithAffordances.INSET;
641
- for (let i = this.controls.length - 1; i >= 0; i--) {
642
- const control = this.controls[i];
643
- control.x = right - control.width;
644
- control.y = _BlockWithAffordances.INSET;
645
- right = control.x - _BlockWithAffordances.GAP;
646
- }
445
+ this.width = width;
446
+ this.height = height;
447
+ this.color = color;
647
448
  }
648
- /**
649
- * Re-places the controls after the block's own box changed.
650
- *
651
- * Called by the owner when a block is resized or its content grew; the controls
652
- * are anchored to the right edge, so a width change moves them.
653
- */
654
- refreshAffordances() {
655
- this.layoutAffordances();
656
- this.scene?.markDirty();
449
+ isPointInside() {
450
+ return false;
657
451
  }
658
- /** The wrapper is a pass-through: its size is the block's size. */
659
- getLayoutControlledProperties() {
660
- return ["x", "y"];
452
+ render(r) {
453
+ r.beginPath();
454
+ r.roundRect(0, 0, this.width, this.height, this.width / 2);
455
+ r.fill(this.color);
661
456
  }
662
- /**
663
- * Projected as a group so assistive technology reports one labelled region
664
- * containing the block and its controls, rather than two unrelated siblings.
665
- */
666
- getA11yAttributes() {
667
- return { role: "group", pointerEvents: "none" };
457
+ };
458
+ var MarkdownContainer = class extends Entity {
459
+ isPointInside(_globalX, _globalY) {
460
+ return false;
668
461
  }
669
- render() {
462
+ render(_r) {
670
463
  }
671
464
  };
672
- function tableContentOf(token) {
673
- return {
674
- headers: token.header.map((cell) => cell.text),
675
- rows: token.rows.map((row) => row.map((cell) => cell.text)),
676
- align: token.align
677
- };
678
- }
679
-
680
- // src/frontMatter.ts
681
- var OPEN_RE = /^---[ \t]*\r?\n/;
682
- var OPENER_PREFIX_RE = /^(?:-|--|---[ \t]*\r?)$/;
683
- var KEY_RE = /^[^\s:#][^:]*:(?:[ \t].*)?$/;
684
- var CLOSE_RE = /^(?:---|\.\.\.)[ \t]*$/;
685
- var MAX_PENDING_CHARS = 4096;
686
- var NONE = { kind: "none" };
687
- var PENDING = { kind: "pending" };
688
- function scanFrontMatter(text, complete) {
689
- if (text.length === 0) return PENDING;
690
- const open = OPEN_RE.exec(text);
691
- if (!open) {
692
- return !complete && OPENER_PREFIX_RE.test(text) ? PENDING : NONE;
693
- }
694
- const decide = complete || text.length > MAX_PENDING_CHARS;
695
- const contentStart = open[0].length;
696
- let cursor = contentStart;
697
- let keyChecked = false;
698
- while (cursor < text.length) {
699
- const nl = text.indexOf("\n", cursor);
700
- if (nl === -1 && !decide) return PENDING;
701
- const line = text.slice(cursor, nl === -1 ? text.length : nl).replace(/\r$/, "");
702
- if (!keyChecked) {
703
- if (!KEY_RE.test(line)) return NONE;
704
- keyChecked = true;
705
- } else if (CLOSE_RE.test(line)) {
706
- return {
707
- kind: "found",
708
- raw: text.slice(contentStart, cursor),
709
- // A closer with no trailing newline ends the document, so the body is
710
- // empty rather than starting one character past the end.
711
- bodyStart: nl === -1 ? text.length : nl + 1
712
- };
713
- }
714
- if (nl === -1) break;
715
- cursor = nl + 1;
716
- }
717
- return decide ? NONE : PENDING;
718
- }
719
- function parseFrontMatterFields(raw) {
720
- const out = {};
721
- for (const rawLine of raw.split("\n")) {
722
- const line = rawLine.replace(/\r$/, "");
723
- if (line.length === 0 || /^[\s#]/.test(line)) continue;
724
- const sep = line.indexOf(":");
725
- if (sep <= 0) continue;
726
- const value = line.slice(sep + 1);
727
- if (value.length > 0 && value[0] !== " " && value[0] !== " ") continue;
728
- out[line.slice(0, sep).trim()] = unquote(value.trim());
729
- }
730
- return out;
731
- }
732
- function unquote(value) {
733
- if (value.length < 2) return value;
734
- const first = value[0];
735
- if ((first === '"' || first === "'") && value.endsWith(first)) {
736
- return value.slice(1, -1);
737
- }
738
- return value;
739
- }
740
465
 
741
- // src/MarkdownWorkerSource.ts
742
- 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';
466
+ // src/markdown-code.ts
467
+ import {
468
+ contentLineInHint,
469
+ GlyphRasterAtlas,
470
+ prepareContentGrid
471
+ } from "@vectojs/core";
472
+ import { measureText, UIComponent } from "@vectojs/ui";
743
473
 
744
- // src/Markdown.ts
745
- var now = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
746
- function lexMarkdown(text, userTiming) {
747
- if (!userTiming) return marked.lexer(text);
748
- const timing = beginVectoUserTiming(VECTO_USER_TIMING.markdown.parse);
749
- try {
750
- return marked.lexer(text);
751
- } finally {
752
- if (timing) endVectoUserTiming(timing);
753
- }
754
- }
755
- marked.use({
756
- extensions: [
757
- {
758
- name: "blockMath",
759
- level: "block",
760
- start(src) {
761
- return src.match(/^ {0,3}\$\$/m)?.index;
762
- },
763
- tokenizer(src) {
764
- const match = /^ {0,3}\$\$([\s\S]+?)\$\$[ \t]*(?:\n|$)/.exec(src);
765
- if (match) {
766
- return {
767
- type: "blockMath",
768
- raw: match[0],
769
- text: match[1].trim()
770
- };
771
- }
772
- return void 0;
773
- },
774
- renderer(token) {
775
- return token.raw;
776
- }
777
- },
778
- {
779
- name: "inlineMath",
780
- level: "inline",
781
- start(src) {
782
- return src.match(/(?<![\\$])\$(?![$\s])/)?.index;
783
- },
784
- tokenizer(src) {
785
- const match = /^\$(?![$\s\d])((?:\\\$|[^$\n])*?)(?<!\s)\$(?!\d)/.exec(src);
786
- if (match) {
787
- return {
788
- type: "inlineMath",
789
- raw: match[0],
790
- text: match[1].trim()
791
- };
792
- }
793
- return void 0;
794
- },
795
- renderer(token) {
796
- return token.raw;
797
- }
798
- }
799
- ]
800
- });
801
- var mathConverter = null;
802
- var mathLoad = null;
803
- function interop(mod, key) {
804
- const ns = mod;
805
- if (typeof ns?.[key] !== "undefined") return ns;
806
- const fallback = ns?.default;
807
- if (fallback && typeof fallback[key] !== "undefined") return fallback;
808
- throw new Error(`mathjax-full module is missing export "${key}"`);
809
- }
810
- function preloadMathJax() {
811
- if (mathLoad) return mathLoad;
812
- mathLoad = (async () => {
813
- const [mathjaxMod, texMod, svgMod, adaptorMod, handlerMod, packagesMod] = await Promise.all([
814
- import("mathjax-full/js/mathjax.js"),
815
- import("mathjax-full/js/input/tex.js"),
816
- import("mathjax-full/js/output/svg.js"),
817
- import("mathjax-full/js/adaptors/liteAdaptor.js"),
818
- import("mathjax-full/js/handlers/html.js"),
819
- import("mathjax-full/js/input/tex/AllPackages.js")
820
- ]);
821
- const { mathjax } = interop(mathjaxMod, "mathjax");
822
- const { TeX } = interop(texMod, "TeX");
823
- const { SVG } = interop(svgMod, "SVG");
824
- const { liteAdaptor } = interop(adaptorMod, "liteAdaptor");
825
- const { RegisterHTMLHandler } = interop(handlerMod, "RegisterHTMLHandler");
826
- const { AllPackages } = interop(packagesMod, "AllPackages");
827
- const adaptor = liteAdaptor();
828
- RegisterHTMLHandler(adaptor);
829
- const tex = new TeX({ packages: AllPackages });
830
- const svg = new SVG({ fontCache: "local" });
831
- const htmlMathJax = mathjax.document("", { InputJax: tex, OutputJax: svg });
832
- mathConverter = (formula, displayMode, color) => convertMathToSVGDataURI(
833
- formula,
834
- displayMode,
835
- (f, d) => adaptor.innerHTML(htmlMathJax.convert(f, { display: d })),
836
- color
837
- );
838
- })().catch((e) => {
839
- console.error("MathJax failed to load; formulas will render as TeX source", e);
840
- });
841
- return mathLoad;
842
- }
843
- function isMathJaxReady() {
844
- return mathConverter !== null;
845
- }
846
- var EX_PER_EM = 0.4421;
847
- function exToPx(ex, fontSize) {
848
- return ex * fontSize * EX_PER_EM;
849
- }
850
- function fontSizeFromFont(font) {
851
- const pxIndex = font.indexOf("px");
852
- if (pxIndex <= 0) return void 0;
853
- let start = pxIndex;
854
- while (start > 0) {
855
- const ch = font[start - 1];
856
- if (ch >= "0" && ch <= "9" || ch === ".") start--;
857
- else break;
858
- }
859
- if (start === pxIndex) return void 0;
860
- const size = parseFloat(font.slice(start, pxIndex));
861
- return Number.isFinite(size) ? size : void 0;
862
- }
863
- var mathCache = /* @__PURE__ */ new Map();
864
- var MATH_CACHE_LIMIT = 256;
865
- var inlineMathRasters = /* @__PURE__ */ new Map();
866
- var inlineMathRasterWaiters = /* @__PURE__ */ new Set();
867
- function ensureInlineMathRaster(uri) {
868
- const existing = inlineMathRasters.get(uri);
869
- if (existing) return existing;
870
- const entry = { decoded: false };
871
- inlineMathRasters.set(uri, entry);
872
- if (typeof globalThis.Image !== "undefined") {
873
- const bitmap = new globalThis.Image();
874
- bitmap.onload = () => {
875
- entry.decoded = true;
876
- for (const notify of inlineMathRasterWaiters) notify();
877
- };
878
- bitmap.src = uri;
879
- entry.bitmap = bitmap;
880
- }
881
- return entry;
882
- }
883
- function paintInlineMath(uri, surface, box) {
884
- const raster = ensureInlineMathRaster(uri);
885
- if (!raster.decoded || !raster.bitmap) return;
886
- surface.drawImage(raster.bitmap, box.x, box.y, box.width, box.height);
887
- }
888
- var MATH_LANGS = /* @__PURE__ */ new Set(["math", "latex", "tex"]);
889
- function containsInlineMath(token) {
890
- if (token.type === "inlineMath") return true;
891
- const anyToken = token;
892
- if (Array.isArray(anyToken.tokens) && anyToken.tokens.some(containsInlineMath)) {
893
- return true;
894
- }
895
- if (Array.isArray(anyToken.items) && anyToken.items.some(containsInlineMath)) {
896
- return true;
897
- }
898
- if (Array.isArray(anyToken.header) && anyToken.header.some(containsInlineMath)) {
899
- return true;
900
- }
901
- if (Array.isArray(anyToken.rows)) {
902
- for (const row of anyToken.rows) {
903
- if (Array.isArray(row) && row.some(containsInlineMath)) return true;
904
- }
905
- }
906
- return false;
907
- }
908
- var FENCE_OPEN_RE = /^ {0,3}(`{3,}|~{3,})/;
909
- var FENCE_CLOSE_RE = /^ {0,3}(`+|~+)[ \t]*$/;
910
- function isFenceClosed(raw) {
911
- const lines = raw.split("\n");
912
- const open = FENCE_OPEN_RE.exec(lines[0]);
913
- if (!open) return false;
914
- const marker = open[1][0];
915
- const minLen = open[1].length;
916
- for (let i = 1; i < lines.length; i++) {
917
- const close = FENCE_CLOSE_RE.exec(lines[i]);
918
- if (close && close[1][0] === marker && close[1].length >= minLen) return true;
474
+ // src/theme.ts
475
+ var DEFAULT_THEME = {
476
+ textColor: "#e2e8f0",
477
+ headingColor: "#f8fafc",
478
+ codeColor: "#a5f3fc",
479
+ codeBgColor: "rgba(30, 41, 59, 0.85)",
480
+ quoteBorderColor: "#6366f1",
481
+ quoteTextColor: "#e2e8f0",
482
+ hrColor: "rgba(148, 163, 184, 0.3)",
483
+ tableBgColor: "rgba(15, 15, 25, 0.4)",
484
+ tableHeaderBgColor: "rgba(255, 255, 255, 0.08)",
485
+ linkColor: "#38bdf8",
486
+ mathFallbackColor: "#fcd34d",
487
+ syntaxKeywordColor: "#c084fc",
488
+ syntaxStringColor: "#86efac",
489
+ syntaxCommentColor: "#64748b",
490
+ syntaxNumberColor: "#fbbf24",
491
+ bodyFont: "Inter, system-ui, sans-serif",
492
+ codeFont: 'ui-monospace, "JetBrains Mono", "Fira Code", monospace',
493
+ fontSize: 16,
494
+ headingSizes: [32, 28, 24, 20, 18, 16],
495
+ codeFontSize: 15,
496
+ tableFontSize: 14,
497
+ codeLineHeight: 24,
498
+ bodyLineHeight: 24,
499
+ blockGap: 16,
500
+ codePadding: 18,
501
+ codeRadius: 8,
502
+ listGap: 6,
503
+ listItemGap: 4,
504
+ quoteIndent: 16,
505
+ quoteBorderWidth: 4,
506
+ quoteInnerGap: 8,
507
+ imageRadius: 8,
508
+ inlineImageScale: 1.15
509
+ };
510
+ function resolveTheme(theme) {
511
+ const merged = { ...DEFAULT_THEME, ...theme };
512
+ if (theme?.tableFontSize === void 0) {
513
+ merged.tableFontSize = Math.max(1, merged.fontSize - 2);
919
514
  }
920
- return false;
921
- }
922
- function paragraphHasImage(token) {
923
- return containsImage(token.tokens);
924
- }
925
- function containsImage(tokens) {
926
- if (!tokens) return false;
927
- for (const token of tokens) {
928
- if (token.type === "image") return true;
929
- if (containsImage(token.tokens)) return true;
515
+ if (theme?.quoteTextColor === void 0) {
516
+ merged.quoteTextColor = merged.textColor;
930
517
  }
931
- return false;
518
+ return merged;
932
519
  }
933
- function imagesOf(tokens) {
934
- const images = [];
935
- for (const token of tokens ?? []) {
936
- if (token.type === "image") {
937
- images.push(token);
938
- continue;
939
- }
940
- images.push(...imagesOf(token.tokens));
941
- }
942
- return images;
520
+ function headingSize(theme, depth) {
521
+ const sizes = theme.headingSizes;
522
+ if (sizes.length === 0) return theme.fontSize;
523
+ const idx = Math.min(Math.max(depth, 1) - 1, sizes.length - 1);
524
+ return sizes[idx] ?? theme.fontSize;
943
525
  }
944
- function stripImages(token) {
945
- const children = token.tokens;
946
- if (!children) return token;
947
- const kept = [];
948
- for (const child of children) {
949
- if (child.type === "image") continue;
950
- const grandchildren = child.tokens;
951
- if (grandchildren && containsImage(grandchildren)) {
952
- const stripped = stripImages(child);
953
- const remaining = stripped.tokens;
954
- if (remaining && remaining.length > 0) kept.push(stripped);
955
- continue;
956
- }
957
- kept.push(child);
958
- }
959
- return { ...token, tokens: kept };
960
- }
961
- function liftNestedImages(tokens) {
962
- const lifted = [];
963
- for (const token of tokens) {
964
- if (token.type === "image") {
965
- lifted.push(token);
966
- continue;
967
- }
968
- const children = token.tokens;
969
- if (children && containsImage(children)) {
970
- lifted.push(...liftNestedImages(children));
971
- continue;
972
- }
973
- lifted.push(token);
974
- }
975
- return lifted;
976
- }
977
- function lastIndexOfImage(tokens) {
978
- for (let i = tokens.length - 1; i >= 0; i--) {
979
- if (tokens[i].type === "image") return i;
980
- }
981
- return -1;
982
- }
983
- function expectedImageParagraphChildren(tokens) {
984
- let children = 0;
985
- let inTextRun = false;
986
- for (const token of liftNestedImages(tokens)) {
987
- if (token.type === "image") {
988
- children++;
989
- inTextRun = false;
990
- } else if (!inTextRun) {
991
- children++;
992
- inTextRun = true;
993
- }
994
- }
995
- return children;
996
- }
997
- function rendersAsMath(token) {
998
- return MATH_LANGS.has((token.lang ?? "").toLowerCase()) && token.text.trim() !== "" && isFenceClosed(token.raw);
999
- }
1000
- function renderMathToSVGDataURI(formula, displayMode, color) {
1001
- const key = `${displayMode ? 1 : 0}\0${color}\0${formula}`;
1002
- const hit = mathCache.get(key);
1003
- if (hit) return hit;
1004
- if (!mathConverter) return null;
1005
- const converted = mathConverter(formula, displayMode, color);
1006
- if (converted) {
1007
- if (mathCache.size >= MATH_CACHE_LIMIT) {
1008
- const oldest = mathCache.keys().next().value;
1009
- if (oldest !== void 0) mathCache.delete(oldest);
1010
- }
1011
- mathCache.set(key, converted);
1012
- }
1013
- return converted;
1014
- }
1015
- function applyMathColor(svg, color) {
1016
- const openTag = svg.match(/<svg\b[^>]*>/);
1017
- if (!openTag) return svg;
1018
- const tag = openTag[0];
1019
- const colored = /\bstyle="/.test(tag) ? tag.replace(/\bstyle="/, `style="color:${color};`) : tag.replace(/^<svg\b/, `<svg style="color:${color}"`);
1020
- return svg.replace(tag, colored);
1021
- }
1022
- function convertMathToSVGDataURI(formula, displayMode, typeset, color) {
1023
- try {
1024
- const svgString = applyMathColor(typeset(formula, displayMode), color);
1025
- const wMatch = svgString.match(/width="([^"]+)ex"/);
1026
- const hMatch = svgString.match(/height="([^"]+)ex"/);
1027
- const wEx = wMatch ? parseFloat(wMatch[1]) : 10;
1028
- const hEx = hMatch ? parseFloat(hMatch[1]) : 2;
1029
- const vMatch = svgString.match(/vertical-align:\s*(-?[\d.]+)ex/);
1030
- const depthEx = vMatch ? Math.max(0, -parseFloat(vMatch[1])) : 0;
1031
- const base64 = btoa(unescape(encodeURIComponent(svgString)));
1032
- return {
1033
- uri: `data:image/svg+xml;base64,${base64}`,
1034
- widthEx: wEx,
1035
- heightEx: hEx,
1036
- depthEx
1037
- };
1038
- } catch (e) {
1039
- console.error("MathJax error", e);
1040
- return null;
1041
- }
1042
- }
1043
- var markdownWorker = null;
1044
- var workerIdCounter = 0;
1045
- var workerInstanceCounter = 0;
1046
- var workerCallbacks = /* @__PURE__ */ new Map();
1047
- function runSyncFallback(entry) {
1048
- try {
1049
- entry.cb(0, lexMarkdown(entry.text, entry.userTiming), true);
1050
- } catch (err) {
1051
- console.warn("Markdown sync fallback parse failed", err);
1052
- entry.onDropped?.();
1053
- }
1054
- }
1055
- if (typeof Worker !== "undefined") {
1056
- try {
1057
- const blob = new Blob([WORKER_SOURCE_STRING], {
1058
- type: "application/javascript"
1059
- });
1060
- markdownWorker = new Worker(URL.createObjectURL(blob));
1061
- markdownWorker.onmessage = (e) => {
1062
- const { id, matchLen, tail, error, needResync, lexerMs, sourceCharsLexed } = e.data;
1063
- const entry = workerCallbacks.get(id);
1064
- if (entry) {
1065
- workerCallbacks.delete(id);
1066
- if (needResync && entry.onNeedResync) {
1067
- entry.onNeedResync();
1068
- } else if (needResync) {
1069
- runSyncFallback(entry);
1070
- } else if (!error) {
1071
- entry.cb(matchLen, tail, false, {
1072
- lexerMs: typeof lexerMs === "number" ? lexerMs : 0,
1073
- sourceCharsLexed: typeof sourceCharsLexed === "number" ? sourceCharsLexed : 0
1074
- });
1075
- } else {
1076
- runSyncFallback(entry);
1077
- }
1078
- }
1079
- };
1080
- markdownWorker.onerror = () => {
1081
- const pending = [...workerCallbacks.values()];
1082
- workerCallbacks.clear();
1083
- markdownWorker = null;
1084
- for (const entry of pending) runSyncFallback(entry);
1085
- };
1086
- } catch (err) {
1087
- console.warn("Failed to initialize MarkdownWorker", err);
1088
- }
1089
- }
1090
- var DEFAULT_THEME = {
1091
- textColor: "#e2e8f0",
1092
- headingColor: "#f8fafc",
1093
- codeColor: "#a5f3fc",
1094
- codeBgColor: "rgba(30, 41, 59, 0.85)",
1095
- quoteBorderColor: "#6366f1",
1096
- quoteTextColor: "#94a3b8",
1097
- hrColor: "rgba(148, 163, 184, 0.3)",
1098
- tableBgColor: "rgba(15, 15, 25, 0.4)",
1099
- tableHeaderBgColor: "rgba(255, 255, 255, 0.08)",
1100
- bodyFont: "Inter, system-ui, sans-serif",
1101
- codeFont: 'ui-monospace, "JetBrains Mono", "Fira Code", monospace',
1102
- fontSize: 16
1103
- };
1104
- var HorizontalRule = class extends Entity {
1105
- color;
1106
- constructor(w, color) {
1107
- super();
1108
- this.width = w;
1109
- this.height = 1;
1110
- this.color = color;
1111
- }
1112
- isPointInside() {
1113
- return false;
1114
- }
1115
- render(r) {
1116
- r.beginPath();
1117
- r.moveTo(0, 0);
1118
- r.lineTo(this.width, 0);
1119
- r.stroke(this.color, 1);
1120
- }
1121
- };
1122
- var QuoteBorder = class extends Entity {
1123
- color;
1124
- constructor(height, color) {
1125
- super();
1126
- this.width = 4;
1127
- this.height = height;
1128
- this.color = color;
1129
- }
1130
- isPointInside() {
1131
- return false;
1132
- }
1133
- render(r) {
1134
- r.beginPath();
1135
- r.roundRect(0, 0, this.width, this.height, 2);
1136
- r.fill(this.color);
1137
- }
1138
- };
1139
- var MarkdownContainer = class extends Entity {
1140
- isPointInside(_globalX, _globalY) {
1141
- return false;
1142
- }
1143
- render(_r) {
1144
- }
1145
- };
1146
- var MathBlock = class extends MarkdownContainer {
1147
- /**
1148
- * The TeX source, exactly as written between the delimiters.
1149
- *
1150
- * Also the projected text and the accessible name, so this is the one string a
1151
- * reader can find, select, and copy.
1152
- */
1153
- formula;
1154
- /** The `data:image/svg+xml` URI of the typeset glyphs. */
1155
- svgUri;
1156
- constructor(formula, svgUri) {
1157
- super();
1158
- this.formula = formula;
1159
- this.svgUri = svgUri;
1160
- }
1161
- getDevtoolsDescriptor() {
1162
- return {
1163
- kind: "MathBlock",
1164
- groups: [
1165
- {
1166
- label: "Math",
1167
- fields: [{ label: "formula", value: this.formula, readOnly: true }]
1168
- }
1169
- ]
1170
- };
1171
- }
1172
- };
526
+
527
+ // src/markdown-code.ts
1173
528
  var KEYWORD_SETS = {
1174
529
  js: /* @__PURE__ */ new Set([
1175
530
  "const",
@@ -1344,10 +699,10 @@ function highlightLine(line, lang, theme) {
1344
699
  return [{ text: line, color: theme.codeColor }];
1345
700
  }
1346
701
  const segments = [];
1347
- const KEYWORD_COLOR = "#c084fc";
1348
- const STRING_COLOR = "#86efac";
1349
- const COMMENT_COLOR = "#64748b";
1350
- const NUMBER_COLOR = "#fbbf24";
702
+ const KEYWORD_COLOR = theme.syntaxKeywordColor;
703
+ const STRING_COLOR = theme.syntaxStringColor;
704
+ const COMMENT_COLOR = theme.syntaxCommentColor;
705
+ const NUMBER_COLOR = theme.syntaxNumberColor;
1351
706
  let i = 0;
1352
707
  let buf = "";
1353
708
  const flush = (color) => {
@@ -1368,469 +723,1230 @@ function highlightLine(line, lang, theme) {
1368
723
  segments.push({ text: line.slice(i), color: COMMENT_COLOR });
1369
724
  return segments;
1370
725
  }
1371
- if (ch === '"' || ch === "'" || ch === "`") {
1372
- const quote = ch;
1373
- let j = i + 1;
1374
- let closed = false;
1375
- while (j < line.length) {
1376
- if (line[j] === "\\") {
1377
- j += 2;
1378
- continue;
726
+ if (ch === '"' || ch === "'" || ch === "`") {
727
+ const quote = ch;
728
+ let j = i + 1;
729
+ let closed = false;
730
+ while (j < line.length) {
731
+ if (line[j] === "\\") {
732
+ j += 2;
733
+ continue;
734
+ }
735
+ if (line[j] === quote) {
736
+ closed = true;
737
+ break;
738
+ }
739
+ j++;
740
+ }
741
+ if (closed) {
742
+ flush(theme.codeColor);
743
+ segments.push({ text: line.slice(i, j + 1), color: STRING_COLOR });
744
+ i = j + 1;
745
+ continue;
746
+ }
747
+ buf += ch;
748
+ i++;
749
+ continue;
750
+ }
751
+ if (/\d/.test(ch) && (i === 0 || /[\s(,=+\-*/<>[\]{}:;]/.test(line[i - 1]))) {
752
+ flush(theme.codeColor);
753
+ let j = i;
754
+ while (j < line.length && /[\d._xXa-fA-F]/.test(line[j])) j++;
755
+ segments.push({ text: line.slice(i, j), color: NUMBER_COLOR });
756
+ i = j;
757
+ continue;
758
+ }
759
+ if (/[a-zA-Z_]/.test(ch)) {
760
+ flush(theme.codeColor);
761
+ let j = i;
762
+ while (j < line.length && /[a-zA-Z0-9_]/.test(line[j])) j++;
763
+ const word = line.slice(i, j);
764
+ segments.push({
765
+ text: word,
766
+ color: keywords.has(word) ? KEYWORD_COLOR : theme.codeColor
767
+ });
768
+ i = j;
769
+ continue;
770
+ }
771
+ buf += ch;
772
+ i++;
773
+ }
774
+ flush(theme.codeColor);
775
+ return segments;
776
+ }
777
+ var CodeBlock = class extends UIComponent {
778
+ lines;
779
+ grid = null;
780
+ /** Raw (unhighlighted) lines of the last build, for prefix reuse in buildLines. */
781
+ rawLines = null;
782
+ cellWidth = 0;
783
+ source;
784
+ /** Bumped by {@link buildLines} and {@link setSelectable}; read by `Scene`. */
785
+ contentEpoch = 0;
786
+ lang;
787
+ theme;
788
+ /**
789
+ * Assigned in the constructor rather than as a field initializer: both come
790
+ * from `theme`, and a field initializer runs before the constructor body has
791
+ * a `theme` to read.
792
+ */
793
+ lineH;
794
+ pad;
795
+ codeFont;
796
+ selectable;
797
+ /**
798
+ * @param theme Any subset of {@link MarkdownTheme}; missing keys fall back to
799
+ * `DEFAULT_THEME` in `./theme`. Accepting a partial theme keeps callers that were
800
+ * written against an earlier, smaller `MarkdownTheme` working — this class
801
+ * is public API, and a hand-built theme literal would otherwise start
802
+ * throwing `lineHeight must be a positive finite number` the moment a new
803
+ * size key was added.
804
+ */
805
+ constructor(code, lang, maxWidth, theme, selectable = true) {
806
+ super();
807
+ const resolved = resolveTheme(theme);
808
+ this.source = code;
809
+ this.lang = lang;
810
+ this.theme = resolved;
811
+ this.lineH = resolved.codeLineHeight;
812
+ this.pad = resolved.codePadding;
813
+ this.codeFont = `${resolved.codeFontSize}px ${resolved.codeFont}`;
814
+ this.selectable = selectable;
815
+ this.lines = [];
816
+ this.width = maxWidth;
817
+ this.buildLines(code);
818
+ }
819
+ /** Re-parse code content (e.g. for live editing). */
820
+ setCode(code, lang) {
821
+ if (lang !== void 0) this.lang = lang;
822
+ this.source = code;
823
+ this.buildLines(code);
824
+ this.scene?.markDirty();
825
+ return this;
826
+ }
827
+ /** Enable or disable browser-native selection for this code block. */
828
+ setSelectable(selectable) {
829
+ this.selectable = selectable;
830
+ this.contentEpoch++;
831
+ this.scene?.markDirty();
832
+ return this;
833
+ }
834
+ getContentEpoch() {
835
+ return this.contentEpoch;
836
+ }
837
+ /**
838
+ * Change the block's box width.
839
+ *
840
+ * Deliberately does **not** rebuild the grid or the highlight, because code does
841
+ * not reflow: lines are placed on a fixed monospace grid at `col × cellWidth` and
842
+ * a long line overflows rather than wrapping, so `height` is a function of line
843
+ * *count* alone. The width only sizes the rounded background. Anything that would
844
+ * change the glyph geometry — the source, the language, the font — goes through
845
+ * {@link setCode} and invalidates the grid there.
846
+ *
847
+ * @returns `this` for chaining.
848
+ */
849
+ setWidth(width) {
850
+ const next = Math.max(0, width);
851
+ if (next === this.width) return this;
852
+ this.width = next;
853
+ this.scene?.markDirty();
854
+ return this;
855
+ }
856
+ getContentProjection(hint) {
857
+ if (!this.source) return null;
858
+ const grid = this.ensureGrid();
859
+ const rows = [];
860
+ rows.length = grid.lines.length;
861
+ for (let row = 0; row < grid.lines.length; row++) {
862
+ const line = grid.lines[row];
863
+ const y = this.pad + row * this.lineH;
864
+ if (!contentLineInHint(hint, y, this.lineH)) continue;
865
+ rows[row] = {
866
+ text: this.source.slice(line.sourceStart, line.sourceEnd),
867
+ separatorAfter: this.source.slice(line.sourceEnd, line.nextSourceStart) || void 0,
868
+ x: this.pad,
869
+ y,
870
+ baseline: this.lineH * 0.75,
871
+ font: this.codeFont,
872
+ lineHeight: this.lineH
873
+ };
874
+ }
875
+ return {
876
+ text: this.source,
877
+ font: this.codeFont,
878
+ lineHeight: this.lineH,
879
+ // Every row is absolutely positioned from the same local coordinates as
880
+ // render(). A single pre-wrap DOM text node would introduce browser
881
+ // wrapping for long source lines that canvas intentionally keeps intact.
882
+ //
883
+ lines: rows,
884
+ selectable: this.selectable,
885
+ // render() draws cell-by-cell (no ligatures can form); the DOM copy
886
+ // must not ligate either or Firefox selection geometry drifts.
887
+ ligatures: "none",
888
+ grid
889
+ };
890
+ }
891
+ /**
892
+ * Re-highlight the code, reusing the highlight of any unchanged line prefix.
893
+ *
894
+ * Streaming appends to the END of a block, so all but the last line or two are
895
+ * byte-identical to the previous call — yet this used to re-highlight every
896
+ * line on every chunk, making a streamed block O(N) per append and O(N^2)
897
+ * overall. Reusing the stable prefix makes an append proportional to what
898
+ * actually changed.
899
+ *
900
+ * The last previously-seen line is deliberately NOT reused: a chunk usually
901
+ * lands mid-line, so that line's text (and therefore its tokenization) changes.
902
+ */
903
+ buildLines(code) {
904
+ this.contentEpoch++;
905
+ const rawLines = code.split(/\r\n|\r|\n/);
906
+ const previous = this.rawLines;
907
+ let reusable = 0;
908
+ if (previous && this.lines.length === previous.length) {
909
+ const limit = Math.min(previous.length - 1, rawLines.length);
910
+ while (reusable < limit && previous[reusable] === rawLines[reusable]) reusable++;
911
+ }
912
+ if (reusable > 0) {
913
+ const next = this.lines.slice(0, reusable);
914
+ for (let i = reusable; i < rawLines.length; i++) {
915
+ next.push(highlightLine(rawLines[i], this.lang, this.theme));
916
+ }
917
+ this.lines = next;
918
+ } else {
919
+ this.lines = rawLines.map((l) => highlightLine(l, this.lang, this.theme));
920
+ }
921
+ this.rawLines = rawLines;
922
+ this.grid = null;
923
+ this.height = this.pad * 2 + rawLines.length * this.lineH;
924
+ }
925
+ ensureGrid() {
926
+ const cellWidth = this.cellWidth || Math.max(1, measureText("M", this.codeFont));
927
+ if (!this.grid || this.grid.source !== this.source || this.grid.font !== this.codeFont || this.grid.cellWidth !== cellWidth) {
928
+ this.grid = prepareContentGrid(this.source, {
929
+ font: this.codeFont,
930
+ cellWidth,
931
+ lineHeight: this.lineH,
932
+ baseline: this.lineH * 0.75
933
+ });
934
+ }
935
+ return this.grid;
936
+ }
937
+ /** Code blocks are decorative — not interactive. */
938
+ isPointInside() {
939
+ return false;
940
+ }
941
+ render(r) {
942
+ r.beginPath();
943
+ r.roundRect(0, 0, this.width, this.height, this.theme.codeRadius);
944
+ r.fill(this.theme.codeBgColor);
945
+ const grid = this.ensureGrid();
946
+ const atlas = codeGlyphAtlas(r);
947
+ const atlasSource = atlas?.source ?? null;
948
+ const blit = atlas ? r.drawImageRect : void 0;
949
+ for (let row = 0; row < grid.lines.length; row++) {
950
+ const yBaseline = this.pad + row * this.lineH + this.lineH * 0.75;
951
+ const segments = this.lines[row];
952
+ let segmentIndex = 0;
953
+ let segmentEnd = segments[0]?.text.length ?? 0;
954
+ const lineStart = grid.lines[row].sourceStart;
955
+ for (const cell of grid.lines[row].cells) {
956
+ const localSourceStart = cell.sourceStart - lineStart;
957
+ while (segmentIndex < segments.length - 1 && localSourceStart >= segmentEnd) {
958
+ segmentIndex++;
959
+ segmentEnd += segments[segmentIndex].text.length;
960
+ }
961
+ const sourceText = this.source.slice(cell.sourceStart, cell.sourceEnd);
962
+ if (cell.advance <= 0 || sourceText === " " || sourceText === " ") continue;
963
+ const color = segments[segmentIndex]?.color ?? this.theme.codeColor;
964
+ const x = this.pad + cell.x;
965
+ if (blit && atlas) {
966
+ const slot = atlas.get(this.codeFont, color, cell.glyph);
967
+ const src = atlasSource ?? atlas.source;
968
+ if (slot && src) {
969
+ blit.call(
970
+ r,
971
+ src,
972
+ slot.sx,
973
+ slot.sy,
974
+ slot.sw,
975
+ slot.sh,
976
+ x - slot.offsetX,
977
+ yBaseline - slot.offsetY,
978
+ slot.w,
979
+ slot.h
980
+ );
981
+ continue;
982
+ }
983
+ }
984
+ r.fillText(cell.glyph, x, yBaseline, this.codeFont, color);
985
+ }
986
+ }
987
+ }
988
+ };
989
+ var codeAtlases = /* @__PURE__ */ new Map();
990
+ var MAX_CODE_ATLASES = 2;
991
+ var lastCodeAtlas = null;
992
+ function codeGlyphAtlas(r) {
993
+ if (typeof r.drawImageRect !== "function") return void 0;
994
+ if (typeof document === "undefined") return void 0;
995
+ const dpr = Math.max(
996
+ 1,
997
+ r.pixelRatio ?? (typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1)
998
+ );
999
+ const existing = codeAtlases.get(dpr);
1000
+ if (existing) {
1001
+ codeAtlases.delete(dpr);
1002
+ codeAtlases.set(dpr, existing);
1003
+ lastCodeAtlas = existing;
1004
+ return existing;
1005
+ }
1006
+ const atlas = new GlyphRasterAtlas({ dpr, maxSize: 2048 });
1007
+ codeAtlases.set(dpr, atlas);
1008
+ if (codeAtlases.size > MAX_CODE_ATLASES) {
1009
+ const oldestKey = codeAtlases.keys().next().value;
1010
+ const oldest = codeAtlases.get(oldestKey);
1011
+ codeAtlases.delete(oldestKey);
1012
+ if (oldest && oldest !== atlas) oldest.destroy();
1013
+ }
1014
+ lastCodeAtlas = atlas;
1015
+ return atlas;
1016
+ }
1017
+ function codeAtlasStats() {
1018
+ return lastCodeAtlas ? lastCodeAtlas.stats : null;
1019
+ }
1020
+ function codeAtlas() {
1021
+ return lastCodeAtlas;
1022
+ }
1023
+
1024
+ // src/markdown-math.ts
1025
+ var mathConverter = null;
1026
+ var mathLoad = null;
1027
+ function preloadMathJax() {
1028
+ if (mathLoad) return mathLoad;
1029
+ mathLoad = (async () => {
1030
+ const { emitSVG, layout } = await import("@vectojs/tex");
1031
+ mathConverter = (formula, displayMode, color) => convertMathToSVGDataURI(formula, displayMode, color, layout, emitSVG);
1032
+ })().catch((e) => {
1033
+ console.error("Math engine failed to load; formulas will render as TeX source", e);
1034
+ });
1035
+ return mathLoad;
1036
+ }
1037
+ function isMathJaxReady() {
1038
+ return mathConverter !== null;
1039
+ }
1040
+ var EX_PER_EM = 0.4421;
1041
+ function exToPx(ex, fontSize) {
1042
+ return ex * fontSize * EX_PER_EM;
1043
+ }
1044
+ function fontSizeFromFont(font) {
1045
+ const pxIndex = font.indexOf("px");
1046
+ if (pxIndex <= 0) return void 0;
1047
+ let start = pxIndex;
1048
+ while (start > 0) {
1049
+ const ch = font[start - 1];
1050
+ if (ch >= "0" && ch <= "9" || ch === ".") start--;
1051
+ else break;
1052
+ }
1053
+ if (start === pxIndex) return void 0;
1054
+ const size = parseFloat(font.slice(start, pxIndex));
1055
+ return Number.isFinite(size) ? size : void 0;
1056
+ }
1057
+ var mathCache = /* @__PURE__ */ new Map();
1058
+ var MATH_CACHE_LIMIT = 256;
1059
+ var inlineMathRasters = /* @__PURE__ */ new Map();
1060
+ var inlineMathRasterWaiters = /* @__PURE__ */ new Set();
1061
+ function subscribeInlineMathRaster(notify) {
1062
+ inlineMathRasterWaiters.add(notify);
1063
+ }
1064
+ function unsubscribeInlineMathRaster(notify) {
1065
+ inlineMathRasterWaiters.delete(notify);
1066
+ }
1067
+ function ensureInlineMathRaster(uri) {
1068
+ const existing = inlineMathRasters.get(uri);
1069
+ if (existing) return existing;
1070
+ const entry = { decoded: false };
1071
+ inlineMathRasters.set(uri, entry);
1072
+ if (typeof globalThis.Image !== "undefined") {
1073
+ const bitmap = new globalThis.Image();
1074
+ bitmap.onload = () => {
1075
+ entry.decoded = true;
1076
+ for (const notify of inlineMathRasterWaiters) notify();
1077
+ };
1078
+ bitmap.src = uri;
1079
+ entry.bitmap = bitmap;
1080
+ }
1081
+ return entry;
1082
+ }
1083
+ function paintInlineMath(uri, surface, box) {
1084
+ const raster = ensureInlineMathRaster(uri);
1085
+ if (!raster.decoded || !raster.bitmap) return;
1086
+ surface.drawImage(raster.bitmap, box.x, box.y, box.width, box.height);
1087
+ }
1088
+ var MATH_LANGS = /* @__PURE__ */ new Set(["math", "latex", "tex"]);
1089
+ function containsInlineMath(token) {
1090
+ if (token.type === "inlineMath") return true;
1091
+ const anyToken = token;
1092
+ if (Array.isArray(anyToken.tokens) && anyToken.tokens.some(containsInlineMath)) {
1093
+ return true;
1094
+ }
1095
+ if (Array.isArray(anyToken.items) && anyToken.items.some(containsInlineMath)) {
1096
+ return true;
1097
+ }
1098
+ if (Array.isArray(anyToken.header) && anyToken.header.some(containsInlineMath)) {
1099
+ return true;
1100
+ }
1101
+ if (Array.isArray(anyToken.rows)) {
1102
+ for (const row of anyToken.rows) {
1103
+ if (Array.isArray(row) && row.some(containsInlineMath)) return true;
1104
+ }
1105
+ }
1106
+ return false;
1107
+ }
1108
+ var FENCE_OPEN_RE = /^ {0,3}(`{3,}|~{3,})/;
1109
+ var FENCE_CLOSE_RE = /^ {0,3}(`+|~+)[ \t]*$/;
1110
+ function isFenceClosed(raw) {
1111
+ const lines = raw.split("\n");
1112
+ const open = FENCE_OPEN_RE.exec(lines[0]);
1113
+ if (!open) return false;
1114
+ const marker = open[1][0];
1115
+ const minLen = open[1].length;
1116
+ for (let i = 1; i < lines.length; i++) {
1117
+ const close = FENCE_CLOSE_RE.exec(lines[i]);
1118
+ if (close && close[1][0] === marker && close[1].length >= minLen) return true;
1119
+ }
1120
+ return false;
1121
+ }
1122
+ function rendersAsMath(token) {
1123
+ return MATH_LANGS.has((token.lang ?? "").toLowerCase()) && token.text.trim() !== "" && isFenceClosed(token.raw);
1124
+ }
1125
+ function renderMathToSVGDataURI(formula, displayMode, color) {
1126
+ const key = `${displayMode ? 1 : 0}\0${color}\0${formula}`;
1127
+ const hit = mathCache.get(key);
1128
+ if (hit) return hit;
1129
+ if (!mathConverter) return null;
1130
+ const converted = mathConverter(formula, displayMode, color);
1131
+ if (converted) {
1132
+ if (mathCache.size >= MATH_CACHE_LIMIT) {
1133
+ const oldest = mathCache.keys().next().value;
1134
+ if (oldest !== void 0) mathCache.delete(oldest);
1135
+ }
1136
+ mathCache.set(key, converted);
1137
+ }
1138
+ return converted;
1139
+ }
1140
+ var MATH_PAD_EM = 0.05;
1141
+ var KATEX_FONT_SCALE = 1.21;
1142
+ var EX_PER_KATEX_EM = KATEX_FONT_SCALE / EX_PER_EM;
1143
+ function convertMathToSVGDataURI(formula, displayMode, color, layout, emitSVG) {
1144
+ try {
1145
+ const emitted = emitSVG(layout(formula, { displayMode }), {
1146
+ color,
1147
+ padEm: MATH_PAD_EM
1148
+ });
1149
+ if (emitted.missing.length > 0) return null;
1150
+ const pad2 = MATH_PAD_EM * 2;
1151
+ const base64 = btoa(unescape(encodeURIComponent(emitted.svg)));
1152
+ return {
1153
+ uri: `data:image/svg+xml;base64,${base64}`,
1154
+ widthEx: (emitted.width + pad2) * EX_PER_KATEX_EM,
1155
+ heightEx: (emitted.height + emitted.depth + pad2) * EX_PER_KATEX_EM,
1156
+ depthEx: (emitted.depth + MATH_PAD_EM) * EX_PER_KATEX_EM
1157
+ };
1158
+ } catch (e) {
1159
+ console.error("Math typesetting error", e);
1160
+ return null;
1161
+ }
1162
+ }
1163
+ var MathBlock = class extends MarkdownContainer {
1164
+ /**
1165
+ * The TeX source, exactly as written between the delimiters.
1166
+ *
1167
+ * Also the projected text and the accessible name, so this is the one string a
1168
+ * reader can find, select, and copy.
1169
+ */
1170
+ formula;
1171
+ /** The `data:image/svg+xml` URI of the typeset glyphs. */
1172
+ svgUri;
1173
+ constructor(formula, svgUri) {
1174
+ super();
1175
+ this.formula = formula;
1176
+ this.svgUri = svgUri;
1177
+ }
1178
+ getDevtoolsDescriptor() {
1179
+ return {
1180
+ kind: "MathBlock",
1181
+ groups: [
1182
+ {
1183
+ label: "Math",
1184
+ fields: [{ label: "formula", value: this.formula, readOnly: true }]
1185
+ }
1186
+ ]
1187
+ };
1188
+ }
1189
+ };
1190
+
1191
+ // src/markdown-inline.ts
1192
+ import { OBJECT_REPLACEMENT } from "@vectojs/core";
1193
+ import { RichText } from "@vectojs/ui";
1194
+
1195
+ // src/markdown-image.ts
1196
+ function paragraphHasImage(token) {
1197
+ return containsImage(token.tokens);
1198
+ }
1199
+ function containsImage(tokens) {
1200
+ if (!tokens) return false;
1201
+ for (const token of tokens) {
1202
+ if (token.type === "image") return true;
1203
+ const anyToken = token;
1204
+ if (containsImage(anyToken.tokens)) return true;
1205
+ if (Array.isArray(anyToken.items) && containsImage(anyToken.items)) {
1206
+ return true;
1207
+ }
1208
+ const table = token;
1209
+ if (Array.isArray(table.header) && table.header.some((cell) => containsImage(cell.tokens))) {
1210
+ return true;
1211
+ }
1212
+ if (Array.isArray(table.rows) && table.rows.some((row) => row.some((cell) => containsImage(cell.tokens)))) {
1213
+ return true;
1214
+ }
1215
+ }
1216
+ return false;
1217
+ }
1218
+ function imagesOf(tokens) {
1219
+ const images = [];
1220
+ for (const token of tokens ?? []) {
1221
+ if (token.type === "image") {
1222
+ images.push(token);
1223
+ continue;
1224
+ }
1225
+ images.push(...imagesOf(token.tokens));
1226
+ }
1227
+ return images;
1228
+ }
1229
+ function stripImages(token) {
1230
+ const children = token.tokens;
1231
+ if (!children) return token;
1232
+ const kept = [];
1233
+ for (const child of children) {
1234
+ if (child.type === "image") continue;
1235
+ const grandchildren = child.tokens;
1236
+ if (grandchildren && containsImage(grandchildren)) {
1237
+ const stripped = stripImages(child);
1238
+ const remaining = stripped.tokens;
1239
+ if (remaining && remaining.length > 0) kept.push(stripped);
1240
+ continue;
1241
+ }
1242
+ kept.push(child);
1243
+ }
1244
+ return { ...token, tokens: kept };
1245
+ }
1246
+ function liftNestedImages(tokens) {
1247
+ const lifted = [];
1248
+ for (const token of tokens) {
1249
+ if (token.type === "image") {
1250
+ lifted.push(token);
1251
+ continue;
1252
+ }
1253
+ const children = token.tokens;
1254
+ if (children && containsImage(children)) {
1255
+ lifted.push(...liftNestedImages(children));
1256
+ continue;
1257
+ }
1258
+ lifted.push(token);
1259
+ }
1260
+ return lifted;
1261
+ }
1262
+ function lastIndexOfImage(tokens) {
1263
+ for (let i = tokens.length - 1; i >= 0; i--) {
1264
+ if (tokens[i].type === "image") return i;
1265
+ }
1266
+ return -1;
1267
+ }
1268
+ var inlineImageRasters = /* @__PURE__ */ new Map();
1269
+ var inlineImageRasterWaiters = /* @__PURE__ */ new Set();
1270
+ function subscribeInlineImageRaster(notify) {
1271
+ inlineImageRasterWaiters.add(notify);
1272
+ }
1273
+ function unsubscribeInlineImageRaster(notify) {
1274
+ inlineImageRasterWaiters.delete(notify);
1275
+ }
1276
+ function ensureInlineImageRaster(src) {
1277
+ const existing = inlineImageRasters.get(src);
1278
+ if (existing) return existing;
1279
+ const entry = { decoded: false };
1280
+ inlineImageRasters.set(src, entry);
1281
+ if (typeof globalThis.Image !== "undefined") {
1282
+ const bitmap = new globalThis.Image();
1283
+ bitmap.onload = () => {
1284
+ entry.decoded = true;
1285
+ entry.naturalWidth = bitmap.naturalWidth || void 0;
1286
+ entry.naturalHeight = bitmap.naturalHeight || void 0;
1287
+ for (const notify of inlineImageRasterWaiters) notify();
1288
+ };
1289
+ bitmap.onerror = () => {
1290
+ entry.failed = true;
1291
+ for (const notify of inlineImageRasterWaiters) notify();
1292
+ };
1293
+ bitmap.src = src;
1294
+ entry.bitmap = bitmap;
1295
+ }
1296
+ return entry;
1297
+ }
1298
+ function paintInlineImage(src, surface, box) {
1299
+ const raster = ensureInlineImageRaster(src);
1300
+ if (!raster.decoded || !raster.bitmap) return;
1301
+ surface.drawImage(raster.bitmap, box.x, box.y, box.width, box.height);
1302
+ }
1303
+ function expectedImageParagraphChildren(tokens) {
1304
+ let children = 0;
1305
+ let inTextRun = false;
1306
+ for (const token of liftNestedImages(tokens)) {
1307
+ if (token.type === "image") {
1308
+ children++;
1309
+ inTextRun = false;
1310
+ } else if (!inTextRun) {
1311
+ children++;
1312
+ inTextRun = true;
1313
+ }
1314
+ }
1315
+ return children;
1316
+ }
1317
+
1318
+ // src/markdown-inline.ts
1319
+ function decodeEntities(text) {
1320
+ return text.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&amp;/g, "&");
1321
+ }
1322
+ function collectSpans(tokens, inherited, theme, out, blockFontSize) {
1323
+ for (const token of tokens) {
1324
+ switch (token.type) {
1325
+ case "strong": {
1326
+ const t = token;
1327
+ if (t.tokens) {
1328
+ collectSpans(t.tokens, { ...inherited, bold: true }, theme, out, blockFontSize);
1329
+ } else {
1330
+ out.push({
1331
+ text: decodeEntities(t.text),
1332
+ style: { ...inherited, bold: true }
1333
+ });
1379
1334
  }
1380
- if (line[j] === quote) {
1381
- closed = true;
1335
+ break;
1336
+ }
1337
+ case "em": {
1338
+ const t = token;
1339
+ if (t.tokens) {
1340
+ collectSpans(t.tokens, { ...inherited, italic: true }, theme, out, blockFontSize);
1341
+ } else {
1342
+ out.push({
1343
+ text: decodeEntities(t.text),
1344
+ style: { ...inherited, italic: true }
1345
+ });
1346
+ }
1347
+ break;
1348
+ }
1349
+ case "del": {
1350
+ const t = token;
1351
+ if (t.tokens) {
1352
+ collectSpans(t.tokens, { ...inherited, lineThrough: true }, theme, out, blockFontSize);
1353
+ } else {
1354
+ out.push({
1355
+ text: decodeEntities(t.text),
1356
+ style: { ...inherited, lineThrough: true }
1357
+ });
1358
+ }
1359
+ break;
1360
+ }
1361
+ case "codespan": {
1362
+ const t = token;
1363
+ out.push({
1364
+ text: decodeEntities(t.text),
1365
+ // Inline code renders in the theme's monospace family (not just tinted
1366
+ // prose) — TextStyle.fontFamily drives both measurement and drawing.
1367
+ style: {
1368
+ ...inherited,
1369
+ color: theme.codeColor,
1370
+ fontFamily: theme.codeFont
1371
+ }
1372
+ });
1373
+ break;
1374
+ }
1375
+ case "br": {
1376
+ out.push({ text: "\n" });
1377
+ break;
1378
+ }
1379
+ case "html": {
1380
+ const t = token;
1381
+ const raw = t.raw ?? t.text ?? "";
1382
+ const brCount = (raw.match(/<br\s*\/?>/gi) ?? []).length;
1383
+ for (let i = 0; i < brCount; i++) out.push({ text: "\n" });
1384
+ break;
1385
+ }
1386
+ case "inlineMath": {
1387
+ const t = token;
1388
+ const runSize = inherited.fontSize ?? blockFontSize ?? theme.fontSize;
1389
+ const runColor = inherited.color ?? theme.textColor;
1390
+ const rendered = renderMathToSVGDataURI(t.text, false, runColor);
1391
+ if (rendered) {
1392
+ const uri = rendered.uri;
1393
+ out.push({
1394
+ text: OBJECT_REPLACEMENT,
1395
+ style: inherited,
1396
+ object: {
1397
+ width: exToPx(rendered.widthEx, runSize),
1398
+ height: exToPx(rendered.heightEx, runSize),
1399
+ depth: exToPx(rendered.depthEx, runSize),
1400
+ // The TeX source is the accessible name: without it a screen reader
1401
+ // receives only the invisible U+FFFC sentinel.
1402
+ alt: t.text,
1403
+ // Without this the box is reserved and stays empty. The engine does
1404
+ // not draw objects, and nothing else in the tree holds the raster.
1405
+ paint: (surface, box) => paintInlineMath(uri, surface, box)
1406
+ }
1407
+ });
1408
+ } else {
1409
+ out.push({
1410
+ text: decodeEntities(t.raw),
1411
+ style: { ...inherited, color: theme.mathFallbackColor }
1412
+ });
1413
+ }
1414
+ break;
1415
+ }
1416
+ case "image": {
1417
+ const t = token;
1418
+ const runSize = inherited.fontSize ?? blockFontSize ?? theme.fontSize;
1419
+ const raster = ensureInlineImageRaster(t.href);
1420
+ if (raster.failed) {
1421
+ out.push({ text: decodeEntities(t.text), style: inherited });
1382
1422
  break;
1383
1423
  }
1384
- j++;
1424
+ const height = runSize * theme.inlineImageScale;
1425
+ const aspect = raster.naturalWidth && raster.naturalHeight ? raster.naturalWidth / raster.naturalHeight : 1;
1426
+ const src = t.href;
1427
+ out.push({
1428
+ text: OBJECT_REPLACEMENT,
1429
+ style: inherited,
1430
+ object: {
1431
+ width: height * aspect,
1432
+ height,
1433
+ // Sits on the baseline like a cap-height glyph rather than hanging
1434
+ // below it; an image has no descender to align.
1435
+ depth: 0,
1436
+ // The accessible name, and what a copy yields. Without it the
1437
+ // invisible U+FFFC sentinel is all a screen reader receives.
1438
+ alt: t.text,
1439
+ // What this object PAINTS, which `alt` does not determine: two badges
1440
+ // can share alt text and differ in URL. Without it the paragraph memo
1441
+ // serves the first one's painter to the second and every row of a badge
1442
+ // column draws the first row's badge.
1443
+ key: src,
1444
+ paint: (surface, box) => paintInlineImage(src, surface, box)
1445
+ }
1446
+ });
1447
+ break;
1385
1448
  }
1386
- if (closed) {
1387
- flush(theme.codeColor);
1388
- segments.push({ text: line.slice(i, j + 1), color: STRING_COLOR });
1389
- i = j + 1;
1390
- continue;
1449
+ case "link": {
1450
+ const t = token;
1451
+ const linkStyle = {
1452
+ ...inherited,
1453
+ href: t.href,
1454
+ color: theme.linkColor
1455
+ };
1456
+ if (t.tokens && t.tokens.length > 0) {
1457
+ collectSpans(t.tokens, linkStyle, theme, out, blockFontSize);
1458
+ } else {
1459
+ out.push({ text: decodeEntities(t.text), style: linkStyle });
1460
+ }
1461
+ break;
1462
+ }
1463
+ case "text": {
1464
+ const t = token;
1465
+ if ("tokens" in t && t.tokens?.length) {
1466
+ collectSpans(t.tokens, inherited, theme, out, blockFontSize);
1467
+ } else {
1468
+ const decoded = decodeEntities(t.text);
1469
+ if (decoded) {
1470
+ const style = Object.keys(inherited).length > 0 ? inherited : void 0;
1471
+ out.push({ text: decoded, style });
1472
+ }
1473
+ }
1474
+ break;
1475
+ }
1476
+ default: {
1477
+ if ("text" in token) {
1478
+ const decoded = decodeEntities(token.text);
1479
+ if (decoded) {
1480
+ const style = Object.keys(inherited).length > 0 ? inherited : void 0;
1481
+ out.push({ text: decoded, style });
1482
+ }
1483
+ }
1484
+ break;
1391
1485
  }
1392
- buf += ch;
1393
- i++;
1394
- continue;
1395
1486
  }
1396
- if (/\d/.test(ch) && (i === 0 || /[\s(,=+\-*/<>[\]{}:;]/.test(line[i - 1]))) {
1397
- flush(theme.codeColor);
1398
- let j = i;
1399
- while (j < line.length && /[\d._xXa-fA-F]/.test(line[j])) j++;
1400
- segments.push({ text: line.slice(i, j), color: NUMBER_COLOR });
1401
- i = j;
1402
- continue;
1487
+ }
1488
+ }
1489
+ function findUnclosedInline(text) {
1490
+ let best = null;
1491
+ const tick = text.lastIndexOf("`");
1492
+ if (tick !== -1 && tick < text.length - 1) {
1493
+ return { kind: "codespan", at: tick, contentAt: tick + 1 };
1494
+ }
1495
+ if (tick !== -1) return null;
1496
+ const emphasis = /(\*{1,2}(?!\*)|_{1,2}(?!_))(?=[^\s])/g;
1497
+ for (let match = emphasis.exec(text); match !== null; match = emphasis.exec(text)) {
1498
+ const marker = match[1];
1499
+ const at = match.index;
1500
+ if (marker[0] === "_" && at > 0 && /[\w]/.test(text[at - 1])) continue;
1501
+ best = {
1502
+ kind: marker.length === 2 ? "strong" : "em",
1503
+ at,
1504
+ contentAt: at + marker.length
1505
+ };
1506
+ }
1507
+ const bracket = text.lastIndexOf("[");
1508
+ if (bracket !== -1 && bracket < text.length - 1 && (best === null || bracket > best.at)) {
1509
+ const closed = /\]\([^)]*\)/.test(text.slice(bracket));
1510
+ if (!closed) {
1511
+ best = { kind: "link", at: bracket, contentAt: bracket + 1 };
1512
+ }
1513
+ }
1514
+ return best;
1515
+ }
1516
+ function renderInlineToRichText(tokens, fallbackText, font, color, maxWidth, theme, selectable, onLinkClick) {
1517
+ const spans = [];
1518
+ if (tokens && tokens.length > 0) {
1519
+ collectSpans(tokens, {}, theme, spans, fontSizeFromFont(font));
1520
+ }
1521
+ if (spans.length === 0) {
1522
+ spans.push({ text: decodeEntities(fallbackText) });
1523
+ }
1524
+ return new RichText(spans, {
1525
+ font,
1526
+ color,
1527
+ maxWidth,
1528
+ linkColor: theme.linkColor,
1529
+ selectable,
1530
+ onLinkClick
1531
+ });
1532
+ }
1533
+
1534
+ // src/Markdown.ts
1535
+ import { RichText as RichText2, Stack, Table, Text, Image, UIComponent as UIComponent3 } from "@vectojs/ui";
1536
+
1537
+ // src/blockAffordances.ts
1538
+ import { Button, measureText as measureText2, UIComponent as UIComponent2 } from "@vectojs/ui";
1539
+ var LANGUAGE_EXTENSIONS = {
1540
+ bash: "sh",
1541
+ c: "c",
1542
+ cpp: "cpp",
1543
+ cs: "cs",
1544
+ css: "css",
1545
+ diff: "diff",
1546
+ dockerfile: "dockerfile",
1547
+ go: "go",
1548
+ graphql: "graphql",
1549
+ haskell: "hs",
1550
+ html: "html",
1551
+ java: "java",
1552
+ javascript: "js",
1553
+ js: "js",
1554
+ json: "json",
1555
+ jsonc: "jsonc",
1556
+ jsx: "jsx",
1557
+ kotlin: "kt",
1558
+ latex: "tex",
1559
+ lua: "lua",
1560
+ make: "mk",
1561
+ markdown: "md",
1562
+ md: "md",
1563
+ nix: "nix",
1564
+ php: "php",
1565
+ python: "py",
1566
+ py: "py",
1567
+ ruby: "rb",
1568
+ rust: "rs",
1569
+ rs: "rs",
1570
+ scss: "scss",
1571
+ sh: "sh",
1572
+ shell: "sh",
1573
+ sql: "sql",
1574
+ svelte: "svelte",
1575
+ swift: "swift",
1576
+ tex: "tex",
1577
+ toml: "toml",
1578
+ ts: "ts",
1579
+ tsx: "tsx",
1580
+ typescript: "ts",
1581
+ vue: "vue",
1582
+ xml: "xml",
1583
+ yaml: "yaml",
1584
+ yml: "yaml",
1585
+ zig: "zig",
1586
+ zsh: "sh"
1587
+ };
1588
+ function extensionForLanguage(lang) {
1589
+ const first = lang.trim().toLowerCase().split(/[\s:,{]/)[0] ?? "";
1590
+ return LANGUAGE_EXTENSIONS[first] ?? "txt";
1591
+ }
1592
+ function mimeForLanguage(lang) {
1593
+ const ext = extensionForLanguage(lang);
1594
+ if (ext === "json" || ext === "jsonc") return "application/json";
1595
+ if (ext === "html") return "text/html";
1596
+ if (ext === "css") return "text/css";
1597
+ if (ext === "xml" || ext === "svelte" || ext === "vue") return "text/plain";
1598
+ return "text/plain";
1599
+ }
1600
+ function escapeCsvField(value) {
1601
+ let needsQuoting = false;
1602
+ let hasQuote = false;
1603
+ for (const char of value) {
1604
+ if (char === '"') {
1605
+ hasQuote = true;
1606
+ needsQuoting = true;
1607
+ break;
1403
1608
  }
1404
- if (/[a-zA-Z_]/.test(ch)) {
1405
- flush(theme.codeColor);
1406
- let j = i;
1407
- while (j < line.length && /[a-zA-Z0-9_]/.test(line[j])) j++;
1408
- const word = line.slice(i, j);
1409
- segments.push({
1410
- text: word,
1411
- color: keywords.has(word) ? KEYWORD_COLOR : theme.codeColor
1412
- });
1413
- i = j;
1414
- continue;
1609
+ if (char === "," || char === "\n" || char === "\r") needsQuoting = true;
1610
+ }
1611
+ if (!needsQuoting) return value;
1612
+ return hasQuote ? `"${value.replace(/"/g, '""')}"` : `"${value}"`;
1613
+ }
1614
+ function escapeMarkdownTableCell(cell) {
1615
+ let needsEscaping = false;
1616
+ for (const char of cell) {
1617
+ if (char === "\\" || char === "|") {
1618
+ needsEscaping = true;
1619
+ break;
1415
1620
  }
1416
- buf += ch;
1417
- i++;
1418
1621
  }
1419
- flush(theme.codeColor);
1420
- return segments;
1622
+ if (!needsEscaping) return cell;
1623
+ return cell.replace(/\\/g, "\\\\").replace(/\|/g, "\\|");
1421
1624
  }
1422
- var CodeBlock = class extends UIComponent2 {
1423
- lines;
1424
- grid = null;
1425
- /** Raw (unhighlighted) lines of the last build, for prefix reuse in buildLines. */
1426
- rawLines = null;
1427
- cellWidth = 0;
1428
- source;
1429
- /** Bumped by {@link buildLines} and {@link setSelectable}; read by `Scene`. */
1430
- contentEpoch = 0;
1431
- lang;
1432
- theme;
1433
- lineH = 24;
1434
- pad = 18;
1435
- codeFont;
1436
- selectable;
1437
- constructor(code, lang, maxWidth, theme, selectable = true) {
1438
- super();
1439
- this.source = code;
1440
- this.lang = lang;
1441
- this.theme = theme;
1442
- this.codeFont = `15px ${theme.codeFont}`;
1443
- this.selectable = selectable;
1444
- this.lines = [];
1445
- this.width = maxWidth;
1446
- this.buildLines(code);
1625
+ function tableToCsv(table) {
1626
+ const lines = [table.headers.map(escapeCsvField).join(",")];
1627
+ for (const row of table.rows) lines.push(row.map(escapeCsvField).join(","));
1628
+ return `\uFEFF${lines.join("\r\n")}`;
1629
+ }
1630
+ function tableToMarkdown(table) {
1631
+ const header = `| ${table.headers.map(escapeMarkdownTableCell).join(" | ")} |`;
1632
+ const divider = `| ${table.headers.map((_cell, index) => {
1633
+ switch (table.align[index]) {
1634
+ case "left":
1635
+ return ":---";
1636
+ case "center":
1637
+ return ":---:";
1638
+ case "right":
1639
+ return "---:";
1640
+ default:
1641
+ return "---";
1642
+ }
1643
+ }).join(" | ")} |`;
1644
+ const body = table.rows.map(
1645
+ (row) => `| ${table.headers.map((_cell, index) => escapeMarkdownTableCell(row[index] ?? "")).join(" | ")} |`
1646
+ );
1647
+ return [header, divider, ...body].join("\n");
1648
+ }
1649
+ function defaultWriteClipboard(text) {
1650
+ const clipboard = globalThis.navigator?.clipboard;
1651
+ clipboard?.writeText?.(text);
1652
+ }
1653
+ function defaultSaveFile(filename, content, mimeType) {
1654
+ const doc = globalThis.document;
1655
+ if (!doc?.body) return;
1656
+ const blob = new Blob([content], { type: mimeType });
1657
+ const url = URL.createObjectURL(blob);
1658
+ const anchor = doc.createElement("a");
1659
+ anchor.href = url;
1660
+ anchor.download = filename;
1661
+ doc.body.appendChild(anchor);
1662
+ anchor.click();
1663
+ doc.body.removeChild(anchor);
1664
+ URL.revokeObjectURL(url);
1665
+ }
1666
+ var BlockAffordanceButton = class _BlockAffordanceButton extends Button {
1667
+ constructor(label, successLabel, act, opts = {}) {
1668
+ super(label, { ...opts, onClick: () => this.run() });
1669
+ this.act = act;
1670
+ this.restingLabel = label;
1671
+ this.successLabel = successLabel;
1672
+ this.width = Math.max(this.width, measureText2(successLabel, this.font) + 24);
1447
1673
  }
1448
- /** Re-parse code content (e.g. for live editing). */
1449
- setCode(code, lang) {
1450
- if (lang !== void 0) this.lang = lang;
1451
- this.source = code;
1452
- this.buildLines(code);
1453
- this.scene?.markDirty();
1454
- return this;
1674
+ act;
1675
+ /** How long the confirmation label stays up, in ms. */
1676
+ static FEEDBACK_MS = 1600;
1677
+ restingLabel;
1678
+ successLabel;
1679
+ feedbackTimer;
1680
+ /**
1681
+ * Runs the action, then shows the confirmation.
1682
+ *
1683
+ * The action runs first and a throw propagates: a clipboard write the browser
1684
+ * rejected must not be reported as a success.
1685
+ */
1686
+ run() {
1687
+ this.act();
1688
+ this.setTransientLabel(this.successLabel);
1689
+ if (this.feedbackTimer !== void 0) clearTimeout(this.feedbackTimer);
1690
+ this.feedbackTimer = setTimeout(() => {
1691
+ this.setTransientLabel(this.restingLabel);
1692
+ this.feedbackTimer = void 0;
1693
+ }, _BlockAffordanceButton.FEEDBACK_MS);
1455
1694
  }
1456
- /** Enable or disable browser-native selection for this code block. */
1457
- setSelectable(selectable) {
1458
- this.selectable = selectable;
1459
- this.contentEpoch++;
1695
+ setTransientLabel(label) {
1696
+ this.label = label;
1697
+ this.textWidth = measureText2(label, this.font);
1460
1698
  this.scene?.markDirty();
1461
- return this;
1462
- }
1463
- getContentEpoch() {
1464
- return this.contentEpoch;
1465
1699
  }
1466
1700
  /**
1467
- * Change the block's box width.
1468
- *
1469
- * Deliberately does **not** rebuild the grid or the highlight, because code does
1470
- * not reflow: lines are placed on a fixed monospace grid at `col × cellWidth` and
1471
- * a long line overflows rather than wrapping, so `height` is a function of line
1472
- * *count* alone. The width only sizes the rounded background. Anything that would
1473
- * change the glyph geometry — the source, the language, the font — goes through
1474
- * {@link setCode} and invalidates the grid there.
1475
- *
1476
- * @returns `this` for chaining.
1701
+ * The label a reader hears is the one they see, transient confirmation
1702
+ * included, so an AT user gets the same feedback a sighted user does.
1477
1703
  */
1478
- setWidth(width) {
1479
- const next = Math.max(0, width);
1480
- if (next === this.width) return this;
1481
- this.width = next;
1482
- this.scene?.markDirty();
1483
- return this;
1704
+ getA11yAttributes() {
1705
+ return { ...super.getA11yAttributes(), label: this.label };
1484
1706
  }
1485
- getContentProjection(hint) {
1486
- if (!this.source) return null;
1487
- const grid = this.ensureGrid();
1488
- const rows = [];
1489
- rows.length = grid.lines.length;
1490
- for (let row = 0; row < grid.lines.length; row++) {
1491
- const line = grid.lines[row];
1492
- const y = this.pad + row * this.lineH;
1493
- if (!contentLineInHint(hint, y, this.lineH)) continue;
1494
- rows[row] = {
1495
- text: this.source.slice(line.sourceStart, line.sourceEnd),
1496
- separatorAfter: this.source.slice(line.sourceEnd, line.nextSourceStart) || void 0,
1497
- x: this.pad,
1498
- y,
1499
- baseline: this.lineH * 0.75,
1500
- font: this.codeFont,
1501
- lineHeight: this.lineH
1502
- };
1707
+ /** Clears the pending revert so a destroyed block leaves no timer behind. */
1708
+ destroy() {
1709
+ if (this.feedbackTimer !== void 0) {
1710
+ clearTimeout(this.feedbackTimer);
1711
+ this.feedbackTimer = void 0;
1712
+ }
1713
+ super.destroy();
1714
+ }
1715
+ };
1716
+ var BlockWithAffordances = class _BlockWithAffordances extends UIComponent2 {
1717
+ constructor(block, controls) {
1718
+ super();
1719
+ this.block = block;
1720
+ this.controls = controls;
1721
+ this.add(block);
1722
+ for (const control of controls) this.add(control);
1723
+ this.layoutAffordances();
1724
+ }
1725
+ block;
1726
+ controls;
1727
+ /** Gap between the block's edges and the controls, in px. */
1728
+ static INSET = 8;
1729
+ /** Gap between adjacent controls, in px. */
1730
+ static GAP = 6;
1731
+ /**
1732
+ * Places the controls right-aligned along the block's top edge.
1733
+ *
1734
+ * Laid out right-to-left from the block's right edge so the first control in
1735
+ * the list ends up leftmost, which keeps DOM order (and therefore tab order and
1736
+ * the a11y reading order) matching the visual order.
1737
+ */
1738
+ layoutAffordances() {
1739
+ this.width = this.block.width;
1740
+ this.height = this.block.height;
1741
+ let right = this.block.width - _BlockWithAffordances.INSET;
1742
+ for (let i = this.controls.length - 1; i >= 0; i--) {
1743
+ const control = this.controls[i];
1744
+ control.x = right - control.width;
1745
+ control.y = _BlockWithAffordances.INSET;
1746
+ right = control.x - _BlockWithAffordances.GAP;
1503
1747
  }
1504
- return {
1505
- text: this.source,
1506
- font: this.codeFont,
1507
- lineHeight: this.lineH,
1508
- // Every row is absolutely positioned from the same local coordinates as
1509
- // render(). A single pre-wrap DOM text node would introduce browser
1510
- // wrapping for long source lines that canvas intentionally keeps intact.
1511
- //
1512
- lines: rows,
1513
- selectable: this.selectable,
1514
- // render() draws cell-by-cell (no ligatures can form); the DOM copy
1515
- // must not ligate either or Firefox selection geometry drifts.
1516
- ligatures: "none",
1517
- grid
1518
- };
1519
1748
  }
1520
1749
  /**
1521
- * Re-highlight the code, reusing the highlight of any unchanged line prefix.
1522
- *
1523
- * Streaming appends to the END of a block, so all but the last line or two are
1524
- * byte-identical to the previous call — yet this used to re-highlight every
1525
- * line on every chunk, making a streamed block O(N) per append and O(N^2)
1526
- * overall. Reusing the stable prefix makes an append proportional to what
1527
- * actually changed.
1750
+ * Re-places the controls after the block's own box changed.
1528
1751
  *
1529
- * The last previously-seen line is deliberately NOT reused: a chunk usually
1530
- * lands mid-line, so that line's text (and therefore its tokenization) changes.
1752
+ * Called by the owner when a block is resized or its content grew; the controls
1753
+ * are anchored to the right edge, so a width change moves them.
1531
1754
  */
1532
- buildLines(code) {
1533
- this.contentEpoch++;
1534
- const rawLines = code.split(/\r\n|\r|\n/);
1535
- const previous = this.rawLines;
1536
- let reusable = 0;
1537
- if (previous && this.lines.length === previous.length) {
1538
- const limit = Math.min(previous.length - 1, rawLines.length);
1539
- while (reusable < limit && previous[reusable] === rawLines[reusable]) reusable++;
1540
- }
1541
- if (reusable > 0) {
1542
- const next = this.lines.slice(0, reusable);
1543
- for (let i = reusable; i < rawLines.length; i++) {
1544
- next.push(highlightLine(rawLines[i], this.lang, this.theme));
1545
- }
1546
- this.lines = next;
1547
- } else {
1548
- this.lines = rawLines.map((l) => highlightLine(l, this.lang, this.theme));
1549
- }
1550
- this.rawLines = rawLines;
1551
- this.grid = null;
1552
- this.height = this.pad * 2 + rawLines.length * this.lineH;
1755
+ refreshAffordances() {
1756
+ this.layoutAffordances();
1757
+ this.scene?.markDirty();
1553
1758
  }
1554
- ensureGrid() {
1555
- const cellWidth = this.cellWidth || Math.max(1, measureText2("M", this.codeFont));
1556
- if (!this.grid || this.grid.source !== this.source || this.grid.font !== this.codeFont || this.grid.cellWidth !== cellWidth) {
1557
- this.grid = prepareContentGrid(this.source, {
1558
- font: this.codeFont,
1559
- cellWidth,
1560
- lineHeight: this.lineH,
1561
- baseline: this.lineH * 0.75
1562
- });
1563
- }
1564
- return this.grid;
1759
+ /** The wrapper is a pass-through: its size is the block's size. */
1760
+ getLayoutControlledProperties() {
1761
+ return ["x", "y"];
1565
1762
  }
1566
- /** Code blocks are decorative — not interactive. */
1567
- isPointInside() {
1568
- return false;
1763
+ /**
1764
+ * Projected as a group so assistive technology reports one labelled region
1765
+ * containing the block and its controls, rather than two unrelated siblings.
1766
+ */
1767
+ getA11yAttributes() {
1768
+ return { role: "group", pointerEvents: "none" };
1569
1769
  }
1570
- render(r) {
1571
- r.beginPath();
1572
- r.roundRect(0, 0, this.width, this.height, 8);
1573
- r.fill(this.theme.codeBgColor);
1574
- const grid = this.ensureGrid();
1575
- const atlas = codeGlyphAtlas(r);
1576
- const atlasSource = atlas?.source ?? null;
1577
- const blit = atlas ? r.drawImageRect : void 0;
1578
- for (let row = 0; row < grid.lines.length; row++) {
1579
- const yBaseline = this.pad + row * this.lineH + this.lineH * 0.75;
1580
- const segments = this.lines[row];
1581
- let segmentIndex = 0;
1582
- let segmentEnd = segments[0]?.text.length ?? 0;
1583
- const lineStart = grid.lines[row].sourceStart;
1584
- for (const cell of grid.lines[row].cells) {
1585
- const localSourceStart = cell.sourceStart - lineStart;
1586
- while (segmentIndex < segments.length - 1 && localSourceStart >= segmentEnd) {
1587
- segmentIndex++;
1588
- segmentEnd += segments[segmentIndex].text.length;
1589
- }
1590
- const sourceText = this.source.slice(cell.sourceStart, cell.sourceEnd);
1591
- if (cell.advance <= 0 || sourceText === " " || sourceText === " ") continue;
1592
- const color = segments[segmentIndex]?.color ?? this.theme.codeColor;
1593
- const x = this.pad + cell.x;
1594
- if (blit && atlas) {
1595
- const slot = atlas.get(this.codeFont, color, cell.glyph);
1596
- const src = atlasSource ?? atlas.source;
1597
- if (slot && src) {
1598
- blit.call(
1599
- r,
1600
- src,
1601
- slot.sx,
1602
- slot.sy,
1603
- slot.sw,
1604
- slot.sh,
1605
- x - slot.offsetX,
1606
- yBaseline - slot.offsetY,
1607
- slot.w,
1608
- slot.h
1609
- );
1610
- continue;
1611
- }
1612
- }
1613
- r.fillText(cell.glyph, x, yBaseline, this.codeFont, color);
1614
- }
1615
- }
1770
+ render() {
1616
1771
  }
1617
1772
  };
1618
- var codeAtlases = /* @__PURE__ */ new Map();
1619
- var MAX_CODE_ATLASES = 2;
1620
- var lastCodeAtlas = null;
1621
- function codeGlyphAtlas(r) {
1622
- if (typeof r.drawImageRect !== "function") return void 0;
1623
- if (typeof document === "undefined") return void 0;
1624
- const dpr = Math.max(
1625
- 1,
1626
- r.pixelRatio ?? (typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1)
1627
- );
1628
- const existing = codeAtlases.get(dpr);
1629
- if (existing) {
1630
- codeAtlases.delete(dpr);
1631
- codeAtlases.set(dpr, existing);
1632
- lastCodeAtlas = existing;
1633
- return existing;
1773
+ function tableContentOf(token) {
1774
+ return {
1775
+ headers: token.header.map((cell) => cell.text),
1776
+ rows: token.rows.map((row) => row.map((cell) => cell.text)),
1777
+ align: token.align
1778
+ };
1779
+ }
1780
+
1781
+ // src/frontMatter.ts
1782
+ var OPEN_RE = /^---[ \t]*\r?\n/;
1783
+ var OPENER_PREFIX_RE = /^(?:-|--|---[ \t]*\r?)$/;
1784
+ var KEY_RE = /^[^\s:#][^:]*:(?:[ \t].*)?$/;
1785
+ var CLOSE_RE = /^(?:---|\.\.\.)[ \t]*$/;
1786
+ var MAX_PENDING_CHARS = 4096;
1787
+ var NONE = { kind: "none" };
1788
+ var PENDING = { kind: "pending" };
1789
+ function scanFrontMatter(text, complete) {
1790
+ if (text.length === 0) return PENDING;
1791
+ const open = OPEN_RE.exec(text);
1792
+ if (!open) {
1793
+ return !complete && OPENER_PREFIX_RE.test(text) ? PENDING : NONE;
1634
1794
  }
1635
- const atlas = new GlyphRasterAtlas({ dpr, maxSize: 2048 });
1636
- codeAtlases.set(dpr, atlas);
1637
- if (codeAtlases.size > MAX_CODE_ATLASES) {
1638
- const oldestKey = codeAtlases.keys().next().value;
1639
- const oldest = codeAtlases.get(oldestKey);
1640
- codeAtlases.delete(oldestKey);
1641
- if (oldest && oldest !== atlas) oldest.destroy();
1795
+ const decide = complete || text.length > MAX_PENDING_CHARS;
1796
+ const contentStart = open[0].length;
1797
+ let cursor = contentStart;
1798
+ let keyChecked = false;
1799
+ while (cursor < text.length) {
1800
+ const nl = text.indexOf("\n", cursor);
1801
+ if (nl === -1 && !decide) return PENDING;
1802
+ const line = text.slice(cursor, nl === -1 ? text.length : nl).replace(/\r$/, "");
1803
+ if (!keyChecked) {
1804
+ if (!KEY_RE.test(line)) return NONE;
1805
+ keyChecked = true;
1806
+ } else if (CLOSE_RE.test(line)) {
1807
+ return {
1808
+ kind: "found",
1809
+ raw: text.slice(contentStart, cursor),
1810
+ // A closer with no trailing newline ends the document, so the body is
1811
+ // empty rather than starting one character past the end.
1812
+ bodyStart: nl === -1 ? text.length : nl + 1
1813
+ };
1814
+ }
1815
+ if (nl === -1) break;
1816
+ cursor = nl + 1;
1642
1817
  }
1643
- lastCodeAtlas = atlas;
1644
- return atlas;
1818
+ return decide ? NONE : PENDING;
1645
1819
  }
1646
- function codeAtlasStats() {
1647
- return lastCodeAtlas ? lastCodeAtlas.stats : null;
1820
+ function parseFrontMatterFields(raw) {
1821
+ const out = {};
1822
+ for (const rawLine of raw.split("\n")) {
1823
+ const line = rawLine.replace(/\r$/, "");
1824
+ if (line.length === 0 || /^[\s#]/.test(line)) continue;
1825
+ const sep = line.indexOf(":");
1826
+ if (sep <= 0) continue;
1827
+ const value = line.slice(sep + 1);
1828
+ if (value.length > 0 && value[0] !== " " && value[0] !== " ") continue;
1829
+ out[line.slice(0, sep).trim()] = unquote(value.trim());
1830
+ }
1831
+ return out;
1648
1832
  }
1649
- function codeAtlas() {
1650
- return lastCodeAtlas;
1833
+ function unquote(value) {
1834
+ if (value.length < 2) return value;
1835
+ const first = value[0];
1836
+ if ((first === '"' || first === "'") && value.endsWith(first)) {
1837
+ return value.slice(1, -1);
1838
+ }
1839
+ return value;
1651
1840
  }
1652
- function decodeEntities(text) {
1653
- return text.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&amp;/g, "&");
1841
+
1842
+ // src/MarkdownWorkerSource.ts
1843
+ 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';
1844
+
1845
+ // src/Markdown.ts
1846
+ var now = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
1847
+ function lexMarkdown(text, userTiming) {
1848
+ if (!userTiming) return marked.lexer(text);
1849
+ const timing = beginVectoUserTiming(VECTO_USER_TIMING.markdown.parse);
1850
+ try {
1851
+ return marked.lexer(text);
1852
+ } finally {
1853
+ if (timing) endVectoUserTiming(timing);
1854
+ }
1654
1855
  }
1655
- function collectSpans(tokens, inherited, theme, out, blockFontSize) {
1656
- for (const token of tokens) {
1657
- switch (token.type) {
1658
- case "strong": {
1659
- const t = token;
1660
- if (t.tokens) {
1661
- collectSpans(t.tokens, { ...inherited, bold: true }, theme, out, blockFontSize);
1662
- } else {
1663
- out.push({
1664
- text: decodeEntities(t.text),
1665
- style: { ...inherited, bold: true }
1666
- });
1667
- }
1668
- break;
1669
- }
1670
- case "em": {
1671
- const t = token;
1672
- if (t.tokens) {
1673
- collectSpans(t.tokens, { ...inherited, italic: true }, theme, out, blockFontSize);
1674
- } else {
1675
- out.push({
1676
- text: decodeEntities(t.text),
1677
- style: { ...inherited, italic: true }
1678
- });
1856
+ marked.use({
1857
+ extensions: [
1858
+ {
1859
+ name: "blockMath",
1860
+ level: "block",
1861
+ start(src) {
1862
+ return src.match(/^ {0,3}\$\$/m)?.index;
1863
+ },
1864
+ tokenizer(src) {
1865
+ const match = /^ {0,3}\$\$([\s\S]+?)\$\$[ \t]*(?:\n|$)/.exec(src);
1866
+ if (match) {
1867
+ return {
1868
+ type: "blockMath",
1869
+ raw: match[0],
1870
+ text: match[1].trim()
1871
+ };
1679
1872
  }
1680
- break;
1873
+ return void 0;
1874
+ },
1875
+ renderer(token) {
1876
+ return token.raw;
1681
1877
  }
1682
- case "del": {
1683
- const t = token;
1684
- if (t.tokens) {
1685
- collectSpans(t.tokens, { ...inherited, lineThrough: true }, theme, out, blockFontSize);
1686
- } else {
1687
- out.push({
1688
- text: decodeEntities(t.text),
1689
- style: { ...inherited, lineThrough: true }
1690
- });
1878
+ },
1879
+ {
1880
+ name: "inlineMath",
1881
+ level: "inline",
1882
+ start(src) {
1883
+ return src.match(/(?<![\\$])\$(?![$\s])/)?.index;
1884
+ },
1885
+ tokenizer(src) {
1886
+ const match = /^\$(?![$\s\d])((?:\\\$|[^$\n])*?)(?<!\s)\$(?!\d)/.exec(src);
1887
+ if (match) {
1888
+ return {
1889
+ type: "inlineMath",
1890
+ raw: match[0],
1891
+ text: match[1].trim()
1892
+ };
1691
1893
  }
1692
- break;
1693
- }
1694
- case "codespan": {
1695
- const t = token;
1696
- out.push({
1697
- text: decodeEntities(t.text),
1698
- // Inline code renders in the theme's monospace family (not just tinted
1699
- // prose) — TextStyle.fontFamily drives both measurement and drawing.
1700
- style: {
1701
- ...inherited,
1702
- color: theme.codeColor,
1703
- fontFamily: theme.codeFont
1704
- }
1705
- });
1706
- break;
1707
- }
1708
- case "br": {
1709
- out.push({ text: "\n" });
1710
- break;
1711
- }
1712
- case "html": {
1713
- const t = token;
1714
- const raw = t.raw ?? t.text ?? "";
1715
- const brCount = (raw.match(/<br\s*\/?>/gi) ?? []).length;
1716
- for (let i = 0; i < brCount; i++) out.push({ text: "\n" });
1717
- break;
1894
+ return void 0;
1895
+ },
1896
+ renderer(token) {
1897
+ return token.raw;
1718
1898
  }
1719
- case "inlineMath": {
1720
- const t = token;
1721
- const runSize = inherited.fontSize ?? blockFontSize ?? theme.fontSize;
1722
- const runColor = inherited.color ?? theme.textColor;
1723
- const rendered = renderMathToSVGDataURI(t.text, false, runColor);
1724
- if (rendered) {
1725
- const uri = rendered.uri;
1726
- out.push({
1727
- text: OBJECT_REPLACEMENT,
1728
- style: inherited,
1729
- object: {
1730
- width: exToPx(rendered.widthEx, runSize),
1731
- height: exToPx(rendered.heightEx, runSize),
1732
- depth: exToPx(rendered.depthEx, runSize),
1733
- // The TeX source is the accessible name: without it a screen reader
1734
- // receives only the invisible U+FFFC sentinel.
1735
- alt: t.text,
1736
- // Without this the box is reserved and stays empty. The engine does
1737
- // not draw objects, and nothing else in the tree holds the raster.
1738
- paint: (surface, box) => paintInlineMath(uri, surface, box)
1739
- }
1740
- });
1741
- } else {
1742
- out.push({
1743
- text: decodeEntities(t.raw),
1744
- style: { ...inherited, color: "#fcd34d" }
1899
+ }
1900
+ ]
1901
+ });
1902
+ var markdownWorker = null;
1903
+ var workerIdCounter = 0;
1904
+ var workerInstanceCounter = 0;
1905
+ var workerCallbacks = /* @__PURE__ */ new Map();
1906
+ function runSyncFallback(entry) {
1907
+ try {
1908
+ entry.cb(0, lexMarkdown(entry.text, entry.userTiming), true);
1909
+ } catch (err) {
1910
+ console.warn("Markdown sync fallback parse failed", err);
1911
+ entry.onDropped?.();
1912
+ }
1913
+ }
1914
+ if (typeof Worker !== "undefined") {
1915
+ try {
1916
+ const blob = new Blob([WORKER_SOURCE_STRING], {
1917
+ type: "application/javascript"
1918
+ });
1919
+ markdownWorker = new Worker(URL.createObjectURL(blob));
1920
+ markdownWorker.onmessage = (e) => {
1921
+ const { id, matchLen, tail, error, needResync, lexerMs, sourceCharsLexed } = e.data;
1922
+ const entry = workerCallbacks.get(id);
1923
+ if (entry) {
1924
+ workerCallbacks.delete(id);
1925
+ if (needResync && entry.onNeedResync) {
1926
+ entry.onNeedResync();
1927
+ } else if (needResync) {
1928
+ runSyncFallback(entry);
1929
+ } else if (!error) {
1930
+ entry.cb(matchLen, tail, false, {
1931
+ lexerMs: typeof lexerMs === "number" ? lexerMs : 0,
1932
+ sourceCharsLexed: typeof sourceCharsLexed === "number" ? sourceCharsLexed : 0
1745
1933
  });
1746
- }
1747
- break;
1748
- }
1749
- case "link": {
1750
- const t = token;
1751
- const linkStyle = {
1752
- ...inherited,
1753
- href: t.href,
1754
- color: "#38bdf8"
1755
- };
1756
- if (t.tokens && t.tokens.length > 0) {
1757
- collectSpans(t.tokens, linkStyle, theme, out, blockFontSize);
1758
- } else {
1759
- out.push({ text: decodeEntities(t.text), style: linkStyle });
1760
- }
1761
- break;
1762
- }
1763
- case "text": {
1764
- const t = token;
1765
- if ("tokens" in t && t.tokens?.length) {
1766
- collectSpans(t.tokens, inherited, theme, out, blockFontSize);
1767
1934
  } else {
1768
- const decoded = decodeEntities(t.text);
1769
- if (decoded) {
1770
- const style = Object.keys(inherited).length > 0 ? inherited : void 0;
1771
- out.push({ text: decoded, style });
1772
- }
1773
- }
1774
- break;
1775
- }
1776
- default: {
1777
- if ("text" in token) {
1778
- const decoded = decodeEntities(token.text);
1779
- if (decoded) {
1780
- const style = Object.keys(inherited).length > 0 ? inherited : void 0;
1781
- out.push({ text: decoded, style });
1782
- }
1935
+ runSyncFallback(entry);
1783
1936
  }
1784
- break;
1785
1937
  }
1786
- }
1787
- }
1788
- }
1789
- function findUnclosedInline(text) {
1790
- let best = null;
1791
- const tick = text.lastIndexOf("`");
1792
- if (tick !== -1 && tick < text.length - 1) {
1793
- return { kind: "codespan", at: tick, contentAt: tick + 1 };
1794
- }
1795
- if (tick !== -1) return null;
1796
- const emphasis = /(\*{1,2}(?!\*)|_{1,2}(?!_))(?=[^\s])/g;
1797
- for (let match = emphasis.exec(text); match !== null; match = emphasis.exec(text)) {
1798
- const marker = match[1];
1799
- const at = match.index;
1800
- if (marker[0] === "_" && at > 0 && /[\w]/.test(text[at - 1])) continue;
1801
- best = {
1802
- kind: marker.length === 2 ? "strong" : "em",
1803
- at,
1804
- contentAt: at + marker.length
1805
1938
  };
1939
+ markdownWorker.onerror = () => {
1940
+ const pending = [...workerCallbacks.values()];
1941
+ workerCallbacks.clear();
1942
+ markdownWorker = null;
1943
+ for (const entry of pending) runSyncFallback(entry);
1944
+ };
1945
+ } catch (err) {
1946
+ console.warn("Failed to initialize MarkdownWorker", err);
1806
1947
  }
1807
- const bracket = text.lastIndexOf("[");
1808
- if (bracket !== -1 && bracket < text.length - 1 && (best === null || bracket > best.at)) {
1809
- const closed = /\]\([^)]*\)/.test(text.slice(bracket));
1810
- if (!closed) {
1811
- best = { kind: "link", at: bracket, contentAt: bracket + 1 };
1812
- }
1813
- }
1814
- return best;
1815
- }
1816
- function renderInlineToRichText(tokens, fallbackText, font, color, maxWidth, theme, selectable, onLinkClick) {
1817
- const spans = [];
1818
- if (tokens && tokens.length > 0) {
1819
- collectSpans(tokens, {}, theme, spans, fontSizeFromFont(font));
1820
- }
1821
- if (spans.length === 0) {
1822
- spans.push({ text: decodeEntities(fallbackText) });
1823
- }
1824
- return new RichText(spans, {
1825
- font,
1826
- color,
1827
- maxWidth,
1828
- linkColor: "#38bdf8",
1829
- selectable,
1830
- onLinkClick
1831
- });
1832
1948
  }
1833
- var Markdown = class _Markdown extends UIComponent2 {
1949
+ var Markdown = class _Markdown extends UIComponent3 {
1834
1950
  content;
1835
1951
  maxWidth;
1836
1952
  theme;
@@ -1923,6 +2039,20 @@ var Markdown = class _Markdown extends UIComponent2 {
1923
2039
  * field only so {@link destroy} can remove the exact closure it added.
1924
2040
  */
1925
2041
  inlineMathRepaint;
2042
+ /**
2043
+ * This instance's entry in the inline-image decode waiters, or `undefined` if it
2044
+ * has never rendered an image. Held as a field only so {@link destroy} can remove
2045
+ * the exact closure it added.
2046
+ */
2047
+ inlineImageRemeasure;
2048
+ /**
2049
+ * URLs whose decoded aspect ratio this document has already reserved a box for.
2050
+ *
2051
+ * The guard that makes the re-measure fire once per image rather than once per
2052
+ * decode-notification-per-image: the waiter set is module-level, so a page of
2053
+ * many documents tells all of them about all decodes.
2054
+ */
2055
+ inlineImagesMeasured = /* @__PURE__ */ new Set();
1926
2056
  /**
1927
2057
  * True while this document is waiting on the lazy MathJax load.
1928
2058
  *
@@ -2068,14 +2198,17 @@ var Markdown = class _Markdown extends UIComponent2 {
2068
2198
  constructor(markdownText, opts = {}) {
2069
2199
  super();
2070
2200
  this.maxWidth = opts.maxWidth ?? 800;
2071
- this.theme = { ...DEFAULT_THEME, ...opts.theme };
2201
+ this.theme = resolveTheme(opts.theme);
2072
2202
  this.onLinkClick = opts.onLinkClick;
2073
2203
  this.selectable = opts.selectable ?? true;
2074
2204
  this._userTiming = opts.userTiming ?? false;
2075
2205
  this.blockAffordances = opts.blockAffordances ?? false;
2076
2206
  this.writeClipboard = opts.writeClipboard ?? defaultWriteClipboard;
2077
2207
  this.saveFile = opts.saveFile ?? defaultSaveFile;
2078
- this.content = new Stack({ direction: "vertical", gap: 16 });
2208
+ this.content = new Stack({
2209
+ direction: "vertical",
2210
+ gap: this.theme.blockGap
2211
+ });
2079
2212
  this.add(this.content);
2080
2213
  this.rawMarkdown = "";
2081
2214
  this.setTokens([]);
@@ -2294,14 +2427,14 @@ var Markdown = class _Markdown extends UIComponent2 {
2294
2427
  switch (token.type) {
2295
2428
  case "heading":
2296
2429
  case "paragraph": {
2297
- if (entity instanceof RichText) {
2430
+ if (entity instanceof RichText2) {
2298
2431
  entity.setMaxWidth(availableWidth);
2299
2432
  return;
2300
2433
  }
2301
2434
  if (entity instanceof Stack) {
2302
2435
  entity.maxWidth = availableWidth;
2303
2436
  for (const run of entity.children) {
2304
- if (run instanceof RichText) run.setMaxWidth(availableWidth);
2437
+ if (run instanceof RichText2) run.setMaxWidth(availableWidth);
2305
2438
  else if (run instanceof Image) this.refitParagraphImage(run, availableWidth);
2306
2439
  }
2307
2440
  entity.layout();
@@ -2317,7 +2450,7 @@ var Markdown = class _Markdown extends UIComponent2 {
2317
2450
  const bqToken = token;
2318
2451
  const innerStack = entity.children.find((c) => c instanceof Stack);
2319
2452
  const border = entity.children.find((c) => c instanceof QuoteBorder);
2320
- const indentStart = Math.min(16, availableWidth);
2453
+ const indentStart = Math.min(this.theme.quoteIndent, availableWidth);
2321
2454
  const childWidth = Math.max(0, availableWidth - indentStart);
2322
2455
  if (innerStack instanceof Stack && bqToken.tokens) {
2323
2456
  let index = 0;
@@ -2344,7 +2477,7 @@ var Markdown = class _Markdown extends UIComponent2 {
2344
2477
  case "list": {
2345
2478
  if (!(entity instanceof Stack)) return;
2346
2479
  for (const item of entity.children) {
2347
- if (item instanceof RichText) item.setMaxWidth(availableWidth);
2480
+ if (item instanceof RichText2) item.setMaxWidth(availableWidth);
2348
2481
  }
2349
2482
  entity.layout();
2350
2483
  return;
@@ -2420,7 +2553,98 @@ var Markdown = class _Markdown extends UIComponent2 {
2420
2553
  this.scene?.markDirty();
2421
2554
  };
2422
2555
  this.inlineMathRepaint = repaint;
2423
- inlineMathRasterWaiters.add(repaint);
2556
+ subscribeInlineMathRaster(repaint);
2557
+ }
2558
+ /**
2559
+ * Re-measure this document when an inline image's raster finishes decoding.
2560
+ *
2561
+ * Inline images differ from inline formulas in one way that matters: a formula's
2562
+ * box is known synchronously the moment it typesets, while an image's aspect
2563
+ * ratio arrives only with the decode. The span reserved a square until then, so a
2564
+ * decode that reports anything else has invalidated a WIDTH, and a repaint into
2565
+ * the old box would letterbox or stretch the picture.
2566
+ *
2567
+ * So this rebuilds through {@link retypesetFromTokens} — the same late-arrival
2568
+ * path MathJax uses — but only when a reserved width actually changed. Every live
2569
+ * document is notified for every decode, including images it does not contain, so
2570
+ * an unconditional rebuild here would be O(documents x images) full re-renders
2571
+ * for a page of many blocks.
2572
+ *
2573
+ * Subscribed lazily and held as a field for the same two reasons as its math
2574
+ * counterpart: a document with no images costs nothing, and `destroy` must remove
2575
+ * the exact closure it added.
2576
+ */
2577
+ subscribeInlineImageRemeasure() {
2578
+ if (this.inlineImageRemeasure || this.isDestroyed) return;
2579
+ const remeasure = () => {
2580
+ if (this.isDestroyed) return;
2581
+ if (this.inlineImageBoxesStale()) this.retypesetFromTokens();
2582
+ else this.scene?.markDirty();
2583
+ };
2584
+ this.inlineImageRemeasure = remeasure;
2585
+ subscribeInlineImageRaster(remeasure);
2586
+ }
2587
+ /**
2588
+ * Whether any inline image in this document has just learned it is not square.
2589
+ *
2590
+ * An inline image's span reserves a square box before its raster decodes, because
2591
+ * that is the only shape available without a natural size. The decode supplies the
2592
+ * real aspect ratio, so a non-square image needs one rebuild to reserve the right
2593
+ * width — and exactly one. Every live document is notified of every decode on the
2594
+ * page, including images it does not contain, so this has to answer "did MY
2595
+ * geometry just change" and not merely "did something decode".
2596
+ *
2597
+ * Walks the tokens rather than the entity tree: the reserved box is a function of
2598
+ * the raster's aspect ratio, which is available here, and a token walk cannot be
2599
+ * confused by an entity a previous rebuild already corrected.
2600
+ *
2601
+ * Only headings and table cells are inspected. Every other context splits an image
2602
+ * into its own block whose `Image` entity resizes itself in `onLoad`, so a rebuild
2603
+ * for one of those would be pure cost.
2604
+ */
2605
+ inlineImageBoxesStale() {
2606
+ const stale = (tokens) => {
2607
+ let changed2 = false;
2608
+ for (const token of tokens ?? []) {
2609
+ if (token.type === "image") {
2610
+ const href = token.href;
2611
+ if (this.inlineImagesMeasured.has(href)) continue;
2612
+ const raster = ensureInlineImageRaster(href);
2613
+ if (raster.failed) {
2614
+ this.inlineImagesMeasured.add(href);
2615
+ changed2 = true;
2616
+ continue;
2617
+ }
2618
+ if (!raster.decoded || !raster.naturalWidth || !raster.naturalHeight) {
2619
+ continue;
2620
+ }
2621
+ this.inlineImagesMeasured.add(href);
2622
+ if (raster.naturalWidth !== raster.naturalHeight) changed2 = true;
2623
+ continue;
2624
+ }
2625
+ if (stale(token.tokens)) {
2626
+ changed2 = true;
2627
+ }
2628
+ }
2629
+ return changed2;
2630
+ };
2631
+ let changed = false;
2632
+ for (const token of this.tokens) {
2633
+ if (token.type === "heading") {
2634
+ if (stale(token.tokens)) changed = true;
2635
+ } else if (token.type === "table") {
2636
+ const table = token;
2637
+ for (const cell of table.header) {
2638
+ if (stale(cell.tokens)) changed = true;
2639
+ }
2640
+ for (const row of table.rows) {
2641
+ for (const cell of row) {
2642
+ if (stale(cell.tokens)) changed = true;
2643
+ }
2644
+ }
2645
+ }
2646
+ }
2647
+ return changed;
2424
2648
  }
2425
2649
  destroy() {
2426
2650
  this.isDestroyed = true;
@@ -2433,9 +2657,13 @@ var Markdown = class _Markdown extends UIComponent2 {
2433
2657
  this.mathLoadPending = false;
2434
2658
  this.flushAppendSettledWaiters();
2435
2659
  if (this.inlineMathRepaint) {
2436
- inlineMathRasterWaiters.delete(this.inlineMathRepaint);
2660
+ unsubscribeInlineMathRaster(this.inlineMathRepaint);
2437
2661
  this.inlineMathRepaint = void 0;
2438
2662
  }
2663
+ if (this.inlineImageRemeasure) {
2664
+ unsubscribeInlineImageRaster(this.inlineImageRemeasure);
2665
+ this.inlineImageRemeasure = void 0;
2666
+ }
2439
2667
  markdownWorker?.postMessage({
2440
2668
  instance: this.workerInstanceId,
2441
2669
  dispose: true
@@ -2829,11 +3057,11 @@ var Markdown = class _Markdown extends UIComponent2 {
2829
3057
  }
2830
3058
  /** One text run of an image-bearing paragraph, as both paths build it. */
2831
3059
  inlineRunRichText(tokens, availableWidth, t) {
2832
- return new RichText(this.inlineRunSpans(tokens, t), {
3060
+ return new RichText2(this.inlineRunSpans(tokens, t), {
2833
3061
  font: `${t.fontSize}px ${t.bodyFont}`,
2834
3062
  color: t.textColor,
2835
3063
  maxWidth: availableWidth,
2836
- linkColor: "#38bdf8",
3064
+ linkColor: t.linkColor,
2837
3065
  selectable: this.selectable,
2838
3066
  onLinkClick: this.onLinkClick
2839
3067
  });
@@ -2937,7 +3165,7 @@ var Markdown = class _Markdown extends UIComponent2 {
2937
3165
  width: initialWidth,
2938
3166
  height: initialHeight,
2939
3167
  alt: imgToken.text,
2940
- radius: 8,
3168
+ radius: this.theme.imageRadius,
2941
3169
  onLoad: () => {
2942
3170
  const bmp = img.bitmap;
2943
3171
  if (bmp && bmp.naturalWidth && bmp.naturalHeight) {
@@ -2952,11 +3180,11 @@ var Markdown = class _Markdown extends UIComponent2 {
2952
3180
  }
2953
3181
  /** One table cell entity, shared by the render arm and the streamed-table path. */
2954
3182
  tableCellRichText(cell, header, t) {
2955
- return new RichText(this.tableCellSpans(cell, t), {
2956
- font: `${t.fontSize - 2}px ${t.bodyFont}`,
3183
+ return new RichText2(this.tableCellSpans(cell, t), {
3184
+ font: `${t.tableFontSize}px ${t.bodyFont}`,
2957
3185
  color: header ? t.headingColor : t.textColor,
2958
3186
  baseStyle: header ? { bold: true } : void 0,
2959
- linkColor: "#38bdf8",
3187
+ linkColor: t.linkColor,
2960
3188
  selectable: this.selectable,
2961
3189
  onLinkClick: this.onLinkClick
2962
3190
  });
@@ -3038,7 +3266,7 @@ var Markdown = class _Markdown extends UIComponent2 {
3038
3266
  listItemBlockStack(token, index, availableWidth, t) {
3039
3267
  const item = token.items[index];
3040
3268
  const children = item.tokens ?? [];
3041
- const stack = new Stack({ direction: "vertical", gap: 4 });
3269
+ const stack = new Stack({ direction: "vertical", gap: t.listItemGap });
3042
3270
  const first = children[0];
3043
3271
  const firstIsInline = Boolean(first) && (first.type === "text" || first.type === "paragraph");
3044
3272
  const leadHasImage = firstIsInline && containsImage(first.tokens);
@@ -3110,11 +3338,11 @@ var Markdown = class _Markdown extends UIComponent2 {
3110
3338
  }
3111
3339
  /** Construct the `RichText` for one list item. */
3112
3340
  listItemRichText(token, index, availableWidth, t) {
3113
- return new RichText(this.listItemSpans(token, index), {
3341
+ return new RichText2(this.listItemSpans(token, index), {
3114
3342
  font: `${t.fontSize}px ${t.bodyFont}`,
3115
3343
  color: t.textColor,
3116
3344
  maxWidth: availableWidth,
3117
- linkColor: "#38bdf8",
3345
+ linkColor: t.linkColor,
3118
3346
  selectable: this.selectable,
3119
3347
  onLinkClick: this.onLinkClick
3120
3348
  });
@@ -3238,7 +3466,7 @@ var Markdown = class _Markdown extends UIComponent2 {
3238
3466
  entity.add(this.inlineRunRichText(newTail, availableWidth, t));
3239
3467
  } else {
3240
3468
  const tailEntity = entity.children[entity.children.length - 1];
3241
- if (!(tailEntity instanceof RichText)) return false;
3469
+ if (!(tailEntity instanceof RichText2)) return false;
3242
3470
  tailEntity.setSpans(this.inlineRunSpans(newTail, t));
3243
3471
  }
3244
3472
  const last = entity.children[entity.children.length - 1];
@@ -3291,7 +3519,7 @@ var Markdown = class _Markdown extends UIComponent2 {
3291
3519
  if (lastRetained >= 0) {
3292
3520
  for (let c = 0; c < oldToken.header.length; c++) {
3293
3521
  const cell = entity.rows[lastRetained]?.[c];
3294
- if (!(cell instanceof RichText)) return false;
3522
+ if (!(cell instanceof RichText2)) return false;
3295
3523
  }
3296
3524
  }
3297
3525
  const t = this.theme;
@@ -3464,12 +3692,12 @@ var Markdown = class _Markdown extends UIComponent2 {
3464
3692
  * queued while the first is outstanding.
3465
3693
  */
3466
3694
  ensureMathJax() {
3467
- if (mathConverter || this.mathLoadPending || this.isDestroyed) return;
3695
+ if (isMathJaxReady() || this.mathLoadPending || this.isDestroyed) return;
3468
3696
  this.mathLoadPending = true;
3469
3697
  void preloadMathJax().then(() => {
3470
3698
  this.mathLoadPending = false;
3471
3699
  if (this.isDestroyed) return;
3472
- if (mathConverter) this.retypesetFromTokens();
3700
+ if (isMathJaxReady()) this.retypesetFromTokens();
3473
3701
  this.flushAppendSettledWaiters();
3474
3702
  });
3475
3703
  }
@@ -3789,10 +4017,10 @@ var Markdown = class _Markdown extends UIComponent2 {
3789
4017
  const width = intrinsicW * scale;
3790
4018
  const height = intrinsicH * scale;
3791
4019
  const uri = mathData.uri;
3792
- const math = new RichText(
4020
+ const math = new RichText2(
3793
4021
  [
3794
4022
  {
3795
- text: OBJECT_REPLACEMENT,
4023
+ text: OBJECT_REPLACEMENT2,
3796
4024
  object: {
3797
4025
  width,
3798
4026
  height,
@@ -3832,15 +4060,15 @@ var Markdown = class _Markdown extends UIComponent2 {
3832
4060
  };
3833
4061
  const availableWidth = metrics.availableWidth;
3834
4062
  if (containsInlineMath(token)) {
3835
- if (!mathConverter) this.ensureMathJax();
4063
+ if (!isMathJaxReady()) this.ensureMathJax();
3836
4064
  this.subscribeInlineMathRepaint();
3837
4065
  }
4066
+ if (containsImage([token])) this.subscribeInlineImageRemeasure();
3838
4067
  switch (token.type) {
3839
4068
  // ── Headings ─────────────────────────────────────────────────────
3840
4069
  case "heading": {
3841
4070
  const hToken = token;
3842
- const sizes = [32, 28, 24, 20, 18, 16];
3843
- const size = sizes[Math.min(hToken.depth - 1, 5)];
4071
+ const size = headingSize(t, hToken.depth);
3844
4072
  const headingFont = `bold ${size}px ${t.bodyFont}`;
3845
4073
  return renderInlineToRichText(
3846
4074
  hToken.tokens,
@@ -3870,7 +4098,7 @@ var Markdown = class _Markdown extends UIComponent2 {
3870
4098
  }
3871
4099
  const stack = new Stack({
3872
4100
  direction: "vertical",
3873
- gap: 16,
4101
+ gap: this.theme.blockGap,
3874
4102
  maxWidth: availableWidth
3875
4103
  });
3876
4104
  let currentTokens = [];
@@ -3916,28 +4144,43 @@ var Markdown = class _Markdown extends UIComponent2 {
3916
4144
  // ── Blockquotes ──────────────────────────────────────────────────
3917
4145
  case "blockquote": {
3918
4146
  const bqToken = token;
3919
- const innerStack = new Stack({ direction: "vertical", gap: 8 });
3920
- const indentStart = Math.min(16, availableWidth);
4147
+ const innerStack = new Stack({
4148
+ direction: "vertical",
4149
+ gap: this.theme.quoteInnerGap
4150
+ });
4151
+ const indentStart = Math.min(this.theme.quoteIndent, availableWidth);
3921
4152
  const childMetrics = {
3922
4153
  marginBefore: 0,
3923
4154
  marginAfter: 0,
3924
4155
  indentStart,
3925
4156
  availableWidth: Math.max(0, availableWidth - indentStart)
3926
4157
  };
3927
- if (bqToken.tokens) {
3928
- for (const inner of bqToken.tokens) {
3929
- const el = this.renderTokenWithMetrics(inner, childMetrics);
3930
- if (el) {
3931
- const wrapper = new MarkdownContainer();
3932
- el.x = childMetrics.indentStart;
3933
- wrapper.add(el);
3934
- wrapper.width = el.width + childMetrics.indentStart;
3935
- wrapper.height = el.height;
3936
- innerStack.add(wrapper);
4158
+ const outerTheme = this.theme;
4159
+ if (t.quoteTextColor !== t.textColor) {
4160
+ this.theme = { ...outerTheme, textColor: t.quoteTextColor };
4161
+ }
4162
+ try {
4163
+ if (bqToken.tokens) {
4164
+ for (const inner of bqToken.tokens) {
4165
+ const el = this.renderTokenWithMetrics(inner, childMetrics);
4166
+ if (el) {
4167
+ const wrapper = new MarkdownContainer();
4168
+ el.x = childMetrics.indentStart;
4169
+ wrapper.add(el);
4170
+ wrapper.width = el.width + childMetrics.indentStart;
4171
+ wrapper.height = el.height;
4172
+ innerStack.add(wrapper);
4173
+ }
3937
4174
  }
3938
4175
  }
4176
+ } finally {
4177
+ this.theme = outerTheme;
3939
4178
  }
3940
- const border = new QuoteBorder(innerStack.height || 20, t.quoteBorderColor);
4179
+ const border = new QuoteBorder(
4180
+ innerStack.height || 20,
4181
+ t.quoteBorderColor,
4182
+ t.quoteBorderWidth
4183
+ );
3941
4184
  const container = new MarkdownContainer();
3942
4185
  border.x = 0;
3943
4186
  border.y = 0;
@@ -3952,7 +4195,10 @@ var Markdown = class _Markdown extends UIComponent2 {
3952
4195
  // ── Lists ────────────────────────────────────────────────
3953
4196
  case "list": {
3954
4197
  const listToken = token;
3955
- const listStack = new Stack({ direction: "vertical", gap: 6 });
4198
+ const listStack = new Stack({
4199
+ direction: "vertical",
4200
+ gap: this.theme.listGap
4201
+ });
3956
4202
  for (let i = 0; i < listToken.items.length; i++) {
3957
4203
  listStack.add(
3958
4204
  this.itemIsInlineOnly(listToken.items[i]) ? this.listItemRichText(listToken, i, availableWidth, t) : this.listItemBlockStack(listToken, i, availableWidth, t)
@@ -3977,7 +4223,7 @@ var Markdown = class _Markdown extends UIComponent2 {
3977
4223
  width: availableWidth,
3978
4224
  textColor: t.textColor,
3979
4225
  headerTextColor: t.headingColor,
3980
- font: `${t.fontSize - 2}px ${t.bodyFont}`,
4226
+ font: `${t.tableFontSize}px ${t.bodyFont}`,
3981
4227
  borderColor: t.hrColor,
3982
4228
  bg: t.tableBgColor,
3983
4229
  headerBg: t.tableHeaderBgColor,
@@ -4007,7 +4253,7 @@ var Markdown = class _Markdown extends UIComponent2 {
4007
4253
  font: bodyFont,
4008
4254
  color: t.textColor,
4009
4255
  maxWidth: availableWidth,
4010
- lineHeight: 24,
4256
+ lineHeight: t.bodyLineHeight,
4011
4257
  selectable: this.selectable
4012
4258
  });
4013
4259
  }