markdown-codec 3.0.0 → 3.1.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.
Files changed (76) hide show
  1. package/README.md +21 -3
  2. package/dist/ast/ast.cjs +2 -1
  3. package/dist/ast/ast.d.cts +2 -2
  4. package/dist/ast/ast.d.ts +2 -2
  5. package/dist/ast/ast.js +2 -1
  6. package/dist/{ast-DbjiuYr8.d.cts → ast-8XCbjRQT.d.cts} +14 -3
  7. package/dist/{ast-DbjiuYr8.d.ts → ast-8XCbjRQT.d.ts} +14 -3
  8. package/dist/block/block.cjs +79 -28
  9. package/dist/block/block.d.cts +6 -3
  10. package/dist/block/block.d.ts +6 -3
  11. package/dist/block/block.js +79 -28
  12. package/dist/block/definitions.d.cts +1 -1
  13. package/dist/block/definitions.d.ts +1 -1
  14. package/dist/block/node.cjs +2 -0
  15. package/dist/block/node.d.cts +3 -2
  16. package/dist/block/node.d.ts +3 -2
  17. package/dist/block/node.js +2 -0
  18. package/dist/block/table.d.cts +1 -1
  19. package/dist/block/table.d.ts +1 -1
  20. package/dist/diagnostics/diagnostics.cjs +15 -0
  21. package/dist/diagnostics/diagnostics.d.cts +2 -2
  22. package/dist/diagnostics/diagnostics.d.ts +2 -2
  23. package/dist/diagnostics/diagnostics.js +15 -1
  24. package/dist/{diagnostics-B72W0P_E.d.cts → diagnostics-BuO5-SW1.d.cts} +10 -1
  25. package/dist/{diagnostics-B72W0P_E.d.ts → diagnostics-BuO5-SW1.d.ts} +10 -1
  26. package/dist/emit/emit.cjs +77 -7
  27. package/dist/emit/emit.js +79 -9
  28. package/dist/emit/inline.cjs +2 -1
  29. package/dist/emit/inline.d.cts +1 -1
  30. package/dist/emit/inline.d.ts +1 -1
  31. package/dist/emit/inline.js +2 -1
  32. package/dist/emit/table.d.cts +1 -1
  33. package/dist/emit/table.d.ts +1 -1
  34. package/dist/footnote-CKk4JbLk.d.cts +15 -0
  35. package/dist/footnote-CKk4JbLk.d.ts +15 -0
  36. package/dist/html/render.cjs +7 -0
  37. package/dist/html/render.d.cts +1 -1
  38. package/dist/html/render.d.ts +1 -1
  39. package/dist/html/render.js +7 -0
  40. package/dist/index.cjs +2 -0
  41. package/dist/index.d.cts +3 -3
  42. package/dist/index.d.ts +3 -3
  43. package/dist/index.js +3 -3
  44. package/dist/inline/footnote.cjs +30 -0
  45. package/dist/inline/footnote.d.cts +2 -0
  46. package/dist/inline/footnote.d.ts +2 -0
  47. package/dist/inline/footnote.js +27 -0
  48. package/dist/inline/inline.cjs +28 -3
  49. package/dist/inline/inline.d.cts +1 -1
  50. package/dist/inline/inline.d.ts +1 -1
  51. package/dist/inline/inline.js +28 -3
  52. package/dist/inline/node.cjs +1 -0
  53. package/dist/inline/node.d.cts +2 -1
  54. package/dist/inline/node.d.ts +2 -1
  55. package/dist/inline/node.js +1 -0
  56. package/dist/{inline-TuBQ2TUr.d.ts → inline-B_V7bs5j.d.ts} +3 -2
  57. package/dist/{inline-uVHJ5xzT.d.cts → inline-CXVQWQnW.d.cts} +3 -2
  58. package/dist/lower/front-matter.d.cts +1 -1
  59. package/dist/lower/front-matter.d.ts +1 -1
  60. package/dist/lower/inline.cjs +7 -0
  61. package/dist/lower/inline.d.cts +2 -2
  62. package/dist/lower/inline.d.ts +2 -2
  63. package/dist/lower/inline.js +8 -1
  64. package/dist/lower/lower.cjs +51 -0
  65. package/dist/lower/lower.js +51 -0
  66. package/dist/lower/table.d.cts +1 -1
  67. package/dist/lower/table.d.ts +1 -1
  68. package/dist/options/options.d.cts +2 -1
  69. package/dist/options/options.d.ts +2 -1
  70. package/dist/read.d.cts +1 -1
  71. package/dist/read.d.ts +1 -1
  72. package/dist/shared/style-constants.cjs +2 -0
  73. package/dist/shared/style-constants.d.cts +2 -1
  74. package/dist/shared/style-constants.d.ts +2 -1
  75. package/dist/shared/style-constants.js +2 -1
  76. package/package.json +2 -2
@@ -1,3 +1,4 @@
1
+ import { matchFootnoteDefinitionMarker } from "../inline/footnote.js";
1
2
  import "../defaults/defaults.js";
2
3
  import { MarkdownDiagnosticCodes, MarkdownNestingLimitExceededError, NOOP_MARKDOWN_DIAGNOSTIC_SINK } from "../diagnostics/diagnostics.js";
3
4
  import { matchHtmlBlockStart, matchesHtmlBlockEnd } from "../html/html.js";
@@ -13,7 +14,7 @@ const TASK_LIST_MARKER_PATTERN = /^\[([ xX])\][ \t]/;
13
14
  const NUL_REPLACEMENT = "�";
14
15
  const NUL_PATTERN = /\0/g;
15
16
  const LINE_ENDING_PATTERN = /\r\n|\n|\r/;
