markdown-codec 0.0.0 → 1.0.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 (171) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +215 -0
  3. package/dist/ast/ast.cjs +25 -0
  4. package/dist/ast/ast.d.cts +2 -0
  5. package/dist/ast/ast.d.ts +2 -0
  6. package/dist/ast/ast.js +23 -0
  7. package/dist/ast-BXYwy08e.d.cts +160 -0
  8. package/dist/ast-BXYwy08e.d.ts +160 -0
  9. package/dist/block/block.cjs +530 -0
  10. package/dist/block/block.d.cts +18 -0
  11. package/dist/block/block.d.ts +18 -0
  12. package/dist/block/block.js +529 -0
  13. package/dist/block/definitions.cjs +59 -0
  14. package/dist/block/definitions.d.cts +6 -0
  15. package/dist/block/definitions.d.ts +6 -0
  16. package/dist/block/definitions.js +58 -0
  17. package/dist/block/line.cjs +76 -0
  18. package/dist/block/line.d.cts +28 -0
  19. package/dist/block/line.d.ts +28 -0
  20. package/dist/block/line.js +74 -0
  21. package/dist/block/list.cjs +110 -0
  22. package/dist/block/list.d.cts +8 -0
  23. package/dist/block/list.d.ts +8 -0
  24. package/dist/block/list.js +107 -0
  25. package/dist/block/node.cjs +68 -0
  26. package/dist/block/node.d.cts +45 -0
  27. package/dist/block/node.d.ts +45 -0
  28. package/dist/block/node.js +65 -0
  29. package/dist/block/table.cjs +64 -0
  30. package/dist/block/table.d.cts +7 -0
  31. package/dist/block/table.d.ts +7 -0
  32. package/dist/block/table.js +61 -0
  33. package/dist/codec.cjs +22 -0
  34. package/dist/codec.d.cts +361 -0
  35. package/dist/codec.d.ts +361 -0
  36. package/dist/codec.js +20 -0
  37. package/dist/defaults/defaults.cjs +31 -0
  38. package/dist/defaults/defaults.d.cts +16 -0
  39. package/dist/defaults/defaults.d.ts +16 -0
  40. package/dist/defaults/defaults.js +20 -0
  41. package/dist/diagnostics/diagnostics.cjs +85 -0
  42. package/dist/diagnostics/diagnostics.d.cts +2 -0
  43. package/dist/diagnostics/diagnostics.d.ts +2 -0
  44. package/dist/diagnostics/diagnostics.js +77 -0
  45. package/dist/diagnostics-DmuWc7d8.d.cts +61 -0
  46. package/dist/diagnostics-DmuWc7d8.d.ts +61 -0
  47. package/dist/emit/emit.cjs +228 -0
  48. package/dist/emit/emit.d.cts +6 -0
  49. package/dist/emit/emit.d.ts +6 -0
  50. package/dist/emit/emit.js +227 -0
  51. package/dist/emit/front-matter.cjs +24 -0
  52. package/dist/emit/front-matter.d.cts +5 -0
  53. package/dist/emit/front-matter.d.ts +5 -0
  54. package/dist/emit/front-matter.js +23 -0
  55. package/dist/emit/image.cjs +10 -0
  56. package/dist/emit/image.d.cts +5 -0
  57. package/dist/emit/image.d.ts +5 -0
  58. package/dist/emit/image.js +9 -0
  59. package/dist/emit/inline.cjs +183 -0
  60. package/dist/emit/inline.d.cts +12 -0
  61. package/dist/emit/inline.d.ts +12 -0
  62. package/dist/emit/inline.js +180 -0
  63. package/dist/emit/table.cjs +73 -0
  64. package/dist/emit/table.d.cts +10 -0
  65. package/dist/emit/table.d.ts +10 -0
  66. package/dist/emit/table.js +72 -0
  67. package/dist/html/html.cjs +116 -0
  68. package/dist/html/html.d.cts +2 -0
  69. package/dist/html/html.d.ts +2 -0
  70. package/dist/html/html.js +113 -0
  71. package/dist/html/render.cjs +193 -0
  72. package/dist/html/render.d.cts +8 -0
  73. package/dist/html/render.d.ts +8 -0
  74. package/dist/html/render.js +189 -0
  75. package/dist/html-bkz2QTuq.d.cts +7 -0
  76. package/dist/html-bkz2QTuq.d.ts +7 -0
  77. package/dist/image/image.cjs +129 -0
  78. package/dist/image/image.d.cts +2 -0
  79. package/dist/image/image.d.ts +2 -0
  80. package/dist/image/image.js +125 -0
  81. package/dist/image-C4KYmz_L.d.cts +19 -0
  82. package/dist/image-Cm3hT5PS.d.ts +19 -0
  83. package/dist/image-DescdRgq.d.cts +12 -0
  84. package/dist/image-DescdRgq.d.ts +12 -0
  85. package/dist/index.cjs +17 -0
  86. package/dist/index.d.cts +7 -0
  87. package/dist/index.d.ts +7 -0
  88. package/dist/index.js +5 -0
  89. package/dist/inline/chars.cjs +50 -0
  90. package/dist/inline/chars.d.cts +11 -0
  91. package/dist/inline/chars.d.ts +11 -0
  92. package/dist/inline/chars.js +42 -0
  93. package/dist/inline/delimiter.cjs +136 -0
  94. package/dist/inline/delimiter.d.cts +29 -0
  95. package/dist/inline/delimiter.d.ts +29 -0
  96. package/dist/inline/delimiter.js +132 -0
  97. package/dist/inline/entity.cjs +67 -0
  98. package/dist/inline/entity.d.cts +9 -0
  99. package/dist/inline/entity.d.ts +9 -0
  100. package/dist/inline/entity.js +65 -0
  101. package/dist/inline/gfm-autolink.cjs +156 -0
  102. package/dist/inline/gfm-autolink.d.cts +5 -0
  103. package/dist/inline/gfm-autolink.d.ts +5 -0
  104. package/dist/inline/gfm-autolink.js +155 -0
  105. package/dist/inline/inline.cjs +457 -0
  106. package/dist/inline/inline.d.cts +2 -0
  107. package/dist/inline/inline.d.ts +2 -0
  108. package/dist/inline/inline.js +456 -0
  109. package/dist/inline/link.cjs +130 -0
  110. package/dist/inline/link.d.cts +2 -0
  111. package/dist/inline/link.d.ts +2 -0
  112. package/dist/inline/link.js +124 -0
  113. package/dist/inline/node.cjs +57 -0
  114. package/dist/inline/node.d.cts +23 -0
  115. package/dist/inline/node.d.ts +23 -0
  116. package/dist/inline/node.js +55 -0
  117. package/dist/inline-B50cM6cn.d.ts +10 -0
  118. package/dist/inline-C9YEGDV5.d.cts +10 -0
  119. package/dist/link-Dv4kxVjk.d.cts +18 -0
  120. package/dist/link-Dv4kxVjk.d.ts +18 -0
  121. package/dist/lower/front-matter.cjs +75 -0
  122. package/dist/lower/front-matter.d.cts +10 -0
  123. package/dist/lower/front-matter.d.ts +10 -0
  124. package/dist/lower/front-matter.js +74 -0
  125. package/dist/lower/image.cjs +29 -0
  126. package/dist/lower/image.d.cts +2 -0
  127. package/dist/lower/image.d.ts +2 -0
  128. package/dist/lower/image.js +28 -0
  129. package/dist/lower/inline.cjs +96 -0
  130. package/dist/lower/inline.d.cts +19 -0
  131. package/dist/lower/inline.d.ts +19 -0
  132. package/dist/lower/inline.js +93 -0
  133. package/dist/lower/lower.cjs +293 -0
  134. package/dist/lower/lower.d.cts +8 -0
  135. package/dist/lower/lower.d.ts +8 -0
  136. package/dist/lower/lower.js +291 -0
  137. package/dist/lower/table.cjs +27 -0
  138. package/dist/lower/table.d.cts +7 -0
  139. package/dist/lower/table.d.ts +7 -0
  140. package/dist/lower/table.js +26 -0
  141. package/dist/options/options.cjs +0 -0
  142. package/dist/options/options.d.cts +43 -0
  143. package/dist/options/options.d.ts +43 -0
  144. package/dist/options/options.js +0 -0
  145. package/dist/read.cjs +20 -0
  146. package/dist/read.d.cts +11 -0
  147. package/dist/read.d.ts +11 -0
  148. package/dist/read.js +19 -0
  149. package/dist/scan/entity-table.cjs +2131 -0
  150. package/dist/scan/entity-table.d.cts +4 -0
  151. package/dist/scan/entity-table.d.ts +4 -0
  152. package/dist/scan/entity-table.js +2130 -0
  153. package/dist/scan/scan.cjs +80 -0
  154. package/dist/scan/scan.d.cts +2 -0
  155. package/dist/scan/scan.d.ts +2 -0
  156. package/dist/scan/scan.js +78 -0
  157. package/dist/scan-DeBxgG-r.d.cts +30 -0
  158. package/dist/scan-DeBxgG-r.d.ts +30 -0
  159. package/dist/shared/list-id.cjs +36 -0
  160. package/dist/shared/list-id.d.cts +22 -0
  161. package/dist/shared/list-id.d.ts +22 -0
  162. package/dist/shared/list-id.js +32 -0
  163. package/dist/shared/style-constants.cjs +34 -0
  164. package/dist/shared/style-constants.d.cts +14 -0
  165. package/dist/shared/style-constants.d.ts +14 -0
  166. package/dist/shared/style-constants.js +23 -0
  167. package/dist/write.cjs +9 -0
  168. package/dist/write.d.cts +6 -0
  169. package/dist/write.d.ts +6 -0
  170. package/dist/write.js +8 -0
  171. package/package.json +92 -2
