@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.
package/dist/cli/main.js CHANGED
@@ -4986,6 +4986,9 @@ var GROUPS = {
4986
4986
  key: ConfigKey.tag_item,
4987
4987
  jsonKey: "item",
4988
4988
  exportJsonKey: { item: "$" },
4989
+ // PLAN-140 W3 (NISO import): the clause/note label of a mapped
4990
+ // source element ([%1], [%ANMERKUNG 1]) — same as group_standardItemLead.
4991
+ mappingKeys: { "xml-niso-iec": { "@el": "label", "@text": "$" } },
4989
4992
  description: "The item for the bit"
4990
4993
  }
4991
4994
  ]
@@ -16611,7 +16614,7 @@ var instance2 = new Config();
16611
16614
  // src/generated/package_info.ts
16612
16615
  var PACKAGE_INFO = {
16613
16616
  "name": "@gmb/bitmark-parser-generator",
16614
- "version": "5.40.0",
16617
+ "version": "5.41.0",
16615
16618
  "license": "ISC"};
16616
16619
  var Environment = {
16617
16620
  unknown: "",
@@ -18409,6 +18412,751 @@ var AstWalkerGenerator = class {
18409
18412
  }
18410
18413
  };
18411
18414
 
18415
+ // src/generator/text/TextGrammarConstraints.ts
18416
+ var COLORS = [
18417
+ "aqua",
18418
+ "black",
18419
+ "blue",
18420
+ "brown",
18421
+ "fuchsia",
18422
+ "lightgrey",
18423
+ "gray",
18424
+ "darkgray",
18425
+ "green",
18426
+ "lime",
18427
+ "magenta",
18428
+ "maroon",
18429
+ "navy",
18430
+ "olive",
18431
+ "orange",
18432
+ "pink",
18433
+ "purple",
18434
+ "red",
18435
+ "silver",
18436
+ "teal",
18437
+ "violet",
18438
+ "white",
18439
+ "yellow"
18440
+ ];
18441
+ var HIGHLIGHT_COLORS = [
18442
+ "orange",
18443
+ "yellow",
18444
+ "green",
18445
+ "blue",
18446
+ "purple",
18447
+ "pink",
18448
+ "brown",
18449
+ "white",
18450
+ "black",
18451
+ "gray"
18452
+ ];
18453
+ var ALTERNATIVE_STYLE_TAGS = [
18454
+ "bold",
18455
+ "italic",
18456
+ "light",
18457
+ "highlightOrange",
18458
+ "highlightYellow",
18459
+ "highlightGreen",
18460
+ "highlightBlue",
18461
+ "highlightPurple",
18462
+ "highlightPink",
18463
+ "highlightBrown",
18464
+ "highlightBlack",
18465
+ "highlightWhite",
18466
+ "highlightGray",
18467
+ "highlight",
18468
+ "strike",
18469
+ "subscript",
18470
+ "superscript",
18471
+ "ins",
18472
+ "del",
18473
+ "underline",
18474
+ "doubleUnderline",
18475
+ "smallcaps",
18476
+ "circle",
18477
+ "languageEmRed",
18478
+ "languageEmOrange",
18479
+ "languageEmYellow",
18480
+ "languageEmGreen",
18481
+ "languageEmBlue",
18482
+ "languageEmPurple",
18483
+ "languageEmPink",
18484
+ "languageEmBrown",
18485
+ "languageEmBlack",
18486
+ "languageEmWhite",
18487
+ "languageEmGray",
18488
+ "languageEm",
18489
+ "userUnderline",
18490
+ "userDoubleUnderline",
18491
+ "userStrike",
18492
+ "userCircle",
18493
+ "userHighlight",
18494
+ "notranslate"
18495
+ ];
18496
+ var MEDIA_ALIGNMENTS = ["left", "center", "right"];
18497
+ var INLINE_MEDIA_ALIGNMENTS = [
18498
+ "top",
18499
+ "middle",
18500
+ "bottom",
18501
+ "baseline",
18502
+ "sub",
18503
+ "super",
18504
+ "text-bottom",
18505
+ "text-top"
18506
+ ];
18507
+ var INLINE_MEDIA_SIZES = [
18508
+ "line-height",
18509
+ "font-height",
18510
+ "super",
18511
+ "sub",
18512
+ "explicit"
18513
+ ];
18514
+ var LINE_TERMINATOR_REGEX = /[\n\r\u2028\u2029]/;
18515
+ var CHAIN_STRING_INVALID_REGEX = /[|\n\r\u2028\u2029]/;
18516
+ var URL_CHAR_CLASS = "a-zA-Z0-9!*'()=+,\\-./_?#@[\\]$&;%:{}~^";
18517
+ var URL_CHAR_REGEX = new RegExp(`^[${URL_CHAR_CLASS}]$`);
18518
+ var URL_HTTP_REGEX = new RegExp(`^https?://[${URL_CHAR_CLASS}]*$`);
18519
+ var URL_REGEX = new RegExp(`^(https?://|mailto:)[${URL_CHAR_CLASS}]*$`);
18520
+ function isChainString(v) {
18521
+ return typeof v === "string" && !CHAIN_STRING_INVALID_REGEX.test(v);
18522
+ }
18523
+ function isSingleLine(v) {
18524
+ return typeof v === "string" && !LINE_TERMINATOR_REGEX.test(v);
18525
+ }
18526
+ function hasLineTerminator(v) {
18527
+ return LINE_TERMINATOR_REGEX.test(v);
18528
+ }
18529
+ function isColor(v) {
18530
+ return typeof v === "string" && COLORS.indexOf(v) !== -1;
18531
+ }
18532
+ function isHighlightColor(v) {
18533
+ return typeof v === "string" && HIGHLIGHT_COLORS.indexOf(v) !== -1;
18534
+ }
18535
+ function isMediaAlignment(v) {
18536
+ return typeof v === "string" && MEDIA_ALIGNMENTS.indexOf(v) !== -1;
18537
+ }
18538
+ function isInlineMediaAlignment(v) {
18539
+ return typeof v === "string" && INLINE_MEDIA_ALIGNMENTS.indexOf(v) !== -1;
18540
+ }
18541
+ function isInlineMediaSize(v) {
18542
+ return typeof v === "string" && INLINE_MEDIA_SIZES.indexOf(v) !== -1;
18543
+ }
18544
+ function toUInt(v) {
18545
+ if (typeof v === "number") return Number.isInteger(v) && v >= 0 ? v : void 0;
18546
+ if (typeof v === "string" && /^[0-9]+$/.test(v)) return parseInt(v, 10);
18547
+ return void 0;
18548
+ }
18549
+ function toBoolean(v) {
18550
+ if (typeof v === "boolean") return v;
18551
+ if (v === "true") return true;
18552
+ if (v === "false") return false;
18553
+ return void 0;
18554
+ }
18555
+ function isDuration(v) {
18556
+ return isChainString(v) && v.trim().startsWith("P");
18557
+ }
18558
+ function isUrlHttp(v) {
18559
+ return typeof v === "string" && URL_HTTP_REGEX.test(v);
18560
+ }
18561
+ function isUrl(v) {
18562
+ return typeof v === "string" && URL_REGEX.test(v);
18563
+ }
18564
+ function isUrlChar(c) {
18565
+ return URL_CHAR_REGEX.test(c);
18566
+ }
18567
+ function bareUrlText(href) {
18568
+ return href.replace(/^(https?:\/\/|mailto:)/, "");
18569
+ }
18570
+ function isInlineAlt(v) {
18571
+ return typeof v === "string" && v.length > 0 && v.indexOf("==") === -1 && !v.startsWith("=") && !v.endsWith("=");
18572
+ }
18573
+ function isHeadingLevel(v) {
18574
+ return typeof v === "number" && Number.isInteger(v) && v >= 1 && v <= 3;
18575
+ }
18576
+ function normalizeInlineCodeLanguage(v) {
18577
+ if (!isChainString(v)) return void 0;
18578
+ return v.trim().toLowerCase();
18579
+ }
18580
+ function normalizeBlockCodeLanguage(v) {
18581
+ if (!isSingleLine(v)) return void 0;
18582
+ return v.trim().toLowerCase();
18583
+ }
18584
+
18585
+ // src/generator/text/TextMediaAttrs.ts
18586
+ var uint = (v) => toUInt(v);
18587
+ var bool = (v) => toBoolean(v);
18588
+ var alignment = (v) => isMediaAlignment(v) ? v : void 0;
18589
+ var chainString = (v) => isChainString(v) ? v.trim() : void 0;
18590
+ var inlineAlignment = (v) => isInlineMediaAlignment(v) ? v : void 0;
18591
+ var inlineSize = (v) => isInlineMediaSize(v) ? v : void 0;
18592
+ var VALIDATORS = {
18593
+ image: {
18594
+ alt: chainString,
18595
+ title: chainString,
18596
+ alignment,
18597
+ textAlign: alignment,
18598
+ zoomDisabled: bool,
18599
+ width: uint,
18600
+ height: uint,
18601
+ comment: chainString
18602
+ },
18603
+ imageInline: {
18604
+ srcAlt: chainString,
18605
+ alignmentVertical: inlineAlignment,
18606
+ size: inlineSize,
18607
+ width: uint,
18608
+ height: uint,
18609
+ comment: chainString
18610
+ },
18611
+ symbol: {
18612
+ alt: chainString,
18613
+ title: chainString,
18614
+ caption: chainString,
18615
+ alignment,
18616
+ textAlign: alignment,
18617
+ captionAlign: alignment,
18618
+ zoomDisabled: bool,
18619
+ width: uint,
18620
+ height: uint,
18621
+ comment: chainString
18622
+ }
18623
+ };
18624
+ var TAG_NAMES = {
18625
+ textAlign: "captionAlign",
18626
+ title: "caption"
18627
+ };
18628
+ var DEFAULTS = {
18629
+ image: { alignment: "center", textAlign: "left", zoomDisabled: true },
18630
+ imageInline: { alignmentVertical: "top", size: "line-height" },
18631
+ symbol: {}
18632
+ };
18633
+ function sanitizeMediaAttrs(kind, attrs) {
18634
+ const result = {};
18635
+ if (!attrs || typeof attrs !== "object") return result;
18636
+ const validators = VALIDATORS[kind];
18637
+ for (const [k, v] of Object.entries(attrs)) {
18638
+ const validator = validators[k];
18639
+ if (!validator || v == null) continue;
18640
+ const valid = validator(v);
18641
+ if (valid !== void 0) result[k] = valid;
18642
+ }
18643
+ if (kind === "symbol") {
18644
+ if ("caption" in result) delete result.title;
18645
+ if ("captionAlign" in result) delete result.textAlign;
18646
+ }
18647
+ return result;
18648
+ }
18649
+ function serializeMediaChain(kind, attrs) {
18650
+ const defaults = DEFAULTS[kind];
18651
+ let s = "";
18652
+ for (const k of Object.keys(VALIDATORS[kind])) {
18653
+ const v = attrs[k];
18654
+ if (v == null) continue;
18655
+ if (k in defaults && defaults[k] === v) continue;
18656
+ if (k === "comment") {
18657
+ if (v) s += `|#${v}`;
18658
+ } else if (typeof v === "string" && v === "") {
18659
+ continue;
18660
+ } else {
18661
+ s += `|${TAG_NAMES[k] ?? k}:${v}`;
18662
+ }
18663
+ }
18664
+ return s;
18665
+ }
18666
+
18667
+ // src/generator/text/TextMarkSanitizer.ts
18668
+ var STANDARD_SHORT_FORM_MARKS = [
18669
+ TextMarkType.bold,
18670
+ TextMarkType.italic,
18671
+ TextMarkType.light,
18672
+ TextMarkType.highlight
18673
+ ];
18674
+ function attrsOf(mark2) {
18675
+ const a = mark2.attrs;
18676
+ return a && typeof a === "object" && !Array.isArray(a) ? a : {};
18677
+ }
18678
+ function chainValue(v) {
18679
+ if (v == null) return "";
18680
+ return isChainString(v) ? v.trim() : void 0;
18681
+ }
18682
+ function mark(type, attrs) {
18683
+ return attrs ? { type, attrs } : { type };
18684
+ }
18685
+ function sanitizeMark(m, options) {
18686
+ const attrs = attrsOf(m);
18687
+ switch (m.type) {
18688
+ case TextMarkType.highlight:
18689
+ case TextMarkType.userHighlight: {
18690
+ const color = attrs.color;
18691
+ return isHighlightColor(color) ? mark(m.type, { color }) : mark(m.type);
18692
+ }
18693
+ case TextMarkType.textStyle:
18694
+ case TextMarkType.color: {
18695
+ const color = attrs.color;
18696
+ return isColor(color) ? mark(TextMarkType.textStyle, { color }) : void 0;
18697
+ }
18698
+ case TextMarkType.link: {
18699
+ const href = chainValue(attrs.href);
18700
+ return href === void 0 ? void 0 : mark(m.type, { href });
18701
+ }
18702
+ case TextMarkType.ref: {
18703
+ const reference = chainValue(attrs.reference);
18704
+ return reference === void 0 ? void 0 : mark(m.type, { reference });
18705
+ }
18706
+ case TextMarkType.xref: {
18707
+ const xref = chainValue(attrs.xref);
18708
+ if (xref === void 0) return void 0;
18709
+ const reference = chainValue(attrs.reference) ?? "";
18710
+ return mark(m.type, { xref, reference });
18711
+ }
18712
+ case TextMarkType.extref: {
18713
+ const extref = chainValue(attrs.extref);
18714
+ const provider = chainValue(attrs.provider);
18715
+ if (extref === void 0 || provider === void 0) return void 0;
18716
+ const refs = Array.isArray(attrs.references) ? attrs.references : [];
18717
+ const references = refs.map((r) => chainValue(r)).filter((r) => r !== void 0);
18718
+ return mark(m.type, { extref, references, provider });
18719
+ }
18720
+ case TextMarkType.footnote:
18721
+ case TextMarkType.footnoteStar: {
18722
+ const content = options.normalizeChainValue ? options.normalizeChainValue(attrs.content) : Array.isArray(attrs.content) ? attrs.content : [];
18723
+ return content === void 0 ? void 0 : mark(m.type, { content });
18724
+ }
18725
+ case TextMarkType.symbol: {
18726
+ const src = chainValue(attrs.src);
18727
+ if (src === void 0) return void 0;
18728
+ return mark(m.type, { src, ...sanitizeMediaAttrs("symbol", attrs) });
18729
+ }
18730
+ case TextMarkType.var: {
18731
+ const name = chainValue(attrs.name);
18732
+ return name === void 0 ? void 0 : mark(m.type, { name });
18733
+ }
18734
+ case TextMarkType.code: {
18735
+ const language = normalizeInlineCodeLanguage(attrs.language);
18736
+ return language === void 0 ? mark(m.type) : mark(m.type, { language });
18737
+ }
18738
+ case TextMarkType.timer: {
18739
+ const duration = attrs.duration;
18740
+ if (!isDuration(duration)) return void 0;
18741
+ const name = chainValue(attrs.name) ?? "";
18742
+ return mark(m.type, { name, duration: duration.trim() });
18743
+ }
18744
+ case TextMarkType.colorPicker: {
18745
+ const propertyRef = chainValue(attrs.propertyRef);
18746
+ return propertyRef === void 0 ? void 0 : mark(m.type, { propertyRef });
18747
+ }
18748
+ case TextMarkType.comment: {
18749
+ const comment = chainValue(m.comment);
18750
+ return comment === void 0 ? void 0 : { type: m.type, comment };
18751
+ }
18752
+ default:
18753
+ if (ALTERNATIVE_STYLE_TAGS.indexOf(m.type) !== -1) return mark(m.type);
18754
+ return void 0;
18755
+ }
18756
+ }
18757
+ function mergeLegacyTimer(marks) {
18758
+ const timer = marks.find((m) => m.type === TextMarkType.timer);
18759
+ const duration = marks.find((m) => m.type === TextMarkType.duration);
18760
+ if (!timer || !duration || attrsOf(timer).duration) return marks;
18761
+ return marks.map(
18762
+ (m) => m === timer ? { ...timer, attrs: { ...attrsOf(timer), duration: attrsOf(duration).duration } } : m
18763
+ );
18764
+ }
18765
+ function orderMarks(marks) {
18766
+ const a = (m) => m.attrs ?? {};
18767
+ const isBareHighlight = (m) => (m.type === TextMarkType.highlight || m.type === TextMarkType.userHighlight) && !a(m).color;
18768
+ const isHighlightColorStyle = (m) => m.type === TextMarkType.textStyle && isHighlightColor(a(m).color);
18769
+ const isEmptyXref = (m) => m.type === TextMarkType.xref && !a(m).reference;
18770
+ const result = [];
18771
+ for (const m of marks) {
18772
+ if (m.type === TextMarkType.ref) {
18773
+ const xrefIdx = result.findIndex(isEmptyXref);
18774
+ if (xrefIdx !== -1) {
18775
+ result.splice(xrefIdx, 0, m);
18776
+ continue;
18777
+ }
18778
+ }
18779
+ result.push(m);
18780
+ }
18781
+ for (let i = 0; i < result.length - 1; i++) {
18782
+ if (isBareHighlight(result[i]) && isHighlightColorStyle(result[i + 1])) {
18783
+ [result[i], result[i + 1]] = [result[i + 1], result[i]];
18784
+ }
18785
+ }
18786
+ const symbols = result.filter((m) => m.type === TextMarkType.symbol);
18787
+ if (symbols.length === 0) return result;
18788
+ return [...result.filter((m) => m.type !== TextMarkType.symbol), symbols[0]];
18789
+ }
18790
+ function sanitizeMarks(marks, options = {}) {
18791
+ if (!Array.isArray(marks)) return [];
18792
+ let loose = marks.filter(
18793
+ (m) => !!m && typeof m === "object" && typeof m.type === "string"
18794
+ );
18795
+ loose = mergeLegacyTimer(loose);
18796
+ const result = [];
18797
+ for (const m of loose) {
18798
+ const s = sanitizeMark(m, options);
18799
+ if (s) result.push(s);
18800
+ }
18801
+ if (options.chainValue) {
18802
+ if (result.length === 1 && STANDARD_SHORT_FORM_MARKS.indexOf(result[0].type) !== -1) {
18803
+ return [mark(result[0].type)];
18804
+ }
18805
+ if (result.length === 1 && result[0].type === TextMarkType.link) return result;
18806
+ return [];
18807
+ }
18808
+ return orderMarks(result);
18809
+ }
18810
+
18811
+ // src/generator/text/TextAstNormalizer.ts
18812
+ var LIST_TYPES = [
18813
+ TextNodeType.noBulletList,
18814
+ TextNodeType.bulletList,
18815
+ TextNodeType.orderedList,
18816
+ TextNodeType.orderedListRoman,
18817
+ TextNodeType.orderedListRomanLower,
18818
+ TextNodeType.letteredList,
18819
+ TextNodeType.letteredListLower,
18820
+ TextNodeType.taskList
18821
+ ];
18822
+ var ORDERED_LIST_TYPES = [
18823
+ TextNodeType.orderedList,
18824
+ TextNodeType.orderedListRoman,
18825
+ TextNodeType.orderedListRomanLower
18826
+ ];
18827
+ var BODY_BIT_TYPES = [
18828
+ TextNodeType.gap,
18829
+ TextNodeType.select,
18830
+ TextNodeType.highlight,
18831
+ TextNodeType.mark
18832
+ ];
18833
+ var LEADING_TAB_REGEX = /(^|[\n\r\u2028\u2029])\t+/g;
18834
+ var isList = (n) => LIST_TYPES.indexOf(n.type) !== -1;
18835
+ var isListItem = (n) => n.type === TextNodeType.listItem || n.type === TextNodeType.taskItem;
18836
+ var isBodyBit = (n) => BODY_BIT_TYPES.indexOf(n.type) !== -1;
18837
+ var isNode = (n) => !!n && typeof n === "object" && typeof n.type === "string";
18838
+ var contentOf = (n) => Array.isArray(n.content) ? n.content.filter(isNode) : [];
18839
+ var attrsOf2 = (n) => n.attrs && typeof n.attrs === "object" ? n.attrs : {};
18840
+ var asNode = (n) => n;
18841
+ var paragraph = (content) => asNode({ type: TextNodeType.paragraph, attrs: {}, content });
18842
+ var hardBreak = () => ({ type: TextNodeType.hardBreak });
18843
+ var isHardBreak = (n) => n?.type === TextNodeType.hardBreak;
18844
+ var hasText = (nodes) => nodes.some(
18845
+ (n) => n.type !== TextNodeType.hardBreak && (n.type !== TextNodeType.text || typeof n.text === "string" && n.text.trim() !== "")
18846
+ );
18847
+ function canFollowBareUrl(next) {
18848
+ if (!next) return true;
18849
+ if (next.type === TextNodeType.hardBreak) return true;
18850
+ if (next.type !== TextNodeType.text) return false;
18851
+ if (next.marks && next.marks.length > 0) return false;
18852
+ const first = (next.text ?? "").charAt(0);
18853
+ return first === "" || !isUrlChar(first);
18854
+ }
18855
+ function isSimpleLinkNode(node, next) {
18856
+ if (node.type !== TextNodeType.text || node.marks?.length !== 1) return false;
18857
+ const m = node.marks[0];
18858
+ if (m.type !== TextMarkType.link) return false;
18859
+ const href = m.attrs?.href;
18860
+ return isUrl(href) && bareUrlText(href) === node.text && canFollowBareUrl(next);
18861
+ }
18862
+ var FLATTENED_BLOCK_TYPES = [
18863
+ TextNodeType.paragraph,
18864
+ TextNodeType.heading,
18865
+ TextNodeType.section,
18866
+ TextNodeType.listItem,
18867
+ TextNodeType.taskItem,
18868
+ TextNodeType.codeBlock
18869
+ ];
18870
+ var TextAstNormalizer = class {
18871
+ options;
18872
+ constructor(options) {
18873
+ this.options = options;
18874
+ }
18875
+ normalize(ast) {
18876
+ if (!Array.isArray(ast)) return [];
18877
+ const nodes = ast.filter(isNode);
18878
+ if (this.options.chainValue) return this.inline(nodes, { plain: true, chainValue: true });
18879
+ if (this.options.location === TextLocation.tag) {
18880
+ return nodes.flatMap((n) => this.inlineRootNode(n, {}));
18881
+ }
18882
+ return nodes.flatMap((n) => this.block(n));
18883
+ }
18884
+ //
18885
+ // Block context
18886
+ //
18887
+ block(n) {
18888
+ switch (n.type) {
18889
+ case TextNodeType.paragraph:
18890
+ return [{ ...n, content: this.inline(contentOf(n)) }];
18891
+ case TextNodeType.heading:
18892
+ return this.heading(n);
18893
+ case TextNodeType.section:
18894
+ return [paragraph(this.inline(contentOf(n)))];
18895
+ case TextNodeType.image: {
18896
+ const image = this.image(n);
18897
+ return image ? [image] : [];
18898
+ }
18899
+ case TextNodeType.codeBlock:
18900
+ return [{ ...n, content: this.code(contentOf(n)) }];
18901
+ case TextNodeType.text:
18902
+ case TextNodeType.hardBreak:
18903
+ case TextNodeType.imageInline:
18904
+ case TextNodeType.latex:
18905
+ return this.inline([n]);
18906
+ default:
18907
+ if (isList(n)) return this.list(n);
18908
+ if (isListItem(n)) return [paragraph(this.inline(contentOf(n)))];
18909
+ if (isBodyBit(n)) return [n];
18910
+ if (Array.isArray(n.content))
18911
+ return [{ ...n, content: this.blocks(contentOf(n)) }];
18912
+ return [n];
18913
+ }
18914
+ }
18915
+ blocks(nodes) {
18916
+ return nodes.flatMap((n) => this.block(n));
18917
+ }
18918
+ heading(n) {
18919
+ const level = attrsOf2(n).level;
18920
+ if (level != null && !isHeadingLevel(level)) {
18921
+ return [paragraph(this.inline(contentOf(n)))];
18922
+ }
18923
+ const content = this.inline(contentOf(n), { singleLine: true });
18924
+ if (!hasText(content)) return [];
18925
+ return [{ ...n, content }];
18926
+ }
18927
+ image(n) {
18928
+ const attrs = attrsOf2(n);
18929
+ if (!isUrlHttp(attrs.src)) return void 0;
18930
+ return asNode({ ...n, attrs: { src: attrs.src, ...sanitizeMediaAttrs("image", attrs) } });
18931
+ }
18932
+ code(nodes) {
18933
+ const result = [];
18934
+ for (const n of nodes) {
18935
+ if (n.type === TextNodeType.text) {
18936
+ if (typeof n.text === "string" && n.text) {
18937
+ result.push({ type: TextNodeType.text, text: n.text });
18938
+ }
18939
+ } else if (n.type === TextNodeType.hardBreak) {
18940
+ result.push(hardBreak());
18941
+ } else {
18942
+ result.push(...this.code(contentOf(n)));
18943
+ }
18944
+ }
18945
+ return result;
18946
+ }
18947
+ //
18948
+ // List context
18949
+ //
18950
+ list(n) {
18951
+ const attrs = attrsOf2(n);
18952
+ const ordered = ORDERED_LIST_TYPES.indexOf(n.type) !== -1;
18953
+ let start;
18954
+ if (ordered && attrs.start != null) {
18955
+ start = toUInt(attrs.start);
18956
+ if (start === void 0) {
18957
+ return contentOf(n).map(
18958
+ (item) => paragraph(this.inline([item], { stripLeadingTabs: true }))
18959
+ );
18960
+ }
18961
+ }
18962
+ const items = [];
18963
+ for (const child of contentOf(n)) {
18964
+ if (isListItem(child)) {
18965
+ items.push(...this.listItem(child));
18966
+ } else {
18967
+ items.push(...this.listItem({ type: TextNodeType.listItem, content: [child] }));
18968
+ }
18969
+ }
18970
+ if (items.length === 0) return [];
18971
+ const newAttrs = { ...attrs };
18972
+ if (ordered && start !== void 0) newAttrs.start = start;
18973
+ return [asNode({ ...n, attrs: newAttrs, content: items })];
18974
+ }
18975
+ /**
18976
+ * A list item holds a paragraph, then at most one sublist. Everything else is merged into the
18977
+ * paragraph; further sublists become new items (with an empty paragraph, which keeps them
18978
+ * attached). Returns the resulting item(s).
18979
+ */
18980
+ listItem(item) {
18981
+ const inlineOpts = { stripLeadingTabs: true };
18982
+ const acc = {};
18983
+ let sublist;
18984
+ const extraItems = [];
18985
+ const merge = (inline) => {
18986
+ if (!acc.para) acc.para = inline;
18987
+ else if (inline.length > 0) acc.para.push(hardBreak(), ...inline);
18988
+ };
18989
+ for (const child of contentOf(item)) {
18990
+ if (isList(child)) {
18991
+ for (const list of this.list(child)) {
18992
+ if (list.type === TextNodeType.paragraph) {
18993
+ merge(list.content ?? []);
18994
+ } else if (!sublist) {
18995
+ sublist = list;
18996
+ } else {
18997
+ extraItems.push({ ...item, content: [paragraph([]), list] });
18998
+ }
18999
+ }
19000
+ } else if (child.type === TextNodeType.image) ; else {
19001
+ merge(this.inline([child], inlineOpts));
19002
+ }
19003
+ }
19004
+ const paraContent = acc.para ?? [];
19005
+ if (!hasText(paraContent) && !sublist) return extraItems;
19006
+ const content = [paragraph(paraContent)];
19007
+ if (sublist) content.push(sublist);
19008
+ return [{ ...item, content }, ...extraItems];
19009
+ }
19010
+ //
19011
+ // Inline context
19012
+ //
19013
+ /** A root node at tag location: paragraphs of inline content only */
19014
+ inlineRootNode(n, opts) {
19015
+ switch (n.type) {
19016
+ case TextNodeType.text:
19017
+ case TextNodeType.hardBreak:
19018
+ case TextNodeType.imageInline:
19019
+ case TextNodeType.latex:
19020
+ return this.inline([n], opts);
19021
+ case TextNodeType.image:
19022
+ return [];
19023
+ default:
19024
+ if (isBodyBit(n)) return [n];
19025
+ if (isList(n)) {
19026
+ return contentOf(n).map(
19027
+ (item) => paragraph(this.inline([item], { ...opts, stripLeadingTabs: true }))
19028
+ );
19029
+ }
19030
+ return [paragraph(this.inline(contentOf(n), opts))];
19031
+ }
19032
+ }
19033
+ inline(nodes, opts = {}) {
19034
+ const result = [];
19035
+ const separator = () => opts.singleLine ? this.spaceText() : hardBreak();
19036
+ const separate = () => {
19037
+ if (result.length > 0 && !isHardBreak(result[result.length - 1])) result.push(separator());
19038
+ };
19039
+ for (const n of nodes) {
19040
+ switch (n.type) {
19041
+ case TextNodeType.text: {
19042
+ const text = this.text(n, opts);
19043
+ if (text) result.push(text);
19044
+ break;
19045
+ }
19046
+ case TextNodeType.hardBreak:
19047
+ result.push(separator());
19048
+ break;
19049
+ case TextNodeType.imageInline: {
19050
+ if (opts.plain) break;
19051
+ const image = this.imageInline(n);
19052
+ if (image) result.push(image);
19053
+ break;
19054
+ }
19055
+ case TextNodeType.latex:
19056
+ if (opts.plain) break;
19057
+ if (typeof attrsOf2(n).formula === "string") result.push(n);
19058
+ break;
19059
+ case TextNodeType.image:
19060
+ break;
19061
+ default:
19062
+ if (isBodyBit(n)) {
19063
+ result.push(n);
19064
+ } else if (isList(n)) {
19065
+ for (const item of contentOf(n)) {
19066
+ separate();
19067
+ result.push(...this.inline([item], opts));
19068
+ }
19069
+ } else if (FLATTENED_BLOCK_TYPES.indexOf(n.type) !== -1) {
19070
+ separate();
19071
+ result.push(...this.inline(contentOf(n), opts));
19072
+ } else if (Array.isArray(n.content)) {
19073
+ result.push({ ...n, content: this.inline(contentOf(n), opts) });
19074
+ } else {
19075
+ result.push(n);
19076
+ }
19077
+ }
19078
+ }
19079
+ return this.dropSymbolsBeforePipes(result);
19080
+ }
19081
+ /**
19082
+ * A symbol's media chain swallows every following `...|` segment on its line (even when sealed
19083
+ * with `^`), so a symbol mark has no representable form when the rest of the line contains `|`.
19084
+ */
19085
+ dropSymbolsBeforePipes(nodes) {
19086
+ for (let i = 0; i < nodes.length; i++) {
19087
+ const n = nodes[i];
19088
+ if (!n.marks?.some((m) => m.type === TextMarkType.symbol)) continue;
19089
+ let pipeFollows = false;
19090
+ for (let j = i + 1; j < nodes.length && !isHardBreak(nodes[j]); j++) {
19091
+ const text = nodes[j].text;
19092
+ if (typeof text !== "string") continue;
19093
+ const firstLine = text.split(/[\n\r\u2028\u2029]/, 1)[0];
19094
+ if (firstLine.indexOf("|") !== -1) pipeFollows = true;
19095
+ if (hasLineTerminator(text)) break;
19096
+ }
19097
+ if (pipeFollows) {
19098
+ const marks = n.marks.filter((m) => m.type !== TextMarkType.symbol);
19099
+ const { marks: _m, ...rest } = n;
19100
+ nodes[i] = marks.length > 0 ? { ...rest, marks } : rest;
19101
+ }
19102
+ }
19103
+ return nodes;
19104
+ }
19105
+ text(n, opts) {
19106
+ if (typeof n.text !== "string") return void 0;
19107
+ let text = n.text;
19108
+ if (opts.stripLeadingTabs) text = text.replace(LEADING_TAB_REGEX, "$1");
19109
+ if (opts.singleLine) text = text.replace(/[\n\r\u2028\u2029]+/g, " ");
19110
+ if (!text) return void 0;
19111
+ const marks = sanitizeMarks(n.marks, {
19112
+ chainValue: opts.chainValue,
19113
+ normalizeChainValue: (content) => this.chainValue(content)
19114
+ });
19115
+ const { marks: _m, ...rest } = n;
19116
+ return marks.length > 0 ? { ...rest, text, marks } : { ...rest, text };
19117
+ }
19118
+ spaceText() {
19119
+ return { type: TextNodeType.text, text: " " };
19120
+ }
19121
+ imageInline(n) {
19122
+ const attrs = attrsOf2(n);
19123
+ if (!isUrl(attrs.src)) return void 0;
19124
+ const alt = attrs.alt;
19125
+ if (!isInlineAlt(alt)) return void 0;
19126
+ return asNode({
19127
+ ...n,
19128
+ attrs: { src: attrs.src, alt, ...sanitizeMediaAttrs("imageInline", attrs) }
19129
+ });
19130
+ }
19131
+ /**
19132
+ * Footnote content: a `|`-free single line of plain text with short-form standard marks.
19133
+ * Returns undefined when the content cannot be represented.
19134
+ */
19135
+ chainValue(content) {
19136
+ if (!Array.isArray(content)) return [];
19137
+ const nodes = this.inline(content.filter(isNode), {
19138
+ plain: true,
19139
+ chainValue: true,
19140
+ singleLine: true
19141
+ });
19142
+ for (let i = 0; i < nodes.length; i++) {
19143
+ const n = nodes[i];
19144
+ const text = n.text;
19145
+ if (typeof text === "string" && (text.indexOf("|") !== -1 || hasLineTerminator(text))) {
19146
+ return void 0;
19147
+ }
19148
+ if (n.marks?.some((m) => m.type === TextMarkType.link) && !isSimpleLinkNode(n, nodes[i + 1])) {
19149
+ const { marks: _m, ...rest } = n;
19150
+ nodes[i] = rest;
19151
+ }
19152
+ }
19153
+ return nodes;
19154
+ }
19155
+ };
19156
+ function normalizeTextAst(ast, options) {
19157
+ return new TextAstNormalizer(options).normalize(ast);
19158
+ }
19159
+
18412
19160
  // src/generator/text/TextGenerator.ts