16
- const MAYBE_SPECIAL_PATTERN = /^[#$`~*+_=<>0-9|:-]/;
17
+ const MAYBE_SPECIAL_PATTERN = /^[#$`~*+_=<>[0-9|:-]/;
17
18
  const ATX_MARKER_PATTERN = /^#{1,6}(?:[ \t]+|$)/;
18
19
  const ATX_ONLY_CLOSING_SEQUENCE_PATTERN = /^[ \t]*#+[ \t]*$/;
19
20
  const ATX_TRAILING_CLOSING_SEQUENCE_PATTERN = /[ \t]+#+[ \t]*$/;
@@ -45,8 +46,10 @@ function headingLevelOf(hashes) {
45
46
  }
46
47
  var BlockParser = class {
47
48
  references = /* @__PURE__ */ new Map();
49
+ footnotes = /* @__PURE__ */ new Set();
48
50
  document = new BlockNode("document", 1);
49
51
  tables;
52
+ footnotesEnabled;
50
53
  sink;
51
54
  maxNesting;
52
55
  tip = this.document;
@@ -58,6 +61,7 @@ var BlockParser = class {
58
61
  nestingDepth = 0;
59
62
  constructor(options) {
60
63
  this.tables = options.gfmTables ?? true;
64
+ this.footnotesEnabled = options.footnotes ?? true;
61
65
  this.sink = options.sink ?? NOOP_MARKDOWN_DIAGNOSTIC_SINK;
62
66
  this.maxNesting = options.maxNesting ?? 250;
63
67
  }
@@ -128,6 +132,7 @@ var BlockParser = class {
128
132
  case "list": return "matched";
129
133
  case "blockquote": return this.continueBlockquote();
130
134
  case "listItem": return this.continueListItem(node);
135
+ case "footnoteDefinition": return this.continueFootnoteDefinition(node);
131
136
  case "codeBlock": return this.continueCodeBlock(node);
132
137
  case "mathBlock": return this.continueMathBlock(node);
133
138
  case "htmlBlock": return this.line.blank && HTML_BLOCK_BLANK_LINE_END_TYPES.includes(node.htmlBlockType) ? "not-matched" : "matched";
@@ -162,6 +167,18 @@ var BlockParser = class {
162
167
  }
163
168
  return "not-matched";
164
169
  }
170
+ continueFootnoteDefinition(node) {
171
+ if (this.line.blank) {
172
+ if (node.children.length === 0) return "not-matched";
173
+ this.line.advanceToNextNonspace();
174
+ return "matched";
175
+ }
176
+ if (this.line.indent >= 4) {
177
+ this.line.advance(4);
178
+ return "matched";
179
+ }
180
+ return "not-matched";
181
+ }
165
182
  continueCodeBlock(node) {
166
183
  if (!node.fenced) {
167
184
  if (this.line.indent >= 4) {
@@ -215,6 +232,7 @@ var BlockParser = class {
215
232
  () => this.tryAtxHeadingStart(),
216
233
  () => this.tryCodeFenceStart(),
217
234
  () => this.tryMathBlockStart(),
235
+ () => this.tryFootnoteDefinitionStart(container),
218
236
  () => this.tryHtmlBlockStart(container),
219
237
  () => this.tryPromoteParagraph(container),
220
238
  () => this.tryThematicBreakStart(),
@@ -272,6 +290,29 @@ var BlockParser = class {
272
290
  this.line.advance(MATH_BLOCK_MARKER_LENGTH);
273
291
  return "leaf";
274
292
  }
293
+ tryFootnoteDefinitionStart(container) {
294
+ if (!this.footnotesEnabled || this.line.indented || !this.footnoteDefinitionMayOpenIn(container)) return "none";
295
+ const marker = matchFootnoteDefinitionMarker(this.line.restFromNextNonspace());
296
+ if (marker === void 0) return "none";
297
+ if (this.footnotes.has(marker.label)) this.sink({
298
+ code: MarkdownDiagnosticCodes.DUPLICATE_FOOTNOTE_DEFINITION,
299
+ severity: "warning",
300
+ message: `footnote "${marker.label}" was already defined earlier in the document; every reference resolves to the first definition, and both definitions are kept as written`,
301
+ line: this.lineNumber
302
+ });
303
+ this.footnotes.add(marker.label);
304
+ this.line.advanceToNextNonspace();
305
+ this.closeUnmatchedBlocks();
306
+ const node = this.addChild("footnoteDefinition");
307
+ node.footnoteLabel = marker.label;
308
+ this.line.advance(marker.markerLength);
309
+ return "container";
310
+ }
311
+ footnoteDefinitionMayOpenIn(container) {
312
+ let node = container;
313
+ while (node?.kind === "list") node = node.parent;
314
+ return node?.kind === "document";
315
+ }
275
316
  tryHtmlBlockStart(container) {
276
317
  if (this.line.indented || this.line.peekNextNonspace() !== "<") return "none";
277
318
  const interruptsParagraph = container.kind === "paragraph" || !this.allClosed && !this.line.blank && this.tip.kind === "paragraph";
@@ -428,15 +469,15 @@ var BlockParser = class {
428
469
  node.literal = breakIndex === -1 ? "" : node.content.slice(breakIndex + 1);
429
470
  }
430
471
  };
431
- function toInlineChildren(content, references, options) {
432
- return parseInlines(content.trim(), references, options);
472
+ function toInlineChildren(content, context) {
473
+ return parseInlines(content.trim(), context.references, context.footnotes, context.options);
433
474
  }
434
- function toHeadingNode(node, references, options) {
475
+ function toHeadingNode(node, context) {
435
476
  return {
436
477
  type: "heading",
437
478
  level: node.level,
438
479
  style: node.setext ? "setext" : "atx",
439
- children: toInlineChildren(node.content, references, options)
480
+ children: toInlineChildren(node.content, context)
440
481
  };
441
482
  }
442
483
  function extractTaskListMarker(itemChildren) {
@@ -447,19 +488,19 @@ function extractTaskListMarker(itemChildren) {
447
488
  first.content = first.content.slice(match[0].length);
448
489
  return match[1] !== " ";
449
490
  }
450
- function toListItemNode(item, references, options) {
451
- const checked = options.gfmTaskLists ?? true ? extractTaskListMarker(item.children) : void 0;
491
+ function toListItemNode(item, context) {
492
+ const checked = context.options.gfmTaskLists ?? true ? extractTaskListMarker(item.children) : void 0;
452
493
  return checked === void 0 ? {
453
494
  type: "listItem",
454
- children: toAstBlocks(item.children, references, options)
495
+ children: toAstBlocks(item.children, context)
455
496
  } : {
456
497
  type: "listItem",
457
498
  checked,
458
- children: toAstBlocks(item.children, references, options)
499
+ children: toAstBlocks(item.children, context)
459
500
  };
460
501
  }
461
- function toListNode(node, references, options) {
462
- const children = node.children.map((item) => toListItemNode(item, references, options));
502
+ function toListNode(node, context) {
503
+ const children = node.children.map((item) => toListItemNode(item, context));
463
504
  const data = node.listData;
464
505
  if (data?.type === "ordered") return {
465
506
  type: "list",
@@ -477,20 +518,20 @@ function toListNode(node, references, options) {
477
518
  children
478
519
  };
479
520
  }
480
- function toTableRow(cells, header, references, options) {
521
+ function toTableRow(cells, header, context) {
481
522
  return {
482
523
  type: "tableRow",
483
524
  header,
484
525
  children: cells.map((cell) => ({
485
526
  type: "tableCell",
486
- children: toInlineChildren(cell, references, options)
527
+ children: toInlineChildren(cell, context)
487
528
  }))
488
529
  };
489
530
  }
490
- function toTableNode(node, references, options) {
491
- const sink = options.sink ?? NOOP_MARKDOWN_DIAGNOSTIC_SINK;
531
+ function toTableNode(node, context) {
532
+ const sink = context.options.sink ?? NOOP_MARKDOWN_DIAGNOSTIC_SINK;
492
533
  const columnCount = node.alignments.length;
493
- const rows = [toTableRow(fitRowToColumns(splitTableRow(node.headerLine), columnCount), true, references, options)];
534
+ const rows = [toTableRow(fitRowToColumns(splitTableRow(node.headerLine), columnCount), true, context)];
494
535
  for (const rowLine of node.content.split("\n")) {
495
536
  if (rowLine.trim().length === 0) continue;
496
537
  const cells = splitTableRow(rowLine);
@@ -500,7 +541,7 @@ function toTableNode(node, references, options) {
500
541
  message: `table row has ${String(cells.length)} cell(s), but the header row declares ${String(columnCount)}; the row is padded with empty cells or truncated to fit`,
501
542
  line: node.startLine
502
543
  });
503
- rows.push(toTableRow(fitRowToColumns(cells, columnCount), false, references, options));
544
+ rows.push(toTableRow(fitRowToColumns(cells, columnCount), false, context));
504
545
  }
505
546
  return {
506
547
  type: "table",
@@ -508,18 +549,23 @@ function toTableNode(node, references, options) {
508
549
  children: rows
509
550
  };
510
551
  }
511
- function toAstBlock(node, references, options) {
552
+ function toAstBlock(node, context) {
512
553
  switch (node.kind) {
513
554
  case "paragraph": return {
514
555
  type: "paragraph",
515
- children: toInlineChildren(node.content, references, options)
556
+ children: toInlineChildren(node.content, context)
516
557
  };
517
- case "heading": return toHeadingNode(node, references, options);
558
+ case "heading": return toHeadingNode(node, context);
518
559
  case "blockquote": return {
519
560
  type: "blockquote",
520
- children: toAstBlocks(node.children, references, options)
561
+ children: toAstBlocks(node.children, context)
562
+ };
563
+ case "list": return toListNode(node, context);
564
+ case "footnoteDefinition": return {
565
+ type: "footnoteDefinition",
566
+ label: node.footnoteLabel,
567
+ children: toAstBlocks(node.children, context)
521
568
  };
522
- case "list": return toListNode(node, references, options);
523
569
  case "codeBlock": return node.fenced ? {
524
570
  type: "codeBlock",
525
571
  fenced: true,
@@ -540,15 +586,15 @@ function toAstBlock(node, references, options) {
540
586
  type: "mathBlock",
541
587
  literal: node.literal
542
588
  };
543
- case "table": return toTableNode(node, references, options);
589
+ case "table": return toTableNode(node, context);
544
590
  case "document":
545
591
  case "listItem": return;
546
592
  }
547
593
  }
548
- function toAstBlocks(nodes, references, options) {
594
+ function toAstBlocks(nodes, context) {
549
595
  const blocks = [];
550
596
  for (const node of nodes) {
551
- const converted = toAstBlock(node, references, options);
597
+ const converted = toAstBlock(node, context);
552
598
  if (converted !== void 0) blocks.push(converted);
553
599
  }
554
600
  return blocks;
@@ -556,13 +602,18 @@ function toAstBlocks(nodes, references, options) {
556
602
  function parseMarkdown(source, options = {}) {
557
603
  const parser = new BlockParser(options);
558
604
  const root = parser.parse(source);
559
- const references = parser.references;
605
+ const context = {
606
+ references: parser.references,
607
+ footnotes: parser.footnotes,
608
+ options
609
+ };
560
610
  return {
561
611
  document: {
562
612
  type: "document",
563
- children: toAstBlocks(root.children, references, options)
613
+ children: toAstBlocks(root.children, context)
564
614
  },
565
- references
615
+ references: context.references,
616
+ footnotes: context.footnotes
566
617
  };
567
618
  }
568
619
  //#endregion
@@ -1,4 +1,4 @@
1
- import { i as MarkdownDiagnosticSink } from "../diagnostics-B72W0P_E.cjs";
1
+ import { i as MarkdownDiagnosticSink } from "../diagnostics-BuO5-SW1.cjs";
2
2
  import { t as LinkReferenceDefinition } from "../link-Dv4kxVjk.cjs";
3
3
  //#region src/block/definitions.d.ts
4
4
  declare function extractDefinitions(content: string, references: Map<string, LinkReferenceDefinition>, sink?: MarkdownDiagnosticSink, startLine?: number): string;
@@ -1,4 +1,4 @@
1
- import { i as MarkdownDiagnosticSink } from "../diagnostics-B72W0P_E.js";
1
+ import { i as MarkdownDiagnosticSink } from "../diagnostics-BuO5-SW1.js";
2
2
  import { t as LinkReferenceDefinition } from "../link-Dv4kxVjk.js";
3
3
  //#region src/block/definitions.d.ts
4
4
  declare function extractDefinitions(content: string, references: Map<string, LinkReferenceDefinition>, sink?: MarkdownDiagnosticSink, startLine?: number): string;
@@ -22,6 +22,7 @@ var BlockNode = class {
22
22
  tight = true;
23
23
  alignments = [];
24
24
  headerLine = "";
25
+ footnoteLabel = "";
25
26
  constructor(kind, startLine) {
26
27
  this.kind = kind;
27
28
  this.startLine = startLine;
@@ -52,6 +53,7 @@ var BlockNode = class {
52
53
  };
53
54
  function canContain(parent, child) {
54
55
  switch (parent) {
56
+ case "footnoteDefinition": return child !== "listItem" && child !== "footnoteDefinition";
55
57
  case "document":
56
58
  case "blockquote":
57
59
  case "listItem": return child !== "listItem";
@@ -1,7 +1,7 @@
1
- import { i as MarkdownBulletMarker, j as MarkdownTableAlignment, w as MarkdownOrderedListDelimiter } from "../ast-DbjiuYr8.cjs";
1
+ import { E as MarkdownOrderedListDelimiter, N as MarkdownTableAlignment, i as MarkdownBulletMarker } from "../ast-8XCbjRQT.cjs";
2
2
  import { t as HtmlBlockType } from "../html-bkz2QTuq.cjs";
3
3
  //#region src/block/node.d.ts
4
- type BlockNodeKind = 'document' | 'paragraph' | 'heading' | 'blockquote' | 'list' | 'listItem' | 'codeBlock' | 'htmlBlock' | 'thematicBreak' | 'table' | 'mathBlock';
4
+ type BlockNodeKind = 'document' | 'paragraph' | 'heading' | 'blockquote' | 'list' | 'listItem' | 'codeBlock' | 'htmlBlock' | 'thematicBreak' | 'table' | 'mathBlock' | 'footnoteDefinition';
5
5
  type BlockHeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
6
6
  interface ListMarkerData {
7
7
  readonly type: 'bullet' | 'ordered';
@@ -33,6 +33,7 @@ declare class BlockNode {
33
33
  tight: boolean;
34
34
  alignments: MarkdownTableAlignment[];
35
35
  headerLine: string;
36
+ footnoteLabel: string;
36
37
  constructor(kind: BlockNodeKind, startLine: number);
37
38
  get lastChild(): BlockNode | undefined;
38
39
  appendChild(child: BlockNode): void;
@@ -1,7 +1,7 @@
1
- import { i as MarkdownBulletMarker, j as MarkdownTableAlignment, w as MarkdownOrderedListDelimiter } from "../ast-DbjiuYr8.js";
1
+ import { E as MarkdownOrderedListDelimiter, N as MarkdownTableAlignment, i as MarkdownBulletMarker } from "../ast-8XCbjRQT.js";
2
2
  import { t as HtmlBlockType } from "../html-bkz2QTuq.js";
3
3
  //#region src/block/node.d.ts
4
- type BlockNodeKind = 'document' | 'paragraph' | 'heading' | 'blockquote' | 'list' | 'listItem' | 'codeBlock' | 'htmlBlock' | 'thematicBreak' | 'table' | 'mathBlock';
4
+ type BlockNodeKind = 'document' | 'paragraph' | 'heading' | 'blockquote' | 'list' | 'listItem' | 'codeBlock' | 'htmlBlock' | 'thematicBreak' | 'table' | 'mathBlock' | 'footnoteDefinition';
5
5
  type BlockHeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
6
6
  interface ListMarkerData {
7
7
  readonly type: 'bullet' | 'ordered';
@@ -33,6 +33,7 @@ declare class BlockNode {
33
33
  tight: boolean;
34
34
  alignments: MarkdownTableAlignment[];
35
35
  headerLine: string;
36
+ footnoteLabel: string;
36
37
  constructor(kind: BlockNodeKind, startLine: number);
37
38
  get lastChild(): BlockNode | undefined;
38
39
  appendChild(child: BlockNode): void;
@@ -21,6 +21,7 @@ var BlockNode = class {
21
21
  tight = true;
22
22
  alignments = [];
23
23
  headerLine = "";
24
+ footnoteLabel = "";
24
25
  constructor(kind, startLine) {
25
26
  this.kind = kind;
26
27
  this.startLine = startLine;
@@ -51,6 +52,7 @@ var BlockNode = class {
51
52
  };
52
53
  function canContain(parent, child) {
53
54
  switch (parent) {
55
+ case "footnoteDefinition": return child !== "listItem" && child !== "footnoteDefinition";
54
56
  case "document":
55
57
  case "blockquote":
56
58
  case "listItem": return child !== "listItem";
@@ -1,4 +1,4 @@
1
- import { j as MarkdownTableAlignment } from "../ast-DbjiuYr8.cjs";
1
+ import { N as MarkdownTableAlignment } from "../ast-8XCbjRQT.cjs";
2
2
  //#region src/block/table.d.ts
3
3
  declare function splitTableRow(line: string): string[];
4
4
  declare function parseTableDelimiterRow(line: string): MarkdownTableAlignment[] | undefined;
@@ -1,4 +1,4 @@
1
- import { j as MarkdownTableAlignment } from "../ast-DbjiuYr8.js";
1
+ import { N as MarkdownTableAlignment } from "../ast-8XCbjRQT.js";
2
2
  //#region src/block/table.d.ts
3
3
  declare function splitTableRow(line: string): string[];
4
4
  declare function parseTableDelimiterRow(line: string): MarkdownTableAlignment[] | undefined;
@@ -7,6 +7,7 @@ const MarkdownDiagnosticCodes = {
7
7
  UNTERMINATED_HTML_BLOCK: "md/unterminated-html-block",
8
8
  TABLE_CELL_COUNT_MISMATCH: "md/table-cell-count-mismatch",
9
9
  DUPLICATE_LINK_REFERENCE: "md/duplicate-link-reference",
10
+ DUPLICATE_FOOTNOTE_DEFINITION: "md/duplicate-footnote-definition",
10
11
  LIST_MARKER_TYPE_CONFLICT: "md/list-marker-type-conflict",
11
12
  INVENTED_PAGE_GEOMETRY: "md/invented-page-geometry",
12
13
  NESTED_EMPHASIS_FLATTENED: "md/nested-emphasis-flattened",
@@ -21,6 +22,9 @@ const MarkdownDiagnosticCodes = {
21
22
  MATH_BLOCK_PRESERVED_AS_TEXT: "md/math-block-preserved-as-text",
22
23
  MATH_INLINE_PRESERVED_AS_TEXT: "md/math-inline-preserved-as-text",
23
24
  FRONT_MATTER_KEY_UNMAPPED: "md/front-matter-key-unmapped",
25
+ FOOTNOTE_REFERENCE_PRESERVED_AS_TEXT: "md/footnote-reference-preserved-as-text",
26
+ FOOTNOTE_BODY_HEADING_FLATTENED: "md/footnote-body-heading-flattened",
27
+ CONSTRUCT_UNREPRESENTED: "md/construct-unrepresented",
24
28
  HEADING_LEVEL_CLAMPED: "md/heading-level-clamped",
25
29
  ADJACENT_LINKS_MERGED: "md/adjacent-links-merged",
26
30
  CODE_SPAN_AS_MONOSPACE_RUN: "md/code-span-as-monospace-run",
@@ -69,6 +73,16 @@ var MarkdownWriteError = class extends Error {
69
73
  this.code = code;
70
74
  }
71
75
  };
76
+ var MarkdownUnbalancedConstructMarkersError = class extends MarkdownWriteError {
77
+ imbalanceKind;
78
+ blockIndex;
79
+ constructor(imbalanceKind, blockIndex) {
80
+ super("md/unbalanced-construct-markers", `${imbalanceKind === "unmatchedEnd" ? "a constructEnd marker closes no open construct" : "a constructStart marker is never closed"} at block index ${String(blockIndex)}; a block list's construct boundary markers must pair as balanced brackets`);
81
+ this.name = "MarkdownUnbalancedConstructMarkersError";
82
+ this.imbalanceKind = imbalanceKind;
83
+ this.blockIndex = blockIndex;
84
+ }
85
+ };
72
86
  var MarkdownUnsupportedDocumentKindError = class extends MarkdownWriteError {
73
87
  kind;
74
88
  constructor(kind) {
@@ -83,6 +97,7 @@ exports.MarkdownInputTooLargeError = MarkdownInputTooLargeError;
83
97
  exports.MarkdownInvalidUtf8Error = MarkdownInvalidUtf8Error;
84
98
  exports.MarkdownNestingLimitExceededError = MarkdownNestingLimitExceededError;
85
99
  exports.MarkdownParseError = MarkdownParseError;
100
+ exports.MarkdownUnbalancedConstructMarkersError = MarkdownUnbalancedConstructMarkersError;
86
101
  exports.MarkdownUnsupportedDocumentKindError = MarkdownUnsupportedDocumentKindError;
87
102
  exports.MarkdownWriteError = MarkdownWriteError;
88
103
  exports.NOOP_MARKDOWN_DIAGNOSTIC_SINK = NOOP_MARKDOWN_DIAGNOSTIC_SINK;
@@ -1,2 +1,2 @@
1
- import { a as MarkdownInputTooLargeError, c as MarkdownParseError, d as NOOP_MARKDOWN_DIAGNOSTIC_SINK, i as MarkdownDiagnosticSink, l as MarkdownUnsupportedDocumentKindError, n as MarkdownDiagnosticCodes, o as MarkdownInvalidUtf8Error, r as MarkdownDiagnosticSeverity, s as MarkdownNestingLimitExceededError, t as MarkdownDiagnostic, u as MarkdownWriteError } from "../diagnostics-B72W0P_E.cjs";
2
- export { MarkdownDiagnostic, MarkdownDiagnosticCodes, MarkdownDiagnosticSeverity, MarkdownDiagnosticSink, MarkdownInputTooLargeError, MarkdownInvalidUtf8Error, MarkdownNestingLimitExceededError, MarkdownParseError, MarkdownUnsupportedDocumentKindError, MarkdownWriteError, NOOP_MARKDOWN_DIAGNOSTIC_SINK };
1
+ import { a as MarkdownInputTooLargeError, c as MarkdownParseError, d as MarkdownWriteError, f as NOOP_MARKDOWN_DIAGNOSTIC_SINK, i as MarkdownDiagnosticSink, l as MarkdownUnbalancedConstructMarkersError, n as MarkdownDiagnosticCodes, o as MarkdownInvalidUtf8Error, r as MarkdownDiagnosticSeverity, s as MarkdownNestingLimitExceededError, t as MarkdownDiagnostic, u as MarkdownUnsupportedDocumentKindError } from "../diagnostics-BuO5-SW1.cjs";
2
+ export { MarkdownDiagnostic, MarkdownDiagnosticCodes, MarkdownDiagnosticSeverity, MarkdownDiagnosticSink, MarkdownInputTooLargeError, MarkdownInvalidUtf8Error, MarkdownNestingLimitExceededError, MarkdownParseError, MarkdownUnbalancedConstructMarkersError, MarkdownUnsupportedDocumentKindError, MarkdownWriteError, NOOP_MARKDOWN_DIAGNOSTIC_SINK };
@@ -1,2 +1,2 @@
1
- import { a as MarkdownInputTooLargeError, c as MarkdownParseError, d as NOOP_MARKDOWN_DIAGNOSTIC_SINK, i as MarkdownDiagnosticSink, l as MarkdownUnsupportedDocumentKindError, n as MarkdownDiagnosticCodes, o as MarkdownInvalidUtf8Error, r as MarkdownDiagnosticSeverity, s as MarkdownNestingLimitExceededError, t as MarkdownDiagnostic, u as MarkdownWriteError } from "../diagnostics-B72W0P_E.js";
2
- export { MarkdownDiagnostic, MarkdownDiagnosticCodes, MarkdownDiagnosticSeverity, MarkdownDiagnosticSink, MarkdownInputTooLargeError, MarkdownInvalidUtf8Error, MarkdownNestingLimitExceededError, MarkdownParseError, MarkdownUnsupportedDocumentKindError, MarkdownWriteError, NOOP_MARKDOWN_DIAGNOSTIC_SINK };
1
+ import { a as MarkdownInputTooLargeError, c as MarkdownParseError, d as MarkdownWriteError, f as NOOP_MARKDOWN_DIAGNOSTIC_SINK, i as MarkdownDiagnosticSink, l as MarkdownUnbalancedConstructMarkersError, n as MarkdownDiagnosticCodes, o as MarkdownInvalidUtf8Error, r as MarkdownDiagnosticSeverity, s as MarkdownNestingLimitExceededError, t as MarkdownDiagnostic, u as MarkdownUnsupportedDocumentKindError } from "../diagnostics-BuO5-SW1.js";
2
+ export { MarkdownDiagnostic, MarkdownDiagnosticCodes, MarkdownDiagnosticSeverity, MarkdownDiagnosticSink, MarkdownInputTooLargeError, MarkdownInvalidUtf8Error, MarkdownNestingLimitExceededError, MarkdownParseError, MarkdownUnbalancedConstructMarkersError, MarkdownUnsupportedDocumentKindError, MarkdownWriteError, NOOP_MARKDOWN_DIAGNOSTIC_SINK };
@@ -6,6 +6,7 @@ const MarkdownDiagnosticCodes = {
6
6
  UNTERMINATED_HTML_BLOCK: "md/unterminated-html-block",
7
7
  TABLE_CELL_COUNT_MISMATCH: "md/table-cell-count-mismatch",
8
8
  DUPLICATE_LINK_REFERENCE: "md/duplicate-link-reference",
9
+ DUPLICATE_FOOTNOTE_DEFINITION: "md/duplicate-footnote-definition",
9
10
  LIST_MARKER_TYPE_CONFLICT: "md/list-marker-type-conflict",
10
11
  INVENTED_PAGE_GEOMETRY: "md/invented-page-geometry",
11
12
  NESTED_EMPHASIS_FLATTENED: "md/nested-emphasis-flattened",
@@ -20,6 +21,9 @@ const MarkdownDiagnosticCodes = {
20
21
  MATH_BLOCK_PRESERVED_AS_TEXT: "md/math-block-preserved-as-text",
21
22
  MATH_INLINE_PRESERVED_AS_TEXT: "md/math-inline-preserved-as-text",
22
23
  FRONT_MATTER_KEY_UNMAPPED: "md/front-matter-key-unmapped",
24
+ FOOTNOTE_REFERENCE_PRESERVED_AS_TEXT: "md/footnote-reference-preserved-as-text",
25
+ FOOTNOTE_BODY_HEADING_FLATTENED: "md/footnote-body-heading-flattened",
26
+ CONSTRUCT_UNREPRESENTED: "md/construct-unrepresented",
23
27
  HEADING_LEVEL_CLAMPED: "md/heading-level-clamped",
24
28
  ADJACENT_LINKS_MERGED: "md/adjacent-links-merged",
25
29
  CODE_SPAN_AS_MONOSPACE_RUN: "md/code-span-as-monospace-run",
@@ -68,6 +72,16 @@ var MarkdownWriteError = class extends Error {
68
72
  this.code = code;
69
73
  }
70
74
  };
75
+ var MarkdownUnbalancedConstructMarkersError = class extends MarkdownWriteError {
76
+ imbalanceKind;
77
+ blockIndex;
78
+ constructor(imbalanceKind, blockIndex) {
79
+ super("md/unbalanced-construct-markers", `${imbalanceKind === "unmatchedEnd" ? "a constructEnd marker closes no open construct" : "a constructStart marker is never closed"} at block index ${String(blockIndex)}; a block list's construct boundary markers must pair as balanced brackets`);
80
+ this.name = "MarkdownUnbalancedConstructMarkersError";
81
+ this.imbalanceKind = imbalanceKind;
82
+ this.blockIndex = blockIndex;
83
+ }
84
+ };
71
85
  var MarkdownUnsupportedDocumentKindError = class extends MarkdownWriteError {
72
86
  kind;
73
87
  constructor(kind) {
@@ -77,4 +91,4 @@ var MarkdownUnsupportedDocumentKindError = class extends MarkdownWriteError {
77
91
  }
78
92
  };
79
93
  //#endregion
80
- export { MarkdownDiagnosticCodes, MarkdownInputTooLargeError, MarkdownInvalidUtf8Error, MarkdownNestingLimitExceededError, MarkdownParseError, MarkdownUnsupportedDocumentKindError, MarkdownWriteError, NOOP_MARKDOWN_DIAGNOSTIC_SINK };
94
+ export { MarkdownDiagnosticCodes, MarkdownInputTooLargeError, MarkdownInvalidUtf8Error, MarkdownNestingLimitExceededError, MarkdownParseError, MarkdownUnbalancedConstructMarkersError, MarkdownUnsupportedDocumentKindError, MarkdownWriteError, NOOP_MARKDOWN_DIAGNOSTIC_SINK };
@@ -14,6 +14,7 @@ declare const MarkdownDiagnosticCodes: {
14
14
  readonly UNTERMINATED_HTML_BLOCK: "md/unterminated-html-block";
15
15
  readonly TABLE_CELL_COUNT_MISMATCH: "md/table-cell-count-mismatch";
16
16
  readonly DUPLICATE_LINK_REFERENCE: "md/duplicate-link-reference";
17
+ readonly DUPLICATE_FOOTNOTE_DEFINITION: "md/duplicate-footnote-definition";
17
18
  readonly LIST_MARKER_TYPE_CONFLICT: "md/list-marker-type-conflict";
18
19
  readonly INVENTED_PAGE_GEOMETRY: "md/invented-page-geometry";
19
20
  readonly NESTED_EMPHASIS_FLATTENED: "md/nested-emphasis-flattened";
@@ -28,6 +29,9 @@ declare const MarkdownDiagnosticCodes: {
28
29
  readonly MATH_BLOCK_PRESERVED_AS_TEXT: "md/math-block-preserved-as-text";
29
30
  readonly MATH_INLINE_PRESERVED_AS_TEXT: "md/math-inline-preserved-as-text";
30
31
  readonly FRONT_MATTER_KEY_UNMAPPED: "md/front-matter-key-unmapped";
32
+ readonly FOOTNOTE_REFERENCE_PRESERVED_AS_TEXT: "md/footnote-reference-preserved-as-text";
33
+ readonly FOOTNOTE_BODY_HEADING_FLATTENED: "md/footnote-body-heading-flattened";
34
+ readonly CONSTRUCT_UNREPRESENTED: "md/construct-unrepresented";
31
35
  readonly HEADING_LEVEL_CLAMPED: "md/heading-level-clamped";
32
36
  readonly ADJACENT_LINKS_MERGED: "md/adjacent-links-merged";
33
37
  readonly CODE_SPAN_AS_MONOSPACE_RUN: "md/code-span-as-monospace-run";
@@ -56,9 +60,14 @@ declare class MarkdownWriteError extends Error {
56
60
  readonly code: string;
57
61
  constructor(code: string, message: string);
58
62
  }
63
+ declare class MarkdownUnbalancedConstructMarkersError extends MarkdownWriteError {
64
+ readonly imbalanceKind: 'unmatchedEnd' | 'unclosedStart';
65
+ readonly blockIndex: number;
66
+ constructor(imbalanceKind: 'unmatchedEnd' | 'unclosedStart', blockIndex: number);
67
+ }
59
68
  declare class MarkdownUnsupportedDocumentKindError extends MarkdownWriteError {
60
69
  readonly kind: string;
61
70
  constructor(kind: string);
62
71
  }
63
72
  //#endregion
64
- export { MarkdownInputTooLargeError as a, MarkdownParseError as c, NOOP_MARKDOWN_DIAGNOSTIC_SINK as d, MarkdownDiagnosticSink as i, MarkdownUnsupportedDocumentKindError as l, MarkdownDiagnosticCodes as n, MarkdownInvalidUtf8Error as o, MarkdownDiagnosticSeverity as r, MarkdownNestingLimitExceededError as s, MarkdownDiagnostic as t, MarkdownWriteError as u };
73
+ export { MarkdownInputTooLargeError as a, MarkdownParseError as c, MarkdownWriteError as d, NOOP_MARKDOWN_DIAGNOSTIC_SINK as f, MarkdownDiagnosticSink as i, MarkdownUnbalancedConstructMarkersError as l, MarkdownDiagnosticCodes as n, MarkdownInvalidUtf8Error as o, MarkdownDiagnosticSeverity as r, MarkdownNestingLimitExceededError as s, MarkdownDiagnostic as t, MarkdownUnsupportedDocumentKindError as u };
@@ -14,6 +14,7 @@ declare const MarkdownDiagnosticCodes: {
14
14
  readonly UNTERMINATED_HTML_BLOCK: "md/unterminated-html-block";
15
15
  readonly TABLE_CELL_COUNT_MISMATCH: "md/table-cell-count-mismatch";
16
16
  readonly DUPLICATE_LINK_REFERENCE: "md/duplicate-link-reference";
17
+ readonly DUPLICATE_FOOTNOTE_DEFINITION: "md/duplicate-footnote-definition";
17
18
  readonly LIST_MARKER_TYPE_CONFLICT: "md/list-marker-type-conflict";
18
19
  readonly INVENTED_PAGE_GEOMETRY: "md/invented-page-geometry";
19
20
  readonly NESTED_EMPHASIS_FLATTENED: "md/nested-emphasis-flattened";
@@ -28,6 +29,9 @@ declare const MarkdownDiagnosticCodes: {
28
29
  readonly MATH_BLOCK_PRESERVED_AS_TEXT: "md/math-block-preserved-as-text";
29
30
  readonly MATH_INLINE_PRESERVED_AS_TEXT: "md/math-inline-preserved-as-text";
30
31
  readonly FRONT_MATTER_KEY_UNMAPPED: "md/front-matter-key-unmapped";
32
+ readonly FOOTNOTE_REFERENCE_PRESERVED_AS_TEXT: "md/footnote-reference-preserved-as-text";
33
+ readonly FOOTNOTE_BODY_HEADING_FLATTENED: "md/footnote-body-heading-flattened";
34
+ readonly CONSTRUCT_UNREPRESENTED: "md/construct-unrepresented";
31
35
  readonly HEADING_LEVEL_CLAMPED: "md/heading-level-clamped";
32
36
  readonly ADJACENT_LINKS_MERGED: "md/adjacent-links-merged";
33
37
  readonly CODE_SPAN_AS_MONOSPACE_RUN: "md/code-span-as-monospace-run";
@@ -56,9 +60,14 @@ declare class MarkdownWriteError extends Error {
56
60
  readonly code: string;
57
61
  constructor(code: string, message: string);
58
62
  }
63
+ declare class MarkdownUnbalancedConstructMarkersError extends MarkdownWriteError {
64
+ readonly imbalanceKind: 'unmatchedEnd' | 'unclosedStart';
65
+ readonly blockIndex: number;
66
+ constructor(imbalanceKind: 'unmatchedEnd' | 'unclosedStart', blockIndex: number);
67
+ }
59
68
  declare class MarkdownUnsupportedDocumentKindError extends MarkdownWriteError {
60
69
  readonly kind: string;
61
70
  constructor(kind: string);
62
71
  }
63
72
  //#endregion
64
- export { MarkdownInputTooLargeError as a, MarkdownParseError as c, NOOP_MARKDOWN_DIAGNOSTIC_SINK as d, MarkdownDiagnosticSink as i, MarkdownUnsupportedDocumentKindError as l, MarkdownDiagnosticCodes as n, MarkdownInvalidUtf8Error as o, MarkdownDiagnosticSeverity as r, MarkdownNestingLimitExceededError as s, MarkdownDiagnostic as t, MarkdownWriteError as u };
73
+ export { MarkdownInputTooLargeError as a, MarkdownParseError as c, MarkdownWriteError as d, NOOP_MARKDOWN_DIAGNOSTIC_SINK as f, MarkdownDiagnosticSink as i, MarkdownUnbalancedConstructMarkersError as l, MarkdownDiagnosticCodes as n, MarkdownInvalidUtf8Error as o, MarkdownDiagnosticSeverity as r, MarkdownNestingLimitExceededError as s, MarkdownDiagnostic as t, MarkdownUnsupportedDocumentKindError as u };
@@ -1,4 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_inline_footnote = require("../inline/footnote.cjs");
2
3
  require("../defaults/defaults.cjs");
3
4
  const require_diagnostics_diagnostics = require("../diagnostics/diagnostics.cjs");
4
5
  const require_shared_list_id = require("../shared/list-id.cjs");
@@ -193,29 +194,98 @@ function renderListRegion(items, context) {
193
194
  }
194
195
  return out;
195
196
  }
196
- function emitBlocks(blocks, context) {
197
- const parts = [];
198
- let index = 0;
197
+ function isConstructItem(item) {
198
+ return "descriptor" in item;
199
+ }
200
+ function groupConstructItems(blocks, start) {
201
+ const items = [];
202
+ let index = start;
199
203
  while (index < blocks.length) {
200
204
  const block = blocks[index];
201
205
  if (block === void 0) break;
202
- if (block.kind === "paragraph" && block.list !== void 0) {
206
+ index += 1;
207
+ if (block.kind === "constructEnd") return {
208
+ items,
209
+ next: index
210
+ };
211
+ if (block.kind === "constructStart") {
212
+ const nested = groupConstructItems(blocks, index);
213
+ items.push({
214
+ descriptor: block.descriptor,
215
+ children: nested.items
216
+ });
217
+ index = nested.next;
218
+ continue;
219
+ }
220
+ items.push({ block });
221
+ }
222
+ return {
223
+ items,
224
+ next: index
225
+ };
226
+ }
227
+ const FOOTNOTE_CONTINUATION_INDENT = 4;
228
+ function renderFootnoteDefinition(name, body) {
229
+ const marker = `[^${name}]:`;
230
+ if (body.length === 0) return marker;
231
+ const indent = " ".repeat(FOOTNOTE_CONTINUATION_INDENT);
232
+ const [firstLine = "", ...restLines] = body.split("\n");
233
+ return [`${marker} ${firstLine}`, ...restLines.map((line) => line.length === 0 ? line : `${indent}${line}`)].join("\n");
234
+ }
235
+ function renderConstruct(item, context) {
236
+ const body = renderItems(item.children, context);
237
+ const { descriptor } = item;
238
+ if (descriptor.kind === "anchor" && descriptor.anchorType === "footnote") {
239
+ if (require_inline_footnote.isValidFootnoteLabel(descriptor.name)) return renderFootnoteDefinition(descriptor.name, body);
240
+ context.sink({
241
+ code: require_diagnostics_diagnostics.MarkdownDiagnosticCodes.CONSTRUCT_UNREPRESENTED,
242
+ severity: "info",
243
+ message: `a footnote anchor's own name "${descriptor.name}" cannot be spelled as a "[^label]:" marker (whitespace or "]" would reparse as something else); its own extent still renders in place, but the construct itself is not represented`
244
+ });
245
+ return body;
246
+ }
247
+ const detail = descriptor.kind === "anchor" ? `${descriptor.kind} (${descriptor.anchorType})` : descriptor.kind;
248
+ context.sink({
249
+ code: require_diagnostics_diagnostics.MarkdownDiagnosticCodes.CONSTRUCT_UNREPRESENTED,
250
+ severity: "info",
251
+ message: `a "${detail}" construct has no markdown syntax; its own extent still renders in place, but the construct itself is not represented`
252
+ });
253
+ return body;
254
+ }
255
+ function renderItems(items, context) {
256
+ const parts = [];
257
+ let index = 0;
258
+ while (index < items.length) {
259
+ const item = items[index];
260
+ if (item === void 0) break;
261
+ if (isConstructItem(item)) {
262
+ const rendered = renderConstruct(item, context);
263
+ if (rendered.length > 0) parts.push(rendered);
264
+ index += 1;
265
+ continue;
266
+ }
267
+ if (item.block.kind === "paragraph" && item.block.list !== void 0) {
203
268
  const region = [];
204
269
  let end = index;
205
- for (let candidate = blocks[end]; candidate?.kind === "paragraph" && candidate.list !== void 0; candidate = blocks[end]) {
206
- region.push(candidate);
270
+ for (let candidate = items[end]; candidate !== void 0 && !isConstructItem(candidate) && candidate.block.kind === "paragraph" && candidate.block.list !== void 0; candidate = items[end]) {
271
+ region.push(candidate.block);
207
272
  end += 1;
208
273
  }
209
274
  parts.push(renderListRegion(region, context));
210
275
  index = end;
211
276
  continue;
212
277
  }
213
- const rendered = renderTopLevelBlock(block, context);
278
+ const rendered = renderTopLevelBlock(item.block, context);
214
279
  if (rendered.length > 0) parts.push(rendered);
215
280
  index += 1;
216
281
  }
217
282
  return parts.join("\n\n");
218
283
  }
284
+ function emitBlocks(blocks, context) {
285
+ const imbalance = (0, document_schema_js.findConstructMarkerImbalance)(blocks);
286
+ if (imbalance !== void 0) throw new require_diagnostics_diagnostics.MarkdownUnbalancedConstructMarkersError(imbalance.kind, imbalance.index);
287
+ return renderItems(groupConstructItems(blocks, 0).items, context);
288
+ }
219
289
  function emitMarkdown(document, options = {}) {
220
290
  if (document.kind !== "wordprocessing") throw new require_diagnostics_diagnostics.MarkdownUnsupportedDocumentKindError(document.kind);
221
291
  const context = {