emdp 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 (199) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +124 -0
  3. package/dist/cjs/cli.js +36 -0
  4. package/dist/cjs/gfm.js +26 -0
  5. package/dist/cjs/index.js +26 -0
  6. package/dist/cjs/parser/block-parser.js +644 -0
  7. package/dist/cjs/parser/blocks/blockquote.js +28 -0
  8. package/dist/cjs/parser/blocks/code-block-fenced.js +58 -0
  9. package/dist/cjs/parser/blocks/code-block-indented.js +47 -0
  10. package/dist/cjs/parser/blocks/heading-atx.js +29 -0
  11. package/dist/cjs/parser/blocks/heading-setext.js +24 -0
  12. package/dist/cjs/parser/blocks/html-block.js +83 -0
  13. package/dist/cjs/parser/blocks/link-reference.js +109 -0
  14. package/dist/cjs/parser/blocks/list.js +155 -0
  15. package/dist/cjs/parser/blocks/paragraph.js +20 -0
  16. package/dist/cjs/parser/blocks/table.js +163 -0
  17. package/dist/cjs/parser/blocks/task-list.js +66 -0
  18. package/dist/cjs/parser/blocks/thematic-break.js +17 -0
  19. package/dist/cjs/parser/entities.js +2133 -0
  20. package/dist/cjs/parser/gfm/block-parser.js +773 -0
  21. package/dist/cjs/parser/gfm/index.js +125 -0
  22. package/dist/cjs/parser/gfm/inline-parser.js +813 -0
  23. package/dist/cjs/parser/gfm/renderer.js +513 -0
  24. package/dist/cjs/parser/index.js +104 -0
  25. package/dist/cjs/parser/inline-parser.js +564 -0
  26. package/dist/cjs/parser/inlines/autolink-extended.js +364 -0
  27. package/dist/cjs/parser/inlines/autolink.js +44 -0
  28. package/dist/cjs/parser/inlines/code-span.js +48 -0
  29. package/dist/cjs/parser/inlines/emphasis.js +64 -0
  30. package/dist/cjs/parser/inlines/entity.js +25 -0
  31. package/dist/cjs/parser/inlines/escape.js +25 -0
  32. package/dist/cjs/parser/inlines/footnote.js +41 -0
  33. package/dist/cjs/parser/inlines/hard-break.js +45 -0
  34. package/dist/cjs/parser/inlines/image.js +9 -0
  35. package/dist/cjs/parser/inlines/link.js +166 -0
  36. package/dist/cjs/parser/inlines/soft-break.js +18 -0
  37. package/dist/cjs/parser/inlines/strikethrough.js +48 -0
  38. package/dist/cjs/parser/inlines/text.js +20 -0
  39. package/dist/cjs/parser/renderer.js +345 -0
  40. package/dist/cjs/parser/types.js +5 -0
  41. package/dist/cjs/parser/utils.js +277 -0
  42. package/dist/cli.d.ts +6 -0
  43. package/dist/cli.js +36 -0
  44. package/dist/esm/cli.js +34 -0
  45. package/dist/esm/gfm.js +5 -0
  46. package/dist/esm/index.js +5 -0
  47. package/dist/esm/package.json +3 -0
  48. package/dist/esm/parser/block-parser.js +640 -0
  49. package/dist/esm/parser/blocks/blockquote.js +22 -0
  50. package/dist/esm/parser/blocks/code-block-fenced.js +52 -0
  51. package/dist/esm/parser/blocks/code-block-indented.js +42 -0
  52. package/dist/esm/parser/blocks/heading-atx.js +24 -0
  53. package/dist/esm/parser/blocks/heading-setext.js +19 -0
  54. package/dist/esm/parser/blocks/html-block.js +77 -0
  55. package/dist/esm/parser/blocks/link-reference.js +105 -0
  56. package/dist/esm/parser/blocks/list.js +145 -0
  57. package/dist/esm/parser/blocks/paragraph.js +15 -0
  58. package/dist/esm/parser/blocks/table.js +152 -0
  59. package/dist/esm/parser/blocks/task-list.js +61 -0
  60. package/dist/esm/parser/blocks/thematic-break.js +13 -0
  61. package/dist/esm/parser/entities.js +2130 -0
  62. package/dist/esm/parser/gfm/block-parser.js +769 -0
  63. package/dist/esm/parser/gfm/index.js +115 -0
  64. package/dist/esm/parser/gfm/inline-parser.js +809 -0
  65. package/dist/esm/parser/gfm/renderer.js +509 -0
  66. package/dist/esm/parser/index.js +80 -0
  67. package/dist/esm/parser/inline-parser.js +560 -0
  68. package/dist/esm/parser/inlines/autolink-extended.js +357 -0
  69. package/dist/esm/parser/inlines/autolink.js +40 -0
  70. package/dist/esm/parser/inlines/code-span.js +44 -0
  71. package/dist/esm/parser/inlines/emphasis.js +59 -0
  72. package/dist/esm/parser/inlines/entity.js +21 -0
  73. package/dist/esm/parser/inlines/escape.js +21 -0
  74. package/dist/esm/parser/inlines/footnote.js +38 -0
  75. package/dist/esm/parser/inlines/hard-break.js +41 -0
  76. package/dist/esm/parser/inlines/image.js +4 -0
  77. package/dist/esm/parser/inlines/link.js +156 -0
  78. package/dist/esm/parser/inlines/soft-break.js +14 -0
  79. package/dist/esm/parser/inlines/strikethrough.js +42 -0
  80. package/dist/esm/parser/inlines/text.js +16 -0
  81. package/dist/esm/parser/renderer.js +341 -0
  82. package/dist/esm/parser/types.js +4 -0
  83. package/dist/esm/parser/utils.js +254 -0
  84. package/dist/gfm.d.ts +6 -0
  85. package/dist/gfm.js +26 -0
  86. package/dist/index.d.ts +5 -0
  87. package/dist/index.js +26 -0
  88. package/dist/parser/block-parser.d.ts +25 -0
  89. package/dist/parser/block-parser.js +644 -0
  90. package/dist/parser/blocks/blockquote.d.ts +8 -0
  91. package/dist/parser/blocks/blockquote.js +28 -0
  92. package/dist/parser/blocks/code-block-fenced.d.ts +14 -0
  93. package/dist/parser/blocks/code-block-fenced.js +58 -0
  94. package/dist/parser/blocks/code-block-indented.d.ts +7 -0
  95. package/dist/parser/blocks/code-block-indented.js +47 -0
  96. package/dist/parser/blocks/heading-atx.d.ts +10 -0
  97. package/dist/parser/blocks/heading-atx.js +29 -0
  98. package/dist/parser/blocks/heading-setext.d.ts +8 -0
  99. package/dist/parser/blocks/heading-setext.js +24 -0
  100. package/dist/parser/blocks/html-block.d.ts +9 -0
  101. package/dist/parser/blocks/html-block.js +83 -0
  102. package/dist/parser/blocks/link-reference.d.ts +11 -0
  103. package/dist/parser/blocks/link-reference.js +109 -0
  104. package/dist/parser/blocks/list.d.ts +25 -0
  105. package/dist/parser/blocks/list.js +155 -0
  106. package/dist/parser/blocks/paragraph.d.ts +7 -0
  107. package/dist/parser/blocks/paragraph.js +20 -0
  108. package/dist/parser/blocks/table.d.ts +13 -0
  109. package/dist/parser/blocks/table.js +163 -0
  110. package/dist/parser/blocks/task-list.d.ts +10 -0
  111. package/dist/parser/blocks/task-list.js +66 -0
  112. package/dist/parser/blocks/thematic-break.d.ts +6 -0
  113. package/dist/parser/blocks/thematic-break.js +17 -0
  114. package/dist/parser/entities.d.ts +4 -0
  115. package/dist/parser/entities.js +2133 -0
  116. package/dist/parser/gfm/block-parser.d.ts +32 -0
  117. package/dist/parser/gfm/block-parser.js +773 -0
  118. package/dist/parser/gfm/index.d.ts +31 -0
  119. package/dist/parser/gfm/index.js +125 -0
  120. package/dist/parser/gfm/inline-parser.d.ts +25 -0
  121. package/dist/parser/gfm/inline-parser.js +813 -0
  122. package/dist/parser/gfm/renderer.d.ts +43 -0
  123. package/dist/parser/gfm/renderer.js +513 -0
  124. package/dist/parser/index.d.ts +33 -0
  125. package/dist/parser/index.js +104 -0
  126. package/dist/parser/inline-parser.d.ts +16 -0
  127. package/dist/parser/inline-parser.js +564 -0
  128. package/dist/parser/inlines/autolink-extended.d.ts +24 -0
  129. package/dist/parser/inlines/autolink-extended.js +364 -0
  130. package/dist/parser/inlines/autolink.d.ts +9 -0
  131. package/dist/parser/inlines/autolink.js +44 -0
  132. package/dist/parser/inlines/code-span.d.ts +9 -0
  133. package/dist/parser/inlines/code-span.js +48 -0
  134. package/dist/parser/inlines/emphasis.d.ts +14 -0
  135. package/dist/parser/inlines/emphasis.js +64 -0
  136. package/dist/parser/inlines/entity.d.ts +8 -0
  137. package/dist/parser/inlines/entity.js +25 -0
  138. package/dist/parser/inlines/escape.d.ts +8 -0
  139. package/dist/parser/inlines/escape.js +25 -0
  140. package/dist/parser/inlines/footnote.d.ts +9 -0
  141. package/dist/parser/inlines/footnote.js +41 -0
  142. package/dist/parser/inlines/hard-break.d.ts +9 -0
  143. package/dist/parser/inlines/hard-break.js +45 -0
  144. package/dist/parser/inlines/image.d.ts +4 -0
  145. package/dist/parser/inlines/image.js +9 -0
  146. package/dist/parser/inlines/link.d.ts +33 -0
  147. package/dist/parser/inlines/link.js +166 -0
  148. package/dist/parser/inlines/soft-break.d.ts +9 -0
  149. package/dist/parser/inlines/soft-break.js +18 -0
  150. package/dist/parser/inlines/strikethrough.d.ts +16 -0
  151. package/dist/parser/inlines/strikethrough.js +48 -0
  152. package/dist/parser/inlines/text.d.ts +6 -0
  153. package/dist/parser/inlines/text.js +20 -0
  154. package/dist/parser/renderer.d.ts +33 -0
  155. package/dist/parser/renderer.js +345 -0
  156. package/dist/parser/types.d.ts +152 -0
  157. package/dist/parser/types.js +5 -0
  158. package/dist/parser/utils.d.ts +32 -0
  159. package/dist/parser/utils.js +277 -0
  160. package/dist/types/cli.d.ts +6 -0
  161. package/dist/types/gfm.d.ts +6 -0
  162. package/dist/types/index.d.ts +5 -0
  163. package/dist/types/parser/block-parser.d.ts +25 -0
  164. package/dist/types/parser/blocks/blockquote.d.ts +8 -0
  165. package/dist/types/parser/blocks/code-block-fenced.d.ts +14 -0
  166. package/dist/types/parser/blocks/code-block-indented.d.ts +7 -0
  167. package/dist/types/parser/blocks/heading-atx.d.ts +10 -0
  168. package/dist/types/parser/blocks/heading-setext.d.ts +8 -0
  169. package/dist/types/parser/blocks/html-block.d.ts +9 -0
  170. package/dist/types/parser/blocks/link-reference.d.ts +11 -0
  171. package/dist/types/parser/blocks/list.d.ts +25 -0
  172. package/dist/types/parser/blocks/paragraph.d.ts +7 -0
  173. package/dist/types/parser/blocks/table.d.ts +13 -0
  174. package/dist/types/parser/blocks/task-list.d.ts +10 -0
  175. package/dist/types/parser/blocks/thematic-break.d.ts +6 -0
  176. package/dist/types/parser/entities.d.ts +4 -0
  177. package/dist/types/parser/gfm/block-parser.d.ts +32 -0
  178. package/dist/types/parser/gfm/index.d.ts +31 -0
  179. package/dist/types/parser/gfm/inline-parser.d.ts +25 -0
  180. package/dist/types/parser/gfm/renderer.d.ts +43 -0
  181. package/dist/types/parser/index.d.ts +33 -0
  182. package/dist/types/parser/inline-parser.d.ts +16 -0
  183. package/dist/types/parser/inlines/autolink-extended.d.ts +24 -0
  184. package/dist/types/parser/inlines/autolink.d.ts +9 -0
  185. package/dist/types/parser/inlines/code-span.d.ts +9 -0
  186. package/dist/types/parser/inlines/emphasis.d.ts +14 -0
  187. package/dist/types/parser/inlines/entity.d.ts +8 -0
  188. package/dist/types/parser/inlines/escape.d.ts +8 -0
  189. package/dist/types/parser/inlines/footnote.d.ts +9 -0
  190. package/dist/types/parser/inlines/hard-break.d.ts +9 -0
  191. package/dist/types/parser/inlines/image.d.ts +4 -0
  192. package/dist/types/parser/inlines/link.d.ts +33 -0
  193. package/dist/types/parser/inlines/soft-break.d.ts +9 -0
  194. package/dist/types/parser/inlines/strikethrough.d.ts +16 -0
  195. package/dist/types/parser/inlines/text.d.ts +6 -0
  196. package/dist/types/parser/renderer.d.ts +33 -0
  197. package/dist/types/parser/types.d.ts +152 -0
  198. package/dist/types/parser/utils.d.ts +32 -0
  199. package/package.json +54 -0
