@gmb/bitmark-parser-generator 5.40.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.
@@ -5089,6 +5089,9 @@ var GROUPS = {
5089
5089
  key: ConfigKey.tag_item,
5090
5090
  jsonKey: "item",
5091
5091
  exportJsonKey: { item: "$" },
5092
+ // PLAN-140 W3 (NISO import): the clause/note label of a mapped
5093
+ // source element ([%1], [%ANMERKUNG 1]) — same as group_standardItemLead.
5094
+ mappingKeys: { "xml-niso-iec": { "@el": "label", "@text": "$" } },
5092
5095
  description: "The item for the bit"
5093
5096
  }
5094
5097
  ]
@@ -16714,7 +16717,7 @@ var instance2 = new Config();
16714
16717
  // src/generated/package_info.ts
16715
16718
  var PACKAGE_INFO = {
16716
16719
  "name": "@gmb/bitmark-parser-generator",
16717
- "version": "5.40.0",
16720
+ "version": "5.41.0",
16718
16721
  "author": "Get More Brain Ltd",
16719
16722
  "license": "ISC",
16720
16723
  "description": "A bitmark parser and generator using Peggy.js"
@@ -18568,6 +18571,752 @@ var AstWalkerGenerator = class {
18568
18571
  }
18569
18572
  };
18570
18573
 
