@jianwen-lang/parser 0.1.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 (89) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +95 -0
  3. package/dist/cli/render.d.ts +1 -0
  4. package/dist/cli/render.js +300 -0
  5. package/dist/core/ast.d.ts +286 -0
  6. package/dist/core/ast.js +2 -0
  7. package/dist/core/block/rules/heading.d.ts +9 -0
  8. package/dist/core/block/rules/heading.js +75 -0
  9. package/dist/core/block/rules/horizontal-rule.d.ts +9 -0
  10. package/dist/core/block/rules/horizontal-rule.js +87 -0
  11. package/dist/core/block/rules/include.d.ts +9 -0
  12. package/dist/core/block/rules/include.js +64 -0
  13. package/dist/core/block/rules/index.d.ts +2 -0
  14. package/dist/core/block/rules/index.js +16 -0
  15. package/dist/core/block/rules/types.d.ts +21 -0
  16. package/dist/core/block/rules/types.js +2 -0
  17. package/dist/core/block/types.d.ts +10 -0
  18. package/dist/core/block/types.js +2 -0
  19. package/dist/core/block-parser.d.ts +3 -0
  20. package/dist/core/block-parser.js +1385 -0
  21. package/dist/core/clone.d.ts +9 -0
  22. package/dist/core/clone.js +32 -0
  23. package/dist/core/diagnostics.d.ts +12 -0
  24. package/dist/core/diagnostics.js +24 -0
  25. package/dist/core/errors.d.ts +12 -0
  26. package/dist/core/errors.js +2 -0
  27. package/dist/core/inline/rules/backtick.d.ts +4 -0
  28. package/dist/core/inline/rules/backtick.js +90 -0
  29. package/dist/core/inline/rules/bracket.d.ts +4 -0
  30. package/dist/core/inline/rules/bracket.js +721 -0
  31. package/dist/core/inline/rules/disabled.d.ts +2 -0
  32. package/dist/core/inline/rules/disabled.js +34 -0
  33. package/dist/core/inline/rules/escape.d.ts +2 -0
  34. package/dist/core/inline/rules/escape.js +11 -0
  35. package/dist/core/inline/rules/index.d.ts +2 -0
  36. package/dist/core/inline/rules/index.js +25 -0
  37. package/dist/core/inline/rules/marker-highlight.d.ts +4 -0
  38. package/dist/core/inline/rules/marker-highlight.js +56 -0
  39. package/dist/core/inline/rules/style.d.ts +4 -0
  40. package/dist/core/inline/rules/style.js +120 -0
  41. package/dist/core/inline/rules/types.d.ts +22 -0
  42. package/dist/core/inline/rules/types.js +2 -0
  43. package/dist/core/inline/types.d.ts +1 -0
  44. package/dist/core/inline/types.js +2 -0
  45. package/dist/core/inline-parser.d.ts +3 -0
  46. package/dist/core/inline-parser.js +52 -0
  47. package/dist/core/location.d.ts +9 -0
  48. package/dist/core/location.js +30 -0
  49. package/dist/core/parser.d.ts +9 -0
  50. package/dist/core/parser.js +423 -0
  51. package/dist/core/traverse.d.ts +7 -0
  52. package/dist/core/traverse.js +71 -0
  53. package/dist/html/convert.d.ts +29 -0
  54. package/dist/html/convert.js +61 -0
  55. package/dist/html/format.d.ts +1 -0
  56. package/dist/html/format.js +17 -0
  57. package/dist/html/render/blocks.d.ts +4 -0
  58. package/dist/html/render/blocks.js +433 -0
  59. package/dist/html/render/html.d.ts +8 -0
  60. package/dist/html/render/html.js +89 -0
  61. package/dist/html/render/inlines.d.ts +4 -0
  62. package/dist/html/render/inlines.js +110 -0
  63. package/dist/html/render/meta.d.ts +3 -0
  64. package/dist/html/render/meta.js +51 -0
  65. package/dist/html/render/utils.d.ts +31 -0
  66. package/dist/html/render/utils.js +213 -0
  67. package/dist/html/theme/base/css.d.ts +2 -0
  68. package/dist/html/theme/base/css.js +383 -0
  69. package/dist/html/theme/dark/css.d.ts +2 -0
  70. package/dist/html/theme/dark/css.js +108 -0
  71. package/dist/html/theme/default/colors.d.ts +13 -0
  72. package/dist/html/theme/default/colors.js +2 -0
  73. package/dist/html/theme/default/css.d.ts +2 -0
  74. package/dist/html/theme/default/css.js +6 -0
  75. package/dist/html/theme/default/runtime.d.ts +0 -0
  76. package/dist/html/theme/default/runtime.js +31 -0
  77. package/dist/html/theme/light/css.d.ts +2 -0
  78. package/dist/html/theme/light/css.js +55 -0
  79. package/dist/html/theme/preset/colors.d.ts +10 -0
  80. package/dist/html/theme/preset/colors.js +14 -0
  81. package/dist/html/theme/runtime.d.ts +0 -0
  82. package/dist/html/theme/runtime.js +31 -0
  83. package/dist/html/theme/theme.d.ts +9 -0
  84. package/dist/html/theme/theme.js +21 -0
  85. package/dist/lexer/lexer.d.ts +17 -0
  86. package/dist/lexer/lexer.js +47 -0
  87. package/dist/parser.d.ts +6 -0
  88. package/dist/parser.js +22 -0
  89. package/package.json +50 -0
