@gmb/bitmark-parser-generator 5.39.0 → 5.41.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.cjs CHANGED
@@ -81,6 +81,8 @@ var BitType = {
81
81
  // Used to indicate a bit is commented out
82
82
  _standard: "_standard",
83
83
  // Not to be used as a bit, but as a base for other bit types
84
+ _standardLight: "_standard-light",
85
+ // PLAN-021: lightweight base (minimal tag set), not to be used as a bit
84
86
  advertising: "advertising",
85
87
  advertisingAdvertorial: "advertising-advertorial",
86
88
  advertisingAdvertorialPage: "advertising-advertorial-page",
@@ -368,6 +370,7 @@ var BitType = {
368
370
  handInSystemMedia: "hand-in-system-media",
369
371
  handInVideo: "hand-in-video",
370
372
  handInVoice: "hand-in-voice",
373
+ h: "h",
371
374
  help: "help",
372
375
  helpAlt: "help-alt",
373
376
  highlightText: "highlight-text",
@@ -453,6 +456,7 @@ var BitType = {
453
456
  leWatchVideoEmbed: "le-watch-video-embed",
454
457
  lifeSkillSticker: "life-skill-sticker",
455
458
  list: "list",
459
+ listAlt: "list-alt",
456
460
  listItem: "list-item",
457
461
  mark: "mark",
458
462
  match: "match",
@@ -483,6 +487,8 @@ var BitType = {
483
487
  notebookArticle: "notebook-article",
484
488
  noteCollapsible: "note-collapsible",
485
489
  output: "output",
490
+ p: "p",
491
+ pAlt: "p-alt",
486
492
  page: "page",
487
493
  pageAcademy: "page-academy",
488
494
  pageArticle: "page-article",
@@ -605,6 +611,7 @@ var BitType = {
605
611
  smartStandardNoteNonNormativeCollapsible: "smart-standard-note-non-normative-collapsible",
606
612
  smartStandardNoteNormative: "smart-standard-note-normative",
607
613
  smartStandardNoteNormativeCollapsible: "smart-standard-note-normative-collapsible",
614
+ smartStandardP: "smart-standard-p",
608
615
  smartStandardRemarkLegend: "smart-standard-remark-legend",
609
616
  smartStandardRemarkLegendNonNormative: "smart-standard-remark-legend-non-normative",
610
617
  smartStandardRemarkLegendNormative: "smart-standard-remark-legend-normative",
@@ -1574,6 +1581,8 @@ var import_superenum12 = require("@ncoderz/superenum");
1574
1581
  var groupKeys = {
1575
1582
  group_accessibilityDecorative: "group_accessibilityDecorative",
1576
1583
  group_standardAllBits: "group_standardAllBits",
1584
+ group_standardExample: "group_standardExample",
1585
+ group_standardItem: "group_standardItem",
1577
1586
  group_standardItemLead: "group_standardItemLead",
1578
1587
  group_standardItemLeadInstructionHint: "group_standardItemLeadInstructionHint",
1579
1588
  group_standardInstructionHint: "group_standardInstructionHint",
@@ -5073,6 +5082,34 @@ var GROUPS = {
5073
5082
  }
5074
5083
  ]
5075
5084
  },
5085
+ [ConfigKey.group_standardExample]: {
5086
+ type: GroupConfigType.standard,
5087
+ description: "PLAN-021: Standard group for the bit-level example property only. Mirror of the group_standardTags property_example entry, used by the lightweight bits (_standardLight).",
5088
+ tags: [
5089
+ {
5090
+ key: ConfigKey.property_example,
5091
+ exportJsonKey: [{ "@keyonly": {} }, { "@absent": { isExample: true } }, { example: "$" }],
5092
+ description: "The example(s) for the bit",
5093
+ format: TagFormat.bitmarkText,
5094
+ nullable: true
5095
+ }
5096
+ ]
5097
+ },
5098
+ [ConfigKey.group_standardItem]: {
5099
+ type: GroupConfigType.standard,
5100
+ description: "PLAN-021: Standard group for the item tag ONLY (no lead/pageNumber/marginNumber chain). Used by the lightweight bits (_standardLight).",
5101
+ tags: [
5102
+ {
5103
+ key: ConfigKey.tag_item,
5104
+ jsonKey: "item",
5105
+ exportJsonKey: { item: "$" },
5106
+ // PLAN-140 W3 (NISO import): the clause/note label of a mapped
5107
+ // source element ([%1], [%ANMERKUNG 1]) — same as group_standardItemLead.
5108
+ mappingKeys: { "xml-niso-iec": { "@el": "label", "@text": "$" } },
5109
+ description: "The item for the bit"
5110
+ }
5111
+ ]
5112
+ },
5076
5113
  [ConfigKey.group_standardItemLead]: {
5077
5114
  type: GroupConfigType.standard,
5078
5115
  description: "Standard group for item, lead, page number, and margin number tags",
@@ -7876,6 +7913,25 @@ var BITS = {
7876
7913
  }
7877
7914
  ]
7878
7915
  },
7916
+ [BitType._standardLight]: {
7917
+ since: "5.40.0",
7918
+ description: "PLAN-021: Lightweight standard base bit with a minimal tag set (item + example only \u2014 no instruction/hint/lead, no resource attachments), used as a base for other bits, should not be used directly",
7919
+ resourceAttachmentAllowed: false,
7920
+ tags: [
7921
+ {
7922
+ key: ConfigKey.group_standardAllBits,
7923
+ description: "Standard tags for all bits"
7924
+ },
7925
+ {
7926
+ key: ConfigKey.group_standardItem,
7927
+ description: "The item tag (no lead/pageNumber/marginNumber chain)"
7928
+ },
7929
+ {
7930
+ key: ConfigKey.group_standardExample,
7931
+ description: "The bit-level example property"
7932
+ }
7933
+ ]
7934
+ },
7879
7935
  [BitType.appFlashcards]: {
7880
7936
  since: "1.3.0",
7881
7937
  title: "Flashcards",
@@ -10703,6 +10759,23 @@ var BITS = {
10703
10759
  baseBitType: BitType.article,
10704
10760
  description: "Glossary term bit, used to define glossary terms in articles or books"
10705
10761
  },
10762
+ [BitType.h]: {
10763
+ since: "5.40.0",
10764
+ title: "Heading",
10765
+ bitGroups: [BitGroup.static],
10766
+ baseBitType: BitType._standardLight,
10767
+ description: "Lightweight heading bit with chapter-style title levels 1-7; title/level + item only \u2014 no body, no footer",
10768
+ bodyAllowed: false,
10769
+ footerAllowed: false,
10770
+ tags: [
10771
+ {
10772
+ key: ConfigKey.tag_title,
10773
+ description: "The title of the heading",
10774
+ jsonKey: "title|setMulti(level)",
10775
+ exportJsonKey: { title: "$", level: "$level" }
10776
+ }
10777
+ ]
10778
+ },
10706
10779
  [BitType.help]: {
10707
10780
  since: "1.3.0",
10708
10781
  title: "Help",
@@ -10889,13 +10962,22 @@ var BITS = {
10889
10962
  since: "1.22.0",
10890
10963
  title: "List",
10891
10964
  bitGroups: [BitGroup.static],
10892
- baseBitType: BitType.article,
10965
+ // PLAN-021: rebased from article onto the lightweight base
10966
+ baseBitType: BitType._standardLight,
10893
10967
  description: "List bit, used to create lists in articles or books"
10894
10968
  },
10969
+ [BitType.listAlt]: {
10970
+ since: "5.40.0",
10971
+ title: "List Alt",
10972
+ bitGroups: [BitGroup.static],
10973
+ baseBitType: BitType.list,
10974
+ description: "Lightweight list bit (alternative), based on list"
10975
+ },
10895
10976
  [BitType.standardList]: {
10896
10977
  since: "1.22.0",
10897
10978
  bitGroups: [BitGroup.static],
10898
- baseBitType: BitType.article,
10979
+ // PLAN-021: re-rooted from article onto the lightweight list
10980
+ baseBitType: BitType.list,
10899
10981
  description: "Standard list bit, used to create standard lists in articles or books"
10900
10982
  },
10901
10983
  [BitType.smartStandardList]: {
@@ -10911,6 +10993,13 @@ var BITS = {
10911
10993
  "xml-niso-iec": { "@el": "ref-list", "@attr": { id: "$customerId" }, "\u25BC": "$anchor" }
10912
10994
  }
10913
10995
  },
10996
+ [BitType.smartStandardP]: {
10997
+ since: "5.40.0",
10998
+ title: "Smart Standard Paragraph",
10999
+ bitGroups: [BitGroup.static],
11000
+ baseBitType: BitType.p,
11001
+ description: "Smart standard paragraph bit, based on p"
11002
+ },
10914
11003
  [BitType.smartStandardListCollapsible]: {
10915
11004
  since: "1.28.0",
10916
11005
  deprecated: "5.37.0",
@@ -13492,7 +13581,8 @@ var BITS = {
13492
13581
  [BitType.listItem]: {
13493
13582
  since: "1.22.0",
13494
13583
  bitGroups: [BitGroup.static],
13495
- baseBitType: BitType.article,
13584
+ // PLAN-021: rebased from article onto the lightweight base
13585
+ baseBitType: BitType._standardLight,
13496
13586
  description: "List item bit, used to create list items in articles or books",
13497
13587
  tags: [
13498
13588
  {
@@ -13897,6 +13987,20 @@ var BITS = {
13897
13987
  baseBitType: BitType.multipleResponse,
13898
13988
  description: "Coach self-reflection multiple response bit, used for self-reflection in coaching"
13899
13989
  },
13990
+ [BitType.p]: {
13991
+ since: "5.40.0",
13992
+ title: "Paragraph",
13993
+ bitGroups: [BitGroup.static],
13994
+ baseBitType: BitType._standardLight,
13995
+ description: "Lightweight paragraph bit with a minimal tag set"
13996
+ },
13997
+ [BitType.pAlt]: {
13998
+ since: "5.40.0",
13999
+ title: "Paragraph Alt",
14000
+ bitGroups: [BitGroup.static],
14001
+ baseBitType: BitType.p,
14002
+ description: "Lightweight paragraph bit (alternative), based on p"
14003
+ },
13900
14004
  [BitType.page]: {
13901
14005
  since: "1.3.0",
13902
14006
  title: "Page",
@@ -16627,7 +16731,7 @@ var instance2 = new Config();
16627
16731
  // src/generated/package_info.ts
16628
16732
  var PACKAGE_INFO = {
16629
16733
  "name": "@gmb/bitmark-parser-generator",
16630
- "version": "5.39.0",
16734
+ "version": "5.41.0",
16631
16735
  "author": "Get More Brain Ltd",
16632
16736
  "license": "ISC",
16633
16737
  "description": "A bitmark parser and generator using Peggy.js"
@@ -18481,6 +18585,752 @@ var AstWalkerGenerator = class {
18481
18585
  }
18482
18586
  };
18483
18587
 
18588
+ // src/generator/text/TextGrammarConstraints.ts
18589
+ var COLORS = [
18590
+ "aqua",
18591
+ "black",
18592
+ "blue",
18593
+ "brown",
18594
+ "fuchsia",
18595
+ "lightgrey",
18596
+ "gray",
18597
+ "darkgray",
18598
+ "green",
18599
+ "lime",
18600
+ "magenta",
18601
+ "maroon",
18602
+ "navy",
18603
+ "olive",
18604
+ "orange",
18605
+ "pink",
18606
+ "purple",
18607
+ "red",
18608
+ "silver",
18609
+ "teal",
18610
+ "violet",
18611
+ "white",
18612
+ "yellow"
18613
+ ];
18614
+ var HIGHLIGHT_COLORS = [
18615
+ "orange",
18616
+ "yellow",
18617
+ "green",
18618
+ "blue",
18619
+ "purple",
18620
+ "pink",
18621
+ "brown",
18622
+ "white",
18623
+ "black",
18624
+ "gray"
18625
+ ];
18626
+ var ALTERNATIVE_STYLE_TAGS = [
18627
+ "bold",
18628
+ "italic",
18629
+ "light",
18630
+ "highlightOrange",
18631
+ "highlightYellow",
18632
+ "highlightGreen",
18633
+ "highlightBlue",
18634
+ "highlightPurple",
18635
+ "highlightPink",
18636
+ "highlightBrown",
18637
+ "highlightBlack",
18638
+ "highlightWhite",
18639
+ "highlightGray",
18640
+ "highlight",
18641
+ "strike",
18642
+ "subscript",
18643
+ "superscript",
18644
+ "ins",
18645
+ "del",
18646
+ "underline",
18647
+ "doubleUnderline",
18648
+ "smallcaps",
18649
+ "circle",
18650
+ "languageEmRed",
18651
+ "languageEmOrange",
18652
+ "languageEmYellow",
18653
+ "languageEmGreen",
18654
+ "languageEmBlue",
18655
+ "languageEmPurple",
18656
+ "languageEmPink",
18657
+ "languageEmBrown",
18658
+ "languageEmBlack",
18659
+ "languageEmWhite",
18660
+ "languageEmGray",
18661
+ "languageEm",
18662
+ "userUnderline",
18663
+ "userDoubleUnderline",
18664
+ "userStrike",
18665
+ "userCircle",
18666
+ "userHighlight",
18667
+ "notranslate"
18668
+ ];
18669
+ var MEDIA_ALIGNMENTS = ["left", "center", "right"];
18670
+ var INLINE_MEDIA_ALIGNMENTS = [
18671
+ "top",
18672
+ "middle",
18673
+ "bottom",
18674
+ "baseline",
18675
+ "sub",
18676
+ "super",
18677
+ "text-bottom",
18678
+ "text-top"
18679
+ ];
18680
+ var INLINE_MEDIA_SIZES = [
18681
+ "line-height",
18682
+ "font-height",
18683
+ "super",
18684
+ "sub",
18685
+ "explicit"
18686
+ ];
18687
+ var LINE_TERMINATOR_REGEX = /[\n\r\u2028\u2029]/;
18688
+ var CHAIN_STRING_INVALID_REGEX = /[|\n\r\u2028\u2029]/;
18689
+ var URL_CHAR_CLASS = "a-zA-Z0-9!*'()=+,\\-./_?#@[\\]$&;%:{}~^";
18690
+ var URL_CHAR_REGEX = new RegExp(`^[${URL_CHAR_CLASS}]$`);
18691
+ var URL_HTTP_REGEX = new RegExp(`^https?://[${URL_CHAR_CLASS}]*$`);
18692
+ var URL_REGEX = new RegExp(`^(https?://|mailto:)[${URL_CHAR_CLASS}]*$`);
18693
+ function isChainString(v) {
18694
+ return typeof v === "string" && !CHAIN_STRING_INVALID_REGEX.test(v);
18695
+ }
18696
+ function isSingleLine(v) {
18697
+ return typeof v === "string" && !LINE_TERMINATOR_REGEX.test(v);
18698
+ }
18699
+ function hasLineTerminator(v) {
18700
+ return LINE_TERMINATOR_REGEX.test(v);
18701
+ }
18702
+ function isColor(v) {
18703
+ return typeof v === "string" && COLORS.indexOf(v) !== -1;
18704
+ }
18705
+ function isHighlightColor(v) {
18706
+ return typeof v === "string" && HIGHLIGHT_COLORS.indexOf(v) !== -1;
18707
+ }
18708
+ function isMediaAlignment(v) {
18709
+ return typeof v === "string" && MEDIA_ALIGNMENTS.indexOf(v) !== -1;
18710
+ }
18711
+ function isInlineMediaAlignment(v) {
18712
+ return typeof v === "string" && INLINE_MEDIA_ALIGNMENTS.indexOf(v) !== -1;
18713
+ }
18714
+ function isInlineMediaSize(v) {
18715
+ return typeof v === "string" && INLINE_MEDIA_SIZES.indexOf(v) !== -1;
18716
+ }
18717
+ function toUInt(v) {
18718
+ if (typeof v === "number") return Number.isInteger(v) && v >= 0 ? v : void 0;
18719
+ if (typeof v === "string" && /^[0-9]+$/.test(v)) return parseInt(v, 10);
18720
+ return void 0;
18721
+ }
18722
+ function toBoolean(v) {
18723
+ if (typeof v === "boolean") return v;
18724
+ if (v === "true") return true;
18725
+ if (v === "false") return false;
18726
+ return void 0;
18727
+ }
18728
+ function isDuration(v) {
18729
+ return isChainString(v) && v.trim().startsWith("P");
18730
+ }
18731
+ function isUrlHttp(v) {
18732
+ return typeof v === "string" && URL_HTTP_REGEX.test(v);
18733
+ }
18734
+ function isUrl(v) {
18735
+ return typeof v === "string" && URL_REGEX.test(v);
18736
+ }
18737
+ function isUrlChar(c) {
18738
+ return URL_CHAR_REGEX.test(c);
18739
+ }
18740
+ function bareUrlText(href) {
18741
+ return href.replace(/^(https?:\/\/|mailto:)/, "");
18742
+ }
18743
+ function isInlineAlt(v) {
18744
+ return typeof v === "string" && v.length > 0 && v.indexOf("==") === -1 && !v.startsWith("=") && !v.endsWith("=");
18745
+ }
18746
+ function isHeadingLevel(v) {
18747
+ return typeof v === "number" && Number.isInteger(v) && v >= 1 && v <= 3;
18748
+ }
18749
+ function normalizeInlineCodeLanguage(v) {
18750
+ if (!isChainString(v)) return void 0;
18751
+ return v.trim().toLowerCase();
18752
+ }
18753
+ function normalizeBlockCodeLanguage(v) {
18754
+ if (!isSingleLine(v)) return void 0;
18755
+ return v.trim().toLowerCase();
18756
+ }
18757
+
18758
+ // src/generator/text/TextMediaAttrs.ts
18759
+ var uint = (v) => toUInt(v);
18760
+ var bool = (v) => toBoolean(v);
18761
+ var alignment = (v) => isMediaAlignment(v) ? v : void 0;
18762
+ var chainString = (v) => isChainString(v) ? v.trim() : void 0;
18763
+ var inlineAlignment = (v) => isInlineMediaAlignment(v) ? v : void 0;
18764
+ var inlineSize = (v) => isInlineMediaSize(v) ? v : void 0;
18765
+ var VALIDATORS = {
18766
+ image: {
18767
+ alt: chainString,
18768
+ title: chainString,
18769
+ alignment,
18770
+ textAlign: alignment,
18771
+ zoomDisabled: bool,
18772
+ width: uint,
18773
+ height: uint,
18774
+ comment: chainString
18775
+ },
18776
+ imageInline: {
18777
+ srcAlt: chainString,
18778
+ alignmentVertical: inlineAlignment,
18779
+ size: inlineSize,
18780
+ width: uint,
18781
+ height: uint,
18782
+ comment: chainString
18783
+ },
18784
+ symbol: {
18785
+ alt: chainString,
18786
+ title: chainString,
18787
+ caption: chainString,
18788
+ alignment,
18789
+ textAlign: alignment,
18790
+ captionAlign: alignment,
18791
+ zoomDisabled: bool,
18792
+ width: uint,
18793
+ height: uint,
18794
+ comment: chainString
18795
+ }
18796
+ };
18797
+ var TAG_NAMES = {
18798
+ textAlign: "captionAlign",
18799
+ title: "caption"
18800
+ };
18801
+ var DEFAULTS = {
18802
+ image: { alignment: "center", textAlign: "left", zoomDisabled: true },
18803
+ imageInline: { alignmentVertical: "top", size: "line-height" },
18804
+ symbol: {}
18805
+ };
18806
+ function sanitizeMediaAttrs(kind, attrs) {
18807
+ const result = {};
18808
+ if (!attrs || typeof attrs !== "object") return result;
18809
+ const validators = VALIDATORS[kind];
18810
+ for (const [k, v] of Object.entries(attrs)) {
18811
+ const validator = validators[k];
18812
+ if (!validator || v == null) continue;
18813
+ const valid = validator(v);
18814
+ if (valid !== void 0) result[k] = valid;
18815
+ }
18816
+ if (kind === "symbol") {
18817
+ if ("caption" in result) delete result.title;
18818
+ if ("captionAlign" in result) delete result.textAlign;
18819
+ }
18820
+ return result;
18821
+ }
18822
+ function serializeMediaChain(kind, attrs) {
18823
+ const defaults = DEFAULTS[kind];
18824
+ let s = "";
18825
+ for (const k of Object.keys(VALIDATORS[kind])) {
18826
+ const v = attrs[k];
18827
+ if (v == null) continue;
18828
+ if (k in defaults && defaults[k] === v) continue;
18829
+ if (k === "comment") {
18830
+ if (v) s += `|#${v}`;
18831
+ } else if (typeof v === "string" && v === "") {
18832
+ continue;
18833
+ } else {
18834
+ s += `|${TAG_NAMES[k] ?? k}:${v}`;
18835
+ }
18836
+ }
18837
+ return s;
18838
+ }
18839
+
18840
+ // src/generator/text/TextMarkSanitizer.ts
18841
+ var STANDARD_SHORT_FORM_MARKS = [
18842
+ TextMarkType.bold,
18843
+ TextMarkType.italic,
18844
+ TextMarkType.light,
18845
+ TextMarkType.highlight
18846
+ ];
18847
+ function attrsOf(mark2) {
18848
+ const a = mark2.attrs;
18849
+ return a && typeof a === "object" && !Array.isArray(a) ? a : {};
18850
+ }
18851
+ function chainValue(v) {
18852
+ if (v == null) return "";
18853
+ return isChainString(v) ? v.trim() : void 0;
18854
+ }
18855
+ function mark(type, attrs) {
18856
+ return attrs ? { type, attrs } : { type };
18857
+ }
18858
+ function sanitizeMark(m, options) {
18859
+ const attrs = attrsOf(m);
18860
+ switch (m.type) {
18861
+ case TextMarkType.highlight:
18862
+ case TextMarkType.userHighlight: {
18863
+ const color = attrs.color;
18864
+ return isHighlightColor(color) ? mark(m.type, { color }) : mark(m.type);
18865
+ }
18866
+ case TextMarkType.textStyle:
18867
+ case TextMarkType.color: {
18868
+ const color = attrs.color;
18869
+ return isColor(color) ? mark(TextMarkType.textStyle, { color }) : void 0;
18870
+ }
18871
+ case TextMarkType.link: {
18872
+ const href = chainValue(attrs.href);
18873
+ return href === void 0 ? void 0 : mark(m.type, { href });
18874
+ }
18875
+ case TextMarkType.ref: {
18876
+ const reference = chainValue(attrs.reference);
18877
+ return reference === void 0 ? void 0 : mark(m.type, { reference });
18878
+ }
18879
+ case TextMarkType.xref: {
18880
+ const xref = chainValue(attrs.xref);
18881
+ if (xref === void 0) return void 0;
18882
+ const reference = chainValue(attrs.reference) ?? "";
18883
+ return mark(m.type, { xref, reference });
18884
+ }
18885
+ case TextMarkType.extref: {
18886
+ const extref = chainValue(attrs.extref);
18887
+ const provider = chainValue(attrs.provider);
18888
+ if (extref === void 0 || provider === void 0) return void 0;
18889
+ const refs = Array.isArray(attrs.references) ? attrs.references : [];
18890
+ const references = refs.map((r) => chainValue(r)).filter((r) => r !== void 0);
18891
+ return mark(m.type, { extref, references, provider });
18892
+ }
18893
+ case TextMarkType.footnote:
18894
+ case TextMarkType.footnoteStar: {
18895
+ const content = options.normalizeChainValue ? options.normalizeChainValue(attrs.content) : Array.isArray(attrs.content) ? attrs.content : [];
18896
+ return content === void 0 ? void 0 : mark(m.type, { content });
18897
+ }
18898
+ case TextMarkType.symbol: {
18899
+ const src = chainValue(attrs.src);
18900
+ if (src === void 0) return void 0;
18901
+ return mark(m.type, { src, ...sanitizeMediaAttrs("symbol", attrs) });
18902
+ }
18903
+ case TextMarkType.var: {
18904
+ const name = chainValue(attrs.name);
18905
+ return name === void 0 ? void 0 : mark(m.type, { name });
18906
+ }
18907
+ case TextMarkType.code: {
18908
+ const language = normalizeInlineCodeLanguage(attrs.language);
18909
+ return language === void 0 ? mark(m.type) : mark(m.type, { language });
18910
+ }
18911
+ case TextMarkType.timer: {
18912
+ const duration = attrs.duration;
18913
+ if (!isDuration(duration)) return void 0;
18914
+ const name = chainValue(attrs.name) ?? "";
18915
+ return mark(m.type, { name, duration: duration.trim() });
18916
+ }
18917
+ case TextMarkType.colorPicker: {
18918
+ const propertyRef = chainValue(attrs.propertyRef);
18919
+ return propertyRef === void 0 ? void 0 : mark(m.type, { propertyRef });
18920
+ }
18921
+ case TextMarkType.comment: {
18922
+ const comment = chainValue(m.comment);
18923
+ return comment === void 0 ? void 0 : { type: m.type, comment };
18924
+ }
18925
+ default:
18926
+ if (ALTERNATIVE_STYLE_TAGS.indexOf(m.type) !== -1) return mark(m.type);
18927
+ return void 0;
18928
+ }
18929
+ }
18930
+ function mergeLegacyTimer(marks) {
18931
+ const timer = marks.find((m) => m.type === TextMarkType.timer);
18932
+ const duration = marks.find((m) => m.type === TextMarkType.duration);
18933
+ if (!timer || !duration || attrsOf(timer).duration) return marks;
18934
+ return marks.map(
18935
+ (m) => m === timer ? { ...timer, attrs: { ...attrsOf(timer), duration: attrsOf(duration).duration } } : m
18936
+ );
18937
+ }
18938
+ function orderMarks(marks) {
18939
+ const a = (m) => m.attrs ?? {};
18940
+ const isBareHighlight = (m) => (m.type === TextMarkType.highlight || m.type === TextMarkType.userHighlight) && !a(m).color;
18941
+ const isHighlightColorStyle = (m) => m.type === TextMarkType.textStyle && isHighlightColor(a(m).color);
18942
+ const isEmptyXref = (m) => m.type === TextMarkType.xref && !a(m).reference;
18943
+ const result = [];
18944
+ for (const m of marks) {
18945
+ if (m.type === TextMarkType.ref) {
18946
+ const xrefIdx = result.findIndex(isEmptyXref);
18947
+ if (xrefIdx !== -1) {
18948
+ result.splice(xrefIdx, 0, m);
18949
+ continue;
18950
+ }
18951
+ }
18952
+ result.push(m);
18953
+ }
18954
+ for (let i = 0; i < result.length - 1; i++) {
18955
+ if (isBareHighlight(result[i]) && isHighlightColorStyle(result[i + 1])) {
18956
+ [result[i], result[i + 1]] = [result[i + 1], result[i]];
18957
+ }
18958
+ }
18959
+ const symbols = result.filter((m) => m.type === TextMarkType.symbol);
18960
+ if (symbols.length === 0) return result;
18961
+ return [...result.filter((m) => m.type !== TextMarkType.symbol), symbols[0]];
18962
+ }
18963
+ function sanitizeMarks(marks, options = {}) {
18964
+ if (!Array.isArray(marks)) return [];
18965
+ let loose = marks.filter(
18966
+ (m) => !!m && typeof m === "object" && typeof m.type === "string"
18967
+ );
18968
+ loose = mergeLegacyTimer(loose);
18969
+ const result = [];
18970
+ for (const m of loose) {
18971
+ const s = sanitizeMark(m, options);
18972
+ if (s) result.push(s);
18973
+ }
18974
+ if (options.chainValue) {
18975
+ if (result.length === 1 && STANDARD_SHORT_FORM_MARKS.indexOf(result[0].type) !== -1) {
18976
+ return [mark(result[0].type)];
18977
+ }
18978
+ if (result.length === 1 && result[0].type === TextMarkType.link) return result;
18979
+ return [];
18980
+ }
18981
+ return orderMarks(result);
18982
+ }
18983
+
18984
+ // src/generator/text/TextAstNormalizer.ts
18985
+ var LIST_TYPES = [
18986
+ TextNodeType.noBulletList,
18987
+ TextNodeType.bulletList,
18988
+ TextNodeType.orderedList,
18989
+ TextNodeType.orderedListRoman,
18990
+ TextNodeType.orderedListRomanLower,
18991
+ TextNodeType.letteredList,
18992
+ TextNodeType.letteredListLower,
18993
+ TextNodeType.taskList
18994
+ ];
18995
+ var ORDERED_LIST_TYPES = [
18996
+ TextNodeType.orderedList,
18997
+ TextNodeType.orderedListRoman,
18998
+ TextNodeType.orderedListRomanLower
18999
+ ];
19000
+ var BODY_BIT_TYPES = [
19001
+ TextNodeType.gap,
19002
+ TextNodeType.select,
19003
+ TextNodeType.highlight,
19004
+ TextNodeType.mark
19005
+ ];
19006
+ var LEADING_TAB_REGEX = /(^|[\n\r\u2028\u2029])\t+/g;
19007
+ var isList = (n) => LIST_TYPES.indexOf(n.type) !== -1;
19008
+ var isListItem = (n) => n.type === TextNodeType.listItem || n.type === TextNodeType.taskItem;
19009
+ var isBodyBit = (n) => BODY_BIT_TYPES.indexOf(n.type) !== -1;
19010
+ var isNode = (n) => !!n && typeof n === "object" && typeof n.type === "string";
19011
+ var contentOf = (n) => Array.isArray(n.content) ? n.content.filter(isNode) : [];
19012
+ var attrsOf2 = (n) => n.attrs && typeof n.attrs === "object" ? n.attrs : {};
19013
+ var asNode = (n) => n;
19014
+ var paragraph = (content) => asNode({ type: TextNodeType.paragraph, attrs: {}, content });
19015
+ var hardBreak = () => ({ type: TextNodeType.hardBreak });
19016
+ var isHardBreak = (n) => n?.type === TextNodeType.hardBreak;
19017
+ var hasText = (nodes) => nodes.some(
19018
+ (n) => n.type !== TextNodeType.hardBreak && (n.type !== TextNodeType.text || typeof n.text === "string" && n.text.trim() !== "")
19019
+ );
19020
+ function canFollowBareUrl(next) {
19021
+ if (!next) return true;
19022
+ if (next.type === TextNodeType.hardBreak) return true;
19023
+ if (next.type !== TextNodeType.text) return false;
19024
+ if (next.marks && next.marks.length > 0) return false;
19025
+ const first = (next.text ?? "").charAt(0);
19026
+ return first === "" || !isUrlChar(first);
19027
+ }
19028
+ function isSimpleLinkNode(node, next) {
19029
+ if (node.type !== TextNodeType.text || node.marks?.length !== 1) return false;
19030
+ const m = node.marks[0];
19031
+ if (m.type !== TextMarkType.link) return false;
19032
+ const href = m.attrs?.href;
19033
+ return isUrl(href) && bareUrlText(href) === node.text && canFollowBareUrl(next);
19034
+ }
19035
+ var FLATTENED_BLOCK_TYPES = [
19036
+ TextNodeType.paragraph,
19037
+ TextNodeType.heading,
19038
+ TextNodeType.section,
19039
+ TextNodeType.listItem,
19040
+ TextNodeType.taskItem,
19041
+ TextNodeType.codeBlock
19042
+ ];
19043
+ var TextAstNormalizer = class {
19044
+ constructor(options) {
19045
+ __publicField(this, "options");
19046
+ this.options = options;
19047
+ }
19048
+ normalize(ast) {
19049
+ if (!Array.isArray(ast)) return [];
19050
+ const nodes = ast.filter(isNode);
19051
+ if (this.options.chainValue) return this.inline(nodes, { plain: true, chainValue: true });
19052
+ if (this.options.location === TextLocation.tag) {
19053
+ return nodes.flatMap((n) => this.inlineRootNode(n, {}));
19054
+ }
19055
+ return nodes.flatMap((n) => this.block(n));
19056
+ }
19057
+ //
19058
+ // Block context
19059
+ //
19060
+ block(n) {
19061
+ switch (n.type) {
19062
+ case TextNodeType.paragraph:
19063
+ return [{ ...n, content: this.inline(contentOf(n)) }];
19064
+ case TextNodeType.heading:
19065
+ return this.heading(n);
19066
+ case TextNodeType.section:
19067
+ return [paragraph(this.inline(contentOf(n)))];
19068
+ case TextNodeType.image: {
19069
+ const image = this.image(n);
19070
+ return image ? [image] : [];
19071
+ }
19072
+ case TextNodeType.codeBlock:
19073
+ return [{ ...n, content: this.code(contentOf(n)) }];
19074
+ case TextNodeType.text:
19075
+ case TextNodeType.hardBreak:
19076
+ case TextNodeType.imageInline:
19077
+ case TextNodeType.latex:
19078
+ return this.inline([n]);
19079
+ default:
19080
+ if (isList(n)) return this.list(n);
19081
+ if (isListItem(n)) return [paragraph(this.inline(contentOf(n)))];
19082
+ if (isBodyBit(n)) return [n];
19083
+ if (Array.isArray(n.content))
19084
+ return [{ ...n, content: this.blocks(contentOf(n)) }];
19085
+ return [n];
19086
+ }
19087
+ }
19088
+ blocks(nodes) {
19089
+ return nodes.flatMap((n) => this.block(n));
19090
+ }
19091
+ heading(n) {
19092
+ const level = attrsOf2(n).level;
19093
+ if (level != null && !isHeadingLevel(level)) {
19094
+ return [paragraph(this.inline(contentOf(n)))];
19095
+ }
19096
+ const content = this.inline(contentOf(n), { singleLine: true });
19097
+ if (!hasText(content)) return [];
19098
+ return [{ ...n, content }];
19099
+ }
19100
+ image(n) {
19101
+ const attrs = attrsOf2(n);
19102
+ if (!isUrlHttp(attrs.src)) return void 0;
19103
+ return asNode({ ...n, attrs: { src: attrs.src, ...sanitizeMediaAttrs("image", attrs) } });
19104
+ }
19105
+ code(nodes) {
19106
+ const result = [];
19107
+ for (const n of nodes) {
19108
+ if (n.type === TextNodeType.text) {
19109
+ if (typeof n.text === "string" && n.text) {
19110
+ result.push({ type: TextNodeType.text, text: n.text });
19111
+ }
19112
+ } else if (n.type === TextNodeType.hardBreak) {
19113
+ result.push(hardBreak());
19114
+ } else {
19115
+ result.push(...this.code(contentOf(n)));
19116
+ }
19117
+ }
19118
+ return result;
19119
+ }
19120
+ //
19121
+ // List context
19122
+ //
19123
+ list(n) {
19124
+ const attrs = attrsOf2(n);
19125
+ const ordered = ORDERED_LIST_TYPES.indexOf(n.type) !== -1;
19126
+ let start;
19127
+ if (ordered && attrs.start != null) {
19128
+ start = toUInt(attrs.start);
19129
+ if (start === void 0) {
19130
+ return contentOf(n).map(
19131
+ (item) => paragraph(this.inline([item], { stripLeadingTabs: true }))
19132
+ );
19133
+ }
19134
+ }
19135
+ const items = [];
19136
+ for (const child of contentOf(n)) {
19137
+ if (isListItem(child)) {
19138
+ items.push(...this.listItem(child));
19139
+ } else {
19140
+ items.push(...this.listItem({ type: TextNodeType.listItem, content: [child] }));
19141
+ }
19142
+ }
19143
+ if (items.length === 0) return [];
19144
+ const newAttrs = { ...attrs };
19145
+ if (ordered && start !== void 0) newAttrs.start = start;
19146
+ return [asNode({ ...n, attrs: newAttrs, content: items })];
19147
+ }
19148
+ /**
19149
+ * A list item holds a paragraph, then at most one sublist. Everything else is merged into the
19150
+ * paragraph; further sublists become new items (with an empty paragraph, which keeps them
19151
+ * attached). Returns the resulting item(s).
19152
+ */
19153
+ listItem(item) {
19154
+ const inlineOpts = { stripLeadingTabs: true };
19155
+ const acc = {};
19156
+ let sublist;
19157
+ const extraItems = [];
19158
+ const merge = (inline) => {
19159
+ if (!acc.para) acc.para = inline;
19160
+ else if (inline.length > 0) acc.para.push(hardBreak(), ...inline);
19161
+ };
19162
+ for (const child of contentOf(item)) {
19163
+ if (isList(child)) {
19164
+ for (const list of this.list(child)) {
19165
+ if (list.type === TextNodeType.paragraph) {
19166
+ merge(list.content ?? []);
19167
+ } else if (!sublist) {
19168
+ sublist = list;
19169
+ } else {
19170
+ extraItems.push({ ...item, content: [paragraph([]), list] });
19171
+ }
19172
+ }
19173
+ } else if (child.type === TextNodeType.image) {
19174
+ } else {
19175
+ merge(this.inline([child], inlineOpts));
19176
+ }
19177
+ }
19178
+ const paraContent = acc.para ?? [];
19179
+ if (!hasText(paraContent) && !sublist) return extraItems;
19180
+ const content = [paragraph(paraContent)];
19181
+ if (sublist) content.push(sublist);
19182
+ return [{ ...item, content }, ...extraItems];
19183
+ }
19184
+ //
19185
+ // Inline context
19186
+ //
19187
+ /** A root node at tag location: paragraphs of inline content only */
19188
+ inlineRootNode(n, opts) {
19189
+ switch (n.type) {
19190
+ case TextNodeType.text:
19191
+ case TextNodeType.hardBreak:
19192
+ case TextNodeType.imageInline:
19193
+ case TextNodeType.latex:
19194
+ return this.inline([n], opts);
19195
+ case TextNodeType.image:
19196
+ return [];
19197
+ default:
19198
+ if (isBodyBit(n)) return [n];
19199
+ if (isList(n)) {
19200
+ return contentOf(n).map(
19201
+ (item) => paragraph(this.inline([item], { ...opts, stripLeadingTabs: true }))
19202
+ );
19203
+ }
19204
+ return [paragraph(this.inline(contentOf(n), opts))];
19205
+ }
19206
+ }
19207
+ inline(nodes, opts = {}) {
19208
+ const result = [];
19209
+ const separator = () => opts.singleLine ? this.spaceText() : hardBreak();
19210
+ const separate = () => {
19211
+ if (result.length > 0 && !isHardBreak(result[result.length - 1])) result.push(separator());
19212
+ };
19213
+ for (const n of nodes) {
19214
+ switch (n.type) {
19215
+ case TextNodeType.text: {
19216
+ const text = this.text(n, opts);
19217
+ if (text) result.push(text);
19218
+ break;
19219
+ }
19220
+ case TextNodeType.hardBreak:
19221
+ result.push(separator());
19222
+ break;
19223
+ case TextNodeType.imageInline: {
19224
+ if (opts.plain) break;
19225
+ const image = this.imageInline(n);
19226
+ if (image) result.push(image);
19227
+ break;
19228
+ }
19229
+ case TextNodeType.latex:
19230
+ if (opts.plain) break;
19231
+ if (typeof attrsOf2(n).formula === "string") result.push(n);
19232
+ break;
19233
+ case TextNodeType.image:
19234
+ break;
19235
+ default:
19236
+ if (isBodyBit(n)) {
19237
+ result.push(n);
19238
+ } else if (isList(n)) {
19239
+ for (const item of contentOf(n)) {
19240
+ separate();
19241
+ result.push(...this.inline([item], opts));
19242
+ }
19243
+ } else if (FLATTENED_BLOCK_TYPES.indexOf(n.type) !== -1) {
19244
+ separate();
19245
+ result.push(...this.inline(contentOf(n), opts));
19246
+ } else if (Array.isArray(n.content)) {
19247
+ result.push({ ...n, content: this.inline(contentOf(n), opts) });
19248
+ } else {
19249
+ result.push(n);
19250
+ }
19251
+ }
19252
+ }
19253
+ return this.dropSymbolsBeforePipes(result);
19254
+ }
19255
+ /**
19256
+ * A symbol's media chain swallows every following `...|` segment on its line (even when sealed
19257
+ * with `^`), so a symbol mark has no representable form when the rest of the line contains `|`.
19258
+ */
19259
+ dropSymbolsBeforePipes(nodes) {
19260
+ for (let i = 0; i < nodes.length; i++) {
19261
+ const n = nodes[i];
19262
+ if (!n.marks?.some((m) => m.type === TextMarkType.symbol)) continue;
19263
+ let pipeFollows = false;
19264
+ for (let j = i + 1; j < nodes.length && !isHardBreak(nodes[j]); j++) {
19265
+ const text = nodes[j].text;
19266
+ if (typeof text !== "string") continue;
19267
+ const firstLine = text.split(/[\n\r\u2028\u2029]/, 1)[0];
19268
+ if (firstLine.indexOf("|") !== -1) pipeFollows = true;
19269
+ if (hasLineTerminator(text)) break;
19270
+ }
19271
+ if (pipeFollows) {
19272
+ const marks = n.marks.filter((m) => m.type !== TextMarkType.symbol);
19273
+ const { marks: _m, ...rest } = n;
19274
+ nodes[i] = marks.length > 0 ? { ...rest, marks } : rest;
19275
+ }
19276
+ }
19277
+ return nodes;
19278
+ }
19279
+ text(n, opts) {
19280
+ if (typeof n.text !== "string") return void 0;
19281
+ let text = n.text;
19282
+ if (opts.stripLeadingTabs) text = text.replace(LEADING_TAB_REGEX, "$1");
19283
+ if (opts.singleLine) text = text.replace(/[\n\r\u2028\u2029]+/g, " ");
19284
+ if (!text) return void 0;
19285
+ const marks = sanitizeMarks(n.marks, {
19286
+ chainValue: opts.chainValue,
19287
+ normalizeChainValue: (content) => this.chainValue(content)
19288
+ });
19289
+ const { marks: _m, ...rest } = n;
19290
+ return marks.length > 0 ? { ...rest, text, marks } : { ...rest, text };
19291
+ }
19292
+ spaceText() {
19293
+ return { type: TextNodeType.text, text: " " };
19294
+ }
19295
+ imageInline(n) {
19296
+ const attrs = attrsOf2(n);
19297
+ if (!isUrl(attrs.src)) return void 0;
19298
+ const alt = attrs.alt;
19299
+ if (!isInlineAlt(alt)) return void 0;
19300
+ return asNode({
19301
+ ...n,
19302
+ attrs: { src: attrs.src, alt, ...sanitizeMediaAttrs("imageInline", attrs) }
19303
+ });
19304
+ }
19305
+ /**
19306
+ * Footnote content: a `|`-free single line of plain text with short-form standard marks.
19307
+ * Returns undefined when the content cannot be represented.
19308
+ */
19309
+ chainValue(content) {
19310
+ if (!Array.isArray(content)) return [];
19311
+ const nodes = this.inline(content.filter(isNode), {
19312
+ plain: true,
19313
+ chainValue: true,
19314
+ singleLine: true
19315
+ });
19316
+ for (let i = 0; i < nodes.length; i++) {
19317
+ const n = nodes[i];
19318
+ const text = n.text;
19319
+ if (typeof text === "string" && (text.indexOf("|") !== -1 || hasLineTerminator(text))) {
19320
+ return void 0;
19321
+ }
19322
+ if (n.marks?.some((m) => m.type === TextMarkType.link) && !isSimpleLinkNode(n, nodes[i + 1])) {
19323
+ const { marks: _m, ...rest } = n;
19324
+ nodes[i] = rest;
19325
+ }
19326
+ }
19327
+ return nodes;
19328
+ }
19329
+ };
19330
+ function normalizeTextAst(ast, options) {
19331
+ return new TextAstNormalizer(options).normalize(ast);
19332
+ }
19333
+
18484
19334
  // src/generator/text/TextGenerator.ts
18485
19335
  var DEFAULT_OPTIONS = {
18486
19336
  bodyBitCallback: void 0,
@@ -18573,21 +19423,9 @@ var INLINE_MARK_TYPES = [
18573
19423
  TextMarkType.colorPicker,
18574
19424
  TextMarkType.comment
18575
19425
  ];
18576
- var HIGHLIGHT_COLORS = [
18577
- "orange",
18578
- "yellow",
18579
- "green",
18580
- "blue",
18581
- "purple",
18582
- "pink",
18583
- "brown",
18584
- "white",
18585
- "black",
18586
- "gray"
18587
- ];
18588
19426
  var INDENTATION_REGEX = new RegExp(/(\n|\r\n)/, "g");
18589
- var LINK_REGEX = new RegExp(/https?:\/\/|mailto:(.*)/, "g");
18590
19427
  var LINK_BREAKSCAPE_REGEX = new RegExp(/\]/, "g");
19428
+ var CHAIN_CONTINUATION_REGEX = /^[^\n\r\u2028\u2029]*\|/;
18591
19429
  var Stage = {
18592
19430
  enter: "enter",
18593
19431
  between: "between",
@@ -18624,6 +19462,8 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
18624
19462
  __publicField(this, "textDepth", 0);
18625
19463
  __publicField(this, "placeholderIndex", 0);
18626
19464
  __publicField(this, "placeholders", {});
19465
+ __publicField(this, "chainJustClosed", false);
19466
+ __publicField(this, "simpleLinkAllowed", true);
18627
19467
  // For pre-text
18628
19468
  __publicField(this, "rootParagraphNodeContentIndex", 0);
18629
19469
  __publicField(this, "previousRootParagraphContextType", TextNodeType.text);
@@ -18669,6 +19509,11 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
18669
19509
  generateSync(ast, textFormat, textLocation, options) {
18670
19510
  if (!ast || !Array.isArray(ast)) return "";
18671
19511
  this.generateOptions = Object.assign({}, options);
19512
+ ast = normalizeTextAst(ast, {
19513
+ format: textFormat ?? TextFormat.bitmarkText,
19514
+ location: textLocation,
19515
+ chainValue: this.generateOptions.chainValueContext
19516
+ });
18672
19517
  this.validateGenerateOptions(ast);
18673
19518
  if (!this.generateOptions.plainTextDividerAllowed) {
18674
19519
  this.resetState(textFormat, textLocation);
@@ -18712,6 +19557,8 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
18712
19557
  this.textDepth = 0;
18713
19558
  this.placeholderIndex = 0;
18714
19559
  this.placeholders = {};
19560
+ this.chainJustClosed = false;
19561
+ this.simpleLinkAllowed = true;
18715
19562
  this.rootParagraphNodeContentIndex = 0;
18716
19563
  this.previousRootParagraphContextType = TextNodeType.hardBreak;
18717
19564
  this.inPreText = false;
@@ -18777,6 +19624,7 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
18777
19624
  this.writeHardBreak(node);
18778
19625
  break;
18779
19626
  case TextNodeType.text: {
19627
+ this.simpleLinkAllowed = this.isSimpleLinkAllowedAfter(route);
18780
19628
  this.writeMarks(node, Stage.enter);
18781
19629
  this.writeText(node);
18782
19630
  this.writeMarks(node, Stage.between);
@@ -18790,9 +19638,6 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
18790
19638
  this.writeHeading(node);
18791
19639
  this.inHeading = true;
18792
19640
  break;
18793
- case TextNodeType.section:
18794
- this.writeSection(node);
18795
- break;
18796
19641
  case TextNodeType.listItem:
18797
19642
  case TextNodeType.taskItem:
18798
19643
  this.writeBullet(node, route);
@@ -18850,7 +19695,6 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
18850
19695
  break;
18851
19696
  case TextNodeType.heading:
18852
19697
  this.inHeading = false;
18853
- case TextNodeType.section:
18854
19698
  case TextNodeType.image:
18855
19699
  if (!this.inParagraph) {
18856
19700
  this.writeNL();
@@ -18962,9 +19806,9 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
18962
19806
  */
18963
19807
  getLinkHref(node) {
18964
19808
  if (node.type === TextNodeType.text && node.marks) {
18965
- const href = node.marks.reduce((acc, mark) => {
18966
- if (mark.type === TextMarkType.link) {
18967
- const linkMark = mark;
19809
+ const href = node.marks.reduce((acc, mark2) => {
19810
+ if (mark2.type === TextMarkType.link) {
19811
+ const linkMark = mark2;
18968
19812
  const href2 = linkMark.attrs?.href;
18969
19813
  if (href2) return href2;
18970
19814
  }
@@ -19029,6 +19873,9 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19029
19873
  const indentationString = this.getIndentationString();
19030
19874
  s = s.replace(INDENTATION_REGEX, `$1${indentationString}`);
19031
19875
  }
19876
+ if (this.chainJustClosed && CHAIN_CONTINUATION_REGEX.test(s)) {
19877
+ s = `^${s}`;
19878
+ }
19032
19879
  if (this.havePreText && this.rootParagraphNodeContentIndex === this.preTextIndex) {
19033
19880
  this.writePlainTextDivider();
19034
19881
  this.writeNL();
@@ -19058,14 +19905,14 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19058
19905
  * @returns true if a simple link, otherwise false
19059
19906
  */
19060
19907
  isSimpleLink(node) {
19061
- if (node.text == null) return false;
19062
- if (node.marks?.length !== 1) return false;
19063
- const href = this.getLinkHref(node);
19064
- if (href) {
19065
- const hrefText = href.replace(LINK_REGEX, "$1");
19066
- return hrefText === node.text;
19067
- }
19068
- return false;
19908
+ return this.simpleLinkAllowed && isSimpleLinkNode(node, void 0);
19909
+ }
19910
+ /**
19911
+ * The bare-URL link short form is only safe when whatever is written next cannot be read as
19912
+ * part of the URL (the parser's Url rule consumes every following UrlChar).
19913
+ */
19914
+ isSimpleLinkAllowedAfter(route) {
19915
+ return canFollowBareUrl(this.getSiblingNodes(route).right);
19069
19916
  }
19070
19917
  /**
19071
19918
  * Get the link text if the node is a link, otherwise return false
@@ -19077,15 +19924,8 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19077
19924
  if (node.text == null) return false;
19078
19925
  const href = this.getLinkHref(node);
19079
19926
  if (href) {
19080
- let res;
19081
- const hrefText = href.replace(LINK_REGEX, "$1");
19082
- if (hrefText === node.text) {
19083
- res = href;
19084
- } else {
19085
- res = node.text;
19086
- }
19087
- res = (res ?? "").replace(LINK_BREAKSCAPE_REGEX, "^]");
19088
- return res;
19927
+ const res = this.isSimpleLink(node) ? href : node.text;
19928
+ return res.replace(LINK_BREAKSCAPE_REGEX, "^]");
19089
19929
  }
19090
19930
  return false;
19091
19931
  }
@@ -19142,22 +19982,17 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19142
19982
  writeMarks(node, stage) {
19143
19983
  if (node.marks) {
19144
19984
  const forceSingleMark = this.generateOptions.forceInline || !!(this.inInline || this.inHeading);
19145
- this.thisNodeIsPreText = false;
19146
- const emptyMarks = node.marks.length === 0;
19147
- if (emptyMarks) {
19148
- this.writeMarkTextWrapper(INLINE_MARK);
19149
- return;
19150
- }
19151
- const marks = this.getWritableMarks(node.marks);
19985
+ const marks = node.marks;
19152
19986
  if (marks.length === 0) return;
19987
+ this.thisNodeIsPreText = false;
19153
19988
  const singleMark = marks.length === 1 && forceSingleMark;
19154
19989
  const markStartEnd = marks.reduce(
19155
- (acc, mark) => {
19990
+ (acc, mark2) => {
19156
19991
  if (acc) return acc;
19157
- if (this.isStandardMark(mark)) {
19158
- if (singleMark) return STANDARD_MARKS[mark.type];
19992
+ if (this.isStandardMark(mark2)) {
19993
+ if (singleMark) return STANDARD_MARKS[mark2.type];
19159
19994
  return INLINE_MARK;
19160
- } else if (this.isInlineMark(mark)) {
19995
+ } else if (this.isInlineMark(mark2)) {
19161
19996
  return INLINE_MARK;
19162
19997
  } else {
19163
19998
  }
@@ -19172,56 +20007,59 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19172
20007
  this.writeMarkTextWrapper(markStartEnd);
19173
20008
  }
19174
20009
  if (stage == Stage.between) {
19175
- for (const mark of marks) {
19176
- if (this.isStandardMark(mark)) {
20010
+ for (const mark2 of marks) {
20011
+ if (this.isStandardMark(mark2)) {
19177
20012
  if (!singleMark) {
19178
20013
  this.writeInlineMarkStartEnd();
19179
- this.writeInlineMark(mark);
20014
+ this.writeInlineMark(mark2);
19180
20015
  }
19181
- } else if (TextMarkType.comment === mark.type) {
20016
+ } else if (TextMarkType.comment === mark2.type) {
19182
20017
  this.writeInlineMarkStartEnd();
19183
- this.writeCommentMark(mark);
19184
- } else if (TextMarkType.link === mark.type) {
20018
+ this.writeCommentMark(mark2);
20019
+ } else if (TextMarkType.link === mark2.type) {
19185
20020
  this.writeInlineMarkStartEnd();
19186
- this.writeLinkMark(mark);
19187
- } else if (TextMarkType.ref === mark.type) {
20021
+ this.writeLinkMark(mark2);
20022
+ } else if (TextMarkType.ref === mark2.type) {
19188
20023
  this.writeInlineMarkStartEnd();
19189
- this.writeRefMark(mark);
19190
- } else if (TextMarkType.xref === mark.type) {
20024
+ this.writeRefMark(mark2);
20025
+ } else if (TextMarkType.xref === mark2.type) {
19191
20026
  this.writeInlineMarkStartEnd();
19192
- this.writeXRefMark(mark);
19193
- } else if (TextMarkType.extref === mark.type) {
20027
+ this.writeXRefMark(mark2);
20028
+ } else if (TextMarkType.extref === mark2.type) {
19194
20029
  this.writeInlineMarkStartEnd();
19195
- this.writeExtRefMark(mark);
19196
- } else if (TextMarkType.footnote === mark.type) {
20030
+ this.writeExtRefMark(mark2);
20031
+ } else if (TextMarkType.footnote === mark2.type) {
19197
20032
  this.writeInlineMarkStartEnd();
19198
- this.writeFootnoteMark(mark);
19199
- } else if (TextMarkType.footnoteStar === mark.type) {
20033
+ this.writeFootnoteMark(mark2);
20034
+ } else if (TextMarkType.footnoteStar === mark2.type) {
19200
20035
  this.writeInlineMarkStartEnd();
19201
- this.writeFootnoteStarMark(mark);
19202
- } else if (TextMarkType.symbol === mark.type) {
20036
+ this.writeFootnoteStarMark(mark2);
20037
+ } else if (TextMarkType.symbol === mark2.type) {
19203
20038
  this.writeInlineMarkStartEnd();
19204
- this.writeSymbolMark(mark);
19205
- } else if (this.isInlineMark(mark)) {
20039
+ this.writeSymbolMark(mark2);
20040
+ } else if (this.isInlineMark(mark2)) {
19206
20041
  this.writeInlineMarkStartEnd();
19207
- this.writeInlineMark(mark);
20042
+ this.writeInlineMark(mark2);
19208
20043
  } else {
19209
20044
  }
19210
20045
  }
19211
20046
  }
19212
20047
  if (stage == Stage.exit) {
19213
20048
  let inlineMarkWritten = false;
19214
- for (const mark of marks) {
19215
- if (this.isStandardMark(mark)) {
20049
+ for (const mark2 of marks) {
20050
+ if (this.isStandardMark(mark2)) {
19216
20051
  if (!singleMark) {
19217
20052
  inlineMarkWritten = true;
19218
20053
  }
19219
- } else if (TextMarkType.comment === mark.type || TextMarkType.link === mark.type || TextMarkType.ref === mark.type || TextMarkType.xref === mark.type || TextMarkType.footnote === mark.type || TextMarkType.footnoteStar === mark.type || this.isInlineMark(mark)) {
20054
+ } else if (TextMarkType.comment === mark2.type || TextMarkType.link === mark2.type || TextMarkType.ref === mark2.type || TextMarkType.xref === mark2.type || TextMarkType.footnote === mark2.type || TextMarkType.footnoteStar === mark2.type || this.isInlineMark(mark2)) {
19220
20055
  inlineMarkWritten = true;
19221
20056
  } else {
19222
20057
  }
19223
20058
  }
19224
- if (inlineMarkWritten) this.writeInlineMarkStartEnd();
20059
+ if (inlineMarkWritten) {
20060
+ this.writeInlineMarkStartEnd();
20061
+ this.chainJustClosed = true;
20062
+ }
19225
20063
  }
19226
20064
  }
19227
20065
  }
@@ -19257,15 +20095,6 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19257
20095
  s += " ";
19258
20096
  this.write(s);
19259
20097
  }
19260
- writeSection(node) {
19261
- let s = "";
19262
- if (node.section) {
19263
- s = `|${node.section}: `;
19264
- } else {
19265
- s = "|";
19266
- }
19267
- this.write(s);
19268
- }
19269
20098
  writeBullet(node, route) {
19270
20099
  let bullet = this.getIndentationString();
19271
20100
  const listParent = this.getParentNode(route, 2);
@@ -19288,7 +20117,7 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19288
20117
  bullet += "\u2022a ";
19289
20118
  } else if (listType === TextNodeType.taskList) {
19290
20119
  const taskList = node;
19291
- const checked = taskList.attrs?.checked ?? false;
20120
+ const checked = taskList.attrs?.checked === true;
19292
20121
  bullet += checked ? "\u2022+ " : "\u2022- ";
19293
20122
  }
19294
20123
  if (bullet) this.write(bullet);
@@ -19297,28 +20126,20 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19297
20126
  if (node.attrs == null || !node.attrs.src) return;
19298
20127
  const attrs = node.attrs;
19299
20128
  const inlineImage = node.type === TextNodeType.imageInline;
19300
- let ignoreAttributes;
19301
- if (inlineImage) {
19302
- ignoreAttributes = /* @__PURE__ */ new Set(["alt", "zoomDisabled", "title"]);
19303
- const a = attrs;
19304
- if (a.alignmentVertical === "top") ignoreAttributes.add("alignmentVertical");
19305
- if (a.size === "line-height") ignoreAttributes.add("size");
19306
- }
19307
- const mediaAttrs = this.getMediaAttrs(inlineImage ? "imageInline" : "image", attrs, {
19308
- ignoreAttributes
19309
- });
20129
+ const kind = inlineImage ? "imageInline" : "image";
20130
+ const chain = serializeMediaChain(kind, attrs);
19310
20131
  let s = "";
19311
20132
  if (inlineImage) {
19312
20133
  s = `==${attrs.alt ?? ""}==`;
19313
20134
  }
19314
- s += mediaAttrs ? `|${mediaAttrs}|` : "";
20135
+ s += `|${kind}:${attrs.src}${chain}|`;
19315
20136
  this.write(s);
19316
20137
  }
19317
20138
  writeCodeBlock(node) {
19318
- if (node.attrs == null || !node.attrs.language) return;
19319
- const attrs = node.attrs;
19320
- const s = `|code:${attrs.language}
19321
- `;
20139
+ const raw = node.attrs?.language ?? node.language;
20140
+ const language = normalizeBlockCodeLanguage(raw) ?? "";
20141
+ const s = language ? `|code:${language}
20142
+ ` : "|code\n";
19322
20143
  this.write(s);
19323
20144
  }
19324
20145
  writeLatex(node) {
@@ -19334,10 +20155,10 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19334
20155
  writeMarkTextWrapper(s) {
19335
20156
  if (s) this.write(s);
19336
20157
  }
19337
- writeInlineMark(mark) {
19338
- const attrs = mark.attrs ?? {};
20158
+ writeInlineMark(mark2) {
20159
+ const attrs = mark2.attrs ?? {};
19339
20160
  let s;
19340
- switch (mark.type) {
20161
+ switch (mark2.type) {
19341
20162
  case TextMarkType.textStyle:
19342
20163
  case TextMarkType.color:
19343
20164
  s = `color:${attrs.color ?? ""}`;
@@ -19348,10 +20169,10 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19348
20169
  break;
19349
20170
  case TextMarkType.highlight:
19350
20171
  case TextMarkType.userHighlight:
19351
- s = attrs.color ? `${mark.type}|color:${attrs.color}` : `${mark.type}`;
20172
+ s = attrs.color ? `${mark2.type}|color:${attrs.color}` : `${mark2.type}`;
19352
20173
  break;
19353
20174
  default: {
19354
- s = `${mark.type}`;
20175
+ s = `${mark2.type}`;
19355
20176
  for (const [k, v] of Object.entries(attrs)) {
19356
20177
  if (k === "language" && v !== "plain text" || k === "propertyRef" || k === "name") {
19357
20178
  s = `${s}:${v}`;
@@ -19361,88 +20182,49 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19361
20182
  }
19362
20183
  this.write(s);
19363
20184
  }
19364
- /**
19365
- * Resolve the marks of a text node into the marks that will actually be written.
19366
- *
19367
- * - Merges a legacy standalone 'duration' mark into its sibling 'timer' mark.
19368
- * - Drops marks the current grammar cannot express (standalone 'duration', 'timer'
19369
- * without a duration).
19370
- * - Moves a 'textStyle'/'color' mark before a preceding bare 'highlight'/'userHighlight'
19371
- * mark when its color is a valid highlight color; written in the original order the
19372
- * output would re-parse as a highlight-with-color compound mark and change meaning.
19373
- */
19374
- getWritableMarks(nodeMarks) {
19375
- const attrsOf = (m) => m.attrs ?? {};
19376
- let marks = [...nodeMarks];
19377
- const timer = marks.find((m) => m.type === TextMarkType.timer);
19378
- const duration = marks.find((m) => m.type === TextMarkType.duration);
19379
- if (timer && duration && !attrsOf(timer).duration) {
19380
- marks = marks.map(
19381
- (m) => m === timer ? {
19382
- ...timer,
19383
- attrs: { ...attrsOf(timer), duration: attrsOf(duration).duration }
19384
- } : m
19385
- );
19386
- }
19387
- marks = marks.filter((m) => {
19388
- if (m.type === TextMarkType.duration) return false;
19389
- if (m.type === TextMarkType.timer) return !!attrsOf(m).duration;
19390
- return true;
19391
- });
19392
- const isBareHighlight = (m) => (m.type === TextMarkType.highlight || m.type === TextMarkType.userHighlight) && !attrsOf(m).color;
19393
- const isHighlightColorStyle = (m) => (m.type === TextMarkType.textStyle || m.type === TextMarkType.color) && HIGHLIGHT_COLORS.indexOf(attrsOf(m).color) !== -1;
19394
- for (let i = 0; i < marks.length - 1; i++) {
19395
- if (isBareHighlight(marks[i]) && isHighlightColorStyle(marks[i + 1])) {
19396
- const tmp = marks[i];
19397
- marks[i] = marks[i + 1];
19398
- marks[i + 1] = tmp;
19399
- }
19400
- }
19401
- return marks;
19402
- }
19403
20185
  /**
19404
20186
  * True if the mark is written using its standard form (e.g. **bold**, !!highlight!!)
19405
20187
  * when it is the only mark. A highlight mark with a color attribute is excluded - it
19406
20188
  * can only be expressed using the inline chain form (==text==|highlight|color:x|).
19407
20189
  */
19408
- isStandardMark(mark) {
19409
- if (STANDARD_MARK_TYPES.indexOf(mark.type) === -1) return false;
19410
- return !(mark.attrs && mark.attrs.color);
20190
+ isStandardMark(mark2) {
20191
+ if (STANDARD_MARK_TYPES.indexOf(mark2.type) === -1) return false;
20192
+ return !(mark2.attrs && mark2.attrs.color);
19411
20193
  }
19412
20194
  /**
19413
20195
  * True if the mark is written using the inline chain form (==text==|mark|).
19414
20196
  */
19415
- isInlineMark(mark) {
19416
- if (INLINE_MARK_TYPES.indexOf(mark.type) !== -1) return true;
19417
- return mark.type === TextMarkType.highlight && !!(mark.attrs && mark.attrs.color);
20197
+ isInlineMark(mark2) {
20198
+ if (INLINE_MARK_TYPES.indexOf(mark2.type) !== -1) return true;
20199
+ return mark2.type === TextMarkType.highlight && !!(mark2.attrs && mark2.attrs.color);
19418
20200
  }
19419
- writeCommentMark(mark) {
19420
- const comment = mark.comment || "";
20201
+ writeCommentMark(mark2) {
20202
+ const comment = mark2.comment || "";
19421
20203
  const s = `#${comment}`;
19422
20204
  this.write(s);
19423
20205
  }
19424
- writeLinkMark(mark) {
19425
- const href = mark.attrs?.href || "";
20206
+ writeLinkMark(mark2) {
20207
+ const href = mark2.attrs?.href || "";
19426
20208
  const linkText = (href ?? "").replace(LINK_BREAKSCAPE_REGEX, "^]");
19427
20209
  const s = `link:${linkText}`;
19428
20210
  this.write(s);
19429
20211
  }
19430
- writeRefMark(mark) {
19431
- const ref = mark.attrs?.reference ?? "";
20212
+ writeRefMark(mark2) {
20213
+ const ref = mark2.attrs?.reference ?? "";
19432
20214
  const s = `\u25BA${ref}`;
19433
20215
  this.write(s);
19434
20216
  }
19435
- writeXRefMark(mark) {
19436
- const xref = mark.attrs?.xref ?? "";
19437
- const ref = mark.attrs?.reference ?? "";
20217
+ writeXRefMark(mark2) {
20218
+ const xref = mark2.attrs?.xref ?? "";
20219
+ const ref = mark2.attrs?.reference ?? "";
19438
20220
  let s = `xref:${xref}`;
19439
20221
  if (ref) s += `|\u25BA${ref}`;
19440
20222
  this.write(s);
19441
20223
  }
19442
- writeExtRefMark(mark) {
19443
- const extref = mark.attrs?.extref ?? "";
19444
- const refs = mark.attrs?.references ?? [];
19445
- const provider = mark.attrs?.provider ?? "";
20224
+ writeExtRefMark(mark2) {
20225
+ const extref = mark2.attrs?.extref ?? "";
20226
+ const refs = mark2.attrs?.references ?? [];
20227
+ const provider = mark2.attrs?.provider ?? "";
19446
20228
  let s = `extref:${extref}`;
19447
20229
  for (const ref of refs) {
19448
20230
  s += `|\u25BA${ref ?? ""}`;
@@ -19450,39 +20232,39 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19450
20232
  s += `|provider:${provider}`;
19451
20233
  this.write(s);
19452
20234
  }
19453
- writeFootnoteMark(mark) {
20235
+ writeFootnoteMark(mark2) {
19454
20236
  const s = `footnote:`;
19455
20237
  this.write(s);
19456
20238
  const text = this.internalTextGenerator?.generateSync(
19457
- mark.attrs?.content,
20239
+ mark2.attrs?.content,
19458
20240
  this.textFormat,
19459
20241
  this.textLocation,
19460
20242
  {
19461
20243
  ...this.generateOptions,
19462
- forceInline: true
20244
+ forceInline: true,
20245
+ chainValueContext: true
19463
20246
  }
19464
20247
  ) ?? "";
19465
20248
  this.write(text);
19466
20249
  }
19467
- writeFootnoteStarMark(mark) {
20250
+ writeFootnoteStarMark(mark2) {
19468
20251
  const s = `footnote*:`;
19469
20252
  this.write(s);
19470
20253
  const text = this.internalTextGenerator?.generateSync(
19471
- mark.attrs?.content,
20254
+ mark2.attrs?.content,
19472
20255
  this.textFormat,
19473
20256
  this.textLocation,
19474
20257
  {
19475
20258
  ...this.generateOptions,
19476
- forceInline: true
20259
+ forceInline: true,
20260
+ chainValueContext: true
19477
20261
  }
19478
20262
  ) ?? "";
19479
20263
  this.write(text);
19480
20264
  }
19481
- writeSymbolMark(mark) {
19482
- if (mark.attrs == null) return;
19483
- const attrs = mark.attrs;
19484
- const mediaAttrs = this.getMediaAttrs("symbol", attrs);
19485
- const s = mediaAttrs ?? "";
20265
+ writeSymbolMark(mark2) {
20266
+ const attrs = mark2.attrs ?? {};
20267
+ const s = `symbol:${attrs.src ?? ""}${serializeMediaChain("symbol", attrs)}`;
19486
20268
  this.write(s);
19487
20269
  }
19488
20270
  writeInlineMarkStartEnd() {
@@ -19512,52 +20294,6 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19512
20294
  }
19513
20295
  this.writeString(tag);
19514
20296
  }
19515
- getMediaAttrs(mediaType, attrs, options) {
19516
- if (!mediaType) return void 0;
19517
- const opts = Object.assign({}, options);
19518
- const ignoreAttributes = opts.ignoreAttributes ?? /* @__PURE__ */ new Set();
19519
- let s = `${mediaType}:${attrs?.src ?? ""}`;
19520
- const entries = Object.entries(attrs).filter(([k, _v]) => k !== "src");
19521
- for (let i = 0; i < entries.length; i++) {
19522
- const [k, v] = entries[i];
19523
- if (ignoreAttributes.has(k)) continue;
19524
- switch (k) {
19525
- case "textAlign":
19526
- if (v !== "left") s += `|captionAlign:${v}`;
19527
- break;
19528
- case "alignment":
19529
- if (v !== "center") {
19530
- if (v) s += `|alignment:${v}`;
19531
- }
19532
- break;
19533
- case "title":
19534
- if (v) s += `|caption:${v}`;
19535
- break;
19536
- case "class":
19537
- if (v !== "center") {
19538
- if (v) s += `|align:${v}`;
19539
- }
19540
- break;
19541
- case "comment":
19542
- if (v) s += `|#${v}`;
19543
- break;
19544
- case "":
19545
- if (stringUtils.isString(v)) s += `|:${v}`;
19546
- else s += `|`;
19547
- break;
19548
- case "zoomDisabled":
19549
- if (!v) s += "|zoomDisabled:false";
19550
- break;
19551
- case "alt":
19552
- case "width":
19553
- case "height":
19554
- default:
19555
- if (k && v) s += `|${k}:${v}`;
19556
- break;
19557
- }
19558
- }
19559
- return s;
19560
- }
19561
20297
  //
19562
20298
  // Helper functions
19563
20299
  //
@@ -19583,6 +20319,7 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19583
20319
  */
19584
20320
  write(value) {
19585
20321
  value = this.getInterTextBreakscape(value) + value;
20322
+ this.chainJustClosed = false;
19586
20323
  if (this.options.writeCallback) {
19587
20324
  this.options.writeCallback(value);
19588
20325
  }
@@ -33768,8 +34505,8 @@ var Builder = class extends BaseBuilder {
33768
34505
  break;
33769
34506
  }
33770
34507
  case BodyBitType.mark: {
33771
- const mark = part;
33772
- instance7.fillBooleanExample([mark], __isDefaultExample, example, false);
34508
+ const mark2 = part;
34509
+ instance7.fillBooleanExample([mark2], __isDefaultExample, example, false);
33773
34510
  break;
33774
34511
  }
33775
34512
  case BodyBitType.select: {
@@ -34550,10 +35287,10 @@ var BitmarkGenerator = class extends AstWalkerGenerator {
34550
35287
  const markConfig = node.value;
34551
35288
  const parent = this.getParentNode(route);
34552
35289
  if (parent?.key !== NodeType.markConfig) return true;
34553
- const { mark, color, emphasis } = markConfig;
34554
- if (mark) {
35290
+ const { mark: mark2, color, emphasis } = markConfig;
35291
+ if (mark2) {
34555
35292
  this.writeNL();
34556
- this.writeProperty("mark", mark, route, {
35293
+ this.writeProperty("mark", mark2, route, {
34557
35294
  format: TagFormat.plainText
34558
35295
  });
34559
35296
  if (color) {
@@ -34770,9 +35507,9 @@ var BitmarkGenerator = class extends AstWalkerGenerator {
34770
35507
  }
34771
35508
  // bodyBit -> mark
34772
35509
  enter_mark(node, _route) {
34773
- const mark = node.value;
35510
+ const mark2 = node.value;
34774
35511
  this.writeOPE();
34775
- this.writeTextOrValue(mark.solution, TextFormat.plainText, TextLocation.tag);
35512
+ this.writeTextOrValue(mark2.solution, TextFormat.plainText, TextLocation.tag);
34776
35513
  this.writeCL();
34777
35514
  return true;
34778
35515
  }
@@ -34832,9 +35569,9 @@ var BitmarkGenerator = class extends AstWalkerGenerator {
34832
35569
  leaf_mark(node, route) {
34833
35570
  const root = route[0];
34834
35571
  if (root?.key !== NodeType.mark) return;
34835
- const mark = node.value;
34836
- if (mark) {
34837
- this.writeProperty("mark", mark, route, {
35572
+ const mark2 = node.value;
35573
+ if (mark2) {
35574
+ this.writeProperty("mark", mark2, route, {
34838
35575
  format: TagFormat.plainText
34839
35576
  });
34840
35577
  }
@@ -35548,7 +36285,7 @@ var BitmarkGenerator = class extends AstWalkerGenerator {
35548
36285
  leaf_level(node, route) {
35549
36286
  const parent = this.getParentNode(route);
35550
36287
  if (parent?.key !== NodeType.bitsValue) return true;
35551
- if (!instance2.isOfBitType(this.bitType, [BitType.chapter])) return true;
36288
+ if (!instance2.isOfBitType(this.bitType, [BitType.chapter, BitType.h])) return true;
35552
36289
  const level = node.value;
35553
36290
  const bit = parent?.value;
35554
36291
  if (level > 0 && bit.title == null) {
@@ -36591,8 +37328,6 @@ var MARK_TO_TAG = {
36591
37328
  highlight: "mark",
36592
37329
  code: "code"
36593
37330
  };
36594
- var INLINE_IMAGE_RE = /==([^=]*(?:=(?!=)[^=]*)*)==\|imageInline:([^|\s]+)((?:\|(?:@?[A-Za-z][A-Za-z0-9_-]*:[^|\s]+|#[^|\s]*))*)\|?/g;
36595
- var MAX_IMAGE_DIMENSION = 9999;
36596
37331
  var HtmlTableGenerator = class {
36597
37332
  constructor() {
36598
37333
  __publicField(this, "indentUnit", " ");
@@ -36734,13 +37469,13 @@ var HtmlTableGenerator = class {
36734
37469
  if (!marks || marks.length === 0) return text;
36735
37470
  let open = "";
36736
37471
  let close = "";
36737
- for (const mark of marks) {
36738
- if (mark.type === "link") {
36739
- const href = mark.attrs?.href ?? "";
37472
+ for (const mark2 of marks) {
37473
+ if (mark2.type === "link") {
37474
+ const href = mark2.attrs?.href ?? "";
36740
37475
  open += `<a href="${this.escapeAttr(href)}">`;
36741
37476
  close = `</a>${close}`;
36742
37477
  } else {
36743
- const tag = MARK_TO_TAG[mark.type];
37478
+ const tag = MARK_TO_TAG[mark2.type];
36744
37479
  if (tag) {
36745
37480
  open += `<${tag}>`;
36746
37481
  close = `</${tag}>${close}`;
@@ -36804,37 +37539,7 @@ var HtmlTableGenerator = class {
36804
37539
  return `<img ${parts.join(" ")}>`;
36805
37540
  }
36806
37541
  textToHtml(text) {
36807
- let html = "";
36808
- let lastIndex = 0;
36809
- for (const match of text.matchAll(INLINE_IMAGE_RE)) {
36810
- const index = match.index ?? 0;
36811
- html += this.escapeText(text.slice(lastIndex, index));
36812
- html += this.inlineImageTokenToHtml(match);
36813
- lastIndex = index + match[0].length;
36814
- }
36815
- html += this.escapeText(text.slice(lastIndex));
36816
- return html;
36817
- }
36818
- inlineImageTokenToHtml(match) {
36819
- const attrs = {
36820
- alt: match[1],
36821
- src: match[2]
36822
- };
36823
- const rawAttrs = match[3] ?? "";
36824
- for (const attr of rawAttrs.split("|")) {
36825
- if (!attr || attr.startsWith("#")) continue;
36826
- const colon = attr.indexOf(":");
36827
- if (colon < 1) continue;
36828
- const key = attr.slice(0, colon).replace(/^@/, "");
36829
- const value = attr.slice(colon + 1);
36830
- if (key === "width" || key === "height") {
36831
- const n = Number.parseInt(value, 10);
36832
- if (!Number.isNaN(n) && n > 0 && n <= MAX_IMAGE_DIMENSION) attrs[key] = n;
36833
- } else if (key === "class" || key === "title") {
36834
- attrs[key] = value;
36835
- }
36836
- }
36837
- return this.imageToHtml({ type: "imageInline", attrs });
37542
+ return this.escapeText(text);
36838
37543
  }
36839
37544
  // --- formulas -------------------------------------------------------------
36840
37545
  latexToHtml(node) {
@@ -41336,13 +42041,13 @@ function markChainContentProcessor(context, contentDepth, tagsConfig, content, t
41336
42041
  if (contentDepth === ContentDepth.Chain) {
41337
42042
  markTagContentProcessor(context, ContentDepth.Chain, content, target);
41338
42043
  } else {
41339
- const mark = buildMark(
42044
+ const mark2 = buildMark(
41340
42045
  context,
41341
42046
  contentDepth,
41342
42047
  tagsConfig,
41343
42048
  content
41344
42049
  );
41345
- if (mark) bodyParts.push(mark);
42050
+ if (mark2) bodyParts.push(mark2);
41346
42051
  }
41347
42052
  }
41348
42053
  function buildMark(context, _contentDepth, tagsConfig, content) {
@@ -41357,13 +42062,13 @@ function buildMark(context, _contentDepth, tagsConfig, content) {
41357
42062
  if (context.DEBUG_CHAIN_TAGS) context.debugPrint("mark TAGS", chainTags);
41358
42063
  const { solution } = tags2;
41359
42064
  const { mark: markType, ...rest } = chainTags;
41360
- const mark = {
42065
+ const mark2 = {
41361
42066
  type: BodyBitType.mark,
41362
42067
  solution: solution ?? "",
41363
42068
  mark: instance4.asSingle(markType) ?? "",
41364
42069
  ...rest
41365
42070
  };
41366
- return mark;
42071
+ return mark2;
41367
42072
  }
41368
42073
 
41369
42074
  // src/parser/bitmark/peg/contentProcessors/PropertyContentProcessor.ts
@@ -41615,7 +42320,7 @@ function markConfigChainContentProcessor(context, _contentDepth, tagsConfig, con
41615
42320
  content.chain
41616
42321
  );
41617
42322
  if (context.DEBUG_CHAIN_TAGS) context.debugPrint("mark TAGS", tags2);
41618
- const mark = instance3.unbreakscape(
42323
+ const mark2 = instance3.unbreakscape(
41619
42324
  stringUtils.trimmedString(content.value) ?? "unknown",
41620
42325
  {
41621
42326
  format: TextFormat.bitmarkText,
@@ -41623,7 +42328,7 @@ function markConfigChainContentProcessor(context, _contentDepth, tagsConfig, con
41623
42328
  }
41624
42329
  );
41625
42330
  const config = {
41626
- mark,
42331
+ mark: mark2,
41627
42332
  emphasis: "underline",
41628
42333
  ...tags2
41629
42334
  };
@@ -42091,15 +42796,23 @@ function titleTagContentProcessor(context, _contentDepth, _tagsConfig, content,
42091
42796
  titleString: titleText ?? ""
42092
42797
  };
42093
42798
  }
42094
- function buildTitles(_context, bitType, title) {
42799
+ var H_TITLE_LEVEL_MAX = 7;
42800
+ function buildTitles(context, bitType, title) {
42095
42801
  title = title ?? [];
42096
- if (instance2.isOfBitType(bitType, BitType.chapter)) {
42802
+ if (instance2.isOfBitType(bitType, [BitType.chapter, BitType.h])) {
42097
42803
  let t;
42098
42804
  if (title.length > 0) t = title[title.length - 1];
42805
+ let level = title.length > 0 ? title.length - 1 : void 0;
42806
+ if (level != null && level > H_TITLE_LEVEL_MAX && instance2.isOfBitType(bitType, BitType.h)) {
42807
+ context.addWarning(
42808
+ `Title level of ${level} too high, setting to max value of ${H_TITLE_LEVEL_MAX}`
42809
+ );
42810
+ level = H_TITLE_LEVEL_MAX;
42811
+ }
42099
42812
  return {
42100
42813
  title: t?.titleAst ?? [],
42101
42814
  titleString: t?.titleString ?? "",
42102
- level: title.length > 0 ? title.length - 1 : void 0
42815
+ level
42103
42816
  };
42104
42817
  } else {
42105
42818
  if (Array.isArray(title)) {
@@ -47431,9 +48144,9 @@ ${nested}` : line;
47431
48144
  parts.push(href);
47432
48145
  }
47433
48146
  if (marks) {
47434
- for (const mark of marks) {
47435
- if (mark.type === "footnote") {
47436
- const footnote = mark;
48147
+ for (const mark2 of marks) {
48148
+ if (mark2.type === "footnote") {
48149
+ const footnote = mark2;
47437
48150
  if (footnote.attrs?.content) {
47438
48151
  const footnoteText = footnote.attrs.content.map((c) => this.textNodeToPlainText(c)).join("");
47439
48152
  if (footnoteText) parts.push(footnoteText);