18574
+ // src/generator/text/TextGrammarConstraints.ts
18575
+ var COLORS = [
18576
+ "aqua",
18577
+ "black",
18578
+ "blue",
18579
+ "brown",
18580
+ "fuchsia",
18581
+ "lightgrey",
18582
+ "gray",
18583
+ "darkgray",
18584
+ "green",
18585
+ "lime",
18586
+ "magenta",
18587
+ "maroon",
18588
+ "navy",
18589
+ "olive",
18590
+ "orange",
18591
+ "pink",
18592
+ "purple",
18593
+ "red",
18594
+ "silver",
18595
+ "teal",
18596
+ "violet",
18597
+ "white",
18598
+ "yellow"
18599
+ ];
18600
+ var HIGHLIGHT_COLORS = [
18601
+ "orange",
18602
+ "yellow",
18603
+ "green",
18604
+ "blue",
18605
+ "purple",
18606
+ "pink",
18607
+ "brown",
18608
+ "white",
18609
+ "black",
18610
+ "gray"
18611
+ ];
18612
+ var ALTERNATIVE_STYLE_TAGS = [
18613
+ "bold",
18614
+ "italic",
18615
+ "light",
18616
+ "highlightOrange",
18617
+ "highlightYellow",
18618
+ "highlightGreen",
18619
+ "highlightBlue",
18620
+ "highlightPurple",
18621
+ "highlightPink",
18622
+ "highlightBrown",
18623
+ "highlightBlack",
18624
+ "highlightWhite",
18625
+ "highlightGray",
18626
+ "highlight",
18627
+ "strike",
18628
+ "subscript",
18629
+ "superscript",
18630
+ "ins",
18631
+ "del",
18632
+ "underline",
18633
+ "doubleUnderline",
18634
+ "smallcaps",
18635
+ "circle",
18636
+ "languageEmRed",
18637
+ "languageEmOrange",
18638
+ "languageEmYellow",
18639
+ "languageEmGreen",
18640
+ "languageEmBlue",
18641
+ "languageEmPurple",
18642
+ "languageEmPink",
18643
+ "languageEmBrown",
18644
+ "languageEmBlack",
18645
+ "languageEmWhite",
18646
+ "languageEmGray",
18647
+ "languageEm",
18648
+ "userUnderline",
18649
+ "userDoubleUnderline",
18650
+ "userStrike",
18651
+ "userCircle",
18652
+ "userHighlight",
18653
+ "notranslate"
18654
+ ];
18655
+ var MEDIA_ALIGNMENTS = ["left", "center", "right"];
18656
+ var INLINE_MEDIA_ALIGNMENTS = [
18657
+ "top",
18658
+ "middle",
18659
+ "bottom",
18660
+ "baseline",
18661
+ "sub",
18662
+ "super",
18663
+ "text-bottom",
18664
+ "text-top"
18665
+ ];
18666
+ var INLINE_MEDIA_SIZES = [
18667
+ "line-height",
18668
+ "font-height",
18669
+ "super",
18670
+ "sub",
18671
+ "explicit"
18672
+ ];
18673
+ var LINE_TERMINATOR_REGEX = /[\n\r\u2028\u2029]/;
18674
+ var CHAIN_STRING_INVALID_REGEX = /[|\n\r\u2028\u2029]/;
18675
+ var URL_CHAR_CLASS = "a-zA-Z0-9!*'()=+,\\-./_?#@[\\]$&;%:{}~^";
18676
+ var URL_CHAR_REGEX = new RegExp(`^[${URL_CHAR_CLASS}]$`);
18677
+ var URL_HTTP_REGEX = new RegExp(`^https?://[${URL_CHAR_CLASS}]*$`);
18678
+ var URL_REGEX = new RegExp(`^(https?://|mailto:)[${URL_CHAR_CLASS}]*$`);
18679
+ function isChainString(v) {
18680
+ return typeof v === "string" && !CHAIN_STRING_INVALID_REGEX.test(v);
18681
+ }
18682
+ function isSingleLine(v) {
18683
+ return typeof v === "string" && !LINE_TERMINATOR_REGEX.test(v);
18684
+ }
18685
+ function hasLineTerminator(v) {
18686
+ return LINE_TERMINATOR_REGEX.test(v);
18687
+ }
18688
+ function isColor(v) {
18689
+ return typeof v === "string" && COLORS.indexOf(v) !== -1;
18690
+ }
18691
+ function isHighlightColor(v) {
18692
+ return typeof v === "string" && HIGHLIGHT_COLORS.indexOf(v) !== -1;
18693
+ }
18694
+ function isMediaAlignment(v) {
18695
+ return typeof v === "string" && MEDIA_ALIGNMENTS.indexOf(v) !== -1;
18696
+ }
18697
+ function isInlineMediaAlignment(v) {
18698
+ return typeof v === "string" && INLINE_MEDIA_ALIGNMENTS.indexOf(v) !== -1;
18699
+ }
18700
+ function isInlineMediaSize(v) {
18701
+ return typeof v === "string" && INLINE_MEDIA_SIZES.indexOf(v) !== -1;
18702
+ }
18703
+ function toUInt(v) {
18704
+ if (typeof v === "number") return Number.isInteger(v) && v >= 0 ? v : void 0;
18705
+ if (typeof v === "string" && /^[0-9]+$/.test(v)) return parseInt(v, 10);
18706
+ return void 0;
18707
+ }
18708
+ function toBoolean(v) {
18709
+ if (typeof v === "boolean") return v;
18710
+ if (v === "true") return true;
18711
+ if (v === "false") return false;
18712
+ return void 0;
18713
+ }
18714
+ function isDuration(v) {
18715
+ return isChainString(v) && v.trim().startsWith("P");
18716
+ }
18717
+ function isUrlHttp(v) {
18718
+ return typeof v === "string" && URL_HTTP_REGEX.test(v);
18719
+ }
18720
+ function isUrl(v) {
18721
+ return typeof v === "string" && URL_REGEX.test(v);
18722
+ }
18723
+ function isUrlChar(c) {
18724
+ return URL_CHAR_REGEX.test(c);
18725
+ }
18726
+ function bareUrlText(href) {
18727
+ return href.replace(/^(https?:\/\/|mailto:)/, "");
18728
+ }
18729
+ function isInlineAlt(v) {
18730
+ return typeof v === "string" && v.length > 0 && v.indexOf("==") === -1 && !v.startsWith("=") && !v.endsWith("=");
18731
+ }
18732
+ function isHeadingLevel(v) {
18733
+ return typeof v === "number" && Number.isInteger(v) && v >= 1 && v <= 3;
18734
+ }
18735
+ function normalizeInlineCodeLanguage(v) {
18736
+ if (!isChainString(v)) return void 0;
18737
+ return v.trim().toLowerCase();
18738
+ }
18739
+ function normalizeBlockCodeLanguage(v) {
18740
+ if (!isSingleLine(v)) return void 0;
18741
+ return v.trim().toLowerCase();
18742
+ }
18743
+
18744
+ // src/generator/text/TextMediaAttrs.ts
18745
+ var uint = (v) => toUInt(v);
18746
+ var bool = (v) => toBoolean(v);
18747
+ var alignment = (v) => isMediaAlignment(v) ? v : void 0;
18748
+ var chainString = (v) => isChainString(v) ? v.trim() : void 0;
18749
+ var inlineAlignment = (v) => isInlineMediaAlignment(v) ? v : void 0;
18750
+ var inlineSize = (v) => isInlineMediaSize(v) ? v : void 0;
18751
+ var VALIDATORS = {
18752
+ image: {
18753
+ alt: chainString,
18754
+ title: chainString,
18755
+ alignment,
18756
+ textAlign: alignment,
18757
+ zoomDisabled: bool,
18758
+ width: uint,
18759
+ height: uint,
18760
+ comment: chainString
18761
+ },
18762
+ imageInline: {
18763
+ srcAlt: chainString,
18764
+ alignmentVertical: inlineAlignment,
18765
+ size: inlineSize,
18766
+ width: uint,
18767
+ height: uint,
18768
+ comment: chainString
18769
+ },
18770
+ symbol: {
18771
+ alt: chainString,
18772
+ title: chainString,
18773
+ caption: chainString,
18774
+ alignment,
18775
+ textAlign: alignment,
18776
+ captionAlign: alignment,
18777
+ zoomDisabled: bool,
18778
+ width: uint,
18779
+ height: uint,
18780
+ comment: chainString
18781
+ }
18782
+ };
18783
+ var TAG_NAMES = {
18784
+ textAlign: "captionAlign",
18785
+ title: "caption"
18786
+ };
18787
+ var DEFAULTS = {
18788
+ image: { alignment: "center", textAlign: "left", zoomDisabled: true },
18789
+ imageInline: { alignmentVertical: "top", size: "line-height" },
18790
+ symbol: {}
18791
+ };
18792
+ function sanitizeMediaAttrs(kind, attrs) {
18793
+ const result = {};
18794
+ if (!attrs || typeof attrs !== "object") return result;
18795
+ const validators = VALIDATORS[kind];
18796
+ for (const [k, v] of Object.entries(attrs)) {
18797
+ const validator = validators[k];
18798
+ if (!validator || v == null) continue;
18799
+ const valid = validator(v);
18800
+ if (valid !== void 0) result[k] = valid;
18801
+ }
18802
+ if (kind === "symbol") {
18803
+ if ("caption" in result) delete result.title;
18804
+ if ("captionAlign" in result) delete result.textAlign;
18805
+ }
18806
+ return result;
18807
+ }
18808
+ function serializeMediaChain(kind, attrs) {
18809
+ const defaults = DEFAULTS[kind];
18810
+ let s = "";
18811
+ for (const k of Object.keys(VALIDATORS[kind])) {
18812
+ const v = attrs[k];
18813
+ if (v == null) continue;
18814
+ if (k in defaults && defaults[k] === v) continue;
18815
+ if (k === "comment") {
18816
+ if (v) s += `|#${v}`;
18817
+ } else if (typeof v === "string" && v === "") {
18818
+ continue;
18819
+ } else {
18820
+ s += `|${TAG_NAMES[k] ?? k}:${v}`;
18821
+ }
18822
+ }
18823
+ return s;
18824
+ }
18825
+
18826
+ // src/generator/text/TextMarkSanitizer.ts
18827
+ var STANDARD_SHORT_FORM_MARKS = [
18828
+ TextMarkType.bold,
18829
+ TextMarkType.italic,
18830
+ TextMarkType.light,
18831
+ TextMarkType.highlight
18832
+ ];
18833
+ function attrsOf(mark2) {
18834
+ const a = mark2.attrs;
18835
+ return a && typeof a === "object" && !Array.isArray(a) ? a : {};
18836
+ }
18837
+ function chainValue(v) {
18838
+ if (v == null) return "";
18839
+ return isChainString(v) ? v.trim() : void 0;
18840
+ }
18841
+ function mark(type, attrs) {
18842
+ return attrs ? { type, attrs } : { type };
18843
+ }
18844
+ function sanitizeMark(m, options) {
18845
+ const attrs = attrsOf(m);
18846
+ switch (m.type) {
18847
+ case TextMarkType.highlight:
18848
+ case TextMarkType.userHighlight: {
18849
+ const color = attrs.color;
18850
+ return isHighlightColor(color) ? mark(m.type, { color }) : mark(m.type);
18851
+ }
18852
+ case TextMarkType.textStyle:
18853
+ case TextMarkType.color: {
18854
+ const color = attrs.color;
18855
+ return isColor(color) ? mark(TextMarkType.textStyle, { color }) : void 0;
18856
+ }
18857
+ case TextMarkType.link: {
18858
+ const href = chainValue(attrs.href);
18859
+ return href === void 0 ? void 0 : mark(m.type, { href });
18860
+ }
18861
+ case TextMarkType.ref: {
18862
+ const reference = chainValue(attrs.reference);
18863
+ return reference === void 0 ? void 0 : mark(m.type, { reference });
18864
+ }
18865
+ case TextMarkType.xref: {
18866
+ const xref = chainValue(attrs.xref);
18867
+ if (xref === void 0) return void 0;
18868
+ const reference = chainValue(attrs.reference) ?? "";
18869
+ return mark(m.type, { xref, reference });
18870
+ }
18871
+ case TextMarkType.extref: {
18872
+ const extref = chainValue(attrs.extref);
18873
+ const provider = chainValue(attrs.provider);
18874
+ if (extref === void 0 || provider === void 0) return void 0;
18875
+ const refs = Array.isArray(attrs.references) ? attrs.references : [];
18876
+ const references = refs.map((r) => chainValue(r)).filter((r) => r !== void 0);
18877
+ return mark(m.type, { extref, references, provider });
18878
+ }
18879
+ case TextMarkType.footnote:
18880
+ case TextMarkType.footnoteStar: {
18881
+ const content = options.normalizeChainValue ? options.normalizeChainValue(attrs.content) : Array.isArray(attrs.content) ? attrs.content : [];
18882
+ return content === void 0 ? void 0 : mark(m.type, { content });
18883
+ }
18884
+ case TextMarkType.symbol: {
18885
+ const src = chainValue(attrs.src);
18886
+ if (src === void 0) return void 0;
18887
+ return mark(m.type, { src, ...sanitizeMediaAttrs("symbol", attrs) });
18888
+ }
18889
+ case TextMarkType.var: {
18890
+ const name = chainValue(attrs.name);
18891
+ return name === void 0 ? void 0 : mark(m.type, { name });
18892
+ }
18893
+ case TextMarkType.code: {
18894
+ const language = normalizeInlineCodeLanguage(attrs.language);
18895
+ return language === void 0 ? mark(m.type) : mark(m.type, { language });
18896
+ }
18897
+ case TextMarkType.timer: {
18898
+ const duration = attrs.duration;
18899
+ if (!isDuration(duration)) return void 0;
18900
+ const name = chainValue(attrs.name) ?? "";
18901
+ return mark(m.type, { name, duration: duration.trim() });
18902
+ }
18903
+ case TextMarkType.colorPicker: {
18904
+ const propertyRef = chainValue(attrs.propertyRef);
18905
+ return propertyRef === void 0 ? void 0 : mark(m.type, { propertyRef });
18906
+ }
18907
+ case TextMarkType.comment: {
18908
+ const comment = chainValue(m.comment);
18909
+ return comment === void 0 ? void 0 : { type: m.type, comment };
18910
+ }
18911
+ default:
18912
+ if (ALTERNATIVE_STYLE_TAGS.indexOf(m.type) !== -1) return mark(m.type);
18913
+ return void 0;
18914
+ }
18915
+ }
18916
+ function mergeLegacyTimer(marks) {
18917
+ const timer = marks.find((m) => m.type === TextMarkType.timer);
18918
+ const duration = marks.find((m) => m.type === TextMarkType.duration);
18919
+ if (!timer || !duration || attrsOf(timer).duration) return marks;
18920
+ return marks.map(
18921
+ (m) => m === timer ? { ...timer, attrs: { ...attrsOf(timer), duration: attrsOf(duration).duration } } : m
18922
+ );
18923
+ }
18924
+ function orderMarks(marks) {
18925
+ const a = (m) => m.attrs ?? {};
18926
+ const isBareHighlight = (m) => (m.type === TextMarkType.highlight || m.type === TextMarkType.userHighlight) && !a(m).color;
18927
+ const isHighlightColorStyle = (m) => m.type === TextMarkType.textStyle && isHighlightColor(a(m).color);
18928
+ const isEmptyXref = (m) => m.type === TextMarkType.xref && !a(m).reference;
18929
+ const result = [];
18930
+ for (const m of marks) {
18931
+ if (m.type === TextMarkType.ref) {
18932
+ const xrefIdx = result.findIndex(isEmptyXref);
18933
+ if (xrefIdx !== -1) {
18934
+ result.splice(xrefIdx, 0, m);
18935
+ continue;
18936
+ }
18937
+ }
18938
+ result.push(m);
18939
+ }
18940
+ for (let i = 0; i < result.length - 1; i++) {
18941
+ if (isBareHighlight(result[i]) && isHighlightColorStyle(result[i + 1])) {
18942
+ [result[i], result[i + 1]] = [result[i + 1], result[i]];
18943
+ }
18944
+ }
18945
+ const symbols = result.filter((m) => m.type === TextMarkType.symbol);
18946
+ if (symbols.length === 0) return result;
18947
+ return [...result.filter((m) => m.type !== TextMarkType.symbol), symbols[0]];
18948
+ }
18949
+ function sanitizeMarks(marks, options = {}) {
18950
+ if (!Array.isArray(marks)) return [];
18951
+ let loose = marks.filter(
18952
+ (m) => !!m && typeof m === "object" && typeof m.type === "string"
18953
+ );
18954
+ loose = mergeLegacyTimer(loose);
18955
+ const result = [];
18956
+ for (const m of loose) {
18957
+ const s = sanitizeMark(m, options);
18958
+ if (s) result.push(s);
18959
+ }
18960
+ if (options.chainValue) {
18961
+ if (result.length === 1 && STANDARD_SHORT_FORM_MARKS.indexOf(result[0].type) !== -1) {
18962
+ return [mark(result[0].type)];
18963
+ }
18964
+ if (result.length === 1 && result[0].type === TextMarkType.link) return result;
18965
+ return [];
18966
+ }
18967
+ return orderMarks(result);
18968
+ }
18969
+
18970
+ // src/generator/text/TextAstNormalizer.ts
18971
+ var LIST_TYPES = [
18972
+ TextNodeType.noBulletList,
18973
+ TextNodeType.bulletList,
18974
+ TextNodeType.orderedList,
18975
+ TextNodeType.orderedListRoman,
18976
+ TextNodeType.orderedListRomanLower,
18977
+ TextNodeType.letteredList,
18978
+ TextNodeType.letteredListLower,
18979
+ TextNodeType.taskList
18980
+ ];
18981
+ var ORDERED_LIST_TYPES = [
18982
+ TextNodeType.orderedList,
18983
+ TextNodeType.orderedListRoman,
18984
+ TextNodeType.orderedListRomanLower
18985
+ ];
18986
+ var BODY_BIT_TYPES = [
18987
+ TextNodeType.gap,
18988
+ TextNodeType.select,
18989
+ TextNodeType.highlight,
18990
+ TextNodeType.mark
18991
+ ];
18992
+ var LEADING_TAB_REGEX = /(^|[\n\r\u2028\u2029])\t+/g;
18993
+ var isList = (n) => LIST_TYPES.indexOf(n.type) !== -1;
18994
+ var isListItem = (n) => n.type === TextNodeType.listItem || n.type === TextNodeType.taskItem;
18995
+ var isBodyBit = (n) => BODY_BIT_TYPES.indexOf(n.type) !== -1;
18996
+ var isNode = (n) => !!n && typeof n === "object" && typeof n.type === "string";
18997
+ var contentOf = (n) => Array.isArray(n.content) ? n.content.filter(isNode) : [];
18998
+ var attrsOf2 = (n) => n.attrs && typeof n.attrs === "object" ? n.attrs : {};
18999
+ var asNode = (n) => n;
19000
+ var paragraph = (content) => asNode({ type: TextNodeType.paragraph, attrs: {}, content });
19001
+ var hardBreak = () => ({ type: TextNodeType.hardBreak });
19002
+ var isHardBreak = (n) => n?.type === TextNodeType.hardBreak;
19003
+ var hasText = (nodes) => nodes.some(
19004
+ (n) => n.type !== TextNodeType.hardBreak && (n.type !== TextNodeType.text || typeof n.text === "string" && n.text.trim() !== "")
19005
+ );
19006
+ function canFollowBareUrl(next) {
19007
+ if (!next) return true;
19008
+ if (next.type === TextNodeType.hardBreak) return true;
19009
+ if (next.type !== TextNodeType.text) return false;
19010
+ if (next.marks && next.marks.length > 0) return false;
19011
+ const first = (next.text ?? "").charAt(0);
19012
+ return first === "" || !isUrlChar(first);
19013
+ }
19014
+ function isSimpleLinkNode(node, next) {
19015
+ if (node.type !== TextNodeType.text || node.marks?.length !== 1) return false;
19016
+ const m = node.marks[0];
19017
+ if (m.type !== TextMarkType.link) return false;
19018
+ const href = m.attrs?.href;
19019
+ return isUrl(href) && bareUrlText(href) === node.text && canFollowBareUrl(next);
19020
+ }
19021
+ var FLATTENED_BLOCK_TYPES = [
19022
+ TextNodeType.paragraph,
19023
+ TextNodeType.heading,
19024
+ TextNodeType.section,
19025
+ TextNodeType.listItem,
19026
+ TextNodeType.taskItem,
19027
+ TextNodeType.codeBlock
19028
+ ];
19029
+ var TextAstNormalizer = class {
19030
+ constructor(options) {
19031
+ __publicField(this, "options");
19032
+ this.options = options;
19033
+ }
19034
+ normalize(ast) {
19035
+ if (!Array.isArray(ast)) return [];
19036
+ const nodes = ast.filter(isNode);
19037
+ if (this.options.chainValue) return this.inline(nodes, { plain: true, chainValue: true });
19038
+ if (this.options.location === TextLocation2.tag) {
19039
+ return nodes.flatMap((n) => this.inlineRootNode(n, {}));
19040
+ }
19041
+ return nodes.flatMap((n) => this.block(n));
19042
+ }
19043
+ //
19044
+ // Block context
19045
+ //
19046
+ block(n) {
19047
+ switch (n.type) {
19048
+ case TextNodeType.paragraph:
19049
+ return [{ ...n, content: this.inline(contentOf(n)) }];
19050
+ case TextNodeType.heading:
19051
+ return this.heading(n);
19052
+ case TextNodeType.section:
19053
+ return [paragraph(this.inline(contentOf(n)))];
19054
+ case TextNodeType.image: {
19055
+ const image = this.image(n);
19056
+ return image ? [image] : [];
19057
+ }
19058
+ case TextNodeType.codeBlock:
19059
+ return [{ ...n, content: this.code(contentOf(n)) }];
19060
+ case TextNodeType.text:
19061
+ case TextNodeType.hardBreak:
19062
+ case TextNodeType.imageInline:
19063
+ case TextNodeType.latex:
19064
+ return this.inline([n]);
19065
+ default:
19066
+ if (isList(n)) return this.list(n);
19067
+ if (isListItem(n)) return [paragraph(this.inline(contentOf(n)))];
19068
+ if (isBodyBit(n)) return [n];
19069
+ if (Array.isArray(n.content))
19070
+ return [{ ...n, content: this.blocks(contentOf(n)) }];
19071
+ return [n];
19072
+ }
19073
+ }
19074
+ blocks(nodes) {
19075
+ return nodes.flatMap((n) => this.block(n));
19076
+ }
19077
+ heading(n) {
19078
+ const level = attrsOf2(n).level;
19079
+ if (level != null && !isHeadingLevel(level)) {
19080
+ return [paragraph(this.inline(contentOf(n)))];
19081
+ }
19082
+ const content = this.inline(contentOf(n), { singleLine: true });
19083
+ if (!hasText(content)) return [];
19084
+ return [{ ...n, content }];
19085
+ }
19086
+ image(n) {
19087
+ const attrs = attrsOf2(n);
19088
+ if (!isUrlHttp(attrs.src)) return void 0;
19089
+ return asNode({ ...n, attrs: { src: attrs.src, ...sanitizeMediaAttrs("image", attrs) } });
19090
+ }
19091
+ code(nodes) {
19092
+ const result = [];
19093
+ for (const n of nodes) {
19094
+ if (n.type === TextNodeType.text) {
19095
+ if (typeof n.text === "string" && n.text) {
19096
+ result.push({ type: TextNodeType.text, text: n.text });
19097
+ }
19098
+ } else if (n.type === TextNodeType.hardBreak) {
19099
+ result.push(hardBreak());
19100
+ } else {
19101
+ result.push(...this.code(contentOf(n)));
19102
+ }
19103
+ }
19104
+ return result;
19105
+ }
19106
+ //
19107
+ // List context
19108
+ //
19109
+ list(n) {
19110
+ const attrs = attrsOf2(n);
19111
+ const ordered = ORDERED_LIST_TYPES.indexOf(n.type) !== -1;
19112
+ let start;
19113
+ if (ordered && attrs.start != null) {
19114
+ start = toUInt(attrs.start);
19115
+ if (start === void 0) {
19116
+ return contentOf(n).map(
19117
+ (item) => paragraph(this.inline([item], { stripLeadingTabs: true }))
19118
+ );
19119
+ }
19120
+ }
19121
+ const items = [];
19122
+ for (const child of contentOf(n)) {
19123
+ if (isListItem(child)) {
19124
+ items.push(...this.listItem(child));
19125
+ } else {
19126
+ items.push(...this.listItem({ type: TextNodeType.listItem, content: [child] }));
19127
+ }
19128
+ }
19129
+ if (items.length === 0) return [];
19130
+ const newAttrs = { ...attrs };
19131
+ if (ordered && start !== void 0) newAttrs.start = start;
19132
+ return [asNode({ ...n, attrs: newAttrs, content: items })];
19133
+ }
19134
+ /**
19135
+ * A list item holds a paragraph, then at most one sublist. Everything else is merged into the
19136
+ * paragraph; further sublists become new items (with an empty paragraph, which keeps them
19137
+ * attached). Returns the resulting item(s).
19138
+ */
19139
+ listItem(item) {
19140
+ const inlineOpts = { stripLeadingTabs: true };
19141
+ const acc = {};
19142
+ let sublist;
19143
+ const extraItems = [];
19144
+ const merge = (inline) => {
19145
+ if (!acc.para) acc.para = inline;
19146
+ else if (inline.length > 0) acc.para.push(hardBreak(), ...inline);
19147
+ };
19148
+ for (const child of contentOf(item)) {
19149
+ if (isList(child)) {
19150
+ for (const list of this.list(child)) {
19151
+ if (list.type === TextNodeType.paragraph) {
19152
+ merge(list.content ?? []);
19153
+ } else if (!sublist) {
19154
+ sublist = list;
19155
+ } else {
19156
+ extraItems.push({ ...item, content: [paragraph([]), list] });
19157
+ }
19158
+ }
19159
+ } else if (child.type === TextNodeType.image) {
19160
+ } else {
19161
+ merge(this.inline([child], inlineOpts));
19162
+ }
19163
+ }
19164
+ const paraContent = acc.para ?? [];
19165
+ if (!hasText(paraContent) && !sublist) return extraItems;
19166
+ const content = [paragraph(paraContent)];
19167
+ if (sublist) content.push(sublist);
19168
+ return [{ ...item, content }, ...extraItems];
19169
+ }
19170
+ //
19171
+ // Inline context
19172
+ //
19173
+ /** A root node at tag location: paragraphs of inline content only */
19174
+ inlineRootNode(n, opts) {
19175
+ switch (n.type) {
19176
+ case TextNodeType.text:
19177
+ case TextNodeType.hardBreak:
19178
+ case TextNodeType.imageInline:
19179
+ case TextNodeType.latex:
19180
+ return this.inline([n], opts);
19181
+ case TextNodeType.image:
19182
+ return [];
19183
+ default:
19184
+ if (isBodyBit(n)) return [n];
19185
+ if (isList(n)) {
19186
+ return contentOf(n).map(
19187
+ (item) => paragraph(this.inline([item], { ...opts, stripLeadingTabs: true }))
19188
+ );
19189
+ }
19190
+ return [paragraph(this.inline(contentOf(n), opts))];
19191
+ }
19192
+ }
19193
+ inline(nodes, opts = {}) {
19194
+ const result = [];
19195
+ const separator = () => opts.singleLine ? this.spaceText() : hardBreak();
19196
+ const separate = () => {
19197
+ if (result.length > 0 && !isHardBreak(result[result.length - 1])) result.push(separator());
19198
+ };
19199
+ for (const n of nodes) {
19200
+ switch (n.type) {
19201
+ case TextNodeType.text: {
19202
+ const text = this.text(n, opts);
19203
+ if (text) result.push(text);
19204
+ break;
19205
+ }
19206
+ case TextNodeType.hardBreak:
19207
+ result.push(separator());
19208
+ break;
19209
+ case TextNodeType.imageInline: {
19210
+ if (opts.plain) break;
19211
+ const image = this.imageInline(n);
19212
+ if (image) result.push(image);
19213
+ break;
19214
+ }
19215
+ case TextNodeType.latex:
19216
+ if (opts.plain) break;
19217
+ if (typeof attrsOf2(n).formula === "string") result.push(n);
19218
+ break;
19219
+ case TextNodeType.image:
19220
+ break;
19221
+ default:
19222
+ if (isBodyBit(n)) {
19223
+ result.push(n);
19224
+ } else if (isList(n)) {
19225
+ for (const item of contentOf(n)) {
19226
+ separate();
19227
+ result.push(...this.inline([item], opts));
19228
+ }
19229
+ } else if (FLATTENED_BLOCK_TYPES.indexOf(n.type) !== -1) {
19230
+ separate();
19231
+ result.push(...this.inline(contentOf(n), opts));
19232
+ } else if (Array.isArray(n.content)) {
19233
+ result.push({ ...n, content: this.inline(contentOf(n), opts) });
19234
+ } else {
19235
+ result.push(n);
19236
+ }
19237
+ }
19238
+ }
19239
+ return this.dropSymbolsBeforePipes(result);
19240
+ }
19241
+ /**
19242
+ * A symbol's media chain swallows every following `...|` segment on its line (even when sealed
19243
+ * with `^`), so a symbol mark has no representable form when the rest of the line contains `|`.
19244
+ */
19245
+ dropSymbolsBeforePipes(nodes) {
19246
+ for (let i = 0; i < nodes.length; i++) {
19247
+ const n = nodes[i];
19248
+ if (!n.marks?.some((m) => m.type === TextMarkType.symbol)) continue;
19249
+ let pipeFollows = false;
19250
+ for (let j = i + 1; j < nodes.length && !isHardBreak(nodes[j]); j++) {
19251
+ const text = nodes[j].text;
19252
+ if (typeof text !== "string") continue;
19253
+ const firstLine = text.split(/[\n\r\u2028\u2029]/, 1)[0];
19254
+ if (firstLine.indexOf("|") !== -1) pipeFollows = true;
19255
+ if (hasLineTerminator(text)) break;
19256
+ }
19257
+ if (pipeFollows) {
19258
+ const marks = n.marks.filter((m) => m.type !== TextMarkType.symbol);
19259
+ const { marks: _m, ...rest } = n;
19260
+ nodes[i] = marks.length > 0 ? { ...rest, marks } : rest;
19261
+ }
19262
+ }
19263
+ return nodes;
19264
+ }
19265
+ text(n, opts) {
19266
+ if (typeof n.text !== "string") return void 0;
19267
+ let text = n.text;
19268
+ if (opts.stripLeadingTabs) text = text.replace(LEADING_TAB_REGEX, "$1");
19269
+ if (opts.singleLine) text = text.replace(/[\n\r\u2028\u2029]+/g, " ");
19270
+ if (!text) return void 0;
19271
+ const marks = sanitizeMarks(n.marks, {
19272
+ chainValue: opts.chainValue,
19273
+ normalizeChainValue: (content) => this.chainValue(content)
19274
+ });
19275
+ const { marks: _m, ...rest } = n;
19276
+ return marks.length > 0 ? { ...rest, text, marks } : { ...rest, text };
19277
+ }
19278
+ spaceText() {
19279
+ return { type: TextNodeType.text, text: " " };
19280
+ }
19281
+ imageInline(n) {
19282
+ const attrs = attrsOf2(n);
19283
+ if (!isUrl(attrs.src)) return void 0;
19284
+ const alt = attrs.alt;
19285
+ if (!isInlineAlt(alt)) return void 0;
19286
+ return asNode({
19287
+ ...n,
19288
+ attrs: { src: attrs.src, alt, ...sanitizeMediaAttrs("imageInline", attrs) }
19289
+ });
19290
+ }
19291
+ /**
19292
+ * Footnote content: a `|`-free single line of plain text with short-form standard marks.
19293
+ * Returns undefined when the content cannot be represented.
19294
+ */
19295
+ chainValue(content) {
19296
+ if (!Array.isArray(content)) return [];
19297
+ const nodes = this.inline(content.filter(isNode), {
19298
+ plain: true,
19299
+ chainValue: true,
19300
+ singleLine: true
19301
+ });
19302
+ for (let i = 0; i < nodes.length; i++) {
19303
+ const n = nodes[i];
19304
+ const text = n.text;
19305
+ if (typeof text === "string" && (text.indexOf("|") !== -1 || hasLineTerminator(text))) {
19306
+ return void 0;
19307
+ }
19308
+ if (n.marks?.some((m) => m.type === TextMarkType.link) && !isSimpleLinkNode(n, nodes[i + 1])) {
19309
+ const { marks: _m, ...rest } = n;
19310
+ nodes[i] = rest;
19311
+ }
19312
+ }
19313
+ return nodes;
19314
+ }
19315
+ };
19316
+ function normalizeTextAst(ast, options) {
19317
+ return new TextAstNormalizer(options).normalize(ast);
19318
+ }
19319
+
18571
19320
  // src/generator/text/TextGenerator.ts