@@ -0,0 +1,1385 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseBlocks = parseBlocks;
4
+ const diagnostics_1 = require("./diagnostics");
5
+ const location_1 = require("./location");
6
+ const rules_1 = require("./block/rules");
7
+ const heading_1 = require("./block/rules/heading");
8
+ const horizontal_rule_1 = require("./block/rules/horizontal-rule");
9
+ const include_1 = require("./block/rules/include");
10
+ const lexer_1 = require("../lexer/lexer");
11
+ function buildLineLocation(lineIndex, lineInfo) {
12
+ return { line: lineIndex + 1, column: lineInfo.tabCount + 1 };
13
+ }
14
+ const MULTI_ARROW_WARNING_CODE = 'layout-multi-arrow';
15
+ const UNKNOWN_ATTRIBUTE_WARNING_CODE = 'unknown-attribute-token';
16
+ function buildBlockAttrs(pending, tabCount) {
17
+ const baseAttrs = pending.attrs ? { ...pending.attrs } : undefined;
18
+ const positionFromTabs = mapTabsToPosition(tabCount);
19
+ let blockAttrs = baseAttrs;
20
+ if (positionFromTabs) {
21
+ if (!blockAttrs) {
22
+ blockAttrs = {};
23
+ }
24
+ if (!blockAttrs.position) {
25
+ blockAttrs.position = positionFromTabs;
26
+ }
27
+ }
28
+ if (pending.foldNext) {
29
+ if (!blockAttrs) {
30
+ blockAttrs = {};
31
+ }
32
+ blockAttrs.fold = true;
33
+ }
34
+ return blockAttrs;
35
+ }
36
+ function resetPending(pending) {
37
+ pending.attrs = undefined;
38
+ pending.foldNext = false;
39
+ pending.tagName = undefined;
40
+ pending.isComment = false;
41
+ pending.isDisabled = false;
42
+ pending.isSheet = false;
43
+ pending.isHtml = false;
44
+ }
45
+ function wrapTaggedIfNeeded(block, pending, blockAttrs, lineLocation) {
46
+ if (!pending.tagName) {
47
+ return block;
48
+ }
49
+ const tagged = {
50
+ type: 'taggedBlock',
51
+ name: pending.tagName,
52
+ child: block,
53
+ blockAttrs,
54
+ };
55
+ (0, location_1.setNodeLocation)(tagged, lineLocation);
56
+ return tagged;
57
+ }
58
+ function wrapCommentIfNeeded(block, pending, lineLocation) {
59
+ if (!pending.isComment) {
60
+ return block;
61
+ }
62
+ const comment = {
63
+ type: 'commentBlock',
64
+ children: [block],
65
+ blockAttrs: undefined,
66
+ };
67
+ (0, location_1.setNodeLocation)(comment, lineLocation);
68
+ return comment;
69
+ }
70
+ function pushBlockAndResetPending(blocks, block, lineInfo, pending, lastBlockPosition) {
71
+ blocks.push(block);
72
+ const nextPosition = resolveNextPosition(getBlockAttributes(block), lineInfo.tabCount, lastBlockPosition);
73
+ resetPending(pending);
74
+ return nextPosition;
75
+ }
76
+ function parseBlocks(source, errors) {
77
+ const blocks = [];
78
+ const lines = source.split(/\r?\n/);
79
+ const pending = {
80
+ attrs: undefined,
81
+ foldNext: false,
82
+ tagName: undefined,
83
+ isComment: false,
84
+ isDisabled: false,
85
+ isSheet: false,
86
+ isHtml: false,
87
+ };
88
+ let lastBlockPosition = 'L';
89
+ let i = 0;
90
+ while (i < lines.length) {
91
+ const raw = lines[i];
92
+ if (raw === undefined) {
93
+ i += 1;
94
+ continue;
95
+ }
96
+ const lineInfo = getLineInfo(raw);
97
+ const lineLocation = buildLineLocation(i, lineInfo);
98
+ const trimmedContent = lineInfo.content.trim();
99
+ if (trimmedContent.length === 0) {
100
+ i += 1;
101
+ continue;
102
+ }
103
+ if (isFootnotesLine(trimmedContent)) {
104
+ const rawLines = [lineInfo.raw];
105
+ const regionLines = [];
106
+ let jFoot = i + 1;
107
+ while (jFoot < lines.length) {
108
+ const nextRaw = lines[jFoot];
109
+ if (nextRaw === undefined) {
110
+ jFoot += 1;
111
+ continue;
112
+ }
113
+ const nextInfo = getLineInfo(nextRaw);
114
+ const nextTrimmed = nextInfo.content.trim();
115
+ if (nextTrimmed.length === 0) {
116
+ break;
117
+ }
118
+ rawLines.push(nextInfo.raw);
119
+ regionLines.push(nextInfo.content);
120
+ jFoot += 1;
121
+ }
122
+ const blockAttrs = buildBlockAttrs(pending, lineInfo.tabCount);
123
+ let block;
124
+ if (pending.isDisabled) {
125
+ const disabled = {
126
+ type: 'disabledBlock',
127
+ raw: rawLines.join('\n'),
128
+ blockAttrs,
129
+ };
130
+ (0, location_1.setNodeLocation)(disabled, lineLocation);
131
+ block = disabled;
132
+ }
133
+ else {
134
+ const children = parseFootnoteDefs(regionLines, errors);
135
+ const footnotesBlock = {
136
+ type: 'footnotes',
137
+ children,
138
+ blockAttrs,
139
+ };
140
+ (0, location_1.setNodeLocation)(footnotesBlock, lineLocation);
141
+ block = wrapTaggedIfNeeded(footnotesBlock, pending, blockAttrs, lineLocation);
142
+ }
143
+ block = wrapCommentIfNeeded(block, pending, lineLocation);
144
+ lastBlockPosition = pushBlockAndResetPending(blocks, block, lineInfo, pending, lastBlockPosition);
145
+ i = jFoot;
146
+ continue;
147
+ }
148
+ // Check for code blocks - both plain ``` and attributed [html]``` forms
149
+ const codeFenceStart = matchCodeFenceStart(trimmedContent);
150
+ const attrCodeFenceStart = codeFenceStart ? null : matchAttributedCodeFence(trimmedContent);
151
+ const effectiveCodeFence = codeFenceStart || attrCodeFenceStart;
152
+ if (effectiveCodeFence) {
153
+ const rawLines = [lineInfo.raw];
154
+ const codeLines = [];
155
+ // Record the indentation level of the opening ``` to strip from content lines
156
+ const fenceIndent = lineInfo.tabCount;
157
+ let jCode = i + 1;
158
+ let closed = false;
159
+ while (jCode < lines.length) {
160
+ const nextRaw = lines[jCode];
161
+ if (nextRaw === undefined) {
162
+ jCode += 1;
163
+ continue;
164
+ }
165
+ const nextInfo = getLineInfo(nextRaw);
166
+ const nextTrimmed = nextInfo.content.trim();
167
+ if (isCodeFenceEnd(nextTrimmed)) {
168
+ rawLines.push(nextInfo.raw);
169
+ closed = true;
170
+ jCode += 1;
171
+ break;
172
+ }
173
+ rawLines.push(nextInfo.raw);
174
+ // Strip leading tabs matching the fence indentation level
175
+ let codeLine = nextRaw;
176
+ for (let t = 0; t < fenceIndent && codeLine.startsWith('\t'); t++) {
177
+ codeLine = codeLine.slice(1);
178
+ }
179
+ codeLines.push(codeLine);
180
+ jCode += 1;
181
+ }
182
+ if (!closed) {
183
+ (0, diagnostics_1.reportParseError)(errors, {
184
+ message: 'Code block is not closed with ```',
185
+ line: i + 1,
186
+ });
187
+ }
188
+ const blockAttrs = buildBlockAttrs(pending, lineInfo.tabCount);
189
+ // Determine if this is an HTML block from either pending state or inline attribute
190
+ const isHtmlBlock = pending.isHtml || (attrCodeFenceStart?.isHtml ?? false);
191
+ let block;
192
+ if (pending.isDisabled) {
193
+ const disabled = {
194
+ type: 'disabledBlock',
195
+ raw: rawLines.join('\n'),
196
+ blockAttrs,
197
+ };
198
+ (0, location_1.setNodeLocation)(disabled, lineLocation);
199
+ block = disabled;
200
+ }
201
+ else {
202
+ const codeBlock = {
203
+ type: 'code',
204
+ language: effectiveCodeFence.language,
205
+ value: codeLines.join('\n'),
206
+ htmlLike: isHtmlBlock ? true : undefined,
207
+ blockAttrs,
208
+ };
209
+ (0, location_1.setNodeLocation)(codeBlock, lineLocation);
210
+ block = wrapTaggedIfNeeded(codeBlock, pending, blockAttrs, lineLocation);
211
+ }
212
+ block = wrapCommentIfNeeded(block, pending, lineLocation);
213
+ lastBlockPosition = pushBlockAndResetPending(blocks, block, lineInfo, pending, lastBlockPosition);
214
+ i = jCode;
215
+ continue;
216
+ }
217
+ if (isAttributeOnlyLine(trimmedContent)) {
218
+ const result = parseAttributeLine(trimmedContent, i + 1, errors, pending.attrs, lastBlockPosition, lineInfo.tabCount);
219
+ if (result.recognizedAny) {
220
+ if (result.attrs) {
221
+ pending.attrs = mergeBlockAttributes(pending.attrs, result.attrs);
222
+ }
223
+ if (result.foldNext) {
224
+ pending.foldNext = true;
225
+ }
226
+ if (result.tagName) {
227
+ pending.tagName = result.tagName;
228
+ }
229
+ if (result.isComment) {
230
+ pending.isComment = true;
231
+ }
232
+ if (result.isDisabled) {
233
+ pending.isDisabled = true;
234
+ }
235
+ if (result.isSheet) {
236
+ pending.isSheet = true;
237
+ }
238
+ if (result.isHtml) {
239
+ pending.isHtml = true;
240
+ }
241
+ i += 1;
242
+ continue;
243
+ }
244
+ }
245
+ const commitBlock = (block, blockAttrs, options) => {
246
+ const allowTag = options?.allowTag !== false;
247
+ const taggedOrOriginal = allowTag
248
+ ? wrapTaggedIfNeeded(block, pending, blockAttrs, lineLocation)
249
+ : block;
250
+ const finalBlock = wrapCommentIfNeeded(taggedOrOriginal, pending, lineLocation);
251
+ lastBlockPosition = pushBlockAndResetPending(blocks, finalBlock, lineInfo, pending, lastBlockPosition);
252
+ options?.postResetPending?.(pending);
253
+ };
254
+ const nextIndexFromRule = (0, rules_1.tryParseBlockRules)({
255
+ lines,
256
+ index: i,
257
+ lineInfo,
258
+ trimmedContent,
259
+ lineLocation,
260
+ pending,
261
+ errors,
262
+ buildBlockAttrs: (tabCount) => buildBlockAttrs(pending, tabCount),
263
+ commitBlock,
264
+ });
265
+ if (nextIndexFromRule !== null) {
266
+ i = nextIndexFromRule;
267
+ continue;
268
+ }
269
+ const contentTitleMatch = matchContentTitle(lineInfo.content);
270
+ if (contentTitleMatch) {
271
+ const text = contentTitleMatch.text;
272
+ let consumedByImageTitle = false;
273
+ if (!pending.attrs &&
274
+ !pending.foldNext &&
275
+ !pending.tagName &&
276
+ !pending.isComment &&
277
+ !pending.isDisabled &&
278
+ !pending.isSheet &&
279
+ !pending.isHtml) {
280
+ const lastBlock = blocks[blocks.length - 1];
281
+ if (lastBlock && lastBlock.type === 'image') {
282
+ lastBlock.title = text;
283
+ consumedByImageTitle = true;
284
+ }
285
+ else if (lastBlock &&
286
+ lastBlock.type === 'taggedBlock' &&
287
+ lastBlock.child.type === 'image') {
288
+ lastBlock.child.title = text;
289
+ consumedByImageTitle = true;
290
+ }
291
+ }
292
+ if (consumedByImageTitle) {
293
+ resetPending(pending);
294
+ i += 1;
295
+ continue;
296
+ }
297
+ const blockAttrs = buildBlockAttrs(pending, lineInfo.tabCount);
298
+ let block;
299
+ if (pending.isDisabled) {
300
+ const disabled = {
301
+ type: 'disabledBlock',
302
+ raw: lineInfo.raw,
303
+ blockAttrs,
304
+ };
305
+ (0, location_1.setNodeLocation)(disabled, lineLocation);
306
+ block = disabled;
307
+ }
308
+ else {
309
+ const contentTitle = {
310
+ type: 'contentTitle',
311
+ children: [{ type: 'text', value: text }],
312
+ };
313
+ (0, location_1.setNodeLocation)(contentTitle, lineLocation);
314
+ block = wrapTaggedIfNeeded(contentTitle, pending, blockAttrs, lineLocation);
315
+ }
316
+ block = wrapCommentIfNeeded(block, pending, lineLocation);
317
+ lastBlockPosition = pushBlockAndResetPending(blocks, block, lineInfo, pending, lastBlockPosition);
318
+ i += 1;
319
+ continue;
320
+ }
321
+ const quoteMatch = matchQuote(lineInfo.content);
322
+ if (quoteMatch) {
323
+ const { level } = quoteMatch;
324
+ const innerLines = [];
325
+ const rawLines = [];
326
+ const first = matchQuote(lineInfo.content);
327
+ if (first) {
328
+ const normalized = normalizeQuoteLine(first, level);
329
+ if (normalized !== undefined) {
330
+ innerLines.push(normalized);
331
+ }
332
+ }
333
+ rawLines.push(lineInfo.raw);
334
+ let jQuote = i + 1;
335
+ while (jQuote < lines.length) {
336
+ const nextRaw = lines[jQuote];
337
+ if (nextRaw === undefined) {
338
+ jQuote += 1;
339
+ continue;
340
+ }
341
+ const nextInfo = getLineInfo(nextRaw);
342
+ const nextTrimmed = nextInfo.content.trim();
343
+ if (nextTrimmed.length === 0) {
344
+ break;
345
+ }
346
+ const m = matchQuote(nextInfo.content);
347
+ if (!m) {
348
+ break;
349
+ }
350
+ const normalized = normalizeQuoteLine(m, level);
351
+ if (normalized === undefined) {
352
+ break;
353
+ }
354
+ innerLines.push(normalized);
355
+ rawLines.push(nextInfo.raw);
356
+ jQuote += 1;
357
+ }
358
+ const innerSource = innerLines.join('\n');
359
+ const blockAttrs = buildBlockAttrs(pending, lineInfo.tabCount);
360
+ let block;
361
+ if (pending.isDisabled) {
362
+ const disabled = {
363
+ type: 'disabledBlock',
364
+ raw: rawLines.join('\n'),
365
+ blockAttrs,
366
+ };
367
+ (0, location_1.setNodeLocation)(disabled, lineLocation);
368
+ block = disabled;
369
+ }
370
+ else {
371
+ const children = parseBlocks(innerSource, errors);
372
+ adjustNestedQuoteLevels(children, level);
373
+ const quote = {
374
+ type: 'quote',
375
+ level,
376
+ children,
377
+ blockAttrs,
378
+ };
379
+ (0, location_1.setNodeLocation)(quote, lineLocation);
380
+ block = wrapTaggedIfNeeded(quote, pending, blockAttrs, lineLocation);
381
+ }
382
+ block = wrapCommentIfNeeded(block, pending, lineLocation);
383
+ lastBlockPosition = pushBlockAndResetPending(blocks, block, lineInfo, pending, lastBlockPosition);
384
+ i = jQuote;
385
+ continue;
386
+ }
387
+ if (pending.isSheet && isTableRow(lineInfo.content)) {
388
+ const rawLines = [lineInfo.raw];
389
+ const rowContents = [
390
+ { text: lineInfo.content, raw: lineInfo.raw, line: i + 1 },
391
+ ];
392
+ let jTable = i + 1;
393
+ while (jTable < lines.length) {
394
+ const nextRaw = lines[jTable];
395
+ if (nextRaw === undefined) {
396
+ jTable += 1;
397
+ continue;
398
+ }
399
+ const nextInfo = getLineInfo(nextRaw);
400
+ const nextTrimmed = nextInfo.content.trim();
401
+ if (nextTrimmed.length === 0) {
402
+ break;
403
+ }
404
+ if (isAttributeOnlyLine(nextTrimmed)) {
405
+ break;
406
+ }
407
+ if (!isTableRow(nextInfo.content)) {
408
+ break;
409
+ }
410
+ rawLines.push(nextInfo.raw);
411
+ rowContents.push({ text: nextInfo.content, raw: nextInfo.raw, line: jTable + 1 });
412
+ jTable += 1;
413
+ }
414
+ const { rows, align } = parseTableRows(rowContents, errors);
415
+ const blockAttrs = buildBlockAttrs(pending, lineInfo.tabCount);
416
+ let tableAlign = align;
417
+ if (!tableAlign && blockAttrs?.align && blockAttrs.align !== 'left') {
418
+ const columnCount = getMaxTableColumnCount(rows);
419
+ if (columnCount > 0) {
420
+ tableAlign = Array.from({ length: columnCount }, () => blockAttrs.align);
421
+ }
422
+ }
423
+ let block;
424
+ if (pending.isDisabled) {
425
+ const disabled = {
426
+ type: 'disabledBlock',
427
+ raw: rawLines.join('\n'),
428
+ blockAttrs,
429
+ };
430
+ (0, location_1.setNodeLocation)(disabled, lineLocation);
431
+ block = disabled;
432
+ }
433
+ else {
434
+ const tableBlock = {
435
+ type: 'table',
436
+ rows,
437
+ align: tableAlign,
438
+ blockAttrs,
439
+ };
440
+ (0, location_1.setNodeLocation)(tableBlock, lineLocation);
441
+ block = wrapTaggedIfNeeded(tableBlock, pending, blockAttrs, lineLocation);
442
+ }
443
+ block = wrapCommentIfNeeded(block, pending, lineLocation);
444
+ lastBlockPosition = pushBlockAndResetPending(blocks, block, lineInfo, pending, lastBlockPosition);
445
+ i = jTable;
446
+ continue;
447
+ }
448
+ const imageMatch = matchImageBlock(trimmedContent);
449
+ if (imageMatch) {
450
+ const blockAttrs = buildBlockAttrs(pending, lineInfo.tabCount);
451
+ let block;
452
+ if (pending.isDisabled) {
453
+ const disabled = {
454
+ type: 'disabledBlock',
455
+ raw: lineInfo.raw,
456
+ blockAttrs,
457
+ };
458
+ (0, location_1.setNodeLocation)(disabled, lineLocation);
459
+ block = disabled;
460
+ }
461
+ else {
462
+ const image = {
463
+ type: 'image',
464
+ url: imageMatch.url,
465
+ shape: imageMatch.shape,
466
+ roundedRadius: imageMatch.roundedRadius,
467
+ blockAttrs,
468
+ };
469
+ (0, location_1.setNodeLocation)(image, lineLocation);
470
+ block = wrapTaggedIfNeeded(image, pending, blockAttrs, lineLocation);
471
+ }
472
+ block = wrapCommentIfNeeded(block, pending, lineLocation);
473
+ lastBlockPosition = pushBlockAndResetPending(blocks, block, lineInfo, pending, lastBlockPosition);
474
+ i += 1;
475
+ continue;
476
+ }
477
+ const htmlMatch = matchHtmlBlock(trimmedContent);
478
+ if (htmlMatch) {
479
+ const blockAttrs = buildBlockAttrs(pending, lineInfo.tabCount);
480
+ let block;
481
+ if (pending.isDisabled) {
482
+ const disabled = {
483
+ type: 'disabledBlock',
484
+ raw: lineInfo.raw,
485
+ blockAttrs,
486
+ };
487
+ (0, location_1.setNodeLocation)(disabled, lineLocation);
488
+ block = disabled;
489
+ }
490
+ else {
491
+ const htmlBlock = {
492
+ type: 'html',
493
+ source: htmlMatch.source,
494
+ blockAttrs,
495
+ };
496
+ (0, location_1.setNodeLocation)(htmlBlock, lineLocation);
497
+ block = wrapTaggedIfNeeded(htmlBlock, pending, blockAttrs, lineLocation);
498
+ }
499
+ block = wrapCommentIfNeeded(block, pending, lineLocation);
500
+ lastBlockPosition = pushBlockAndResetPending(blocks, block, lineInfo, pending, lastBlockPosition);
501
+ i += 1;
502
+ continue;
503
+ }
504
+ const listFirstMatch = matchListItem(lineInfo.content, i + 1, lineInfo.tabCount + 1);
505
+ if (listFirstMatch) {
506
+ const listMatches = [listFirstMatch];
507
+ const rawLines = [lineInfo.raw];
508
+ let jList = i + 1;
509
+ while (jList < lines.length) {
510
+ const nextRaw = lines[jList];
511
+ if (nextRaw === undefined) {
512
+ jList += 1;
513
+ continue;
514
+ }
515
+ const nextInfo = getLineInfo(nextRaw);
516
+ const nextTrimmed = nextInfo.content.trim();
517
+ if (nextTrimmed.length === 0) {
518
+ break;
519
+ }
520
+ if (isAttributeOnlyLine(nextTrimmed)) {
521
+ break;
522
+ }
523
+ const nextMatch = matchListItem(nextInfo.content, jList + 1, nextInfo.tabCount + 1);
524
+ if (!nextMatch) {
525
+ // Check if this is a code block that should be attached to the previous list item
526
+ // Support both plain ``` and attributed [html]``` forms
527
+ const codeFence = matchCodeFenceStart(nextTrimmed);
528
+ const attrCodeFence = codeFence ? null : matchAttributedCodeFence(nextTrimmed);
529
+ const effectiveFence = codeFence || attrCodeFence;
530
+ if (effectiveFence && listMatches.length > 0) {
531
+ // Parse the code block
532
+ const codeLines = [];
533
+ const fenceIndent = nextInfo.tabCount;
534
+ let kCode = jList + 1;
535
+ let codeClosed = false;
536
+ while (kCode < lines.length) {
537
+ const codeRaw = lines[kCode];
538
+ if (codeRaw === undefined) {
539
+ kCode += 1;
540
+ continue;
541
+ }
542
+ const codeInfo = getLineInfo(codeRaw);
543
+ const codeTrimmed = codeInfo.content.trim();
544
+ if (isCodeFenceEnd(codeTrimmed)) {
545
+ codeClosed = true;
546
+ kCode += 1;
547
+ break;
548
+ }
549
+ // Strip leading tabs matching the fence indentation level
550
+ let codeLine = codeRaw;
551
+ for (let t = 0; t < fenceIndent && codeLine.startsWith('\t'); t++) {
552
+ codeLine = codeLine.slice(1);
553
+ }
554
+ codeLines.push(codeLine);
555
+ kCode += 1;
556
+ }
557
+ if (codeClosed) {
558
+ const isHtmlBlock = attrCodeFence?.isHtml ?? false;
559
+ const codeBlock = {
560
+ type: 'code',
561
+ language: effectiveFence.language,
562
+ value: codeLines.join('\n'),
563
+ htmlLike: isHtmlBlock ? true : undefined,
564
+ };
565
+ (0, location_1.setNodeLocation)(codeBlock, buildLineLocation(jList, nextInfo));
566
+ // Attach to the last list item
567
+ const lastItem = listMatches[listMatches.length - 1];
568
+ if (lastItem) {
569
+ if (!lastItem.childBlocks) {
570
+ lastItem.childBlocks = [];
571
+ }
572
+ lastItem.childBlocks.push(codeBlock);
573
+ }
574
+ jList = kCode;
575
+ continue;
576
+ }
577
+ }
578
+ break;
579
+ }
580
+ if (nextMatch.kind !== listFirstMatch.kind) {
581
+ break;
582
+ }
583
+ if (nextMatch.indent < listFirstMatch.indent) {
584
+ break;
585
+ }
586
+ listMatches.push(nextMatch);
587
+ rawLines.push(nextInfo.raw);
588
+ jList += 1;
589
+ }
590
+ const blockAttrs = buildBlockAttrs(pending, lineInfo.tabCount);
591
+ let block;
592
+ if (pending.isDisabled) {
593
+ const disabled = {
594
+ type: 'disabledBlock',
595
+ raw: rawLines.join('\n'),
596
+ blockAttrs,
597
+ };
598
+ (0, location_1.setNodeLocation)(disabled, lineLocation);
599
+ block = disabled;
600
+ }
601
+ else {
602
+ const { items } = buildListItems(listMatches, 0, listFirstMatch.indent);
603
+ let listKind = listFirstMatch.kind;
604
+ const firstItem = items[0];
605
+ if (firstItem) {
606
+ listKind = firstItem.kind;
607
+ }
608
+ const listBlock = {
609
+ type: 'list',
610
+ kind: listKind,
611
+ orderedStyle: listKind === 'ordered' ? 'decimal' : undefined,
612
+ children: items,
613
+ blockAttrs,
614
+ };
615
+ (0, location_1.setNodeLocation)(listBlock, lineLocation);
616
+ block = wrapTaggedIfNeeded(listBlock, pending, blockAttrs, lineLocation);
617
+ }
618
+ block = wrapCommentIfNeeded(block, pending, lineLocation);
619
+ lastBlockPosition = pushBlockAndResetPending(blocks, block, lineInfo, pending, lastBlockPosition);
620
+ i = jList;
621
+ continue;
622
+ }
623
+ const blockRawLines = [lineInfo.raw];
624
+ const blockTextLines = [lineInfo.content];
625
+ let j = i + 1;
626
+ while (j < lines.length) {
627
+ const nextRaw = lines[j];
628
+ if (nextRaw === undefined) {
629
+ j += 1;
630
+ continue;
631
+ }
632
+ const nextInfo = getLineInfo(nextRaw);
633
+ const nextTrimmed = nextInfo.content.trim();
634
+ if (nextTrimmed.length === 0) {
635
+ break;
636
+ }
637
+ if (isAttributeOnlyLine(nextTrimmed)) {
638
+ break;
639
+ }
640
+ if (isFootnotesLine(nextTrimmed)) {
641
+ break;
642
+ }
643
+ if ((0, include_1.matchInclude)(nextInfo.content)) {
644
+ break;
645
+ }
646
+ if ((0, heading_1.matchHeading)(nextInfo.content)) {
647
+ break;
648
+ }
649
+ if (matchContentTitle(nextInfo.content)) {
650
+ break;
651
+ }
652
+ if (matchQuote(nextInfo.content)) {
653
+ break;
654
+ }
655
+ if (matchCodeFenceStart(nextTrimmed)) {
656
+ break;
657
+ }
658
+ if ((0, horizontal_rule_1.matchHorizontalRule)(nextTrimmed)) {
659
+ break;
660
+ }
661
+ if (matchImageBlock(nextTrimmed)) {
662
+ break;
663
+ }
664
+ if (matchHtmlBlock(nextTrimmed)) {
665
+ break;
666
+ }
667
+ if (matchListItem(nextInfo.content)) {
668
+ break;
669
+ }
670
+ blockRawLines.push(nextInfo.raw);
671
+ blockTextLines.push(nextInfo.content);
672
+ j += 1;
673
+ }
674
+ const blockText = blockTextLines.join('\n');
675
+ const blockAttrs = buildBlockAttrs(pending, lineInfo.tabCount);
676
+ let block;
677
+ if (pending.isDisabled) {
678
+ const disabled = {
679
+ type: 'disabledBlock',
680
+ raw: blockRawLines.join('\n'),
681
+ blockAttrs,
682
+ };
683
+ (0, location_1.setNodeLocation)(disabled, lineLocation);
684
+ block = disabled;
685
+ }
686
+ else {
687
+ const paragraph = {
688
+ type: 'paragraph',
689
+ children: [{ type: 'text', value: blockText }],
690
+ blockAttrs,
691
+ };
692
+ (0, location_1.setNodeLocation)(paragraph, lineLocation);
693
+ block = paragraph;
694
+ if (pending.tagName) {
695
+ block = wrapTaggedIfNeeded(block, pending, blockAttrs, lineLocation);
696
+ }
697
+ }
698
+ block = wrapCommentIfNeeded(block, pending, lineLocation);
699
+ lastBlockPosition = pushBlockAndResetPending(blocks, block, lineInfo, pending, lastBlockPosition);
700
+ i = j;
701
+ }
702
+ return blocks;
703
+ }
704
+ function getBlockAttributes(block) {
705
+ if ('blockAttrs' in block) {
706
+ const candidate = block.blockAttrs;
707
+ return candidate;
708
+ }
709
+ return undefined;
710
+ }
711
+ function resolveNextPosition(attrs, tabCount, fallback) {
712
+ if (attrs?.position) {
713
+ return attrs.position;
714
+ }
715
+ const tabPosition = mapTabsToPosition(tabCount);
716
+ if (tabPosition) {
717
+ return tabPosition;
718
+ }
719
+ return fallback;
720
+ }
721
+ function getLineInfo(raw) {
722
+ return (0, lexer_1.getLineInfo)(raw);
723
+ }
724
+ function mapTabsToPosition(tabCount) {
725
+ if (tabCount === 0) {
726
+ return 'L';
727
+ }
728
+ if (tabCount === 1) {
729
+ return 'C';
730
+ }
731
+ if (tabCount >= 2) {
732
+ return 'R';
733
+ }
734
+ return undefined;
735
+ }
736
+ function isAttributeOnlyLine(text) {
737
+ if (text.length === 0) {
738
+ return false;
739
+ }
740
+ const trimmed = text.trim();
741
+ if ((0, include_1.matchInclude)(trimmed)) {
742
+ return false;
743
+ }
744
+ let i = 0;
745
+ while (i < text.length) {
746
+ const ch = text[i];
747
+ if (ch === '[') {
748
+ const end = text.indexOf(']', i + 1);
749
+ if (end === -1) {
750
+ return false;
751
+ }
752
+ i = end + 1;
753
+ continue;
754
+ }
755
+ if (ch === ' ' || ch === '\t') {
756
+ i += 1;
757
+ continue;
758
+ }
759
+ return false;
760
+ }
761
+ return true;
762
+ }
763
+ function isFootnotesLine(trimmed) {
764
+ return trimmed === '[footnotes]';
765
+ }
766
+ function parseFootnoteDefs(lines, errors) {
767
+ const defs = [];
768
+ let i = 0;
769
+ while (i < lines.length) {
770
+ const raw = lines[i];
771
+ if (raw === undefined) {
772
+ i += 1;
773
+ continue;
774
+ }
775
+ const trimmed = raw.trim();
776
+ const match = trimmed.match(/^\[fn=([^\]]+)\]\s*$/);
777
+ if (!match) {
778
+ i += 1;
779
+ continue;
780
+ }
781
+ const idGroup = match[1];
782
+ if (!idGroup) {
783
+ i += 1;
784
+ continue;
785
+ }
786
+ const id = idGroup.trim();
787
+ i += 1;
788
+ const contentLines = [];
789
+ while (i < lines.length) {
790
+ const innerRaw = lines[i];
791
+ if (innerRaw === undefined) {
792
+ i += 1;
793
+ continue;
794
+ }
795
+ const innerTrimmed = innerRaw.trim();
796
+ if (innerTrimmed.length === 0) {
797
+ break;
798
+ }
799
+ if (/^\[fn=[^\]]+\]\s*$/.test(innerTrimmed)) {
800
+ break;
801
+ }
802
+ contentLines.push(innerRaw);
803
+ i += 1;
804
+ }
805
+ const contentSource = contentLines.join('\n');
806
+ const children = contentSource.length > 0 ? parseBlocks(contentSource, errors) : [];
807
+ const def = {
808
+ type: 'footnoteDef',
809
+ id,
810
+ children,
811
+ };
812
+ defs.push(def);
813
+ }
814
+ return defs;
815
+ }
816
+ function isTableRow(content) {
817
+ const trimmed = content.trim();
818
+ if (!trimmed.startsWith('|')) {
819
+ return false;
820
+ }
821
+ return trimmed.indexOf('|', 1) !== -1;
822
+ }
823
+ function parseTableRows(lines, errors) {
824
+ if (lines.length === 0) {
825
+ return { rows: [], align: undefined };
826
+ }
827
+ for (const line of lines) {
828
+ const trimmed = line.text.trim();
829
+ if (isTableRow(trimmed) && !trimmed.endsWith('|')) {
830
+ const contentStart = line.raw.length - line.text.length;
831
+ const trimmedContent = line.text.replace(/\s+$/, '');
832
+ const column = contentStart + trimmedContent.length + 1;
833
+ (0, diagnostics_1.reportParseError)(errors, {
834
+ message: 'Table row is missing closing "|" border',
835
+ line: line.line,
836
+ column,
837
+ });
838
+ }
839
+ }
840
+ const remaining = [...lines];
841
+ let align;
842
+ // Check if the first line is an alignment row (JianWen native syntax: alignment row comes first)
843
+ const firstLine = remaining[0];
844
+ if (firstLine !== undefined) {
845
+ const firstTrimmed = firstLine.text.trim();
846
+ if (isAlignmentRow(firstTrimmed)) {
847
+ align = parseAlignmentLine(firstTrimmed);
848
+ remaining.shift();
849
+ }
850
+ }
851
+ // Check if the second line is an alignment row (Markdown compatible syntax: alignment row after header row)
852
+ if (align === undefined && remaining.length >= 2) {
853
+ const secondLine = remaining[1];
854
+ if (secondLine !== undefined) {
855
+ const secondTrimmed = secondLine.text.trim();
856
+ if (isAlignmentRow(secondTrimmed)) {
857
+ align = parseAlignmentLine(secondTrimmed);
858
+ remaining.splice(1, 1); // Remove the second line (alignment row)
859
+ }
860
+ }
861
+ }
862
+ const rows = [];
863
+ for (const line of remaining) {
864
+ const trimmed = line.text.trim();
865
+ if (!isTableRow(trimmed)) {
866
+ continue;
867
+ }
868
+ const rawCells = trimmed.split('|').slice(1, -1);
869
+ const cells = [];
870
+ for (let ci = 0; ci < rawCells.length; ci += 1) {
871
+ const rawCell = rawCells[ci];
872
+ if (rawCell === undefined) {
873
+ continue;
874
+ }
875
+ let cellText = rawCell.trim();
876
+ let cellAlign;
877
+ if (cellText.startsWith('[r]')) {
878
+ cellAlign = 'right';
879
+ cellText = cellText.slice(3).trim();
880
+ }
881
+ else if (cellText.startsWith('[c]')) {
882
+ cellAlign = 'center';
883
+ cellText = cellText.slice(3).trim();
884
+ }
885
+ else if (align && ci < align.length) {
886
+ cellAlign = align[ci];
887
+ }
888
+ const cell = {
889
+ type: 'tableCell',
890
+ children: cellText.length > 0 ? [{ type: 'text', value: cellText }] : [],
891
+ align: cellAlign,
892
+ };
893
+ (0, location_1.setNodeLocation)(cell, { line: line.line, column: 1 });
894
+ cells.push(cell);
895
+ }
896
+ const row = {
897
+ type: 'tableRow',
898
+ cells,
899
+ };
900
+ rows.push(row);
901
+ }
902
+ return { rows, align };
903
+ }
904
+ function isAlignmentRow(trimmed) {
905
+ if (!isTableRow(trimmed)) {
906
+ return false;
907
+ }
908
+ const segments = trimmed.split('|').slice(1, -1);
909
+ if (segments.length === 0) {
910
+ return false;
911
+ }
912
+ for (const seg of segments) {
913
+ const t = seg.trim();
914
+ if (!/^:?-+:?$/.test(t)) {
915
+ return false;
916
+ }
917
+ }
918
+ return true;
919
+ }
920
+ function parseAlignmentLine(trimmed) {
921
+ const segments = trimmed.split('|').slice(1, -1);
922
+ const result = [];
923
+ for (const seg of segments) {
924
+ const t = seg.trim();
925
+ const left = t.startsWith(':');
926
+ const right = t.endsWith(':');
927
+ if (left && right) {
928
+ result.push('center');
929
+ }
930
+ else if (right) {
931
+ result.push('right');
932
+ }
933
+ else {
934
+ result.push('left');
935
+ }
936
+ }
937
+ return result;
938
+ }
939
+ function getMaxTableColumnCount(rows) {
940
+ let max = 0;
941
+ for (const row of rows) {
942
+ if (row.cells.length > max) {
943
+ max = row.cells.length;
944
+ }
945
+ }
946
+ return max;
947
+ }
948
+ function matchImageBlock(trimmed) {
949
+ const m = trimmed.match(/^\[([^\]]+)\]\(([^)]+)\)\s*$/);
950
+ if (!m) {
951
+ return undefined;
952
+ }
953
+ const inside = m[1];
954
+ const urlGroup = m[2];
955
+ if (inside === undefined || urlGroup === undefined) {
956
+ return undefined;
957
+ }
958
+ const url = urlGroup.trim();
959
+ if (url.length === 0) {
960
+ return undefined;
961
+ }
962
+ const parts = inside
963
+ .split(',')
964
+ .map((part) => part.trim())
965
+ .filter((part) => part.length > 0);
966
+ if (!parts.includes('img')) {
967
+ return undefined;
968
+ }
969
+ let shape;
970
+ let roundedRadius;
971
+ for (const part of parts) {
972
+ if (part === 'rounded') {
973
+ shape = 'rounded';
974
+ continue;
975
+ }
976
+ if (part === 'square') {
977
+ shape = 'square';
978
+ continue;
979
+ }
980
+ const roundedMatch = part.match(/^rounded=([0-9.]+)$/);
981
+ if (roundedMatch && roundedMatch[1]) {
982
+ const num = parseFloat(roundedMatch[1]);
983
+ if (!isNaN(num) && num > 0) {
984
+ shape = 'rounded';
985
+ roundedRadius = num;
986
+ }
987
+ }
988
+ }
989
+ return { url, shape, roundedRadius };
990
+ }
991
+ function matchHtmlBlock(trimmed) {
992
+ const m = trimmed.match(/^\[html\]\(([^)]+)\)\s*$/);
993
+ if (!m) {
994
+ return undefined;
995
+ }
996
+ const urlGroup = m[1];
997
+ if (urlGroup === undefined) {
998
+ return undefined;
999
+ }
1000
+ const source = urlGroup.trim();
1001
+ if (source.length === 0) {
1002
+ return undefined;
1003
+ }
1004
+ return { source };
1005
+ }
1006
+ function matchContentTitle(content) {
1007
+ const m = content.match(/^>\s+(.+)$/);
1008
+ if (!m) {
1009
+ return undefined;
1010
+ }
1011
+ const group = m[1];
1012
+ if (group === undefined) {
1013
+ return undefined;
1014
+ }
1015
+ const text = group.trimEnd();
1016
+ return { text };
1017
+ }
1018
+ function matchQuote(content) {
1019
+ const m = content.match(/^(@+)\s+(.+)$/);
1020
+ if (!m) {
1021
+ return undefined;
1022
+ }
1023
+ const atGroup = m[1];
1024
+ const textGroup = m[2];
1025
+ if (atGroup === undefined || textGroup === undefined) {
1026
+ return undefined;
1027
+ }
1028
+ const level = atGroup.length;
1029
+ const text = textGroup.trimEnd();
1030
+ return { level, text };
1031
+ }
1032
+ function normalizeQuoteLine(match, baseLevel) {
1033
+ if (match.level < baseLevel) {
1034
+ return undefined;
1035
+ }
1036
+ const relativeLevel = match.level - baseLevel;
1037
+ if (relativeLevel === 0) {
1038
+ return match.text;
1039
+ }
1040
+ const nestedMarkers = '@'.repeat(relativeLevel);
1041
+ return `${nestedMarkers} ${match.text}`;
1042
+ }
1043
+ function adjustNestedQuoteLevels(nodes, parentLevel) {
1044
+ for (const node of nodes) {
1045
+ if (node.type !== 'quote') {
1046
+ continue;
1047
+ }
1048
+ node.level += parentLevel;
1049
+ adjustNestedQuoteLevels(node.children, node.level);
1050
+ }
1051
+ }
1052
+ function matchCodeFenceStart(trimmed) {
1053
+ if (!trimmed.startsWith('```')) {
1054
+ return undefined;
1055
+ }
1056
+ const m = trimmed.match(/^```([^\s`]*)\s*$/);
1057
+ if (!m) {
1058
+ return undefined;
1059
+ }
1060
+ const group = m[1];
1061
+ if (group === undefined || group.length === 0) {
1062
+ return { language: undefined };
1063
+ }
1064
+ return { language: group };
1065
+ }
1066
+ function isCodeFenceEnd(trimmed) {
1067
+ return /^```\s*$/.test(trimmed);
1068
+ }
1069
+ /**
1070
+ * Match code fence with optional leading attributes like [html]```
1071
+ * Returns the language and whether it's an HTML block
1072
+ */
1073
+ function matchAttributedCodeFence(trimmed) {
1074
+ // Match pattern: optional [attr]... followed by ```language?
1075
+ const match = trimmed.match(/^(\[.+\])*\s*```([^\s`]*)\s*$/);
1076
+ if (!match) {
1077
+ return undefined;
1078
+ }
1079
+ const attrPart = match[1] || '';
1080
+ const language = match[2] || undefined;
1081
+ const isHtml = /\[html\]/i.test(attrPart);
1082
+ return { language, isHtml };
1083
+ }
1084
+ function matchListItem(content, line, column) {
1085
+ const taskMatch = content.match(/^(-+)(\[(.|..)?\])(?:\s+(.*))?$/);
1086
+ if (taskMatch) {
1087
+ const dashes = taskMatch[1];
1088
+ const markerGroup = taskMatch[2];
1089
+ const markerInner = taskMatch[3];
1090
+ const textGroup = taskMatch[4] || '';
1091
+ if (!dashes || !markerGroup) {
1092
+ return undefined;
1093
+ }
1094
+ const indent = dashes.length;
1095
+ const taskStatus = mapTaskStatus(markerInner);
1096
+ const text = textGroup.trimEnd();
1097
+ const textColumn = getListTextColumn(column, taskMatch[0], textGroup);
1098
+ return { kind: 'task', indent, taskStatus, text, line, column: textColumn };
1099
+ }
1100
+ const orderedMatch = content.match(/^(\d+(?:\.\d+)*)\.?\s*(\[(.|..)?\])?(?:\s+(.*))?$/);
1101
+ if (orderedMatch) {
1102
+ const ordinalGroup = orderedMatch[1];
1103
+ const markerGroup = orderedMatch[2];
1104
+ const markerInner = orderedMatch[3];
1105
+ const textGroup = orderedMatch[4] || '';
1106
+ if (!ordinalGroup) {
1107
+ return undefined;
1108
+ }
1109
+ const ordinal = ordinalGroup;
1110
+ const indent = ordinal.split('.').length;
1111
+ const taskStatus = markerGroup ? mapTaskStatus(markerInner) : undefined;
1112
+ const text = textGroup.trimEnd();
1113
+ const textColumn = getListTextColumn(column, orderedMatch[0], textGroup);
1114
+ return { kind: 'ordered', indent, ordinal, taskStatus, text, line, column: textColumn };
1115
+ }
1116
+ const foldableMatch = content.match(/^(\++)(\[(.|..)?\])?(?:\s+(.*))?$/);
1117
+ if (foldableMatch) {
1118
+ const pluses = foldableMatch[1];
1119
+ const markerGroup = foldableMatch[2];
1120
+ const markerInner = foldableMatch[3];
1121
+ const textGroup = foldableMatch[4] || '';
1122
+ if (!pluses) {
1123
+ return undefined;
1124
+ }
1125
+ const indent = pluses.length;
1126
+ const taskStatus = markerGroup ? mapTaskStatus(markerInner) : undefined;
1127
+ const text = textGroup.trimEnd();
1128
+ const textColumn = getListTextColumn(column, foldableMatch[0], textGroup);
1129
+ return {
1130
+ kind: 'foldable',
1131
+ indent,
1132
+ ordinal: ordinalFromIndent(indent),
1133
+ taskStatus,
1134
+ text,
1135
+ line,
1136
+ column: textColumn,
1137
+ };
1138
+ }
1139
+ const bulletMatch = content.match(/^(-+)(?:\s+(.*))?$/);
1140
+ if (bulletMatch) {
1141
+ const dashes = bulletMatch[1];
1142
+ const textGroup = bulletMatch[2] || '';
1143
+ if (!dashes) {
1144
+ return undefined;
1145
+ }
1146
+ const indent = dashes.length;
1147
+ const text = textGroup.trimEnd();
1148
+ const textColumn = getListTextColumn(column, bulletMatch[0], textGroup);
1149
+ return { kind: 'bullet', indent, text, line, column: textColumn };
1150
+ }
1151
+ return undefined;
1152
+ }
1153
+ function getListTextColumn(baseColumn, matchText, rawText) {
1154
+ if (baseColumn === undefined) {
1155
+ return undefined;
1156
+ }
1157
+ const prefixLength = matchText.length - rawText.length;
1158
+ return baseColumn + Math.max(0, prefixLength);
1159
+ }
1160
+ function mapTaskStatus(markerInner) {
1161
+ if (!markerInner || markerInner === '') {
1162
+ return 'unknown';
1163
+ }
1164
+ if (markerInner === 'o') {
1165
+ return 'in_progress';
1166
+ }
1167
+ if (markerInner === 'x') {
1168
+ return 'not_done';
1169
+ }
1170
+ if (markerInner === 'v') {
1171
+ return 'done';
1172
+ }
1173
+ return 'unknown';
1174
+ }
1175
+ function ordinalFromIndent(indent) {
1176
+ if (indent <= 0) {
1177
+ return '1';
1178
+ }
1179
+ return Array(indent).fill('1').join('.');
1180
+ }
1181
+ function buildListItems(matches, startIndex, baseIndent) {
1182
+ const items = [];
1183
+ let index = startIndex;
1184
+ while (index < matches.length) {
1185
+ const current = matches[index];
1186
+ if (!current) {
1187
+ break;
1188
+ }
1189
+ if (current.indent < baseIndent) {
1190
+ break;
1191
+ }
1192
+ if (current.indent > baseIndent) {
1193
+ break;
1194
+ }
1195
+ const paragraph = {
1196
+ type: 'paragraph',
1197
+ children: [{ type: 'text', value: current.text }],
1198
+ };
1199
+ if (current.line !== undefined && current.column !== undefined) {
1200
+ (0, location_1.setNodeLocation)(paragraph, {
1201
+ line: current.line,
1202
+ column: current.column,
1203
+ });
1204
+ }
1205
+ const childrenBlocks = [paragraph];
1206
+ // Add any child blocks (code blocks, etc.) that follow this list item
1207
+ if (current.childBlocks && current.childBlocks.length > 0) {
1208
+ childrenBlocks.push(...current.childBlocks);
1209
+ }
1210
+ index += 1;
1211
+ const next = matches[index];
1212
+ if (next && next.indent > current.indent) {
1213
+ const childResult = buildListItems(matches, index, next.indent);
1214
+ childrenBlocks.push({
1215
+ type: 'list',
1216
+ kind: next.kind,
1217
+ orderedStyle: next.kind === 'ordered' ? 'decimal' : undefined,
1218
+ children: childResult.items,
1219
+ });
1220
+ index = childResult.nextIndex;
1221
+ }
1222
+ const item = {
1223
+ type: 'listItem',
1224
+ kind: current.kind,
1225
+ ordinal: current.ordinal,
1226
+ taskStatus: current.taskStatus,
1227
+ indent: current.indent,
1228
+ children: childrenBlocks,
1229
+ };
1230
+ items.push(item);
1231
+ }
1232
+ return { items, nextIndex: index };
1233
+ }
1234
+ function parseAttributeLine(text, lineNumber, errors, baseAttrs, fallbackPosition, tabCount) {
1235
+ const result = {
1236
+ attrs: undefined,
1237
+ foldNext: false,
1238
+ tagName: undefined,
1239
+ isComment: false,
1240
+ isDisabled: false,
1241
+ isSheet: false,
1242
+ isHtml: false,
1243
+ recognizedAny: false,
1244
+ };
1245
+ let attrs = baseAttrs ? { ...baseAttrs } : undefined;
1246
+ const unknownTokens = [];
1247
+ let arrowCount = 0;
1248
+ let i = 0;
1249
+ while (i < text.length) {
1250
+ const start = text.indexOf('[', i);
1251
+ if (start === -1) {
1252
+ break;
1253
+ }
1254
+ const end = text.indexOf(']', start + 1);
1255
+ if (end === -1) {
1256
+ break;
1257
+ }
1258
+ const inside = text.slice(start + 1, end).trim();
1259
+ if (inside.length === 0) {
1260
+ i = end + 1;
1261
+ continue;
1262
+ }
1263
+ const parts = inside.split(',');
1264
+ for (const rawPart of parts) {
1265
+ const part = rawPart.trim();
1266
+ if (part.length === 0) {
1267
+ continue;
1268
+ }
1269
+ if (part === 'c') {
1270
+ attrs = ensureBlockAttributes(attrs);
1271
+ attrs.align = 'center';
1272
+ result.recognizedAny = true;
1273
+ continue;
1274
+ }
1275
+ if (part === 'r') {
1276
+ attrs = ensureBlockAttributes(attrs);
1277
+ attrs.align = 'right';
1278
+ result.recognizedAny = true;
1279
+ continue;
1280
+ }
1281
+ if (part === '->' || part === '<-' || part === '<->') {
1282
+ arrowCount += 1;
1283
+ result.recognizedAny = true;
1284
+ if (part === '->' && arrowCount > 2) {
1285
+ (0, diagnostics_1.reportParseWarning)(errors, {
1286
+ message: 'More than two [->] attributes in a row; extra [->] will be treated as plain text.',
1287
+ line: lineNumber,
1288
+ code: MULTI_ARROW_WARNING_CODE,
1289
+ });
1290
+ continue;
1291
+ }
1292
+ attrs = ensureBlockAttributes(attrs);
1293
+ if (part === '->' || part === '<->') {
1294
+ const basePosition = attrs.position ??
1295
+ fallbackPosition ??
1296
+ (tabCount !== undefined ? mapTabsToPosition(tabCount) : undefined);
1297
+ attrs.position = shiftPositionRight(basePosition);
1298
+ attrs.sameLine = true;
1299
+ }
1300
+ if (part === '<-' || part === '<->') {
1301
+ attrs.truncateRight = true;
1302
+ }
1303
+ continue;
1304
+ }
1305
+ if (part === 'fold') {
1306
+ result.foldNext = true;
1307
+ result.recognizedAny = true;
1308
+ continue;
1309
+ }
1310
+ if (part === 'sheet') {
1311
+ result.isSheet = true;
1312
+ result.recognizedAny = true;
1313
+ continue;
1314
+ }
1315
+ if (part === 'html') {
1316
+ result.isHtml = true;
1317
+ result.recognizedAny = true;
1318
+ continue;
1319
+ }
1320
+ if (part === 'comment') {
1321
+ result.isComment = true;
1322
+ result.recognizedAny = true;
1323
+ continue;
1324
+ }
1325
+ if (part === 'disable' || part === 'd') {
1326
+ result.isDisabled = true;
1327
+ result.recognizedAny = true;
1328
+ continue;
1329
+ }
1330
+ if (part.startsWith('tag=')) {
1331
+ result.tagName = part.slice('tag='.length);
1332
+ result.recognizedAny = true;
1333
+ continue;
1334
+ }
1335
+ if (part.startsWith('t=')) {
1336
+ result.tagName = part.slice(2);
1337
+ result.recognizedAny = true;
1338
+ continue;
1339
+ }
1340
+ if (part.startsWith('f=')) {
1341
+ result.tagName = part.slice(2);
1342
+ result.recognizedAny = true;
1343
+ continue;
1344
+ }
1345
+ unknownTokens.push(part);
1346
+ continue;
1347
+ }
1348
+ i = end + 1;
1349
+ }
1350
+ if (!result.recognizedAny && unknownTokens.length > 0) {
1351
+ for (const token of unknownTokens) {
1352
+ (0, diagnostics_1.reportParseWarning)(errors, {
1353
+ message: `Unknown block attribute token "${token}"`,
1354
+ line: lineNumber,
1355
+ code: UNKNOWN_ATTRIBUTE_WARNING_CODE,
1356
+ });
1357
+ }
1358
+ }
1359
+ result.attrs = attrs;
1360
+ return result;
1361
+ }
1362
+ function ensureBlockAttributes(attrs) {
1363
+ if (attrs) {
1364
+ return attrs;
1365
+ }
1366
+ return {};
1367
+ }
1368
+ function mergeBlockAttributes(base, extra) {
1369
+ if (!base) {
1370
+ return { ...extra };
1371
+ }
1372
+ return { ...base, ...extra };
1373
+ }
1374
+ function shiftPositionRight(position) {
1375
+ if (position === 'L') {
1376
+ return 'C';
1377
+ }
1378
+ if (position === 'C') {
1379
+ return 'R';
1380
+ }
1381
+ if (position === 'R') {
1382
+ return 'R';
1383
+ }
1384
+ return 'C';
1385
+ }