18413
19161
  var DEFAULT_OPTIONS = {
18414
19162
  bodyBitCallback: void 0,
@@ -18501,21 +19249,9 @@ var INLINE_MARK_TYPES = [
18501
19249
  TextMarkType.colorPicker,
18502
19250
  TextMarkType.comment
18503
19251
  ];
18504
- var HIGHLIGHT_COLORS = [
18505
- "orange",
18506
- "yellow",
18507
- "green",
18508
- "blue",
18509
- "purple",
18510
- "pink",
18511
- "brown",
18512
- "white",
18513
- "black",
18514
- "gray"
18515
- ];
18516
19252
  var INDENTATION_REGEX = new RegExp(/(\n|\r\n)/, "g");
18517
- var LINK_REGEX = new RegExp(/https?:\/\/|mailto:(.*)/, "g");
18518
19253
  var LINK_BREAKSCAPE_REGEX = new RegExp(/\]/, "g");
19254
+ var CHAIN_CONTINUATION_REGEX = /^[^\n\r\u2028\u2029]*\|/;
18519
19255
  var Stage = {
18520
19256
  enter: "enter",
18521
19257
  between: "between",
@@ -18544,6 +19280,8 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
18544
19280
  textDepth = 0;
18545
19281
  placeholderIndex = 0;
18546
19282
  placeholders = {};
19283
+ chainJustClosed = false;
19284
+ simpleLinkAllowed = true;
18547
19285
  // For pre-text
18548
19286
  rootParagraphNodeContentIndex = 0;
18549
19287
  previousRootParagraphContextType = TextNodeType.text;
@@ -18595,6 +19333,11 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
18595
19333
  generateSync(ast, textFormat, textLocation, options) {
18596
19334
  if (!ast || !Array.isArray(ast)) return "";
18597
19335
  this.generateOptions = Object.assign({}, options);
19336
+ ast = normalizeTextAst(ast, {
19337
+ format: textFormat ?? TextFormat.bitmarkText,
19338
+ location: textLocation,
19339
+ chainValue: this.generateOptions.chainValueContext
19340
+ });
18598
19341
  this.validateGenerateOptions(ast);
18599
19342
  if (!this.generateOptions.plainTextDividerAllowed) {
18600
19343
  this.resetState(textFormat, textLocation);
@@ -18638,6 +19381,8 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
18638
19381
  this.textDepth = 0;
18639
19382
  this.placeholderIndex = 0;
18640
19383
  this.placeholders = {};
19384
+ this.chainJustClosed = false;
19385
+ this.simpleLinkAllowed = true;
18641
19386
  this.rootParagraphNodeContentIndex = 0;
18642
19387
  this.previousRootParagraphContextType = TextNodeType.hardBreak;
18643
19388
  this.inPreText = false;
@@ -18703,6 +19448,7 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
18703
19448
  this.writeHardBreak(node);
18704
19449
  break;
18705
19450
  case TextNodeType.text: {
19451
+ this.simpleLinkAllowed = this.isSimpleLinkAllowedAfter(route);
18706
19452
  this.writeMarks(node, Stage.enter);
18707
19453
  this.writeText(node);
18708
19454
  this.writeMarks(node, Stage.between);
@@ -18716,9 +19462,6 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
18716
19462
  this.writeHeading(node);
18717
19463
  this.inHeading = true;
18718
19464
  break;
18719
- case TextNodeType.section:
18720
- this.writeSection(node);
18721
- break;
18722
19465
  case TextNodeType.listItem:
18723
19466
  case TextNodeType.taskItem:
18724
19467
  this.writeBullet(node, route);
@@ -18774,7 +19517,6 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
18774
19517
  break;
18775
19518
  case TextNodeType.heading:
18776
19519
  this.inHeading = false;
18777
- case TextNodeType.section:
18778
19520
  case TextNodeType.image:
18779
19521
  if (!this.inParagraph) {
18780
19522
  this.writeNL();
@@ -18883,9 +19625,9 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
18883
19625
  */
18884
19626
  getLinkHref(node) {
18885
19627
  if (node.type === TextNodeType.text && node.marks) {
18886
- const href = node.marks.reduce((acc, mark) => {
18887
- if (mark.type === TextMarkType.link) {
18888
- const linkMark = mark;
19628
+ const href = node.marks.reduce((acc, mark2) => {
19629
+ if (mark2.type === TextMarkType.link) {
19630
+ const linkMark = mark2;
18889
19631
  const href2 = linkMark.attrs?.href;
18890
19632
  if (href2) return href2;
18891
19633
  }
@@ -18950,6 +19692,9 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
18950
19692
  const indentationString = this.getIndentationString();
18951
19693
  s = s.replace(INDENTATION_REGEX, `$1${indentationString}`);
18952
19694
  }
19695
+ if (this.chainJustClosed && CHAIN_CONTINUATION_REGEX.test(s)) {
19696
+ s = `^${s}`;
19697
+ }
18953
19698
  if (this.havePreText && this.rootParagraphNodeContentIndex === this.preTextIndex) {
18954
19699
  this.writePlainTextDivider();
18955
19700
  this.writeNL();
@@ -18979,14 +19724,14 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
18979
19724
  * @returns true if a simple link, otherwise false
18980
19725
  */
18981
19726
  isSimpleLink(node) {
18982
- if (node.text == null) return false;
18983
- if (node.marks?.length !== 1) return false;
18984
- const href = this.getLinkHref(node);
18985
- if (href) {
18986
- const hrefText = href.replace(LINK_REGEX, "$1");
18987
- return hrefText === node.text;
18988
- }
18989
- return false;
19727
+ return this.simpleLinkAllowed && isSimpleLinkNode(node, void 0);
19728
+ }
19729
+ /**
19730
+ * The bare-URL link short form is only safe when whatever is written next cannot be read as
19731
+ * part of the URL (the parser's Url rule consumes every following UrlChar).
19732
+ */
19733
+ isSimpleLinkAllowedAfter(route) {
19734
+ return canFollowBareUrl(this.getSiblingNodes(route).right);
18990
19735
  }
18991
19736
  /**
18992
19737
  * Get the link text if the node is a link, otherwise return false
@@ -18998,15 +19743,8 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
18998
19743
  if (node.text == null) return false;
18999
19744
  const href = this.getLinkHref(node);
19000
19745
  if (href) {
19001
- let res;
19002
- const hrefText = href.replace(LINK_REGEX, "$1");
19003
- if (hrefText === node.text) {
19004
- res = href;
19005
- } else {
19006
- res = node.text;
19007
- }
19008
- res = (res ?? "").replace(LINK_BREAKSCAPE_REGEX, "^]");
19009
- return res;
19746
+ const res = this.isSimpleLink(node) ? href : node.text;
19747
+ return res.replace(LINK_BREAKSCAPE_REGEX, "^]");
19010
19748
  }
19011
19749
  return false;
19012
19750
  }
@@ -19063,22 +19801,17 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19063
19801
  writeMarks(node, stage) {
19064
19802
  if (node.marks) {
19065
19803
  const forceSingleMark = this.generateOptions.forceInline || !!(this.inInline || this.inHeading);
19066
- this.thisNodeIsPreText = false;
19067
- const emptyMarks = node.marks.length === 0;
19068
- if (emptyMarks) {
19069
- this.writeMarkTextWrapper(INLINE_MARK);
19070
- return;
19071
- }
19072
- const marks = this.getWritableMarks(node.marks);
19804
+ const marks = node.marks;
19073
19805
  if (marks.length === 0) return;
19806
+ this.thisNodeIsPreText = false;
19074
19807
  const singleMark = marks.length === 1 && forceSingleMark;
19075
19808
  const markStartEnd = marks.reduce(
19076
- (acc, mark) => {
19809
+ (acc, mark2) => {
19077
19810
  if (acc) return acc;
19078
- if (this.isStandardMark(mark)) {
19079
- if (singleMark) return STANDARD_MARKS[mark.type];
19811
+ if (this.isStandardMark(mark2)) {
19812
+ if (singleMark) return STANDARD_MARKS[mark2.type];
19080
19813
  return INLINE_MARK;
19081
- } else if (this.isInlineMark(mark)) {
19814
+ } else if (this.isInlineMark(mark2)) {
19082
19815
  return INLINE_MARK;
19083
19816
  } else ;
19084
19817
  return acc;
@@ -19092,54 +19825,57 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19092
19825
  this.writeMarkTextWrapper(markStartEnd);
19093
19826
  }
19094
19827
  if (stage == Stage.between) {
19095
- for (const mark of marks) {
19096
- if (this.isStandardMark(mark)) {
19828
+ for (const mark2 of marks) {
19829
+ if (this.isStandardMark(mark2)) {
19097
19830
  if (!singleMark) {
19098
19831
  this.writeInlineMarkStartEnd();
19099
- this.writeInlineMark(mark);
19832
+ this.writeInlineMark(mark2);
19100
19833
  }
19101
- } else if (TextMarkType.comment === mark.type) {
19834
+ } else if (TextMarkType.comment === mark2.type) {
19102
19835
  this.writeInlineMarkStartEnd();
19103
- this.writeCommentMark(mark);
19104
- } else if (TextMarkType.link === mark.type) {
19836
+ this.writeCommentMark(mark2);
19837
+ } else if (TextMarkType.link === mark2.type) {
19105
19838
  this.writeInlineMarkStartEnd();
19106
- this.writeLinkMark(mark);
19107
- } else if (TextMarkType.ref === mark.type) {
19839
+ this.writeLinkMark(mark2);
19840
+ } else if (TextMarkType.ref === mark2.type) {
19108
19841
  this.writeInlineMarkStartEnd();
19109
- this.writeRefMark(mark);
19110
- } else if (TextMarkType.xref === mark.type) {
19842
+ this.writeRefMark(mark2);
19843
+ } else if (TextMarkType.xref === mark2.type) {
19111
19844
  this.writeInlineMarkStartEnd();
19112
- this.writeXRefMark(mark);
19113
- } else if (TextMarkType.extref === mark.type) {
19845
+ this.writeXRefMark(mark2);
19846
+ } else if (TextMarkType.extref === mark2.type) {
19114
19847
  this.writeInlineMarkStartEnd();
19115
- this.writeExtRefMark(mark);
19116
- } else if (TextMarkType.footnote === mark.type) {
19848
+ this.writeExtRefMark(mark2);
19849
+ } else if (TextMarkType.footnote === mark2.type) {
19117
19850
  this.writeInlineMarkStartEnd();
19118
- this.writeFootnoteMark(mark);
19119
- } else if (TextMarkType.footnoteStar === mark.type) {
19851
+ this.writeFootnoteMark(mark2);
19852
+ } else if (TextMarkType.footnoteStar === mark2.type) {
19120
19853
  this.writeInlineMarkStartEnd();
19121
- this.writeFootnoteStarMark(mark);
19122
- } else if (TextMarkType.symbol === mark.type) {
19854
+ this.writeFootnoteStarMark(mark2);
19855
+ } else if (TextMarkType.symbol === mark2.type) {
19123
19856
  this.writeInlineMarkStartEnd();
19124
- this.writeSymbolMark(mark);
19125
- } else if (this.isInlineMark(mark)) {
19857
+ this.writeSymbolMark(mark2);
19858
+ } else if (this.isInlineMark(mark2)) {
19126
19859
  this.writeInlineMarkStartEnd();
19127
- this.writeInlineMark(mark);
19860
+ this.writeInlineMark(mark2);
19128
19861
  } else ;
19129
19862
  }
19130
19863
  }
19131
19864
  if (stage == Stage.exit) {
19132
19865
  let inlineMarkWritten = false;
19133
- for (const mark of marks) {
19134
- if (this.isStandardMark(mark)) {
19866
+ for (const mark2 of marks) {
19867
+ if (this.isStandardMark(mark2)) {
19135
19868
  if (!singleMark) {
19136
19869
  inlineMarkWritten = true;
19137
19870
  }
19138
- } 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)) {
19871
+ } 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)) {
19139
19872
  inlineMarkWritten = true;
19140
19873
  } else ;
19141
19874
  }
19142
- if (inlineMarkWritten) this.writeInlineMarkStartEnd();
19875
+ if (inlineMarkWritten) {
19876
+ this.writeInlineMarkStartEnd();
19877
+ this.chainJustClosed = true;
19878
+ }
19143
19879
  }
19144
19880
  }
19145
19881
  }
@@ -19175,15 +19911,6 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19175
19911
  s += " ";
19176
19912
  this.write(s);
19177
19913
  }
19178
- writeSection(node) {
19179
- let s = "";
19180
- if (node.section) {
19181
- s = `|${node.section}: `;
19182
- } else {
19183
- s = "|";
19184
- }
19185
- this.write(s);
19186
- }
19187
19914
  writeBullet(node, route) {
19188
19915
  let bullet = this.getIndentationString();
19189
19916
  const listParent = this.getParentNode(route, 2);
@@ -19206,7 +19933,7 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19206
19933
  bullet += "\u2022a ";
19207
19934
  } else if (listType === TextNodeType.taskList) {
19208
19935
  const taskList = node;
19209
- const checked = taskList.attrs?.checked ?? false;
19936
+ const checked = taskList.attrs?.checked === true;
19210
19937
  bullet += checked ? "\u2022+ " : "\u2022- ";
19211
19938
  }
19212
19939
  if (bullet) this.write(bullet);
@@ -19215,28 +19942,20 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19215
19942
  if (node.attrs == null || !node.attrs.src) return;
19216
19943
  const attrs = node.attrs;
19217
19944
  const inlineImage = node.type === TextNodeType.imageInline;
19218
- let ignoreAttributes;
19219
- if (inlineImage) {
19220
- ignoreAttributes = /* @__PURE__ */ new Set(["alt", "zoomDisabled", "title"]);
19221
- const a = attrs;
19222
- if (a.alignmentVertical === "top") ignoreAttributes.add("alignmentVertical");
19223
- if (a.size === "line-height") ignoreAttributes.add("size");
19224
- }
19225
- const mediaAttrs = this.getMediaAttrs(inlineImage ? "imageInline" : "image", attrs, {
19226
- ignoreAttributes
19227
- });
19945
+ const kind = inlineImage ? "imageInline" : "image";
19946
+ const chain = serializeMediaChain(kind, attrs);
19228
19947
  let s = "";
19229
19948
  if (inlineImage) {
19230
19949
  s = `==${attrs.alt ?? ""}==`;
19231
19950
  }
19232
- s += mediaAttrs ? `|${mediaAttrs}|` : "";
19951
+ s += `|${kind}:${attrs.src}${chain}|`;
19233
19952
  this.write(s);
19234
19953
  }
19235
19954
  writeCodeBlock(node) {
19236
- if (node.attrs == null || !node.attrs.language) return;
19237
- const attrs = node.attrs;
19238
- const s = `|code:${attrs.language}
19239
- `;
19955
+ const raw = node.attrs?.language ?? node.language;
19956
+ const language = normalizeBlockCodeLanguage(raw) ?? "";
19957
+ const s = language ? `|code:${language}
19958
+ ` : "|code\n";
19240
19959
  this.write(s);
19241
19960
  }
19242
19961
  writeLatex(node) {
@@ -19252,10 +19971,10 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19252
19971
  writeMarkTextWrapper(s) {
19253
19972
  if (s) this.write(s);
19254
19973
  }
19255
- writeInlineMark(mark) {
19256
- const attrs = mark.attrs ?? {};
19974
+ writeInlineMark(mark2) {
19975
+ const attrs = mark2.attrs ?? {};
19257
19976
  let s;
19258
- switch (mark.type) {
19977
+ switch (mark2.type) {
19259
19978
  case TextMarkType.textStyle:
19260
19979
  case TextMarkType.color:
19261
19980
  s = `color:${attrs.color ?? ""}`;
@@ -19266,10 +19985,10 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19266
19985
  break;
19267
19986
  case TextMarkType.highlight:
19268
19987
  case TextMarkType.userHighlight:
19269
- s = attrs.color ? `${mark.type}|color:${attrs.color}` : `${mark.type}`;
19988
+ s = attrs.color ? `${mark2.type}|color:${attrs.color}` : `${mark2.type}`;
19270
19989
  break;
19271
19990
  default: {
19272
- s = `${mark.type}`;
19991
+ s = `${mark2.type}`;
19273
19992
  for (const [k, v] of Object.entries(attrs)) {
19274
19993
  if (k === "language" && v !== "plain text" || k === "propertyRef" || k === "name") {
19275
19994
  s = `${s}:${v}`;
@@ -19279,88 +19998,49 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19279
19998
  }
19280
19999
  this.write(s);
19281
20000
  }
19282
- /**
19283
- * Resolve the marks of a text node into the marks that will actually be written.
19284
- *
19285
- * - Merges a legacy standalone 'duration' mark into its sibling 'timer' mark.
19286
- * - Drops marks the current grammar cannot express (standalone 'duration', 'timer'
19287
- * without a duration).
19288
- * - Moves a 'textStyle'/'color' mark before a preceding bare 'highlight'/'userHighlight'
19289
- * mark when its color is a valid highlight color; written in the original order the
19290
- * output would re-parse as a highlight-with-color compound mark and change meaning.
19291
- */
19292
- getWritableMarks(nodeMarks) {
19293
- const attrsOf = (m) => m.attrs ?? {};
19294
- let marks = [...nodeMarks];
19295
- const timer = marks.find((m) => m.type === TextMarkType.timer);
19296
- const duration = marks.find((m) => m.type === TextMarkType.duration);
19297
- if (timer && duration && !attrsOf(timer).duration) {
19298
- marks = marks.map(
19299
- (m) => m === timer ? {
19300
- ...timer,
19301
- attrs: { ...attrsOf(timer), duration: attrsOf(duration).duration }
19302
- } : m
19303
- );
19304
- }
19305
- marks = marks.filter((m) => {
19306
- if (m.type === TextMarkType.duration) return false;
19307
- if (m.type === TextMarkType.timer) return !!attrsOf(m).duration;
19308
- return true;
19309
- });
19310
- const isBareHighlight = (m) => (m.type === TextMarkType.highlight || m.type === TextMarkType.userHighlight) && !attrsOf(m).color;
19311
- const isHighlightColorStyle = (m) => (m.type === TextMarkType.textStyle || m.type === TextMarkType.color) && HIGHLIGHT_COLORS.indexOf(attrsOf(m).color) !== -1;
19312
- for (let i = 0; i < marks.length - 1; i++) {
19313
- if (isBareHighlight(marks[i]) && isHighlightColorStyle(marks[i + 1])) {
19314
- const tmp = marks[i];
19315
- marks[i] = marks[i + 1];
19316
- marks[i + 1] = tmp;
19317
- }
19318
- }
19319
- return marks;
19320
- }
19321
20001
  /**
19322
20002
  * True if the mark is written using its standard form (e.g. **bold**, !!highlight!!)
19323
20003
  * when it is the only mark. A highlight mark with a color attribute is excluded - it
19324
20004
  * can only be expressed using the inline chain form (==text==|highlight|color:x|).
19325
20005
  */
19326
- isStandardMark(mark) {
19327
- if (STANDARD_MARK_TYPES.indexOf(mark.type) === -1) return false;
19328
- return !(mark.attrs && mark.attrs.color);
20006
+ isStandardMark(mark2) {
20007
+ if (STANDARD_MARK_TYPES.indexOf(mark2.type) === -1) return false;
20008
+ return !(mark2.attrs && mark2.attrs.color);
19329
20009
  }
19330
20010
  /**
19331
20011
  * True if the mark is written using the inline chain form (==text==|mark|).
19332
20012
  */
19333
- isInlineMark(mark) {
19334
- if (INLINE_MARK_TYPES.indexOf(mark.type) !== -1) return true;
19335
- return mark.type === TextMarkType.highlight && !!(mark.attrs && mark.attrs.color);
20013
+ isInlineMark(mark2) {
20014
+ if (INLINE_MARK_TYPES.indexOf(mark2.type) !== -1) return true;
20015
+ return mark2.type === TextMarkType.highlight && !!(mark2.attrs && mark2.attrs.color);
19336
20016
  }
19337
- writeCommentMark(mark) {
19338
- const comment = mark.comment || "";
20017
+ writeCommentMark(mark2) {
20018
+ const comment = mark2.comment || "";
19339
20019
  const s = `#${comment}`;
19340
20020
  this.write(s);
19341
20021
  }
19342
- writeLinkMark(mark) {
19343
- const href = mark.attrs?.href || "";
20022
+ writeLinkMark(mark2) {
20023
+ const href = mark2.attrs?.href || "";
19344
20024
  const linkText = (href ?? "").replace(LINK_BREAKSCAPE_REGEX, "^]");
19345
20025
  const s = `link:${linkText}`;
19346
20026
  this.write(s);
19347
20027
  }
19348
- writeRefMark(mark) {
19349
- const ref = mark.attrs?.reference ?? "";
20028
+ writeRefMark(mark2) {
20029
+ const ref = mark2.attrs?.reference ?? "";
19350
20030
  const s = `\u25BA${ref}`;
19351
20031
  this.write(s);
19352
20032
  }
19353
- writeXRefMark(mark) {
19354
- const xref = mark.attrs?.xref ?? "";
19355
- const ref = mark.attrs?.reference ?? "";
20033
+ writeXRefMark(mark2) {
20034
+ const xref = mark2.attrs?.xref ?? "";
20035
+ const ref = mark2.attrs?.reference ?? "";
19356
20036
  let s = `xref:${xref}`;
19357
20037
  if (ref) s += `|\u25BA${ref}`;
19358
20038
  this.write(s);
19359
20039
  }
19360
- writeExtRefMark(mark) {
19361
- const extref = mark.attrs?.extref ?? "";
19362
- const refs = mark.attrs?.references ?? [];
19363
- const provider = mark.attrs?.provider ?? "";
20040
+ writeExtRefMark(mark2) {
20041
+ const extref = mark2.attrs?.extref ?? "";
20042
+ const refs = mark2.attrs?.references ?? [];
20043
+ const provider = mark2.attrs?.provider ?? "";
19364
20044
  let s = `extref:${extref}`;
19365
20045
  for (const ref of refs) {
19366
20046
  s += `|\u25BA${ref ?? ""}`;
@@ -19368,39 +20048,39 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19368
20048
  s += `|provider:${provider}`;
19369
20049
  this.write(s);
19370
20050
  }
19371
- writeFootnoteMark(mark) {
20051
+ writeFootnoteMark(mark2) {
19372
20052
  const s = `footnote:`;
19373
20053
  this.write(s);
19374
20054
  const text = this.internalTextGenerator?.generateSync(
19375
- mark.attrs?.content,
20055
+ mark2.attrs?.content,
19376
20056
  this.textFormat,
19377
20057
  this.textLocation,
19378
20058
  {
19379
20059
  ...this.generateOptions,
19380
- forceInline: true
20060
+ forceInline: true,
20061
+ chainValueContext: true
19381
20062
  }
19382
20063
  ) ?? "";
19383
20064
  this.write(text);
19384
20065
  }
19385
- writeFootnoteStarMark(mark) {
20066
+ writeFootnoteStarMark(mark2) {
19386
20067
  const s = `footnote*:`;
19387
20068
  this.write(s);
19388
20069
  const text = this.internalTextGenerator?.generateSync(
19389
- mark.attrs?.content,
20070
+ mark2.attrs?.content,
19390
20071
  this.textFormat,
19391
20072
  this.textLocation,
19392
20073
  {
19393
20074
  ...this.generateOptions,
19394
- forceInline: true
20075
+ forceInline: true,
20076
+ chainValueContext: true
19395
20077
  }
19396
20078
  ) ?? "";
19397
20079
  this.write(text);
19398
20080
  }
19399
- writeSymbolMark(mark) {
19400
- if (mark.attrs == null) return;
19401
- const attrs = mark.attrs;
19402
- const mediaAttrs = this.getMediaAttrs("symbol", attrs);
19403
- const s = mediaAttrs ?? "";
20081
+ writeSymbolMark(mark2) {
20082
+ const attrs = mark2.attrs ?? {};
20083
+ const s = `symbol:${attrs.src ?? ""}${serializeMediaChain("symbol", attrs)}`;
19404
20084
  this.write(s);
19405
20085
  }
19406
20086
  writeInlineMarkStartEnd() {
@@ -19430,52 +20110,6 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19430
20110
  }
19431
20111
  this.writeString(tag);
19432
20112
  }
19433
- getMediaAttrs(mediaType, attrs, options) {
19434
- if (!mediaType) return void 0;
19435
- const opts = Object.assign({}, options);
19436
- const ignoreAttributes = opts.ignoreAttributes ?? /* @__PURE__ */ new Set();
19437
- let s = `${mediaType}:${attrs?.src ?? ""}`;
19438
- const entries = Object.entries(attrs).filter(([k, _v]) => k !== "src");
19439
- for (let i = 0; i < entries.length; i++) {
19440
- const [k, v] = entries[i];
19441
- if (ignoreAttributes.has(k)) continue;
19442
- switch (k) {
19443
- case "textAlign":
19444
- if (v !== "left") s += `|captionAlign:${v}`;
19445
- break;
19446
- case "alignment":
19447
- if (v !== "center") {
19448
- if (v) s += `|alignment:${v}`;
19449
- }
19450
- break;
19451
- case "title":
19452
- if (v) s += `|caption:${v}`;
19453
- break;
19454
- case "class":
19455
- if (v !== "center") {
19456
- if (v) s += `|align:${v}`;
19457
- }
19458
- break;
19459
- case "comment":
19460
- if (v) s += `|#${v}`;
19461
- break;
19462
- case "":
19463
- if (stringUtils.isString(v)) s += `|:${v}`;
19464
- else s += `|`;
19465
- break;
19466
- case "zoomDisabled":
19467
- if (!v) s += "|zoomDisabled:false";
19468
- break;
19469
- case "alt":
19470
- case "width":
19471
- case "height":
19472
- default:
19473
- if (k && v) s += `|${k}:${v}`;
19474
- break;
19475
- }
19476
- }
19477
- return s;
19478
- }
19479
20113
  //
19480
20114
  // Helper functions
19481
20115
  //
@@ -19501,6 +20135,7 @@ var TextGenerator = class _TextGenerator extends AstWalkerGenerator {
19501
20135
  */
19502
20136
  write(value) {
19503
20137
  value = this.getInterTextBreakscape(value) + value;
20138
+ this.chainJustClosed = false;
19504
20139
  if (this.options.writeCallback) {
19505
20140
  this.options.writeCallback(value);
19506
20141
  }
@@ -33533,8 +34168,8 @@ var Builder = class extends BaseBuilder {
33533
34168
  break;
33534
34169
  }
33535
34170
  case BodyBitType.mark: {
33536
- const mark = part;
33537
- instance7.fillBooleanExample([mark], __isDefaultExample, example, false);
34171
+ const mark2 = part;
34172
+ instance7.fillBooleanExample([mark2], __isDefaultExample, example, false);
33538
34173
  break;
33539
34174
  }
33540
34175
  case BodyBitType.select: {
@@ -34304,10 +34939,10 @@ var BitmarkGenerator = class extends AstWalkerGenerator {
34304
34939
  const markConfig = node.value;
34305
34940
  const parent = this.getParentNode(route);
34306
34941
  if (parent?.key !== NodeType.markConfig) return true;
34307
- const { mark, color, emphasis } = markConfig;
34308
- if (mark) {
34942
+ const { mark: mark2, color, emphasis } = markConfig;
34943
+ if (mark2) {
34309
34944
  this.writeNL();
34310
- this.writeProperty("mark", mark, route, {
34945
+ this.writeProperty("mark", mark2, route, {
34311
34946
  format: TagFormat.plainText
34312
34947
  });
34313
34948
  if (color) {
@@ -34524,9 +35159,9 @@ var BitmarkGenerator = class extends AstWalkerGenerator {
34524
35159
  }
34525
35160
  // bodyBit -> mark
34526
35161
  enter_mark(node, _route) {
34527
- const mark = node.value;
35162
+ const mark2 = node.value;
34528
35163
  this.writeOPE();
34529
- this.writeTextOrValue(mark.solution, TextFormat.plainText, TextLocation.tag);
35164
+ this.writeTextOrValue(mark2.solution, TextFormat.plainText, TextLocation.tag);
34530
35165
  this.writeCL();
34531
35166
  return true;
34532
35167
  }
@@ -34584,9 +35219,9 @@ var BitmarkGenerator = class extends AstWalkerGenerator {
34584
35219
  leaf_mark(node, route) {
34585
35220
  const root = route[0];
34586
35221
  if (root?.key !== NodeType.mark) return;
34587
- const mark = node.value;
34588
- if (mark) {
34589
- this.writeProperty("mark", mark, route, {
35222
+ const mark2 = node.value;
35223
+ if (mark2) {
35224
+ this.writeProperty("mark", mark2, route, {
34590
35225
  format: TagFormat.plainText
34591
35226
  });
34592
35227
  }
@@ -36338,8 +36973,6 @@ var MARK_TO_TAG = {
36338
36973
  highlight: "mark",
36339
36974
  code: "code"
36340
36975
  };
36341
- var INLINE_IMAGE_RE = /==([^=]*(?:=(?!=)[^=]*)*)==\|imageInline:([^|\s]+)((?:\|(?:@?[A-Za-z][A-Za-z0-9_-]*:[^|\s]+|#[^|\s]*))*)\|?/g;
36342
- var MAX_IMAGE_DIMENSION = 9999;
36343
36976
  var HtmlTableGenerator = class {
36344
36977
  indentUnit = " ";
36345
36978
  /**
@@ -36479,13 +37112,13 @@ var HtmlTableGenerator = class {
36479
37112
  if (!marks || marks.length === 0) return text;
36480
37113
  let open = "";
36481
37114
  let close = "";
36482
- for (const mark of marks) {
36483
- if (mark.type === "link") {
36484
- const href = mark.attrs?.href ?? "";
37115
+ for (const mark2 of marks) {
37116
+ if (mark2.type === "link") {
37117
+ const href = mark2.attrs?.href ?? "";
36485
37118
  open += `<a href="${this.escapeAttr(href)}">`;
36486
37119
  close = `</a>${close}`;
36487
37120
  } else {
36488
- const tag = MARK_TO_TAG[mark.type];
37121
+ const tag = MARK_TO_TAG[mark2.type];
36489
37122
  if (tag) {
36490
37123
  open += `<${tag}>`;
36491
37124
  close = `</${tag}>${close}`;
@@ -36549,37 +37182,7 @@ var HtmlTableGenerator = class {
36549
37182
  return `<img ${parts.join(" ")}>`;
36550
37183
  }
36551
37184
  textToHtml(text) {
36552
- let html = "";
36553
- let lastIndex = 0;
36554
- for (const match of text.matchAll(INLINE_IMAGE_RE)) {
36555
- const index = match.index ?? 0;
36556
- html += this.escapeText(text.slice(lastIndex, index));
36557
- html += this.inlineImageTokenToHtml(match);
36558
- lastIndex = index + match[0].length;
36559
- }
36560
- html += this.escapeText(text.slice(lastIndex));
36561
- return html;
36562
- }
36563
- inlineImageTokenToHtml(match) {
36564
- const attrs = {
36565
- alt: match[1],
36566
- src: match[2]
36567
- };
36568
- const rawAttrs = match[3] ?? "";
36569
- for (const attr of rawAttrs.split("|")) {
36570
- if (!attr || attr.startsWith("#")) continue;
36571
- const colon = attr.indexOf(":");
36572
- if (colon < 1) continue;
36573
- const key = attr.slice(0, colon).replace(/^@/, "");
36574
- const value = attr.slice(colon + 1);
36575
- if (key === "width" || key === "height") {
36576
- const n = Number.parseInt(value, 10);
36577
- if (!Number.isNaN(n) && n > 0 && n <= MAX_IMAGE_DIMENSION) attrs[key] = n;
36578
- } else if (key === "class" || key === "title") {
36579
- attrs[key] = value;
36580
- }
36581
- }
36582
- return this.imageToHtml({ type: "imageInline", attrs });
37185
+ return this.escapeText(text);
36583
37186
  }
36584
37187
  // --- formulas -------------------------------------------------------------
36585
37188
  latexToHtml(node) {
@@ -40992,13 +41595,13 @@ function markChainContentProcessor(context, contentDepth, tagsConfig, content, t
40992
41595
  if (contentDepth === ContentDepth.Chain) {
40993
41596
  markTagContentProcessor(context, ContentDepth.Chain, content, target);
40994
41597
  } else {
40995
- const mark = buildMark(
41598
+ const mark2 = buildMark(
40996
41599
  context,
40997
41600
  contentDepth,
40998
41601
  tagsConfig,
40999
41602
  content
41000
41603
  );
41001
- if (mark) bodyParts.push(mark);
41604
+ if (mark2) bodyParts.push(mark2);
41002
41605
  }
41003
41606
  }
41004
41607
  function buildMark(context, _contentDepth, tagsConfig, content) {
@@ -41013,13 +41616,13 @@ function buildMark(context, _contentDepth, tagsConfig, content) {
41013
41616
  if (context.DEBUG_CHAIN_TAGS) context.debugPrint("mark TAGS", chainTags);
41014
41617
  const { solution } = tags2;
41015
41618
  const { mark: markType, ...rest } = chainTags;
41016
- const mark = {
41619
+ const mark2 = {
41017
41620
  type: BodyBitType.mark,
41018
41621
  solution: solution ?? "",
41019
41622
  mark: instance4.asSingle(markType) ?? "",
41020
41623
  ...rest
41021
41624
  };
41022
- return mark;
41625
+ return mark2;
41023
41626
  }
41024
41627
 
41025
41628
  // src/parser/bitmark/peg/contentProcessors/BookChainContentProcessor.ts
@@ -41261,7 +41864,7 @@ function markConfigChainContentProcessor(context, _contentDepth, tagsConfig, con
41261
41864
  content.chain
41262
41865
  );
41263
41866
  if (context.DEBUG_CHAIN_TAGS) context.debugPrint("mark TAGS", tags2);
41264
- const mark = instance3.unbreakscape(
41867
+ const mark2 = instance3.unbreakscape(
41265
41868
  stringUtils.trimmedString(content.value) ?? "unknown",
41266
41869
  {
41267
41870
  format: TextFormat.bitmarkText,
@@ -41269,7 +41872,7 @@ function markConfigChainContentProcessor(context, _contentDepth, tagsConfig, con
41269
41872
  }
41270
41873
  );
41271
41874
  const config = {
41272
- mark,
41875
+ mark: mark2,
41273
41876
  emphasis: "underline",
41274
41877
  ...tags2
41275
41878
  };
@@ -47014,9 +47617,9 @@ ${nested}` : line;
47014
47617
  parts.push(href);
47015
47618
  }
47016
47619
  if (marks) {
47017
- for (const mark of marks) {
47018
- if (mark.type === "footnote") {
47019
- const footnote = mark;
47620
+ for (const mark2 of marks) {
47621
+ if (mark2.type === "footnote") {
47622
+ const footnote = mark2;
47020
47623
  if (footnote.attrs?.content) {
47021
47624
  const footnoteText = footnote.attrs.content.map((c) => this.textNodeToPlainText(c)).join("");
47022
47625
  if (footnoteText) parts.push(footnoteText);