18572
19321
  var DEFAULT_OPTIONS = {
18573
19322
  bodyBitCallback: void 0,
@@ -18660,21 +19409,9 @@ var INLINE_MARK_TYPES = [
18660
19409
  TextMarkType.colorPicker,
18661
19410
  TextMarkType.comment
18662
19411
  ];
18663
- var HIGHLIGHT_COLORS = [
18664
- "orange",
18665
- "yellow",
18666
- "green",
18667
- "blue",
18668
- "purple",
18669
- "pink",
18670
- "brown",
18671
- "white",
18672
- "black",
18673
- "gray"
18674
- ];
18675
19412
  var INDENTATION_REGEX = new RegExp(/(\n|\r\n)/, "g");
18676
- var LINK_REGEX = new RegExp(/https?:\/\/|mailto:(.*)/, "g");
18677
19413
  var LINK_BREAKSCAPE_REGEX = new RegExp(/\]/, "g");
19414
+ var CHAIN_CONTINUATION_REGEX = /^[^\n\r\u2028\u2029]*\|/;
18678
19415
  var Stage = {
18679
19416
  enter: "enter",
18680
19417
  between: "between",
@@ -18711,6 +19448,8 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
18711
19448
  __publicField(this, "textDepth", 0);
18712
19449
  __publicField(this, "placeholderIndex", 0);
18713
19450
  __publicField(this, "placeholders", {});
19451
+ __publicField(this, "chainJustClosed", false);
19452
+ __publicField(this, "simpleLinkAllowed", true);
18714
19453
  // For pre-text
18715
19454
  __publicField(this, "rootParagraphNodeContentIndex", 0);
18716
19455
  __publicField(this, "previousRootParagraphContextType", TextNodeType.text);
@@ -18756,6 +19495,11 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
18756
19495
  generateSync(ast, textFormat, textLocation, options) {
18757
19496
  if (!ast || !Array.isArray(ast)) return "";
18758
19497
  this.generateOptions = Object.assign({}, options);
19498
+ ast = normalizeTextAst(ast, {
19499
+ format: textFormat ?? TextFormat2.bitmarkText,
19500
+ location: textLocation,
19501
+ chainValue: this.generateOptions.chainValueContext
19502
+ });
18759
19503
  this.validateGenerateOptions(ast);
18760
19504
  if (!this.generateOptions.plainTextDividerAllowed) {
18761
19505
  this.resetState(textFormat, textLocation);
@@ -18799,6 +19543,8 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
18799
19543
  this.textDepth = 0;
18800
19544
  this.placeholderIndex = 0;
18801
19545
  this.placeholders = {};
19546
+ this.chainJustClosed = false;
19547
+ this.simpleLinkAllowed = true;
18802
19548
  this.rootParagraphNodeContentIndex = 0;
18803
19549
  this.previousRootParagraphContextType = TextNodeType.hardBreak;
18804
19550
  this.inPreText = false;
@@ -18864,6 +19610,7 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
18864
19610
  this.writeHardBreak(node);
18865
19611
  break;
18866
19612
  case TextNodeType.text: {
19613
+ this.simpleLinkAllowed = this.isSimpleLinkAllowedAfter(route);
18867
19614
  this.writeMarks(node, Stage.enter);
18868
19615
  this.writeText(node);
18869
19616
  this.writeMarks(node, Stage.between);
@@ -18877,9 +19624,6 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
18877
19624
  this.writeHeading(node);
18878
19625
  this.inHeading = true;
18879
19626
  break;
18880
- case TextNodeType.section:
18881
- this.writeSection(node);
18882
- break;
18883
19627
  case TextNodeType.listItem:
18884
19628
  case TextNodeType.taskItem:
18885
19629
  this.writeBullet(node, route);
@@ -18937,7 +19681,6 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
18937
19681
  break;
18938
19682
  case TextNodeType.heading:
18939
19683
  this.inHeading = false;
18940
- case TextNodeType.section:
18941
19684
  case TextNodeType.image:
18942
19685
  if (!this.inParagraph) {
18943
19686
  this.writeNL();
@@ -19049,9 +19792,9 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19049
19792
  */
19050
19793
  getLinkHref(node) {
19051
19794
  if (node.type === TextNodeType.text && node.marks) {
19052
- const href = node.marks.reduce((acc, mark) => {
19053
- if (mark.type === TextMarkType.link) {
19054
- const linkMark = mark;
19795
+ const href = node.marks.reduce((acc, mark2) => {
19796
+ if (mark2.type === TextMarkType.link) {
19797
+ const linkMark = mark2;
19055
19798
  const href2 = linkMark.attrs?.href;
19056
19799
  if (href2) return href2;
19057
19800
  }
@@ -19116,6 +19859,9 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19116
19859
  const indentationString = this.getIndentationString();
19117
19860
  s = s.replace(INDENTATION_REGEX, `$1${indentationString}`);
19118
19861
  }
19862
+ if (this.chainJustClosed && CHAIN_CONTINUATION_REGEX.test(s)) {
19863
+ s = `^${s}`;
19864
+ }
19119
19865
  if (this.havePreText && this.rootParagraphNodeContentIndex === this.preTextIndex) {
19120
19866
  this.writePlainTextDivider();
19121
19867
  this.writeNL();
@@ -19145,14 +19891,14 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19145
19891
  * @returns true if a simple link, otherwise false
19146
19892
  */
19147
19893
  isSimpleLink(node) {
19148
- if (node.text == null) return false;
19149
- if (node.marks?.length !== 1) return false;
19150
- const href = this.getLinkHref(node);
19151
- if (href) {
19152
- const hrefText = href.replace(LINK_REGEX, "$1");
19153
- return hrefText === node.text;
19154
- }
19155
- return false;
19894
+ return this.simpleLinkAllowed && isSimpleLinkNode(node, void 0);
19895
+ }
19896
+ /**
19897
+ * The bare-URL link short form is only safe when whatever is written next cannot be read as
19898
+ * part of the URL (the parser's Url rule consumes every following UrlChar).
19899
+ */
19900
+ isSimpleLinkAllowedAfter(route) {
19901
+ return canFollowBareUrl(this.getSiblingNodes(route).right);
19156
19902
  }
19157
19903
  /**
19158
19904
  * Get the link text if the node is a link, otherwise return false
@@ -19164,15 +19910,8 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19164
19910
  if (node.text == null) return false;
19165
19911
  const href = this.getLinkHref(node);
19166
19912
  if (href) {
19167
- let res;
19168
- const hrefText = href.replace(LINK_REGEX, "$1");
19169
- if (hrefText === node.text) {
19170
- res = href;
19171
- } else {
19172
- res = node.text;
19173
- }
19174
- res = (res ?? "").replace(LINK_BREAKSCAPE_REGEX, "^]");
19175
- return res;
19913
+ const res = this.isSimpleLink(node) ? href : node.text;
19914
+ return res.replace(LINK_BREAKSCAPE_REGEX, "^]");
19176
19915
  }
19177
19916
  return false;
19178
19917
  }
@@ -19229,22 +19968,17 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19229
19968
  writeMarks(node, stage) {
19230
19969
  if (node.marks) {
19231
19970
  const forceSingleMark = this.generateOptions.forceInline || !!(this.inInline || this.inHeading);
19232
- this.thisNodeIsPreText = false;
19233
- const emptyMarks = node.marks.length === 0;
19234
- if (emptyMarks) {
19235
- this.writeMarkTextWrapper(INLINE_MARK);
19236
- return;
19237
- }
19238
- const marks = this.getWritableMarks(node.marks);
19971
+ const marks = node.marks;
19239
19972
  if (marks.length === 0) return;
19973
+ this.thisNodeIsPreText = false;
19240
19974
  const singleMark = marks.length === 1 && forceSingleMark;
19241
19975
  const markStartEnd = marks.reduce(
19242
- (acc, mark) => {
19976
+ (acc, mark2) => {
19243
19977
  if (acc) return acc;
19244
- if (this.isStandardMark(mark)) {
19245
- if (singleMark) return STANDARD_MARKS[mark.type];
19978
+ if (this.isStandardMark(mark2)) {
19979
+ if (singleMark) return STANDARD_MARKS[mark2.type];
19246
19980
  return INLINE_MARK;
19247
- } else if (this.isInlineMark(mark)) {
19981
+ } else if (this.isInlineMark(mark2)) {
19248
19982
  return INLINE_MARK;
19249
19983
  } else {
19250
19984
  }
@@ -19259,56 +19993,59 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19259
19993
  this.writeMarkTextWrapper(markStartEnd);
19260
19994
  }
19261
19995
  if (stage == Stage.between) {
19262
- for (const mark of marks) {
19263
- if (this.isStandardMark(mark)) {
19996
+ for (const mark2 of marks) {
19997
+ if (this.isStandardMark(mark2)) {
19264
19998
  if (!singleMark) {
19265
19999
  this.writeInlineMarkStartEnd();
19266
- this.writeInlineMark(mark);
20000
+ this.writeInlineMark(mark2);
19267
20001
  }
19268
- } else if (TextMarkType.comment === mark.type) {
20002
+ } else if (TextMarkType.comment === mark2.type) {
19269
20003
  this.writeInlineMarkStartEnd();
19270
- this.writeCommentMark(mark);
19271
- } else if (TextMarkType.link === mark.type) {
20004
+ this.writeCommentMark(mark2);
20005
+ } else if (TextMarkType.link === mark2.type) {
19272
20006
  this.writeInlineMarkStartEnd();
19273
- this.writeLinkMark(mark);
19274
- } else if (TextMarkType.ref === mark.type) {
20007
+ this.writeLinkMark(mark2);
20008
+ } else if (TextMarkType.ref === mark2.type) {
19275
20009
  this.writeInlineMarkStartEnd();
19276
- this.writeRefMark(mark);
19277
- } else if (TextMarkType.xref === mark.type) {
20010
+ this.writeRefMark(mark2);
20011
+ } else if (TextMarkType.xref === mark2.type) {
19278
20012
  this.writeInlineMarkStartEnd();
19279
- this.writeXRefMark(mark);
19280
- } else if (TextMarkType.extref === mark.type) {
20013
+ this.writeXRefMark(mark2);
20014
+ } else if (TextMarkType.extref === mark2.type) {
19281
20015
  this.writeInlineMarkStartEnd();
19282
- this.writeExtRefMark(mark);
19283
- } else if (TextMarkType.footnote === mark.type) {
20016
+ this.writeExtRefMark(mark2);
20017
+ } else if (TextMarkType.footnote === mark2.type) {
19284
20018
  this.writeInlineMarkStartEnd();
19285
- this.writeFootnoteMark(mark);
19286
- } else if (TextMarkType.footnoteStar === mark.type) {
20019
+ this.writeFootnoteMark(mark2);
20020
+ } else if (TextMarkType.footnoteStar === mark2.type) {
19287
20021
  this.writeInlineMarkStartEnd();
19288
- this.writeFootnoteStarMark(mark);
19289
- } else if (TextMarkType.symbol === mark.type) {
20022
+ this.writeFootnoteStarMark(mark2);
20023
+ } else if (TextMarkType.symbol === mark2.type) {
19290
20024
  this.writeInlineMarkStartEnd();
19291
- this.writeSymbolMark(mark);
19292
- } else if (this.isInlineMark(mark)) {
20025
+ this.writeSymbolMark(mark2);
20026
+ } else if (this.isInlineMark(mark2)) {
19293
20027
  this.writeInlineMarkStartEnd();
19294
- this.writeInlineMark(mark);
20028
+ this.writeInlineMark(mark2);
19295
20029
  } else {
19296
20030
  }
19297
20031
  }
19298
20032
  }
19299
20033
  if (stage == Stage.exit) {
19300
20034
  let inlineMarkWritten = false;
19301
- for (const mark of marks) {
19302
- if (this.isStandardMark(mark)) {
20035
+ for (const mark2 of marks) {
20036
+ if (this.isStandardMark(mark2)) {
19303
20037
  if (!singleMark) {
19304
20038
  inlineMarkWritten = true;
19305
20039
  }
19306
- } 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)) {
20040
+ } 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)) {
19307
20041
  inlineMarkWritten = true;
19308
20042
  } else {
19309
20043
  }
19310
20044
  }
19311
- if (inlineMarkWritten) this.writeInlineMarkStartEnd();
20045
+ if (inlineMarkWritten) {
20046
+ this.writeInlineMarkStartEnd();
20047
+ this.chainJustClosed = true;
20048
+ }
19312
20049
  }
19313
20050
  }
19314
20051
  }
@@ -19344,15 +20081,6 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19344
20081
  s += " ";
19345
20082
  this.write(s);
19346
20083
  }
19347
- writeSection(node) {
19348
- let s = "";
19349
- if (node.section) {
19350
- s = `|${node.section}: `;
19351
- } else {
19352
- s = "|";
19353
- }
19354
- this.write(s);
19355
- }
19356
20084
  writeBullet(node, route) {
19357
20085
  let bullet = this.getIndentationString();
19358
20086
  const listParent = this.getParentNode(route, 2);
@@ -19375,7 +20103,7 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19375
20103
  bullet += "\u2022a ";
19376
20104
  } else if (listType === TextNodeType.taskList) {
19377
20105
  const taskList = node;
19378
- const checked = taskList.attrs?.checked ?? false;
20106
+ const checked = taskList.attrs?.checked === true;
19379
20107
  bullet += checked ? "\u2022+ " : "\u2022- ";
19380
20108
  }
19381
20109
  if (bullet) this.write(bullet);
@@ -19384,28 +20112,20 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19384
20112
  if (node.attrs == null || !node.attrs.src) return;
19385
20113
  const attrs = node.attrs;
19386
20114
  const inlineImage = node.type === TextNodeType.imageInline;
19387
- let ignoreAttributes;
19388
- if (inlineImage) {
19389
- ignoreAttributes = /* @__PURE__ */ new Set(["alt", "zoomDisabled", "title"]);
19390
- const a = attrs;
19391
- if (a.alignmentVertical === "top") ignoreAttributes.add("alignmentVertical");
19392
- if (a.size === "line-height") ignoreAttributes.add("size");
19393
- }
19394
- const mediaAttrs = this.getMediaAttrs(inlineImage ? "imageInline" : "image", attrs, {
19395
- ignoreAttributes
19396
- });
20115
+ const kind = inlineImage ? "imageInline" : "image";
20116
+ const chain = serializeMediaChain(kind, attrs);
19397
20117
  let s = "";
19398
20118
  if (inlineImage) {
19399
20119
  s = `==${attrs.alt ?? ""}==`;
19400
20120
  }
19401
- s += mediaAttrs ? `|${mediaAttrs}|` : "";
20121
+ s += `|${kind}:${attrs.src}${chain}|`;
19402
20122
  this.write(s);
19403
20123
  }
19404
20124
  writeCodeBlock(node) {
19405
- if (node.attrs == null || !node.attrs.language) return;
19406
- const attrs = node.attrs;
19407
- const s = `|code:${attrs.language}
19408
- `;
20125
+ const raw = node.attrs?.language ?? node.language;
20126
+ const language = normalizeBlockCodeLanguage(raw) ?? "";
20127
+ const s = language ? `|code:${language}
20128
+ ` : "|code\n";
19409
20129
  this.write(s);
19410
20130
  }
19411
20131
  writeLatex(node) {
@@ -19421,10 +20141,10 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19421
20141
  writeMarkTextWrapper(s) {
19422
20142
  if (s) this.write(s);
19423
20143
  }
19424
- writeInlineMark(mark) {
19425
- const attrs = mark.attrs ?? {};
20144
+ writeInlineMark(mark2) {
20145
+ const attrs = mark2.attrs ?? {};
19426
20146
  let s;
19427
- switch (mark.type) {
20147
+ switch (mark2.type) {
19428
20148
  case TextMarkType.textStyle:
19429
20149
  case TextMarkType.color:
19430
20150
  s = `color:${attrs.color ?? ""}`;
@@ -19435,10 +20155,10 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19435
20155
  break;
19436
20156
  case TextMarkType.highlight:
19437
20157
  case TextMarkType.userHighlight:
19438
- s = attrs.color ? `${mark.type}|color:${attrs.color}` : `${mark.type}`;
20158
+ s = attrs.color ? `${mark2.type}|color:${attrs.color}` : `${mark2.type}`;
19439
20159
  break;
19440
20160
  default: {
19441
- s = `${mark.type}`;
20161
+ s = `${mark2.type}`;
19442
20162
  for (const [k, v] of Object.entries(attrs)) {
19443
20163
  if (k === "language" && v !== "plain text" || k === "propertyRef" || k === "name") {
19444
20164
  s = `${s}:${v}`;
@@ -19448,88 +20168,49 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19448
20168
  }
19449
20169
  this.write(s);
19450
20170
  }
19451
- /**
19452
- * Resolve the marks of a text node into the marks that will actually be written.
19453
- *
19454
- * - Merges a legacy standalone 'duration' mark into its sibling 'timer' mark.
19455
- * - Drops marks the current grammar cannot express (standalone 'duration', 'timer'
19456
- * without a duration).
19457
- * - Moves a 'textStyle'/'color' mark before a preceding bare 'highlight'/'userHighlight'
19458
- * mark when its color is a valid highlight color; written in the original order the
19459
- * output would re-parse as a highlight-with-color compound mark and change meaning.
19460
- */
19461
- getWritableMarks(nodeMarks) {
19462
- const attrsOf = (m) => m.attrs ?? {};
19463
- let marks = [...nodeMarks];
19464
- const timer = marks.find((m) => m.type === TextMarkType.timer);
19465
- const duration = marks.find((m) => m.type === TextMarkType.duration);
19466
- if (timer && duration && !attrsOf(timer).duration) {
19467
- marks = marks.map(
19468
- (m) => m === timer ? {
19469
- ...timer,
19470
- attrs: { ...attrsOf(timer), duration: attrsOf(duration).duration }
19471
- } : m
19472
- );
19473
- }
19474
- marks = marks.filter((m) => {
19475
- if (m.type === TextMarkType.duration) return false;
19476
- if (m.type === TextMarkType.timer) return !!attrsOf(m).duration;
19477
- return true;
19478
- });
19479
- const isBareHighlight = (m) => (m.type === TextMarkType.highlight || m.type === TextMarkType.userHighlight) && !attrsOf(m).color;
19480
- const isHighlightColorStyle = (m) => (m.type === TextMarkType.textStyle || m.type === TextMarkType.color) && HIGHLIGHT_COLORS.indexOf(attrsOf(m).color) !== -1;
19481
- for (let i = 0; i < marks.length - 1; i++) {
19482
- if (isBareHighlight(marks[i]) && isHighlightColorStyle(marks[i + 1])) {
19483
- const tmp = marks[i];
19484
- marks[i] = marks[i + 1];
19485
- marks[i + 1] = tmp;
19486
- }
19487
- }
19488
- return marks;
19489
- }
19490
20171
  /**
19491
20172
  * True if the mark is written using its standard form (e.g. **bold**, !!highlight!!)
19492
20173
  * when it is the only mark. A highlight mark with a color attribute is excluded - it
19493
20174
  * can only be expressed using the inline chain form (==text==|highlight|color:x|).
19494
20175
  */
19495
- isStandardMark(mark) {
19496
- if (STANDARD_MARK_TYPES.indexOf(mark.type) === -1) return false;
19497
- return !(mark.attrs && mark.attrs.color);
20176
+ isStandardMark(mark2) {
20177
+ if (STANDARD_MARK_TYPES.indexOf(mark2.type) === -1) return false;
20178
+ return !(mark2.attrs && mark2.attrs.color);
19498
20179
  }
19499
20180
  /**
19500
20181
  * True if the mark is written using the inline chain form (==text==|mark|).
19501
20182
  */
19502
- isInlineMark(mark) {
19503
- if (INLINE_MARK_TYPES.indexOf(mark.type) !== -1) return true;
19504
- return mark.type === TextMarkType.highlight && !!(mark.attrs && mark.attrs.color);
20183
+ isInlineMark(mark2) {
20184
+ if (INLINE_MARK_TYPES.indexOf(mark2.type) !== -1) return true;
20185
+ return mark2.type === TextMarkType.highlight && !!(mark2.attrs && mark2.attrs.color);
19505
20186
  }
19506
- writeCommentMark(mark) {
19507
- const comment = mark.comment || "";
20187
+ writeCommentMark(mark2) {
20188
+ const comment = mark2.comment || "";
19508
20189
  const s = `#${comment}`;
19509
20190
  this.write(s);
19510
20191
  }
19511
- writeLinkMark(mark) {
19512
- const href = mark.attrs?.href || "";
20192
+ writeLinkMark(mark2) {
20193
+ const href = mark2.attrs?.href || "";
19513
20194
  const linkText = (href ?? "").replace(LINK_BREAKSCAPE_REGEX, "^]");
19514
20195
  const s = `link:${linkText}`;
19515
20196
  this.write(s);
19516
20197
  }
19517
- writeRefMark(mark) {
19518
- const ref = mark.attrs?.reference ?? "";
20198
+ writeRefMark(mark2) {
20199
+ const ref = mark2.attrs?.reference ?? "";
19519
20200
  const s = `\u25BA${ref}`;
19520
20201
  this.write(s);
19521
20202
  }
19522
- writeXRefMark(mark) {
19523
- const xref = mark.attrs?.xref ?? "";
19524
- const ref = mark.attrs?.reference ?? "";
20203
+ writeXRefMark(mark2) {
20204
+ const xref = mark2.attrs?.xref ?? "";
20205
+ const ref = mark2.attrs?.reference ?? "";
19525
20206
  let s = `xref:${xref}`;
19526
20207
  if (ref) s += `|\u25BA${ref}`;
19527
20208
  this.write(s);
19528
20209
  }
19529
- writeExtRefMark(mark) {
19530
- const extref = mark.attrs?.extref ?? "";
19531
- const refs = mark.attrs?.references ?? [];
19532
- const provider = mark.attrs?.provider ?? "";
20210
+ writeExtRefMark(mark2) {
20211
+ const extref = mark2.attrs?.extref ?? "";
20212
+ const refs = mark2.attrs?.references ?? [];
20213
+ const provider = mark2.attrs?.provider ?? "";
19533
20214
  let s = `extref:${extref}`;
19534
20215
  for (const ref of refs) {
19535
20216
  s += `|\u25BA${ref ?? ""}`;
@@ -19537,39 +20218,39 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19537
20218
  s += `|provider:${provider}`;
19538
20219
  this.write(s);
19539
20220
  }
19540
- writeFootnoteMark(mark) {
20221
+ writeFootnoteMark(mark2) {
19541
20222
  const s = `footnote:`;
19542
20223
  this.write(s);
19543
20224
  const text = this.internalTextGenerator?.generateSync(
19544
- mark.attrs?.content,
20225
+ mark2.attrs?.content,
19545
20226
  this.textFormat,
19546
20227
  this.textLocation,
19547
20228
  {
19548
20229
  ...this.generateOptions,
19549
- forceInline: true
20230
+ forceInline: true,
20231
+ chainValueContext: true
19550
20232
  }
19551
20233
  ) ?? "";
19552
20234
  this.write(text);
19553
20235
  }
19554
- writeFootnoteStarMark(mark) {
20236
+ writeFootnoteStarMark(mark2) {
19555
20237
  const s = `footnote*:`;
19556
20238
  this.write(s);
19557
20239
  const text = this.internalTextGenerator?.generateSync(
19558
- mark.attrs?.content,
20240
+ mark2.attrs?.content,
19559
20241
  this.textFormat,
19560
20242
  this.textLocation,
19561
20243
  {
19562
20244
  ...this.generateOptions,
19563
- forceInline: true
20245
+ forceInline: true,
20246
+ chainValueContext: true
19564
20247
  }
19565
20248
  ) ?? "";
19566
20249
  this.write(text);
19567
20250
  }
19568
- writeSymbolMark(mark) {
19569
- if (mark.attrs == null) return;
19570
- const attrs = mark.attrs;
19571
- const mediaAttrs = this.getMediaAttrs("symbol", attrs);
19572
- const s = mediaAttrs ?? "";
20251
+ writeSymbolMark(mark2) {
20252
+ const attrs = mark2.attrs ?? {};
20253
+ const s = `symbol:${attrs.src ?? ""}${serializeMediaChain("symbol", attrs)}`;
19573
20254
  this.write(s);
19574
20255
  }
19575
20256
  writeInlineMarkStartEnd() {
@@ -19599,52 +20280,6 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19599
20280
  }
19600
20281
  this.writeString(tag);
19601
20282
  }
19602
- getMediaAttrs(mediaType, attrs, options) {
19603
- if (!mediaType) return void 0;
19604
- const opts = Object.assign({}, options);
19605
- const ignoreAttributes = opts.ignoreAttributes ?? /* @__PURE__ */ new Set();
19606
- let s = `${mediaType}:${attrs?.src ?? ""}`;
19607
- const entries = Object.entries(attrs).filter(([k, _v]) => k !== "src");
19608
- for (let i = 0; i < entries.length; i++) {
19609
- const [k, v] = entries[i];
19610
- if (ignoreAttributes.has(k)) continue;
19611
- switch (k) {
19612
- case "textAlign":
19613
- if (v !== "left") s += `|captionAlign:${v}`;
19614
- break;
19615
- case "alignment":
19616
- if (v !== "center") {
19617
- if (v) s += `|alignment:${v}`;
19618
- }
19619
- break;
19620
- case "title":
19621
- if (v) s += `|caption:${v}`;
19622
- break;
19623
- case "class":
19624
- if (v !== "center") {
19625
- if (v) s += `|align:${v}`;
19626
- }
19627
- break;
19628
- case "comment":
19629
- if (v) s += `|#${v}`;
19630
- break;
19631
- case "":
19632
- if (stringUtils.isString(v)) s += `|:${v}`;
19633
- else s += `|`;
19634
- break;
19635
- case "zoomDisabled":
19636
- if (!v) s += "|zoomDisabled:false";
19637
- break;
19638
- case "alt":
19639
- case "width":
19640
- case "height":
19641
- default:
19642
- if (k && v) s += `|${k}:${v}`;
19643
- break;
19644
- }
19645
- }
19646
- return s;
19647
- }
19648
20283
  //
19649
20284
  // Helper functions
19650
20285
  //
@@ -19670,6 +20305,7 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19670
20305
  */
19671
20306
  write(value) {
19672
20307
  value = this.getInterTextBreakscape(value) + value;
20308
+ this.chainJustClosed = false;
19673
20309
  if (this.options.writeCallback) {
19674
20310
  this.options.writeCallback(value);
19675
20311
  }
@@ -33855,8 +34491,8 @@ var Builder = class extends BaseBuilder {
33855
34491
  break;
33856
34492
  }
33857
34493
  case BodyBitType.mark: {
33858
- const mark = part;
33859
- instance7.fillBooleanExample([mark], __isDefaultExample, example, false);
34494
+ const mark2 = part;
34495
+ instance7.fillBooleanExample([mark2], __isDefaultExample, example, false);
33860
34496
  break;
33861
34497
  }
33862
34498
  case BodyBitType.select: {
@@ -34637,10 +35273,10 @@ var BitmarkGenerator = class extends AstWalkerGenerator {
34637
35273
  const markConfig = node.value;
34638
35274
  const parent = this.getParentNode(route);
34639
35275
  if (parent?.key !== NodeType.markConfig) return true;
34640
- const { mark, color, emphasis } = markConfig;
34641
- if (mark) {
35276
+ const { mark: mark2, color, emphasis } = markConfig;
35277
+ if (mark2) {
34642
35278
  this.writeNL();
34643
- this.writeProperty("mark", mark, route, {
35279
+ this.writeProperty("mark", mark2, route, {
34644
35280
  format: TagFormat.plainText
34645
35281
  });
34646
35282
  if (color) {
@@ -34857,9 +35493,9 @@ var BitmarkGenerator = class extends AstWalkerGenerator {
34857
35493
  }
34858
35494
  // bodyBit -> mark
34859
35495
  enter_mark(node, _route) {
34860
- const mark = node.value;
35496
+ const mark2 = node.value;
34861
35497
  this.writeOPE();
34862
- this.writeTextOrValue(mark.solution, TextFormat2.plainText, TextLocation2.tag);
35498
+ this.writeTextOrValue(mark2.solution, TextFormat2.plainText, TextLocation2.tag);
34863
35499
  this.writeCL();
34864
35500
  return true;
34865
35501
  }
@@ -34919,9 +35555,9 @@ var BitmarkGenerator = class extends AstWalkerGenerator {
34919
35555
  leaf_mark(node, route) {
34920
35556
  const root = route[0];
34921
35557
  if (root?.key !== NodeType.mark) return;
34922
- const mark = node.value;
34923
- if (mark) {
34924
- this.writeProperty("mark", mark, route, {
35558
+ const mark2 = node.value;
35559
+ if (mark2) {
35560
+ this.writeProperty("mark", mark2, route, {
34925
35561
  format: TagFormat.plainText
34926
35562
  });
34927
35563
  }
@@ -36678,8 +37314,6 @@ var MARK_TO_TAG = {
36678
37314
  highlight: "mark",
36679
37315
  code: "code"
36680
37316
  };
36681
- var INLINE_IMAGE_RE = /==([^=]*(?:=(?!=)[^=]*)*)==\|imageInline:([^|\s]+)((?:\|(?:@?[A-Za-z][A-Za-z0-9_-]*:[^|\s]+|#[^|\s]*))*)\|?/g;
36682
- var MAX_IMAGE_DIMENSION = 9999;
36683
37317
  var HtmlTableGenerator = class {
36684
37318
  constructor() {
36685
37319
  __publicField(this, "indentUnit", " ");
@@ -36821,13 +37455,13 @@ var HtmlTableGenerator = class {
36821
37455
  if (!marks || marks.length === 0) return text;
36822
37456
  let open = "";
36823
37457
  let close = "";
36824
- for (const mark of marks) {
36825
- if (mark.type === "link") {
36826
- const href = mark.attrs?.href ?? "";
37458
+ for (const mark2 of marks) {
37459
+ if (mark2.type === "link") {
37460
+ const href = mark2.attrs?.href ?? "";
36827
37461
  open += `<a href="${this.escapeAttr(href)}">`;
36828
37462
  close = `</a>${close}`;
36829
37463
  } else {
36830
- const tag = MARK_TO_TAG[mark.type];
37464
+ const tag = MARK_TO_TAG[mark2.type];
36831
37465
  if (tag) {
36832
37466
  open += `<${tag}>`;
36833
37467
  close = `</${tag}>${close}`;
@@ -36891,37 +37525,7 @@ var HtmlTableGenerator = class {
36891
37525
  return `<img ${parts.join(" ")}>`;
36892
37526
  }
36893
37527
  textToHtml(text) {
36894
- let html = "";
36895
- let lastIndex = 0;
36896
- for (const match of text.matchAll(INLINE_IMAGE_RE)) {
36897
- const index = match.index ?? 0;
36898
- html += this.escapeText(text.slice(lastIndex, index));
36899
- html += this.inlineImageTokenToHtml(match);
36900
- lastIndex = index + match[0].length;
36901
- }
36902
- html += this.escapeText(text.slice(lastIndex));
36903
- return html;
36904
- }
36905
- inlineImageTokenToHtml(match) {
36906
- const attrs = {
36907
- alt: match[1],
36908
- src: match[2]
36909
- };
36910
- const rawAttrs = match[3] ?? "";
36911
- for (const attr of rawAttrs.split("|")) {
36912
- if (!attr || attr.startsWith("#")) continue;
36913
- const colon = attr.indexOf(":");
36914
- if (colon < 1) continue;
36915
- const key = attr.slice(0, colon).replace(/^@/, "");
36916
- const value = attr.slice(colon + 1);
36917
- if (key === "width" || key === "height") {
36918
- const n = Number.parseInt(value, 10);
36919
- if (!Number.isNaN(n) && n > 0 && n <= MAX_IMAGE_DIMENSION) attrs[key] = n;
36920
- } else if (key === "class" || key === "title") {
36921
- attrs[key] = value;
36922
- }
36923
- }
36924
- return this.imageToHtml({ type: "imageInline", attrs });
37528
+ return this.escapeText(text);
36925
37529
  }
36926
37530
  // --- formulas -------------------------------------------------------------
36927
37531
  latexToHtml(node) {
@@ -41405,13 +42009,13 @@ function markChainContentProcessor(context, contentDepth, tagsConfig, content, t
41405
42009
  if (contentDepth === ContentDepth.Chain) {
41406
42010
  markTagContentProcessor(context, ContentDepth.Chain, content, target);
41407
42011
  } else {
41408
- const mark = buildMark(
42012
+ const mark2 = buildMark(
41409
42013
  context,
41410
42014
  contentDepth,
41411
42015
  tagsConfig,
41412
42016
  content
41413
42017
  );
41414
- if (mark) bodyParts.push(mark);
42018
+ if (mark2) bodyParts.push(mark2);
41415
42019
  }
41416
42020
  }
41417
42021
  function buildMark(context, _contentDepth, tagsConfig, content) {
@@ -41426,13 +42030,13 @@ function buildMark(context, _contentDepth, tagsConfig, content) {
41426
42030
  if (context.DEBUG_CHAIN_TAGS) context.debugPrint("mark TAGS", chainTags);
41427
42031
  const { solution } = tags2;
41428
42032
  const { mark: markType, ...rest } = chainTags;
41429
- const mark = {
42033
+ const mark2 = {
41430
42034
  type: BodyBitType.mark,
41431
42035
  solution: solution ?? "",
41432
42036
  mark: instance4.asSingle(markType) ?? "",
41433
42037
  ...rest
41434
42038
  };
41435
- return mark;
42039
+ return mark2;
41436
42040
  }
41437
42041
 
41438
42042
  // src/parser/bitmark/peg/contentProcessors/PropertyContentProcessor.ts
@@ -41684,7 +42288,7 @@ function markConfigChainContentProcessor(context, _contentDepth, tagsConfig, con
41684
42288
  content.chain
41685
42289
  );
41686
42290
  if (context.DEBUG_CHAIN_TAGS) context.debugPrint("mark TAGS", tags2);
41687
- const mark = instance3.unbreakscape(
42291
+ const mark2 = instance3.unbreakscape(
41688
42292
  stringUtils.trimmedString(content.value) ?? "unknown",
41689
42293
  {
41690
42294
  format: TextFormat2.bitmarkText,
@@ -41692,7 +42296,7 @@ function markConfigChainContentProcessor(context, _contentDepth, tagsConfig, con
41692
42296
  }
41693
42297
  );
41694
42298
  const config = {
41695
- mark,
42299
+ mark: mark2,
41696
42300
  emphasis: "underline",
41697
42301
  ...tags2
41698
42302
  };