@@ -0,0 +1,61 @@
1
+ //#region src/diagnostics/diagnostics.d.ts
2
+ type MarkdownDiagnosticSeverity = 'info' | 'warning';
3
+ interface MarkdownDiagnostic {
4
+ readonly code: string;
5
+ readonly severity: MarkdownDiagnosticSeverity;
6
+ readonly message: string;
7
+ readonly line?: number;
8
+ }
9
+ type MarkdownDiagnosticSink = (diagnostic: MarkdownDiagnostic) => void;
10
+ declare const NOOP_MARKDOWN_DIAGNOSTIC_SINK: MarkdownDiagnosticSink;
11
+ declare const MarkdownDiagnosticCodes: {
12
+ readonly UNCLOSED_FENCE: "md/unclosed-fence";
13
+ readonly UNTERMINATED_HTML_BLOCK: "md/unterminated-html-block";
14
+ readonly TABLE_CELL_COUNT_MISMATCH: "md/table-cell-count-mismatch";
15
+ readonly DUPLICATE_LINK_REFERENCE: "md/duplicate-link-reference";
16
+ readonly LIST_MARKER_TYPE_CONFLICT: "md/list-marker-type-conflict";
17
+ readonly INVENTED_PAGE_GEOMETRY: "md/invented-page-geometry";
18
+ readonly NESTED_EMPHASIS_FLATTENED: "md/nested-emphasis-flattened";
19
+ readonly LINK_TITLE_DROPPED: "md/link-title-dropped";
20
+ readonly CODE_BLOCK_INFO_STRING_DROPPED: "md/code-block-info-string-dropped";
21
+ readonly BLOCKQUOTE_NESTED_DEPTH: "md/blockquote-nested-depth";
22
+ readonly LIST_ITEM_BLOCK_UNLISTED: "md/list-item-block-unlisted";
23
+ readonly LIST_ITEM_MULTI_BLOCK_FLATTENED: "md/list-item-multi-block-flattened";
24
+ readonly IMAGE_UNRESOLVED: "md/image-unresolved";
25
+ readonly RAW_HTML_PRESERVED_AS_TEXT: "md/raw-html-preserved-as-text";
26
+ readonly RAW_HTML_DROPPED: "md/raw-html-dropped";
27
+ readonly FRONT_MATTER_KEY_UNMAPPED: "md/front-matter-key-unmapped";
28
+ readonly HEADING_LEVEL_CLAMPED: "md/heading-level-clamped";
29
+ readonly ADJACENT_LINKS_MERGED: "md/adjacent-links-merged";
30
+ readonly CODE_SPAN_AS_MONOSPACE_RUN: "md/code-span-as-monospace-run";
31
+ readonly PARAGRAPH_INDENT_DROPPED: "md/paragraph-indent-dropped";
32
+ readonly LIST_NUMID_FALLBACK: "md/list-numid-fallback";
33
+ readonly TABLE_CELL_FORMATTING_DROPPED: "md/table-cell-formatting-dropped";
34
+ readonly TABLE_CELL_MULTI_PARAGRAPH_JOINED: "md/table-cell-multi-paragraph-joined";
35
+ };
36
+ declare class MarkdownParseError extends Error {
37
+ readonly code: string;
38
+ constructor(code: string, message: string);
39
+ }
40
+ declare class MarkdownInvalidUtf8Error extends MarkdownParseError {
41
+ constructor(message?: string);
42
+ }
43
+ declare class MarkdownInputTooLargeError extends MarkdownParseError {
44
+ readonly maxInputBytes: number;
45
+ readonly actualBytes: number;
46
+ constructor(maxInputBytes: number, actualBytes: number);
47
+ }
48
+ declare class MarkdownNestingLimitExceededError extends MarkdownParseError {
49
+ readonly maxNesting: number;
50
+ constructor(maxNesting: number);
51
+ }
52
+ declare class MarkdownWriteError extends Error {
53
+ readonly code: string;
54
+ constructor(code: string, message: string);
55
+ }
56
+ declare class MarkdownUnsupportedDocumentKindError extends MarkdownWriteError {
57
+ readonly kind: string;
58
+ constructor(kind: string);
59
+ }
60
+ //#endregion
61
+ 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 };
@@ -0,0 +1,61 @@
1
+ //#region src/diagnostics/diagnostics.d.ts
2
+ type MarkdownDiagnosticSeverity = 'info' | 'warning';
3
+ interface MarkdownDiagnostic {
4
+ readonly code: string;
5
+ readonly severity: MarkdownDiagnosticSeverity;
6
+ readonly message: string;
7
+ readonly line?: number;
8
+ }
9
+ type MarkdownDiagnosticSink = (diagnostic: MarkdownDiagnostic) => void;
10
+ declare const NOOP_MARKDOWN_DIAGNOSTIC_SINK: MarkdownDiagnosticSink;
11
+ declare const MarkdownDiagnosticCodes: {
12
+ readonly UNCLOSED_FENCE: "md/unclosed-fence";
13
+ readonly UNTERMINATED_HTML_BLOCK: "md/unterminated-html-block";
14
+ readonly TABLE_CELL_COUNT_MISMATCH: "md/table-cell-count-mismatch";
15
+ readonly DUPLICATE_LINK_REFERENCE: "md/duplicate-link-reference";
16
+ readonly LIST_MARKER_TYPE_CONFLICT: "md/list-marker-type-conflict";
17
+ readonly INVENTED_PAGE_GEOMETRY: "md/invented-page-geometry";
18
+ readonly NESTED_EMPHASIS_FLATTENED: "md/nested-emphasis-flattened";
19
+ readonly LINK_TITLE_DROPPED: "md/link-title-dropped";
20
+ readonly CODE_BLOCK_INFO_STRING_DROPPED: "md/code-block-info-string-dropped";
21
+ readonly BLOCKQUOTE_NESTED_DEPTH: "md/blockquote-nested-depth";
22
+ readonly LIST_ITEM_BLOCK_UNLISTED: "md/list-item-block-unlisted";
23
+ readonly LIST_ITEM_MULTI_BLOCK_FLATTENED: "md/list-item-multi-block-flattened";
24
+ readonly IMAGE_UNRESOLVED: "md/image-unresolved";
25
+ readonly RAW_HTML_PRESERVED_AS_TEXT: "md/raw-html-preserved-as-text";
26
+ readonly RAW_HTML_DROPPED: "md/raw-html-dropped";
27
+ readonly FRONT_MATTER_KEY_UNMAPPED: "md/front-matter-key-unmapped";
28
+ readonly HEADING_LEVEL_CLAMPED: "md/heading-level-clamped";
29
+ readonly ADJACENT_LINKS_MERGED: "md/adjacent-links-merged";
30
+ readonly CODE_SPAN_AS_MONOSPACE_RUN: "md/code-span-as-monospace-run";
31
+ readonly PARAGRAPH_INDENT_DROPPED: "md/paragraph-indent-dropped";
32
+ readonly LIST_NUMID_FALLBACK: "md/list-numid-fallback";
33
+ readonly TABLE_CELL_FORMATTING_DROPPED: "md/table-cell-formatting-dropped";
34
+ readonly TABLE_CELL_MULTI_PARAGRAPH_JOINED: "md/table-cell-multi-paragraph-joined";
35
+ };
36
+ declare class MarkdownParseError extends Error {
37
+ readonly code: string;
38
+ constructor(code: string, message: string);
39
+ }
40
+ declare class MarkdownInvalidUtf8Error extends MarkdownParseError {
41
+ constructor(message?: string);
42
+ }
43
+ declare class MarkdownInputTooLargeError extends MarkdownParseError {
44
+ readonly maxInputBytes: number;
45
+ readonly actualBytes: number;
46
+ constructor(maxInputBytes: number, actualBytes: number);
47
+ }
48
+ declare class MarkdownNestingLimitExceededError extends MarkdownParseError {
49
+ readonly maxNesting: number;
50
+ constructor(maxNesting: number);
51
+ }
52
+ declare class MarkdownWriteError extends Error {
53
+ readonly code: string;
54
+ constructor(code: string, message: string);
55
+ }
56
+ declare class MarkdownUnsupportedDocumentKindError extends MarkdownWriteError {
57
+ readonly kind: string;
58
+ constructor(kind: string);
59
+ }
60
+ //#endregion
61
+ 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 };
@@ -0,0 +1,228 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ require("../defaults/defaults.cjs");
3
+ const require_diagnostics_diagnostics = require("../diagnostics/diagnostics.cjs");
4
+ const require_shared_list_id = require("../shared/list-id.cjs");
5
+ const require_shared_style_constants = require("../shared/style-constants.cjs");
6
+ const require_emit_front_matter = require("./front-matter.cjs");
7
+ const require_emit_inline = require("./inline.cjs");
8
+ const require_emit_image = require("./image.cjs");
9
+ const require_emit_table = require("./table.cjs");
10
+ //#region src/emit/emit.ts
11
+ const MAX_SETEXT_LEVEL = 2;
12
+ const SETEXT_LEVEL_1_CHAR = "=";
13
+ const SETEXT_LEVEL_2_CHAR = "-";
14
+ const MIN_SETEXT_UNDERLINE_LENGTH = 1;
15
+ function renderSetextHeading(level, text) {
16
+ const underlineChar = level === 1 ? SETEXT_LEVEL_1_CHAR : SETEXT_LEVEL_2_CHAR;
17
+ const firstLine = text.split("\n")[0] ?? "";
18
+ return `${text}\n${underlineChar.repeat(Math.max(MIN_SETEXT_UNDERLINE_LENGTH, firstLine.length))}`;
19
+ }
20
+ const MIN_CODE_FENCE_LENGTH = 3;
21
+ function longestRunLength(text, char) {
22
+ let longest = 0;
23
+ let current = 0;
24
+ for (const candidate of text) if (candidate === char) {
25
+ current += 1;
26
+ longest = Math.max(longest, current);
27
+ } else current = 0;
28
+ return longest;
29
+ }
30
+ function codeFenceFor(literal, fenceChar) {
31
+ return fenceChar.repeat(Math.max(MIN_CODE_FENCE_LENGTH, longestRunLength(literal, fenceChar) + 1));
32
+ }
33
+ const QUOTABLE_STYLE_IDS = /* @__PURE__ */ new Set([
34
+ require_shared_style_constants.QUOTE_STYLE_ID,
35
+ require_shared_style_constants.CODE_BLOCK_STYLE_ID,
36
+ require_shared_style_constants.HORIZONTAL_RULE_STYLE_ID,
37
+ require_shared_style_constants.HTML_PREFORMATTED_STYLE_ID
38
+ ]);
39
+ function isQuotableStyle(styleId) {
40
+ if (styleId === void 0) return false;
41
+ return QUOTABLE_STYLE_IDS.has(styleId) || require_shared_style_constants.parseHeadingStyleId(styleId) !== void 0;
42
+ }
43
+ function quoteDepthOf(paragraph) {
44
+ if (paragraph.indentLeftPt === void 0 || paragraph.indentLeftPt <= 0) return 0;
45
+ return Math.max(1, Math.round(paragraph.indentLeftPt / 36));
46
+ }
47
+ function renderParagraphBody(paragraph, context) {
48
+ if (paragraph.styleId === "HorizontalRule") return context.thematicBreakChar.repeat(3);
49
+ if (paragraph.styleId === "CodeBlock") {
50
+ const literal = paragraph.runs.map((run) => run.text).join("");
51
+ const fence = codeFenceFor(literal, context.codeFenceChar);
52
+ return literal.length === 0 ? `${fence}\n${fence}` : `${fence}\n${literal}\n${fence}`;
53
+ }
54
+ if (paragraph.styleId === "HTMLPreformatted") return paragraph.runs.map((run) => run.text).join("");
55
+ const headingLevel = paragraph.styleId === void 0 ? void 0 : require_shared_style_constants.parseHeadingStyleId(paragraph.styleId);
56
+ if (headingLevel !== void 0) {
57
+ let level = headingLevel;
58
+ if (level > 6) {
59
+ context.sink({
60
+ code: require_diagnostics_diagnostics.MarkdownDiagnosticCodes.HEADING_LEVEL_CLAMPED,
61
+ severity: "info",
62
+ message: `heading level ${String(level)} exceeds ATX's own six-"#" ceiling and is clamped to ${String(6)}`
63
+ });
64
+ level = 6;
65
+ }
66
+ const text = require_emit_inline.emitRuns(paragraph.runs, context);
67
+ if (context.headingStyle === "setext" && level <= MAX_SETEXT_LEVEL) return renderSetextHeading(level, text);
68
+ return `${"#".repeat(level)} ${text}`;
69
+ }
70
+ return require_emit_inline.emitRuns(paragraph.runs, context);
71
+ }
72
+ function renderParagraph(paragraph, context) {
73
+ const body = renderParagraphBody(paragraph, context);
74
+ const depth = quoteDepthOf(paragraph);
75
+ if (depth === 0) return body;
76
+ if (!isQuotableStyle(paragraph.styleId)) {
77
+ context.sink({
78
+ code: require_diagnostics_diagnostics.MarkdownDiagnosticCodes.PARAGRAPH_INDENT_DROPPED,
79
+ severity: "info",
80
+ message: `paragraph carries indentLeftPt (${String(paragraph.indentLeftPt)}pt) with no styleId this package recognises as quotable; the indent has no other markdown representation and is dropped`
81
+ });
82
+ return body;
83
+ }
84
+ const prefix = "> ".repeat(depth);
85
+ return body.split("\n").map((line) => `${prefix}${line}`).join("\n");
86
+ }
87
+ function renderTopLevelBlock(block, context) {
88
+ switch (block.kind) {
89
+ case "paragraph": return renderParagraph(block, context);
90
+ case "table": return require_emit_table.emitTable(block, context);
91
+ case "image": return require_emit_image.emitImage(block, context.embedImages);
92
+ case "pageBreak":
93
+ case "embeddedObject": return "";
94
+ }
95
+ }
96
+ function listInfoFor(numId, context) {
97
+ const info = require_shared_list_id.parseListNumId(numId);
98
+ if (info === void 0 && !context.reportedFallbackNumIds.has(numId)) {
99
+ context.reportedFallbackNumIds.add(numId);
100
+ context.sink({
101
+ code: require_diagnostics_diagnostics.MarkdownDiagnosticCodes.LIST_NUMID_FALLBACK,
102
+ severity: "info",
103
+ message: `numId "${numId}" was not minted by this package's own src/lower and falls back to an ordinary, tight, non-task bullet list`
104
+ });
105
+ }
106
+ return info;
107
+ }
108
+ function checkboxPrefixFor(item) {
109
+ const first = item.runs[0];
110
+ if (first === void 0) return;
111
+ if (first.text.startsWith(`☒ `)) return "[x] ";
112
+ if (first.text.startsWith(`☐ `)) return "[ ] ";
113
+ }
114
+ function stripCheckboxRun(item, checkboxPrefix) {
115
+ if (checkboxPrefix === void 0) return item;
116
+ const first = item.runs[0];
117
+ const glyphPrefix = checkboxPrefix === "[x] " ? `☒ ` : `☐ `;
118
+ if (!first?.text.startsWith(glyphPrefix)) return item;
119
+ const strippedText = first.text.slice(glyphPrefix.length);
120
+ const runs = strippedText.length === 0 ? item.runs.slice(1) : [{
121
+ ...first,
122
+ text: strippedText
123
+ }, ...item.runs.slice(1)];
124
+ return {
125
+ ...item,
126
+ runs
127
+ };
128
+ }
129
+ function renderListItemMarker(numId, info, item, context) {
130
+ const checkboxText = (info?.task === true ? checkboxPrefixFor(item) : void 0) ?? "";
131
+ if (info?.type === "ordered") {
132
+ const next = context.orderedCounters.get(numId) ?? info.start ?? 1;
133
+ context.orderedCounters.set(numId, next + 1);
134
+ const bare = `${String(next)}${context.orderedDelimiter} `;
135
+ return {
136
+ full: `${bare}${checkboxText}`,
137
+ bareLength: bare.length
138
+ };
139
+ }
140
+ const bare = `${context.bulletMarker} `;
141
+ return {
142
+ full: `${bare}${checkboxText}`,
143
+ bareLength: bare.length
144
+ };
145
+ }
146
+ function renderListRegion(items, context) {
147
+ const parts = [];
148
+ let index = 0;
149
+ while (index < items.length) {
150
+ const item = items[index];
151
+ if (item?.list === void 0) break;
152
+ const { numId, level } = item.list;
153
+ const info = listInfoFor(numId, context);
154
+ let lookahead = index + 1;
155
+ while (lookahead < items.length && (items[lookahead]?.list?.level ?? -1) > level) lookahead += 1;
156
+ const nestedItems = items.slice(index + 1, lookahead);
157
+ const checkboxPrefix = info?.task === true ? checkboxPrefixFor(item) : void 0;
158
+ const marker = renderListItemMarker(numId, info, item, context);
159
+ const bodyLines = renderParagraphBody(stripCheckboxRun(item, checkboxPrefix), context).split("\n");
160
+ const indent = " ".repeat(marker.bareLength);
161
+ const [firstLine = "", ...restLines] = bodyLines;
162
+ let text = [`${marker.full}${firstLine}`, ...restLines.map((line) => `${indent}${line}`)].join("\n");
163
+ if (nestedItems.length > 0) {
164
+ const nested = renderListRegion(nestedItems, context).split("\n").map((line) => line.length === 0 ? line : `${indent}${line}`).join("\n");
165
+ text += `\n${nested}`;
166
+ }
167
+ parts.push({
168
+ numId,
169
+ text
170
+ });
171
+ index = lookahead;
172
+ }
173
+ let out = "";
174
+ for (const [partIndex, part] of parts.entries()) {
175
+ if (partIndex > 0) {
176
+ const previous = parts[partIndex - 1];
177
+ const sameList = previous.numId === part.numId;
178
+ const loose = sameList && (require_shared_list_id.parseListNumId(previous.numId)?.loose ?? false);
179
+ out += sameList && !loose ? "\n" : "\n\n";
180
+ }
181
+ out += part.text;
182
+ }
183
+ return out;
184
+ }
185
+ function emitBlocks(blocks, context) {
186
+ const parts = [];
187
+ let index = 0;
188
+ while (index < blocks.length) {
189
+ const block = blocks[index];
190
+ if (block === void 0) break;
191
+ if (block.kind === "paragraph" && block.list !== void 0) {
192
+ const region = [];
193
+ let end = index;
194
+ for (let candidate = blocks[end]; candidate?.kind === "paragraph" && candidate.list !== void 0; candidate = blocks[end]) {
195
+ region.push(candidate);
196
+ end += 1;
197
+ }
198
+ parts.push(renderListRegion(region, context));
199
+ index = end;
200
+ continue;
201
+ }
202
+ const rendered = renderTopLevelBlock(block, context);
203
+ if (rendered.length > 0) parts.push(rendered);
204
+ index += 1;
205
+ }
206
+ return parts.join("\n\n");
207
+ }
208
+ function emitMarkdown(document, options = {}) {
209
+ if (document.kind !== "wordprocessing") throw new require_diagnostics_diagnostics.MarkdownUnsupportedDocumentKindError(document.kind);
210
+ const context = {
211
+ sink: options.sink ?? require_diagnostics_diagnostics.NOOP_MARKDOWN_DIAGNOSTIC_SINK,
212
+ emphasisMarker: options.emphasisMarker ?? "_",
213
+ bulletMarker: options.bulletListMarker ?? "-",
214
+ orderedDelimiter: options.orderedListDelimiter ?? ".",
215
+ codeFenceChar: options.codeFenceChar ?? "`",
216
+ thematicBreakChar: options.thematicBreakChar ?? "-",
217
+ headingStyle: options.headingStyle ?? "atx",
218
+ embedImages: options.images ?? true,
219
+ orderedCounters: /* @__PURE__ */ new Map(),
220
+ reportedFallbackNumIds: /* @__PURE__ */ new Set()
221
+ };
222
+ const body = document.sections.map((section) => emitBlocks(section.blocks, context)).join("\n\n");
223
+ const frontMatter = options.frontMatter === true ? require_emit_front_matter.emitFrontMatter(document.metadata) : void 0;
224
+ const text = frontMatter === void 0 ? body : `${frontMatter}\n\n${body}`;
225
+ return (options.lineEnding ?? "lf") === "crlf" ? text.replaceAll("\n", "\r\n") : text;
226
+ }
227
+ //#endregion
228
+ exports.emitMarkdown = emitMarkdown;
@@ -0,0 +1,6 @@
1
+ import { WriteMarkdownOptions } from "../options/options.cjs";
2
+ import { ContentDocument } from "document-schema.js";
3
+ //#region src/emit/emit.d.ts
4
+ declare function emitMarkdown(document: ContentDocument, options?: WriteMarkdownOptions): string;
5
+ //#endregion
6
+ export { emitMarkdown };
@@ -0,0 +1,6 @@
1
+ import { WriteMarkdownOptions } from "../options/options.js";
2
+ import { ContentDocument } from "document-schema.js";
3
+ //#region src/emit/emit.d.ts
4
+ declare function emitMarkdown(document: ContentDocument, options?: WriteMarkdownOptions): string;
5
+ //#endregion
6
+ export { emitMarkdown };
@@ -0,0 +1,227 @@
1
+ import "../defaults/defaults.js";
2
+ import { MarkdownDiagnosticCodes, MarkdownUnsupportedDocumentKindError, NOOP_MARKDOWN_DIAGNOSTIC_SINK } from "../diagnostics/diagnostics.js";
3
+ import { parseListNumId } from "../shared/list-id.js";
4
+ import { CODE_BLOCK_STYLE_ID, HORIZONTAL_RULE_STYLE_ID, HTML_PREFORMATTED_STYLE_ID, QUOTE_STYLE_ID, parseHeadingStyleId } from "../shared/style-constants.js";
5
+ import { emitFrontMatter } from "./front-matter.js";
6
+ import { emitRuns } from "./inline.js";
7
+ import { emitImage } from "./image.js";
8
+ import { emitTable } from "./table.js";
9
+ //#region src/emit/emit.ts
10
+ const MAX_SETEXT_LEVEL = 2;
11
+ const SETEXT_LEVEL_1_CHAR = "=";
12
+ const SETEXT_LEVEL_2_CHAR = "-";
13
+ const MIN_SETEXT_UNDERLINE_LENGTH = 1;
14
+ function renderSetextHeading(level, text) {
15
+ const underlineChar = level === 1 ? SETEXT_LEVEL_1_CHAR : SETEXT_LEVEL_2_CHAR;
16
+ const firstLine = text.split("\n")[0] ?? "";
17
+ return `${text}\n${underlineChar.repeat(Math.max(MIN_SETEXT_UNDERLINE_LENGTH, firstLine.length))}`;
18
+ }
19
+ const MIN_CODE_FENCE_LENGTH = 3;
20
+ function longestRunLength(text, char) {
21
+ let longest = 0;
22
+ let current = 0;
23
+ for (const candidate of text) if (candidate === char) {
24
+ current += 1;
25
+ longest = Math.max(longest, current);
26
+ } else current = 0;
27
+ return longest;
28
+ }
29
+ function codeFenceFor(literal, fenceChar) {
30
+ return fenceChar.repeat(Math.max(MIN_CODE_FENCE_LENGTH, longestRunLength(literal, fenceChar) + 1));
31
+ }
32
+ const QUOTABLE_STYLE_IDS = /* @__PURE__ */ new Set([
33
+ QUOTE_STYLE_ID,
34
+ CODE_BLOCK_STYLE_ID,
35
+ HORIZONTAL_RULE_STYLE_ID,
36
+ HTML_PREFORMATTED_STYLE_ID
37
+ ]);
38
+ function isQuotableStyle(styleId) {
39
+ if (styleId === void 0) return false;
40
+ return QUOTABLE_STYLE_IDS.has(styleId) || parseHeadingStyleId(styleId) !== void 0;
41
+ }
42
+ function quoteDepthOf(paragraph) {
43
+ if (paragraph.indentLeftPt === void 0 || paragraph.indentLeftPt <= 0) return 0;
44
+ return Math.max(1, Math.round(paragraph.indentLeftPt / 36));
45
+ }
46
+ function renderParagraphBody(paragraph, context) {
47
+ if (paragraph.styleId === "HorizontalRule") return context.thematicBreakChar.repeat(3);
48
+ if (paragraph.styleId === "CodeBlock") {
49
+ const literal = paragraph.runs.map((run) => run.text).join("");
50
+ const fence = codeFenceFor(literal, context.codeFenceChar);
51
+ return literal.length === 0 ? `${fence}\n${fence}` : `${fence}\n${literal}\n${fence}`;
52
+ }
53
+ if (paragraph.styleId === "HTMLPreformatted") return paragraph.runs.map((run) => run.text).join("");
54
+ const headingLevel = paragraph.styleId === void 0 ? void 0 : parseHeadingStyleId(paragraph.styleId);
55
+ if (headingLevel !== void 0) {
56
+ let level = headingLevel;
57
+ if (level > 6) {
58
+ context.sink({
59
+ code: MarkdownDiagnosticCodes.HEADING_LEVEL_CLAMPED,
60
+ severity: "info",
61
+ message: `heading level ${String(level)} exceeds ATX's own six-"#" ceiling and is clamped to ${String(6)}`
62
+ });
63
+ level = 6;
64
+ }
65
+ const text = emitRuns(paragraph.runs, context);
66
+ if (context.headingStyle === "setext" && level <= MAX_SETEXT_LEVEL) return renderSetextHeading(level, text);
67
+ return `${"#".repeat(level)} ${text}`;
68
+ }
69
+ return emitRuns(paragraph.runs, context);
70
+ }
71
+ function renderParagraph(paragraph, context) {
72
+ const body = renderParagraphBody(paragraph, context);
73
+ const depth = quoteDepthOf(paragraph);
74
+ if (depth === 0) return body;
75
+ if (!isQuotableStyle(paragraph.styleId)) {
76
+ context.sink({
77
+ code: MarkdownDiagnosticCodes.PARAGRAPH_INDENT_DROPPED,
78
+ severity: "info",
79
+ message: `paragraph carries indentLeftPt (${String(paragraph.indentLeftPt)}pt) with no styleId this package recognises as quotable; the indent has no other markdown representation and is dropped`
80
+ });
81
+ return body;
82
+ }
83
+ const prefix = "> ".repeat(depth);
84
+ return body.split("\n").map((line) => `${prefix}${line}`).join("\n");
85
+ }
86
+ function renderTopLevelBlock(block, context) {
87
+ switch (block.kind) {
88
+ case "paragraph": return renderParagraph(block, context);
89
+ case "table": return emitTable(block, context);
90
+ case "image": return emitImage(block, context.embedImages);
91
+ case "pageBreak":
92
+ case "embeddedObject": return "";
93
+ }
94
+ }
95
+ function listInfoFor(numId, context) {
96
+ const info = parseListNumId(numId);
97
+ if (info === void 0 && !context.reportedFallbackNumIds.has(numId)) {
98
+ context.reportedFallbackNumIds.add(numId);
99
+ context.sink({
100
+ code: MarkdownDiagnosticCodes.LIST_NUMID_FALLBACK,
101
+ severity: "info",
102
+ message: `numId "${numId}" was not minted by this package's own src/lower and falls back to an ordinary, tight, non-task bullet list`
103
+ });
104
+ }
105
+ return info;
106
+ }
107
+ function checkboxPrefixFor(item) {
108
+ const first = item.runs[0];
109
+ if (first === void 0) return;
110
+ if (first.text.startsWith(`☒ `)) return "[x] ";
111
+ if (first.text.startsWith(`☐ `)) return "[ ] ";
112
+ }
113
+ function stripCheckboxRun(item, checkboxPrefix) {
114
+ if (checkboxPrefix === void 0) return item;
115
+ const first = item.runs[0];
116
+ const glyphPrefix = checkboxPrefix === "[x] " ? `☒ ` : `☐ `;
117
+ if (!first?.text.startsWith(glyphPrefix)) return item;
118
+ const strippedText = first.text.slice(glyphPrefix.length);
119
+ const runs = strippedText.length === 0 ? item.runs.slice(1) : [{
120
+ ...first,
121
+ text: strippedText
122
+ }, ...item.runs.slice(1)];
123
+ return {
124
+ ...item,
125
+ runs
126
+ };
127
+ }
128
+ function renderListItemMarker(numId, info, item, context) {
129
+ const checkboxText = (info?.task === true ? checkboxPrefixFor(item) : void 0) ?? "";
130
+ if (info?.type === "ordered") {
131
+ const next = context.orderedCounters.get(numId) ?? info.start ?? 1;
132
+ context.orderedCounters.set(numId, next + 1);
133
+ const bare = `${String(next)}${context.orderedDelimiter} `;
134
+ return {
135
+ full: `${bare}${checkboxText}`,
136
+ bareLength: bare.length
137
+ };
138
+ }
139
+ const bare = `${context.bulletMarker} `;
140
+ return {
141
+ full: `${bare}${checkboxText}`,
142
+ bareLength: bare.length
143
+ };
144
+ }
145
+ function renderListRegion(items, context) {
146
+ const parts = [];
147
+ let index = 0;
148
+ while (index < items.length) {
149
+ const item = items[index];
150
+ if (item?.list === void 0) break;
151
+ const { numId, level } = item.list;
152
+ const info = listInfoFor(numId, context);
153
+ let lookahead = index + 1;
154
+ while (lookahead < items.length && (items[lookahead]?.list?.level ?? -1) > level) lookahead += 1;
155
+ const nestedItems = items.slice(index + 1, lookahead);
156
+ const checkboxPrefix = info?.task === true ? checkboxPrefixFor(item) : void 0;
157
+ const marker = renderListItemMarker(numId, info, item, context);
158
+ const bodyLines = renderParagraphBody(stripCheckboxRun(item, checkboxPrefix), context).split("\n");
159
+ const indent = " ".repeat(marker.bareLength);
160
+ const [firstLine = "", ...restLines] = bodyLines;
161
+ let text = [`${marker.full}${firstLine}`, ...restLines.map((line) => `${indent}${line}`)].join("\n");
162
+ if (nestedItems.length > 0) {
163
+ const nested = renderListRegion(nestedItems, context).split("\n").map((line) => line.length === 0 ? line : `${indent}${line}`).join("\n");
164
+ text += `\n${nested}`;
165
+ }
166
+ parts.push({
167
+ numId,
168
+ text
169
+ });
170
+ index = lookahead;
171
+ }
172
+ let out = "";
173
+ for (const [partIndex, part] of parts.entries()) {
174
+ if (partIndex > 0) {
175
+ const previous = parts[partIndex - 1];
176
+ const sameList = previous.numId === part.numId;
177
+ const loose = sameList && (parseListNumId(previous.numId)?.loose ?? false);
178
+ out += sameList && !loose ? "\n" : "\n\n";
179
+ }
180
+ out += part.text;
181
+ }
182
+ return out;
183
+ }
184
+ function emitBlocks(blocks, context) {
185
+ const parts = [];
186
+ let index = 0;
187
+ while (index < blocks.length) {
188
+ const block = blocks[index];
189
+ if (block === void 0) break;
190
+ if (block.kind === "paragraph" && block.list !== void 0) {
191
+ const region = [];
192
+ let end = index;
193
+ for (let candidate = blocks[end]; candidate?.kind === "paragraph" && candidate.list !== void 0; candidate = blocks[end]) {
194
+ region.push(candidate);
195
+ end += 1;
196
+ }
197
+ parts.push(renderListRegion(region, context));
198
+ index = end;
199
+ continue;
200
+ }
201
+ const rendered = renderTopLevelBlock(block, context);
202
+ if (rendered.length > 0) parts.push(rendered);
203
+ index += 1;
204
+ }
205
+ return parts.join("\n\n");
206
+ }
207
+ function emitMarkdown(document, options = {}) {
208
+ if (document.kind !== "wordprocessing") throw new MarkdownUnsupportedDocumentKindError(document.kind);
209
+ const context = {
210
+ sink: options.sink ?? NOOP_MARKDOWN_DIAGNOSTIC_SINK,
211
+ emphasisMarker: options.emphasisMarker ?? "_",
212
+ bulletMarker: options.bulletListMarker ?? "-",
213
+ orderedDelimiter: options.orderedListDelimiter ?? ".",
214
+ codeFenceChar: options.codeFenceChar ?? "`",
215
+ thematicBreakChar: options.thematicBreakChar ?? "-",
216
+ headingStyle: options.headingStyle ?? "atx",
217
+ embedImages: options.images ?? true,
218
+ orderedCounters: /* @__PURE__ */ new Map(),
219
+ reportedFallbackNumIds: /* @__PURE__ */ new Set()
220
+ };
221
+ const body = document.sections.map((section) => emitBlocks(section.blocks, context)).join("\n\n");
222
+ const frontMatter = options.frontMatter === true ? emitFrontMatter(document.metadata) : void 0;
223
+ const text = frontMatter === void 0 ? body : `${frontMatter}\n\n${body}`;
224
+ return (options.lineEnding ?? "lf") === "crlf" ? text.replaceAll("\n", "\r\n") : text;
225
+ }
226
+ //#endregion
227
+ export { emitMarkdown };
@@ -0,0 +1,24 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/emit/front-matter.ts
3
+ const NEEDS_QUOTING_PATTERN = /^[-?#!&*"'@`|>[\]{}%]|: |:$/;
4
+ function emitScalar(value) {
5
+ if (!NEEDS_QUOTING_PATTERN.test(value) && value.trim() === value && value.length > 0) return value;
6
+ return `"${value.replaceAll("\\", "\\\\").replaceAll("\"", "\\\"")}"`;
7
+ }
8
+ function emitFrontMatter(metadata) {
9
+ const lines = [];
10
+ if (metadata.title !== void 0) lines.push(`title: ${emitScalar(metadata.title)}`);
11
+ if (metadata.author !== void 0) lines.push(`author: ${emitScalar(metadata.author)}`);
12
+ if (metadata.subject !== void 0) lines.push(`subject: ${emitScalar(metadata.subject)}`);
13
+ if (metadata.creator !== void 0) lines.push(`creator: ${emitScalar(metadata.creator)}`);
14
+ if (metadata.createdIso !== void 0) lines.push(`date: ${emitScalar(metadata.createdIso)}`);
15
+ if (metadata.keywords !== void 0 && metadata.keywords.length > 0) lines.push(`keywords: [${metadata.keywords.map((keyword) => emitScalar(keyword)).join(", ")}]`);
16
+ if (lines.length === 0) return;
17
+ return [
18
+ "---",
19
+ ...lines,
20
+ "---"
21
+ ].join("\n");
22
+ }
23
+ //#endregion
24
+ exports.emitFrontMatter = emitFrontMatter;
@@ -0,0 +1,5 @@
1
+ import { LayoutMetadata } from "document-schema.js";
2
+ //#region src/emit/front-matter.d.ts
3
+ declare function emitFrontMatter(metadata: LayoutMetadata): string | undefined;
4
+ //#endregion
5
+ export { emitFrontMatter };
@@ -0,0 +1,5 @@
1
+ import { LayoutMetadata } from "document-schema.js";
2
+ //#region src/emit/front-matter.d.ts
3
+ declare function emitFrontMatter(metadata: LayoutMetadata): string | undefined;
4
+ //#endregion
5
+ export { emitFrontMatter };
@@ -0,0 +1,23 @@
1
+ //#region src/emit/front-matter.ts
2
+ const NEEDS_QUOTING_PATTERN = /^[-?#!&*"'@`|>[\]{}%]|: |:$/;
3
+ function emitScalar(value) {
4
+ if (!NEEDS_QUOTING_PATTERN.test(value) && value.trim() === value && value.length > 0) return value;
5
+ return `"${value.replaceAll("\\", "\\\\").replaceAll("\"", "\\\"")}"`;
6
+ }
7
+ function emitFrontMatter(metadata) {
8
+ const lines = [];
9
+ if (metadata.title !== void 0) lines.push(`title: ${emitScalar(metadata.title)}`);
10
+ if (metadata.author !== void 0) lines.push(`author: ${emitScalar(metadata.author)}`);
11
+ if (metadata.subject !== void 0) lines.push(`subject: ${emitScalar(metadata.subject)}`);
12
+ if (metadata.creator !== void 0) lines.push(`creator: ${emitScalar(metadata.creator)}`);
13
+ if (metadata.createdIso !== void 0) lines.push(`date: ${emitScalar(metadata.createdIso)}`);
14
+ if (metadata.keywords !== void 0 && metadata.keywords.length > 0) lines.push(`keywords: [${metadata.keywords.map((keyword) => emitScalar(keyword)).join(", ")}]`);
15
+ if (lines.length === 0) return;
16
+ return [
17
+ "---",
18
+ ...lines,
19
+ "---"
20
+ ].join("\n");
21
+ }
22
+ //#endregion
23
+ export { emitFrontMatter };
@@ -0,0 +1,10 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_emit_inline = require("./inline.cjs");
3
+ //#region src/emit/image.ts
4
+ function emitImage(block, embedData) {
5
+ const alt = require_emit_inline.escapeMarkdownText(block.altText ?? "");
6
+ if (!embedData) return `![${alt}]()`;
7
+ return `![${alt}](data:image/${block.format};base64,${block.base64})`;
8
+ }
9
+ //#endregion
10
+ exports.emitImage = emitImage;
@@ -0,0 +1,5 @@
1
+ import { ContentImageBlock } from "document-schema.js";
2
+ //#region src/emit/image.d.ts
3
+ declare function emitImage(block: ContentImageBlock, embedData: boolean): string;
4
+ //#endregion
5
+ export { emitImage };