markdown-codec 0.0.0 → 1.0.1

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 +492 -0
  35. package/dist/codec.d.ts +492 -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,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 };
@@ -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 };
@@ -0,0 +1,9 @@
1
+ import { escapeMarkdownText } from "./inline.js";
2
+ //#region src/emit/image.ts
3
+ function emitImage(block, embedData) {
4
+ const alt = escapeMarkdownText(block.altText ?? "");
5
+ if (!embedData) return `![${alt}]()`;
6
+ return `![${alt}](data:image/${block.format};base64,${block.base64})`;
7
+ }
8
+ //#endregion
9
+ export { emitImage };
@@ -0,0 +1,183 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_diagnostics_diagnostics = require("../diagnostics/diagnostics.cjs");
3
+ const require_html_html = require("../html/html.cjs");
4
+ require("../shared/style-constants.cjs");
5
+ //#region src/emit/inline.ts
6
+ const ESCAPE_CHARS = /* @__PURE__ */ new Set([
7
+ "!",
8
+ "\"",
9
+ "#",
10
+ "$",
11
+ "%",
12
+ "&",
13
+ "'",
14
+ "(",
15
+ ")",
16
+ "*",
17
+ "+",
18
+ ",",
19
+ "-",
20
+ ".",
21
+ "/",
22
+ ":",
23
+ ";",
24
+ "<",
25
+ "=",
26
+ ">",
27
+ "?",
28
+ "@",
29
+ "[",
30
+ "\\",
31
+ "]",
32
+ "^",
33
+ "_",
34
+ "`",
35
+ "{",
36
+ "|",
37
+ "}",
38
+ "~"
39
+ ]);
40
+ function escapeMarkdownText(text) {
41
+ let out = "";
42
+ let index = 0;
43
+ while (index < text.length) {
44
+ const char = text.charAt(index);
45
+ if (char === "<") {
46
+ const tag = require_html_html.matchHtmlTag(text, index);
47
+ if (tag !== void 0) {
48
+ out += tag;
49
+ index += tag.length;
50
+ continue;
51
+ }
52
+ }
53
+ if (char === "\n") {
54
+ out += "\\\n";
55
+ index += 1;
56
+ continue;
57
+ }
58
+ if (ESCAPE_CHARS.has(char)) {
59
+ out += `\\${char}`;
60
+ index += 1;
61
+ continue;
62
+ }
63
+ out += char;
64
+ index += 1;
65
+ }
66
+ return out;
67
+ }
68
+ function renderCodeSpan(text) {
69
+ let longestBacktickRun = 0;
70
+ let current = 0;
71
+ for (const char of text) if (char === "`") {
72
+ current += 1;
73
+ longestBacktickRun = Math.max(longestBacktickRun, current);
74
+ } else current = 0;
75
+ const fence = "`".repeat(longestBacktickRun + 1);
76
+ const isAllSpaces = text.length > 0 && text.trim().length === 0;
77
+ const risksFenceCollision = text.startsWith("`") || text.endsWith("`");
78
+ const wouldBeStrippedOnReparse = !isAllSpaces && text.startsWith(" ") && text.endsWith(" ");
79
+ return risksFenceCollision || wouldBeStrippedOnReparse ? `${fence} ${text} ${fence}` : `${fence}${text}${fence}`;
80
+ }
81
+ function renderLeaf(run, context) {
82
+ if (run.fontFamily === "Courier New") {
83
+ context.sink({
84
+ code: require_diagnostics_diagnostics.MarkdownDiagnosticCodes.CODE_SPAN_AS_MONOSPACE_RUN,
85
+ severity: "info",
86
+ message: "a run styled with the Courier New font family is rendered as a code span; a genuinely monospace run from another format is indistinguishable from a real markdown code span on the way back out"
87
+ });
88
+ return renderCodeSpan(run.text);
89
+ }
90
+ return escapeMarkdownText(run.text);
91
+ }
92
+ const STYLE_KEYS = [
93
+ "bold",
94
+ "italic",
95
+ "strike"
96
+ ];
97
+ function styleActive(run, key) {
98
+ return run[key] === true;
99
+ }
100
+ const WORD_CHAR_PATTERN = /[\p{L}\p{N}]/u;
101
+ function isIntrawordRisk(body) {
102
+ if (body.length === 0) return false;
103
+ return WORD_CHAR_PATTERN.test(body.charAt(0)) || WORD_CHAR_PATTERN.test(body.charAt(body.length - 1));
104
+ }
105
+ function hasMarkerConflict(body, candidate, precedingText) {
106
+ if (candidate === "_" && isIntrawordRisk(body)) return true;
107
+ if (body.length > 0 && (body.startsWith(candidate) || body.endsWith(candidate))) return true;
108
+ return precedingText.endsWith(candidate);
109
+ }
110
+ function pickEmphasisMarker(body, configured, precedingText) {
111
+ if (!hasMarkerConflict(body, configured, precedingText)) return configured;
112
+ const alternate = configured === "_" ? "*" : "_";
113
+ return hasMarkerConflict(body, alternate, precedingText) ? configured : alternate;
114
+ }
115
+ function wrapForStyle(body, key, context, precedingText) {
116
+ if (key === "strike") return `~~${body}~~`;
117
+ const marker = pickEmphasisMarker(body, context.emphasisMarker, precedingText);
118
+ const delimiter = key === "bold" ? marker.repeat(2) : marker;
119
+ return `${delimiter}${body}${delimiter}`;
120
+ }
121
+ function renderNestedStyles(runs, depth, context) {
122
+ if (depth >= STYLE_KEYS.length) return runs.map((run) => renderLeaf(run, context)).join("");
123
+ const key = STYLE_KEYS[depth];
124
+ let out = "";
125
+ let index = 0;
126
+ while (index < runs.length) {
127
+ const current = runs[index];
128
+ if (current === void 0) break;
129
+ const active = styleActive(current, key);
130
+ let end = index + 1;
131
+ while (end < runs.length && styleActive(runs[end], key) === active) end += 1;
132
+ const inner = renderNestedStyles(runs.slice(index, end), depth + 1, context);
133
+ out += active ? wrapForStyle(inner, key, context, out) : inner;
134
+ index = end;
135
+ }
136
+ return out;
137
+ }
138
+ function isPlainAutolink(run) {
139
+ if (run.hyperlink === void 0 || run.hyperlink.length === 0 || run.bold === true || run.italic === true || run.strike === true || run.fontFamily === "Courier New") return false;
140
+ return run.text === run.hyperlink || run.hyperlink === `mailto:${run.text}`;
141
+ }
142
+ function escapeLinkDestination(destination) {
143
+ if (!/[\s()]/.test(destination)) return destination;
144
+ return `<${destination.replace(/[<>]/g, (char) => `\\${char}`)}>`;
145
+ }
146
+ function emitRuns(runs, context) {
147
+ let out = "";
148
+ let index = 0;
149
+ while (index < runs.length) {
150
+ const run = runs[index];
151
+ if (run === void 0) break;
152
+ if (run.hyperlink === void 0) {
153
+ let end = index + 1;
154
+ while (end < runs.length && runs[end]?.hyperlink === void 0) end += 1;
155
+ out += renderNestedStyles(runs.slice(index, end), 0, context);
156
+ index = end;
157
+ continue;
158
+ }
159
+ const hyperlink = run.hyperlink;
160
+ let groupEnd = index + 1;
161
+ while (groupEnd < runs.length && runs[groupEnd]?.hyperlink === hyperlink) groupEnd += 1;
162
+ const group = runs.slice(index, groupEnd);
163
+ if (group.length > 1) context.sink({
164
+ code: require_diagnostics_diagnostics.MarkdownDiagnosticCodes.ADJACENT_LINKS_MERGED,
165
+ severity: "info",
166
+ message: `${String(group.length)} adjacent runs share the hyperlink "${hyperlink}"; markdown has no way to place two link boundaries back to back, so they render as one link spanning their combined text`
167
+ });
168
+ if (group.length === 1 && isPlainAutolink(group[0])) out += `<${group[0].text}>`;
169
+ else {
170
+ const linkText = renderNestedStyles(group, 0, context);
171
+ out += `[${linkText}](${escapeLinkDestination(hyperlink)})`;
172
+ }
173
+ index = groupEnd;
174
+ }
175
+ return out;
176
+ }
177
+ function emitRunsSingleLine(runs, context) {
178
+ return emitRuns(runs, context).replace(/\\\n/g, " ");
179
+ }
180
+ //#endregion
181
+ exports.emitRuns = emitRuns;
182
+ exports.emitRunsSingleLine = emitRunsSingleLine;
183
+ exports.escapeMarkdownText = escapeMarkdownText;
@@ -0,0 +1,12 @@
1
+ import { i as MarkdownDiagnosticSink } from "../diagnostics-DmuWc7d8.cjs";
2
+ import { ContentRun } from "document-schema.js";
3
+ //#region src/emit/inline.d.ts
4
+ interface InlineEmitContext {
5
+ readonly sink: MarkdownDiagnosticSink;
6
+ readonly emphasisMarker: string;
7
+ }
8
+ declare function escapeMarkdownText(text: string): string;
9
+ declare function emitRuns(runs: readonly ContentRun[], context: InlineEmitContext): string;
10
+ declare function emitRunsSingleLine(runs: readonly ContentRun[], context: InlineEmitContext): string;
11
+ //#endregion
12
+ export { InlineEmitContext, emitRuns, emitRunsSingleLine, escapeMarkdownText };
@@ -0,0 +1,12 @@
1
+ import { i as MarkdownDiagnosticSink } from "../diagnostics-DmuWc7d8.js";
2
+ import { ContentRun } from "document-schema.js";
3
+ //#region src/emit/inline.d.ts
4
+ interface InlineEmitContext {
5
+ readonly sink: MarkdownDiagnosticSink;
6
+ readonly emphasisMarker: string;
7
+ }
8
+ declare function escapeMarkdownText(text: string): string;
9
+ declare function emitRuns(runs: readonly ContentRun[], context: InlineEmitContext): string;
10
+ declare function emitRunsSingleLine(runs: readonly ContentRun[], context: InlineEmitContext): string;
11
+ //#endregion
12
+ export { InlineEmitContext, emitRuns, emitRunsSingleLine, escapeMarkdownText };
@@ -0,0 +1,180 @@
1
+ import { MarkdownDiagnosticCodes } from "../diagnostics/diagnostics.js";
2
+ import { matchHtmlTag } from "../html/html.js";
3
+ import "../shared/style-constants.js";
4
+ //#region src/emit/inline.ts
5
+ const ESCAPE_CHARS = /* @__PURE__ */ new Set([
6
+ "!",
7
+ "\"",
8
+ "#",
9
+ "$",
10
+ "%",
11
+ "&",
12
+ "'",
13
+ "(",
14
+ ")",
15
+ "*",
16
+ "+",
17
+ ",",
18
+ "-",
19
+ ".",
20
+ "/",
21
+ ":",
22
+ ";",
23
+ "<",
24
+ "=",
25
+ ">",
26
+ "?",
27
+ "@",
28
+ "[",
29
+ "\\",
30
+ "]",
31
+ "^",
32
+ "_",
33
+ "`",
34
+ "{",
35
+ "|",
36
+ "}",
37
+ "~"
38
+ ]);
39
+ function escapeMarkdownText(text) {
40
+ let out = "";
41
+ let index = 0;
42
+ while (index < text.length) {
43
+ const char = text.charAt(index);
44
+ if (char === "<") {
45
+ const tag = matchHtmlTag(text, index);
46
+ if (tag !== void 0) {
47
+ out += tag;
48
+ index += tag.length;
49
+ continue;
50
+ }
51
+ }
52
+ if (char === "\n") {
53
+ out += "\\\n";
54
+ index += 1;
55
+ continue;
56
+ }
57
+ if (ESCAPE_CHARS.has(char)) {
58
+ out += `\\${char}`;
59
+ index += 1;
60
+ continue;
61
+ }
62
+ out += char;
63
+ index += 1;
64
+ }
65
+ return out;
66
+ }
67
+ function renderCodeSpan(text) {
68
+ let longestBacktickRun = 0;
69
+ let current = 0;
70
+ for (const char of text) if (char === "`") {
71
+ current += 1;
72
+ longestBacktickRun = Math.max(longestBacktickRun, current);
73
+ } else current = 0;
74
+ const fence = "`".repeat(longestBacktickRun + 1);
75
+ const isAllSpaces = text.length > 0 && text.trim().length === 0;
76
+ const risksFenceCollision = text.startsWith("`") || text.endsWith("`");
77
+ const wouldBeStrippedOnReparse = !isAllSpaces && text.startsWith(" ") && text.endsWith(" ");
78
+ return risksFenceCollision || wouldBeStrippedOnReparse ? `${fence} ${text} ${fence}` : `${fence}${text}${fence}`;
79
+ }
80
+ function renderLeaf(run, context) {
81
+ if (run.fontFamily === "Courier New") {
82
+ context.sink({
83
+ code: MarkdownDiagnosticCodes.CODE_SPAN_AS_MONOSPACE_RUN,
84
+ severity: "info",
85
+ message: "a run styled with the Courier New font family is rendered as a code span; a genuinely monospace run from another format is indistinguishable from a real markdown code span on the way back out"
86
+ });
87
+ return renderCodeSpan(run.text);
88
+ }
89
+ return escapeMarkdownText(run.text);
90
+ }
91
+ const STYLE_KEYS = [
92
+ "bold",
93
+ "italic",
94
+ "strike"
95
+ ];
96
+ function styleActive(run, key) {
97
+ return run[key] === true;
98
+ }
99
+ const WORD_CHAR_PATTERN = /[\p{L}\p{N}]/u;
100
+ function isIntrawordRisk(body) {
101
+ if (body.length === 0) return false;
102
+ return WORD_CHAR_PATTERN.test(body.charAt(0)) || WORD_CHAR_PATTERN.test(body.charAt(body.length - 1));
103
+ }
104
+ function hasMarkerConflict(body, candidate, precedingText) {
105
+ if (candidate === "_" && isIntrawordRisk(body)) return true;
106
+ if (body.length > 0 && (body.startsWith(candidate) || body.endsWith(candidate))) return true;
107
+ return precedingText.endsWith(candidate);
108
+ }
109
+ function pickEmphasisMarker(body, configured, precedingText) {
110
+ if (!hasMarkerConflict(body, configured, precedingText)) return configured;
111
+ const alternate = configured === "_" ? "*" : "_";
112
+ return hasMarkerConflict(body, alternate, precedingText) ? configured : alternate;
113
+ }
114
+ function wrapForStyle(body, key, context, precedingText) {
115
+ if (key === "strike") return `~~${body}~~`;
116
+ const marker = pickEmphasisMarker(body, context.emphasisMarker, precedingText);
117
+ const delimiter = key === "bold" ? marker.repeat(2) : marker;
118
+ return `${delimiter}${body}${delimiter}`;
119
+ }
120
+ function renderNestedStyles(runs, depth, context) {
121
+ if (depth >= STYLE_KEYS.length) return runs.map((run) => renderLeaf(run, context)).join("");
122
+ const key = STYLE_KEYS[depth];
123
+ let out = "";
124
+ let index = 0;
125
+ while (index < runs.length) {
126
+ const current = runs[index];
127
+ if (current === void 0) break;
128
+ const active = styleActive(current, key);
129
+ let end = index + 1;
130
+ while (end < runs.length && styleActive(runs[end], key) === active) end += 1;
131
+ const inner = renderNestedStyles(runs.slice(index, end), depth + 1, context);
132
+ out += active ? wrapForStyle(inner, key, context, out) : inner;
133
+ index = end;
134
+ }
135
+ return out;
136
+ }
137
+ function isPlainAutolink(run) {
138
+ if (run.hyperlink === void 0 || run.hyperlink.length === 0 || run.bold === true || run.italic === true || run.strike === true || run.fontFamily === "Courier New") return false;
139
+ return run.text === run.hyperlink || run.hyperlink === `mailto:${run.text}`;
140
+ }
141
+ function escapeLinkDestination(destination) {
142
+ if (!/[\s()]/.test(destination)) return destination;
143
+ return `<${destination.replace(/[<>]/g, (char) => `\\${char}`)}>`;
144
+ }
145
+ function emitRuns(runs, context) {
146
+ let out = "";
147
+ let index = 0;
148
+ while (index < runs.length) {
149
+ const run = runs[index];
150
+ if (run === void 0) break;
151
+ if (run.hyperlink === void 0) {
152
+ let end = index + 1;
153
+ while (end < runs.length && runs[end]?.hyperlink === void 0) end += 1;
154
+ out += renderNestedStyles(runs.slice(index, end), 0, context);
155
+ index = end;
156
+ continue;
157
+ }
158
+ const hyperlink = run.hyperlink;
159
+ let groupEnd = index + 1;
160
+ while (groupEnd < runs.length && runs[groupEnd]?.hyperlink === hyperlink) groupEnd += 1;
161
+ const group = runs.slice(index, groupEnd);
162
+ if (group.length > 1) context.sink({
163
+ code: MarkdownDiagnosticCodes.ADJACENT_LINKS_MERGED,
164
+ severity: "info",
165
+ message: `${String(group.length)} adjacent runs share the hyperlink "${hyperlink}"; markdown has no way to place two link boundaries back to back, so they render as one link spanning their combined text`
166
+ });
167
+ if (group.length === 1 && isPlainAutolink(group[0])) out += `<${group[0].text}>`;
168
+ else {
169
+ const linkText = renderNestedStyles(group, 0, context);
170
+ out += `[${linkText}](${escapeLinkDestination(hyperlink)})`;
171
+ }
172
+ index = groupEnd;
173
+ }
174
+ return out;
175
+ }
176
+ function emitRunsSingleLine(runs, context) {
177
+ return emitRuns(runs, context).replace(/\\\n/g, " ");
178
+ }
179
+ //#endregion
180
+ export { emitRuns, emitRunsSingleLine, escapeMarkdownText };
@@ -0,0 +1,73 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_diagnostics_diagnostics = require("../diagnostics/diagnostics.cjs");
3
+ const require_emit_inline = require("./inline.cjs");
4
+ //#region src/emit/table.ts
5
+ function toMarkdownAlignment(alignment) {
6
+ return alignment === void 0 || alignment === "justify" ? "none" : alignment;
7
+ }
8
+ function delimiterCell(alignment) {
9
+ switch (alignment) {
10
+ case "left": return ":---";
11
+ case "right": return "---:";
12
+ case "center": return ":---:";
13
+ case "none": return "---";
14
+ }
15
+ }
16
+ function escapeUnescapedPipes(text) {
17
+ let out = "";
18
+ let index = 0;
19
+ while (index < text.length) {
20
+ const char = text.charAt(index);
21
+ if (char === "\\" && index + 1 < text.length) {
22
+ out += char + text.charAt(index + 1);
23
+ index += 2;
24
+ continue;
25
+ }
26
+ if (char === "|") {
27
+ out += "\\|";
28
+ index += 1;
29
+ continue;
30
+ }
31
+ out += char;
32
+ index += 1;
33
+ }
34
+ return out;
35
+ }
36
+ function renderCellText(cell, context) {
37
+ if (cell.colSpan !== void 0 || cell.rowSpan !== void 0 || cell.background !== void 0) context.sink({
38
+ code: require_diagnostics_diagnostics.MarkdownDiagnosticCodes.TABLE_CELL_FORMATTING_DROPPED,
39
+ severity: "info",
40
+ message: "a table cell's own colSpan/rowSpan/background has no GFM table equivalent; the cell renders as an ordinary unmerged, unstyled cell"
41
+ });
42
+ if (cell.blocks.length > 1) context.sink({
43
+ code: require_diagnostics_diagnostics.MarkdownDiagnosticCodes.TABLE_CELL_MULTI_PARAGRAPH_JOINED,
44
+ severity: "info",
45
+ message: `a table cell with ${String(cell.blocks.length)} blocks has no multi-paragraph equivalent in a GFM table cell; their own rendered text is space-joined into the one line a cell allows`
46
+ });
47
+ const parts = [];
48
+ for (const block of cell.blocks) {
49
+ if (block.kind !== "paragraph") {
50
+ context.sink({
51
+ code: require_diagnostics_diagnostics.MarkdownDiagnosticCodes.TABLE_CELL_FORMATTING_DROPPED,
52
+ severity: "info",
53
+ message: `a table cell containing a "${block.kind}" block has no GFM table equivalent; it is dropped entirely`
54
+ });
55
+ continue;
56
+ }
57
+ const text = require_emit_inline.emitRunsSingleLine(block.runs, context);
58
+ if (text.length > 0) parts.push(text);
59
+ }
60
+ return escapeUnescapedPipes(parts.join(" "));
61
+ }
62
+ function emitTable(table, context) {
63
+ const [header, ...body] = table.rows;
64
+ if (header === void 0) return "";
65
+ const alignments = header.cells.map((cell) => toMarkdownAlignment(cell.blocks[0]?.kind === "paragraph" ? cell.blocks[0].alignment : void 0));
66
+ return [
67
+ `| ${header.cells.map((cell) => renderCellText(cell, context)).join(" | ")} |`,
68
+ `| ${alignments.map((alignment) => delimiterCell(alignment)).join(" | ")} |`,
69
+ ...body.map((row) => `| ${row.cells.map((cell) => renderCellText(cell, context)).join(" | ")} |`)
70
+ ].join("\n");
71
+ }
72
+ //#endregion
73
+ exports.emitTable = emitTable;
@@ -0,0 +1,10 @@
1
+ import { i as MarkdownDiagnosticSink } from "../diagnostics-DmuWc7d8.cjs";
2
+ import { InlineEmitContext } from "./inline.cjs";
3
+ import { ContentTable } from "document-schema.js";
4
+ //#region src/emit/table.d.ts
5
+ interface TableEmitContext extends InlineEmitContext {
6
+ readonly sink: MarkdownDiagnosticSink;
7
+ }
8
+ declare function emitTable(table: ContentTable, context: TableEmitContext): string;
9
+ //#endregion
10
+ export { TableEmitContext, emitTable };
@@ -0,0 +1,10 @@
1
+ import { i as MarkdownDiagnosticSink } from "../diagnostics-DmuWc7d8.js";
2
+ import { InlineEmitContext } from "./inline.js";
3
+ import { ContentTable } from "document-schema.js";
4
+ //#region src/emit/table.d.ts
5
+ interface TableEmitContext extends InlineEmitContext {
6
+ readonly sink: MarkdownDiagnosticSink;
7
+ }
8
+ declare function emitTable(table: ContentTable, context: TableEmitContext): string;
9
+ //#endregion
10
+ export { TableEmitContext, emitTable };
@@ -0,0 +1,72 @@
1
+ import { MarkdownDiagnosticCodes } from "../diagnostics/diagnostics.js";
2
+ import { emitRunsSingleLine } from "./inline.js";
3
+ //#region src/emit/table.ts
4
+ function toMarkdownAlignment(alignment) {
5
+ return alignment === void 0 || alignment === "justify" ? "none" : alignment;
6
+ }
7
+ function delimiterCell(alignment) {
8
+ switch (alignment) {
9
+ case "left": return ":---";
10
+ case "right": return "---:";
11
+ case "center": return ":---:";
12
+ case "none": return "---";
13
+ }
14
+ }
15
+ function escapeUnescapedPipes(text) {
16
+ let out = "";
17
+ let index = 0;
18
+ while (index < text.length) {
19
+ const char = text.charAt(index);
20
+ if (char === "\\" && index + 1 < text.length) {
21
+ out += char + text.charAt(index + 1);
22
+ index += 2;
23
+ continue;
24
+ }
25
+ if (char === "|") {
26
+ out += "\\|";
27
+ index += 1;
28
+ continue;
29
+ }
30
+ out += char;
31
+ index += 1;
32
+ }
33
+ return out;
34
+ }
35
+ function renderCellText(cell, context) {
36
+ if (cell.colSpan !== void 0 || cell.rowSpan !== void 0 || cell.background !== void 0) context.sink({
37
+ code: MarkdownDiagnosticCodes.TABLE_CELL_FORMATTING_DROPPED,
38
+ severity: "info",
39
+ message: "a table cell's own colSpan/rowSpan/background has no GFM table equivalent; the cell renders as an ordinary unmerged, unstyled cell"
40
+ });
41
+ if (cell.blocks.length > 1) context.sink({
42
+ code: MarkdownDiagnosticCodes.TABLE_CELL_MULTI_PARAGRAPH_JOINED,
43
+ severity: "info",
44
+ message: `a table cell with ${String(cell.blocks.length)} blocks has no multi-paragraph equivalent in a GFM table cell; their own rendered text is space-joined into the one line a cell allows`
45
+ });
46
+ const parts = [];
47
+ for (const block of cell.blocks) {
48
+ if (block.kind !== "paragraph") {
49
+ context.sink({
50
+ code: MarkdownDiagnosticCodes.TABLE_CELL_FORMATTING_DROPPED,
51
+ severity: "info",
52
+ message: `a table cell containing a "${block.kind}" block has no GFM table equivalent; it is dropped entirely`
53
+ });
54
+ continue;
55
+ }
56
+ const text = emitRunsSingleLine(block.runs, context);
57
+ if (text.length > 0) parts.push(text);
58
+ }
59
+ return escapeUnescapedPipes(parts.join(" "));
60
+ }
61
+ function emitTable(table, context) {
62
+ const [header, ...body] = table.rows;
63
+ if (header === void 0) return "";
64
+ const alignments = header.cells.map((cell) => toMarkdownAlignment(cell.blocks[0]?.kind === "paragraph" ? cell.blocks[0].alignment : void 0));
65
+ return [
66
+ `| ${header.cells.map((cell) => renderCellText(cell, context)).join(" | ")} |`,
67
+ `| ${alignments.map((alignment) => delimiterCell(alignment)).join(" | ")} |`,
68
+ ...body.map((row) => `| ${row.cells.map((cell) => renderCellText(cell, context)).join(" | ")} |`)
69
+ ].join("\n");
70
+ }
71
+ //#endregion
72
+ export { emitTable };