@@ -0,0 +1,769 @@
1
+ /**
2
+ * GFM block parser that extends CommonMark with table support.
3
+ */
4
+ import { normalizeLineEndings, removeIndent, unescapeString, decodeHtmlEntities } from '../utils.js';
5
+ import { isThematicBreak, parseThematicBreak } from '../blocks/thematic-break.js';
6
+ import { parseAtxHeading, createHeadingNode } from '../blocks/heading-atx.js';
7
+ import { getSetextLevel } from '../blocks/heading-setext.js';
8
+ import { createIndentedCodeBlock } from '../blocks/code-block-indented.js';
9
+ import { parseFenceOpen, isFenceClose, createFencedCodeBlock } from '../blocks/code-block-fenced.js';
10
+ import { createBlockquoteNode } from '../blocks/blockquote.js';
11
+ import { parseListMarker, createListNode, createListItemNode, listsMatch } from '../blocks/list.js';
12
+ import { getHtmlBlockType, isHtmlBlockClose } from '../blocks/html-block.js';
13
+ import { createHtmlBlockNode } from '../blocks/html-block.js';
14
+ import { createParagraphNode } from '../blocks/paragraph.js';
15
+ import { parseLinkReferenceDefinition } from '../blocks/link-reference.js';
16
+ import { isTableRow, isTableStart, createTableNode, createTableRowNode, parseTableRowCells, } from '../blocks/table.js';
17
+ import { processTaskLists } from '../blocks/task-list.js';
18
+ import { parseFootnoteLabel } from '../inlines/footnote.js';
19
+ function getIndent(raw) {
20
+ let indent = 0;
21
+ for (const char of raw) {
22
+ if (char === ' ')
23
+ indent++;
24
+ else if (char === '\t')
25
+ indent += 4 - (indent % 4);
26
+ else
27
+ break;
28
+ }
29
+ return indent;
30
+ }
31
+ export class GFMBlockParser {
32
+ lines = [];
33
+ lineIndex = 0;
34
+ linkReferences = new Map();
35
+ footnoteDefinitions = new Map();
36
+ static LAZY_PREFIX = '\u0000';
37
+ enableTables;
38
+ enableTaskLists;
39
+ enableFootnotes;
40
+ constructor(extensions) {
41
+ this.enableTables = !extensions || extensions.has('table');
42
+ this.enableTaskLists = !extensions || extensions.has('tasklist');
43
+ this.enableFootnotes = !extensions || extensions.has('footnotes');
44
+ }
45
+ parse(input) {
46
+ this.lines = normalizeLineEndings(input).split('\n');
47
+ this.lineIndex = 0;
48
+ this.linkReferences = new Map();
49
+ this.footnoteDefinitions = new Map();
50
+ const document = {
51
+ type: 'document',
52
+ children: [],
53
+ };
54
+ this.parseBlocks(document, 0);
55
+ if (this.enableTaskLists) {
56
+ processTaskLists(document.children);
57
+ }
58
+ return {
59
+ document,
60
+ linkReferences: this.linkReferences,
61
+ footnoteDefinitions: this.footnoteDefinitions,
62
+ };
63
+ }
64
+ currentLine() {
65
+ return this.lines[this.lineIndex];
66
+ }
67
+ advance() {
68
+ this.lineIndex++;
69
+ }
70
+ parseBlocks(container, baseIndent) {
71
+ let paragraphLines = [];
72
+ const finishParagraph = () => {
73
+ if (paragraphLines.length > 0) {
74
+ let text = paragraphLines.join('\n');
75
+ let consumed = 0;
76
+ while (text.length > 0) {
77
+ const result = parseLinkReferenceDefinition(text);
78
+ if (!result)
79
+ break;
80
+ if (!this.linkReferences.has(result.label)) {
81
+ this.linkReferences.set(result.label, result.definition);
82
+ }
83
+ text = text.slice(result.consumed);
84
+ consumed += result.consumed;
85
+ }
86
+ text = text.trim();
87
+ if (text.length > 0) {
88
+ const para = createParagraphNode();
89
+ para.rawContent = text;
90
+ container.children.push(para);
91
+ }
92
+ paragraphLines = [];
93
+ return consumed > 0 || text.length > 0;
94
+ }
95
+ return false;
96
+ };
97
+ while (this.lineIndex < this.lines.length) {
98
+ const line = this.currentLine();
99
+ if (line.startsWith(GFMBlockParser.LAZY_PREFIX)) {
100
+ const raw = line.slice(GFMBlockParser.LAZY_PREFIX.length);
101
+ const rawIndent = getIndent(raw);
102
+ paragraphLines.push(removeIndent(raw, Math.min(rawIndent, 3)));
103
+ this.advance();
104
+ continue;
105
+ }
106
+ const lineIndent = getIndent(line);
107
+ if (line.trim() === '') {
108
+ finishParagraph();
109
+ this.advance();
110
+ continue;
111
+ }
112
+ const dedented = removeIndent(line, Math.min(3, lineIndent));
113
+ const trimmed = line.replace(/^ {0,3}/, '');
114
+ if (this.enableFootnotes) {
115
+ const footnoteLabel = parseFootnoteLabel(trimmed, 0);
116
+ if (footnoteLabel && trimmed[footnoteLabel.length] === ':') {
117
+ finishParagraph();
118
+ this.parseFootnoteDefinition(footnoteLabel.label, footnoteLabel.normalized, trimmed, footnoteLabel.length);
119
+ continue;
120
+ }
121
+ }
122
+ if (this.enableTables && paragraphLines.length >= 1) {
123
+ const lastLine = paragraphLines[paragraphLines.length - 1];
124
+ if (isTableRow(lastLine)) {
125
+ const alignments = isTableStart(lastLine, line);
126
+ if (alignments) {
127
+ if (paragraphLines.length > 1) {
128
+ const precedingLines = paragraphLines.slice(0, -1);
129
+ let text = precedingLines.join('\n');
130
+ while (text.length > 0) {
131
+ const result = parseLinkReferenceDefinition(text);
132
+ if (!result)
133
+ break;
134
+ if (!this.linkReferences.has(result.label)) {
135
+ this.linkReferences.set(result.label, result.definition);
136
+ }
137
+ text = text.slice(result.consumed);
138
+ }
139
+ text = text.trim();
140
+ if (text.length > 0) {
141
+ const para = createParagraphNode();
142
+ para.rawContent = text;
143
+ container.children.push(para);
144
+ }
145
+ }
146
+ const table = this.parseTable(lastLine, alignments);
147
+ paragraphLines = [];
148
+ container.children.push(table);
149
+ continue;
150
+ }
151
+ }
152
+ }
153
+ if (paragraphLines.length > 0) {
154
+ const setextLevel = getSetextLevel(line);
155
+ if (setextLevel) {
156
+ let content = paragraphLines.join('\n');
157
+ while (content.length > 0) {
158
+ const result = parseLinkReferenceDefinition(content);
159
+ if (!result)
160
+ break;
161
+ if (!this.linkReferences.has(result.label)) {
162
+ this.linkReferences.set(result.label, result.definition);
163
+ }
164
+ content = content.slice(result.consumed);
165
+ }
166
+ content = content.trim();
167
+ paragraphLines = [];
168
+ if (content.length > 0) {
169
+ const heading = createHeadingNode(setextLevel);
170
+ heading.rawContent = content;
171
+ container.children.push(heading);
172
+ }
173
+ else if (isThematicBreak(line)) {
174
+ container.children.push(parseThematicBreak(line));
175
+ }
176
+ else {
177
+ paragraphLines.push(line);
178
+ }
179
+ this.advance();
180
+ continue;
181
+ }
182
+ }
183
+ if (isThematicBreak(line)) {
184
+ finishParagraph();
185
+ container.children.push(parseThematicBreak(line));
186
+ this.advance();
187
+ continue;
188
+ }
189
+ const atxResult = parseAtxHeading(line);
190
+ if (atxResult) {
191
+ finishParagraph();
192
+ const heading = createHeadingNode(atxResult.level);
193
+ heading.rawContent = atxResult.content;
194
+ container.children.push(heading);
195
+ this.advance();
196
+ continue;
197
+ }
198
+ if (paragraphLines.length > 0 && /^ {0,3}=+[ \t]*$/.test(line)) {
199
+ let content = paragraphLines.join('\n');
200
+ while (content.length > 0) {
201
+ const result = parseLinkReferenceDefinition(content);
202
+ if (!result)
203
+ break;
204
+ if (!this.linkReferences.has(result.label)) {
205
+ this.linkReferences.set(result.label, result.definition);
206
+ }
207
+ content = content.slice(result.consumed);
208
+ }
209
+ content = content.trim();
210
+ paragraphLines = [];
211
+ if (content.length > 0) {
212
+ const heading = createHeadingNode(1);
213
+ heading.rawContent = content;
214
+ container.children.push(heading);
215
+ }
216
+ else {
217
+ paragraphLines.push(line);
218
+ }
219
+ this.advance();
220
+ continue;
221
+ }
222
+ const fenceInfo = parseFenceOpen(line);
223
+ if (fenceInfo) {
224
+ finishParagraph();
225
+ const codeLines = [];
226
+ this.advance();
227
+ let closedProperly = false;
228
+ while (this.lineIndex < this.lines.length) {
229
+ const codeLine = this.currentLine();
230
+ if (isFenceClose(codeLine, fenceInfo)) {
231
+ this.advance();
232
+ closedProperly = true;
233
+ break;
234
+ }
235
+ codeLines.push(codeLine);
236
+ this.advance();
237
+ }
238
+ if (!closedProperly) {
239
+ while (codeLines.length > 0 && codeLines[codeLines.length - 1] === '') {
240
+ codeLines.pop();
241
+ }
242
+ }
243
+ const info = unescapeString(decodeHtmlEntities(fenceInfo.info));
244
+ container.children.push(createFencedCodeBlock(info, codeLines, fenceInfo.indent));
245
+ continue;
246
+ }
247
+ if (paragraphLines.length === 0 && lineIndent >= 4) {
248
+ const codeLines = [removeIndent(line, 4)];
249
+ this.advance();
250
+ while (this.lineIndex < this.lines.length) {
251
+ const codeLine = this.currentLine();
252
+ const codeIndent = getIndent(codeLine);
253
+ if (codeIndent >= 4) {
254
+ codeLines.push(removeIndent(codeLine, 4));
255
+ this.advance();
256
+ }
257
+ else if (codeLine.trim() === '') {
258
+ codeLines.push('');
259
+ this.advance();
260
+ }
261
+ else {
262
+ break;
263
+ }
264
+ }
265
+ while (codeLines.length > 0 && codeLines[codeLines.length - 1] === '') {
266
+ codeLines.pop();
267
+ }
268
+ container.children.push(createIndentedCodeBlock(codeLines));
269
+ continue;
270
+ }
271
+ const bqMatch = line.match(/^ {0,3}>([ \t]?)/);
272
+ if (bqMatch) {
273
+ finishParagraph();
274
+ const blockquote = createBlockquoteNode();
275
+ const quoteLines = [];
276
+ let inFence = null;
277
+ while (this.lineIndex < this.lines.length) {
278
+ const quoteLine = this.currentLine();
279
+ const qMatch = quoteLine.match(/^ {0,3}>([ \t]?)/);
280
+ if (qMatch) {
281
+ const content = this.extractBlockquoteContent(quoteLine, qMatch);
282
+ quoteLines.push(content);
283
+ if (inFence) {
284
+ if (isFenceClose(content, inFence)) {
285
+ inFence = null;
286
+ }
287
+ }
288
+ else {
289
+ const fenceInfo = parseFenceOpen(content);
290
+ if (fenceInfo) {
291
+ inFence = fenceInfo;
292
+ }
293
+ }
294
+ this.advance();
295
+ }
296
+ else if (quoteLine.trim() === '') {
297
+ break;
298
+ }
299
+ else if (quoteLines.length > 0) {
300
+ if (inFence) {
301
+ break;
302
+ }
303
+ if (isThematicBreak(quoteLine) || parseFenceOpen(quoteLine)) {
304
+ break;
305
+ }
306
+ if (quoteLines[quoteLines.length - 1].trim() === '') {
307
+ break;
308
+ }
309
+ const lastContent = this.lastNonBlankLine(quoteLines);
310
+ if (lastContent &&
311
+ !parseFenceOpen(lastContent) &&
312
+ getIndent(lastContent) < 4 &&
313
+ this.allowsLazyAfterListMarker(lastContent)) {
314
+ const nestedPrefix = this.getBlockquotePrefix(lastContent);
315
+ quoteLines.push(nestedPrefix + GFMBlockParser.LAZY_PREFIX + quoteLine);
316
+ this.advance();
317
+ }
318
+ else {
319
+ break;
320
+ }
321
+ }
322
+ else {
323
+ break;
324
+ }
325
+ }
326
+ const subParser = new GFMBlockParser();
327
+ const result = subParser.parse(quoteLines.join('\n'));
328
+ blockquote.children = result.document.children;
329
+ result.linkReferences.forEach((def, label) => {
330
+ if (!this.linkReferences.has(label)) {
331
+ this.linkReferences.set(label, def);
332
+ }
333
+ });
334
+ result.footnoteDefinitions.forEach((def, label) => {
335
+ if (!this.footnoteDefinitions.has(label)) {
336
+ this.footnoteDefinitions.set(label, def);
337
+ }
338
+ });
339
+ container.children.push(blockquote);
340
+ continue;
341
+ }
342
+ const listMarker = parseListMarker(line);
343
+ if (listMarker) {
344
+ const canInterrupt = paragraphLines.length === 0 ||
345
+ (listMarker.type === 'bullet' || listMarker.start === 1) &&
346
+ line.slice(listMarker.indent + listMarker.marker.length + listMarker.padding).trim() !== '';
347
+ if (canInterrupt) {
348
+ finishParagraph();
349
+ const list = createListNode(listMarker);
350
+ this.parseList(list, listMarker);
351
+ container.children.push(list);
352
+ continue;
353
+ }
354
+ }
355
+ const htmlType = getHtmlBlockType(line, paragraphLines.length === 0);
356
+ if (htmlType !== null) {
357
+ finishParagraph();
358
+ const htmlLines = [line];
359
+ const closeOnSameLine = htmlType >= 1 && htmlType <= 5 && isHtmlBlockClose(line, htmlType);
360
+ this.advance();
361
+ if (!closeOnSameLine) {
362
+ while (this.lineIndex < this.lines.length) {
363
+ const htmlLine = this.currentLine();
364
+ if (htmlType === 6 || htmlType === 7) {
365
+ if (htmlLine.trim() === '') {
366
+ break;
367
+ }
368
+ htmlLines.push(htmlLine);
369
+ this.advance();
370
+ }
371
+ else {
372
+ htmlLines.push(htmlLine);
373
+ this.advance();
374
+ if (isHtmlBlockClose(htmlLine, htmlType)) {
375
+ break;
376
+ }
377
+ }
378
+ }
379
+ }
380
+ container.children.push(createHtmlBlockNode(htmlLines.join('\n') + '\n'));
381
+ continue;
382
+ }
383
+ paragraphLines.push(removeIndent(line, Math.min(lineIndent, 3)));
384
+ this.advance();
385
+ }
386
+ finishParagraph();
387
+ }
388
+ parseTable(headerLine, alignments) {
389
+ const table = createTableNode(alignments);
390
+ const headerCells = parseTableRowCells(headerLine, alignments, true);
391
+ const headerRow = createTableRowNode(true, headerCells);
392
+ table.children.push(headerRow);
393
+ this.advance();
394
+ while (this.lineIndex < this.lines.length) {
395
+ const line = this.currentLine();
396
+ if (line.trim() === '') {
397
+ break;
398
+ }
399
+ if (line.match(/^ {0,3}>/)) {
400
+ break;
401
+ }
402
+ if (isThematicBreak(line)) {
403
+ break;
404
+ }
405
+ if (parseAtxHeading(line)) {
406
+ break;
407
+ }
408
+ if (parseFenceOpen(line)) {
409
+ break;
410
+ }
411
+ if (getHtmlBlockType(line, true) !== null) {
412
+ break;
413
+ }
414
+ const cells = parseTableRowCells(line, alignments, false);
415
+ const row = createTableRowNode(false, cells);
416
+ table.children.push(row);
417
+ this.advance();
418
+ }
419
+ return table;
420
+ }
421
+ parseFootnoteDefinition(label, key, trimmedLine, labelLength) {
422
+ if (!key) {
423
+ this.advance();
424
+ return;
425
+ }
426
+ const contentLines = [];
427
+ const afterColon = trimmedLine.slice(labelLength + 1);
428
+ const firstContent = afterColon.replace(/^[ \t]+/, '');
429
+ if (firstContent.length > 0) {
430
+ contentLines.push(firstContent);
431
+ }
432
+ this.advance();
433
+ while (this.lineIndex < this.lines.length) {
434
+ const line = this.currentLine();
435
+ if (line.trim() === '') {
436
+ let lookahead = this.lineIndex + 1;
437
+ while (lookahead < this.lines.length && this.lines[lookahead].trim() === '') {
438
+ lookahead++;
439
+ }
440
+ if (lookahead < this.lines.length && getIndent(this.lines[lookahead]) >= 4) {
441
+ contentLines.push('');
442
+ this.advance();
443
+ continue;
444
+ }
445
+ break;
446
+ }
447
+ if (getIndent(line) >= 4) {
448
+ contentLines.push(removeIndent(line, 4));
449
+ this.advance();
450
+ continue;
451
+ }
452
+ break;
453
+ }
454
+ const subParser = new GFMBlockParser();
455
+ const result = subParser.parse(contentLines.join('\n'));
456
+ result.linkReferences.forEach((def, refLabel) => {
457
+ if (!this.linkReferences.has(refLabel)) {
458
+ this.linkReferences.set(refLabel, def);
459
+ }
460
+ });
461
+ if (!this.footnoteDefinitions.has(key)) {
462
+ this.footnoteDefinitions.set(key, { label, blocks: result.document.children });
463
+ }
464
+ }
465
+ parseList(list, firstMarker) {
466
+ let sawBlankLine = false;
467
+ let sawBlankLineInItem = false;
468
+ let sawBlankBetweenItems = false;
469
+ while (this.lineIndex < this.lines.length) {
470
+ const line = this.currentLine();
471
+ if (isThematicBreak(line)) {
472
+ break;
473
+ }
474
+ const marker = parseListMarker(line);
475
+ if (marker && listsMatch(firstMarker, marker)) {
476
+ if (sawBlankLine) {
477
+ sawBlankBetweenItems = true;
478
+ }
479
+ sawBlankLine = false;
480
+ const item = createListItemNode();
481
+ const itemResult = this.parseListItem(item, marker);
482
+ if (itemResult.blankInItem) {
483
+ sawBlankLineInItem = true;
484
+ }
485
+ if (itemResult.endsWithBlank) {
486
+ sawBlankLine = true;
487
+ }
488
+ list.children.push(item);
489
+ }
490
+ else if (line.trim() === '') {
491
+ sawBlankLine = true;
492
+ this.advance();
493
+ let nextIdx = this.lineIndex;
494
+ while (nextIdx < this.lines.length && this.lines[nextIdx].trim() === '') {
495
+ nextIdx++;
496
+ }
497
+ if (nextIdx < this.lines.length) {
498
+ const nextLine = this.lines[nextIdx];
499
+ const nextMarker = parseListMarker(nextLine);
500
+ if (!nextMarker || !listsMatch(firstMarker, nextMarker)) {
501
+ if (getIndent(nextLine) < firstMarker.contentIndent) {
502
+ break;
503
+ }
504
+ }
505
+ }
506
+ else {
507
+ break;
508
+ }
509
+ }
510
+ else {
511
+ break;
512
+ }
513
+ }
514
+ if (sawBlankLineInItem || sawBlankBetweenItems) {
515
+ list.tight = false;
516
+ }
517
+ }
518
+ parseListItem(item, marker) {
519
+ const itemLines = [];
520
+ let firstLine = this.currentLine();
521
+ if (firstLine.startsWith(GFMBlockParser.LAZY_PREFIX)) {
522
+ firstLine = firstLine.slice(GFMBlockParser.LAZY_PREFIX.length);
523
+ }
524
+ let firstContent = this.extractListItemContent(firstLine, marker);
525
+ if (firstContent.trim() === '' && firstLine.slice(marker.indentChars + marker.marker.length).match(/^[ \t]/)) {
526
+ itemLines.push('');
527
+ }
528
+ else {
529
+ itemLines.push(firstContent);
530
+ }
531
+ this.advance();
532
+ let sawBlankLine = false;
533
+ let blankLineInItem = false;
534
+ let trailingBlanks = 0;
535
+ const contentIndent = marker.contentIndent;
536
+ const baseThreshold = contentIndent + 1;
537
+ let lastNonBlankIndent = firstContent.trim() === '' ? null : contentIndent;
538
+ let lastNonBlankWasListMarker = false;
539
+ let sawNonBlankContent = firstContent.trim() !== '';
540
+ let inFence = null;
541
+ if (firstContent.trim() !== '') {
542
+ const firstFence = parseFenceOpen(firstContent);
543
+ if (firstFence) {
544
+ inFence = firstFence;
545
+ }
546
+ lastNonBlankWasListMarker = parseListMarker(firstContent) !== null;
547
+ }
548
+ while (this.lineIndex < this.lines.length) {
549
+ let line = this.currentLine();
550
+ let lazyLine = false;
551
+ if (line.startsWith(GFMBlockParser.LAZY_PREFIX)) {
552
+ line = line.slice(GFMBlockParser.LAZY_PREFIX.length);
553
+ lazyLine = true;
554
+ }
555
+ const lineIndent = getIndent(line);
556
+ if (inFence) {
557
+ const contentLine = lineIndent >= contentIndent ? removeIndent(line, contentIndent) : line;
558
+ itemLines.push(contentLine);
559
+ if (isFenceClose(contentLine, inFence)) {
560
+ inFence = null;
561
+ }
562
+ this.advance();
563
+ continue;
564
+ }
565
+ if (line.trim() === '') {
566
+ sawBlankLine = true;
567
+ trailingBlanks++;
568
+ itemLines.push('');
569
+ this.advance();
570
+ continue;
571
+ }
572
+ const newMarker = lazyLine ? null : parseListMarker(line);
573
+ if (newMarker && listsMatch(marker, newMarker) && newMarker.indent < contentIndent) {
574
+ break;
575
+ }
576
+ if (!sawNonBlankContent && sawBlankLine && lineIndent >= contentIndent) {
577
+ break;
578
+ }
579
+ if (lineIndent >= contentIndent) {
580
+ const contentLine = removeIndent(line, contentIndent);
581
+ const isListMarker = parseListMarker(contentLine) !== null;
582
+ if (sawBlankLine && (lineIndent <= baseThreshold ||
583
+ (lastNonBlankIndent !== null && lastNonBlankIndent <= baseThreshold && !lastNonBlankWasListMarker))) {
584
+ blankLineInItem = true;
585
+ }
586
+ sawBlankLine = false;
587
+ trailingBlanks = 0;
588
+ itemLines.push(contentLine);
589
+ lastNonBlankIndent = lineIndent;
590
+ lastNonBlankWasListMarker = isListMarker;
591
+ sawNonBlankContent = true;
592
+ if (!inFence) {
593
+ const fenceInfo = parseFenceOpen(contentLine);
594
+ if (fenceInfo) {
595
+ inFence = fenceInfo;
596
+ }
597
+ }
598
+ this.advance();
599
+ }
600
+ else if (sawBlankLine) {
601
+ break;
602
+ }
603
+ else {
604
+ if (!isThematicBreak(line) && !parseAtxHeading(line) &&
605
+ !parseFenceOpen(line) && !line.match(/^ {0,3}>/) &&
606
+ !newMarker) {
607
+ trailingBlanks = 0;
608
+ itemLines.push(line);
609
+ lastNonBlankIndent = lineIndent;
610
+ lastNonBlankWasListMarker = false;
611
+ sawNonBlankContent = true;
612
+ this.advance();
613
+ }
614
+ else {
615
+ break;
616
+ }
617
+ }
618
+ }
619
+ const endsWithBlank = trailingBlanks > 0;
620
+ while (itemLines.length > 0 && itemLines[itemLines.length - 1] === '') {
621
+ itemLines.pop();
622
+ }
623
+ const subParser = new GFMBlockParser();
624
+ const result = subParser.parse(itemLines.join('\n'));
625
+ item.children = result.document.children;
626
+ result.linkReferences.forEach((def, label) => {
627
+ if (!this.linkReferences.has(label)) {
628
+ this.linkReferences.set(label, def);
629
+ }
630
+ });
631
+ result.footnoteDefinitions.forEach((def, label) => {
632
+ if (!this.footnoteDefinitions.has(label)) {
633
+ this.footnoteDefinitions.set(label, def);
634
+ }
635
+ });
636
+ const paragraphCount = item.children.filter((child) => child.type === 'paragraph').length;
637
+ if (paragraphCount >= 2) {
638
+ blankLineInItem = true;
639
+ }
640
+ return { blankInItem: blankLineInItem, endsWithBlank };
641
+ }
642
+ lastNonBlankLine(lines) {
643
+ for (let i = lines.length - 1; i >= 0; i--) {
644
+ const line = lines[i];
645
+ if (line.trim() !== '') {
646
+ return line;
647
+ }
648
+ }
649
+ return null;
650
+ }
651
+ getBlockquotePrefix(line) {
652
+ let i = 0;
653
+ let prefix = '';
654
+ while (i < line.length) {
655
+ let spaces = 0;
656
+ const start = i;
657
+ while (i < line.length && line[i] === ' ' && spaces < 3) {
658
+ spaces++;
659
+ i++;
660
+ }
661
+ if (i < line.length && line[i] === '>') {
662
+ i++;
663
+ if (i < line.length && (line[i] === ' ' || line[i] === '\t')) {
664
+ i++;
665
+ }
666
+ prefix += line.slice(start, i);
667
+ }
668
+ else {
669
+ break;
670
+ }
671
+ }
672
+ return prefix;
673
+ }
674
+ allowsLazyAfterListMarker(line) {
675
+ const marker = parseListMarker(line);
676
+ if (!marker) {
677
+ return true;
678
+ }
679
+ const afterMarker = line.slice(marker.contentCharIndex);
680
+ return /^[ \t]*>/.test(afterMarker);
681
+ }
682
+ extractBlockquoteContent(line, match) {
683
+ const optionalSpace = match[1];
684
+ let column = 0;
685
+ let charIndex = 0;
686
+ while (charIndex < line.length && line[charIndex] === ' ' && charIndex < 3) {
687
+ column++;
688
+ charIndex++;
689
+ }
690
+ charIndex++;
691
+ column++;
692
+ let result = '';
693
+ if (optionalSpace === '\t') {
694
+ const tabWidth = 4 - (column % 4);
695
+ const remaining = tabWidth - 1;
696
+ if (remaining > 0) {
697
+ result = ' '.repeat(remaining);
698
+ }
699
+ charIndex++;
700
+ column += tabWidth;
701
+ }
702
+ else if (optionalSpace === ' ') {
703
+ charIndex++;
704
+ column++;
705
+ }
706
+ while (charIndex < line.length) {
707
+ const char = line[charIndex];
708
+ if (char === '\t') {
709
+ const tabWidth = 4 - (column % 4);
710
+ result += ' '.repeat(tabWidth);
711
+ column += tabWidth;
712
+ }
713
+ else {
714
+ result += char;
715
+ column++;
716
+ }
717
+ charIndex++;
718
+ }
719
+ return result;
720
+ }
721
+ extractListItemContent(line, marker) {
722
+ let column = 0;
723
+ let charIndex = 0;
724
+ let result = '';
725
+ while (charIndex < line.length && charIndex < marker.indentChars) {
726
+ if (line[charIndex] === '\t') {
727
+ column = column + (4 - (column % 4));
728
+ }
729
+ else {
730
+ column++;
731
+ }
732
+ charIndex++;
733
+ }
734
+ charIndex += marker.marker.length;
735
+ column += marker.marker.length;
736
+ if (charIndex < line.length && marker.paddingChars > 0) {
737
+ const paddingChar = line[charIndex];
738
+ if (paddingChar === '\t') {
739
+ const tabWidth = 4 - (column % 4);
740
+ const consumed = Math.min(tabWidth, marker.padding);
741
+ column += consumed;
742
+ charIndex += marker.paddingChars;
743
+ const remaining = tabWidth - consumed;
744
+ if (remaining > 0) {
745
+ result += ' '.repeat(remaining);
746
+ column += remaining;
747
+ }
748
+ }
749
+ else {
750
+ column += marker.padding;
751
+ charIndex += marker.paddingChars;
752
+ }
753
+ }
754
+ while (charIndex < line.length) {
755
+ const char = line[charIndex];
756
+ if (char === '\t') {
757
+ const tabWidth = 4 - (column % 4);
758
+ result += ' '.repeat(tabWidth);
759
+ column += tabWidth;
760
+ }
761
+ else {
762
+ result += char;
763
+ column++;
764
+ }
765
+ charIndex++;
766
+ }
767
+ return result;
768
+ }
769
+ }