@orkestrel/markdown 0.0.7 → 0.0.9

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.
@@ -544,152 +544,6 @@ function parseBlocks(lines, depth) {
544
544
  return blocks;
545
545
  }
546
546
  /**
547
- * Collects a GFM table starting at a header row, parsing the header, the
548
- * alignment row, and every contiguous body row that follows.
549
- *
550
- * @param lines - The markdown lines to scan.
551
- * @param start - The index of the header row.
552
- * @returns The parsed table node and the index of the first line after it.
553
- *
554
- * @example
555
- * ```ts
556
- * collectTable(['| a |', '| - |'], 0) // { node: { element: 'table', ... }, next: 2 }
557
- * ```
558
- */
559
- function collectTable(lines, start) {
560
- const headerCells = splitTableRow(lines[start] ?? "");
561
- const columns = headerCells.length;
562
- const header = headerCells.map((cell) => parseInline(cell.trim()));
563
- const align = delimiterToAlignments(lines[start + 1] ?? "");
564
- const padded = [];
565
- for (let column = 0; column < columns; column += 1) padded.push(align[column] ?? null);
566
- const rows = [];
567
- let index = start + 2;
568
- while (index < lines.length && !isBlankLine(lines[index] ?? "") && (lines[index] ?? "").includes("|")) {
569
- const cells = splitTableRow(lines[index] ?? "");
570
- const row = [];
571
- for (let column = 0; column < columns; column += 1) row.push(parseInline((cells[column] ?? "").trim()));
572
- rows.push(row);
573
- index += 1;
574
- }
575
- return {
576
- node: {
577
- element: "table",
578
- header,
579
- rows,
580
- align: padded
581
- },
582
- next: index
583
- };
584
- }
585
- /**
586
- * Collects a list starting at the first item, gathering sibling items at the
587
- * same indent/ordering and recursing into each item's own block content.
588
- *
589
- * @param lines - The markdown lines to scan.
590
- * @param start - The index of the first list item.
591
- * @param depth - The current recursion depth (each item recurses at `depth + 1`).
592
- * @returns The parsed list node and the index of the first line after it.
593
- *
594
- * @example
595
- * ```ts
596
- * collectList(['- item'], 0, 0) // { node: { element: 'list', ... }, next: 1 }
597
- * ```
598
- */
599
- function collectList(lines, start, depth) {
600
- const first = extractListItem(lines[start] ?? "");
601
- const ordered = first?.ordered ?? false;
602
- const startOrdinal = first?.start ?? 1;
603
- const topIndent = first?.indent ?? 0;
604
- const items = [];
605
- const chain = [];
606
- let nested = true;
607
- for (let cursor = start; cursor < lines.length; cursor += 1) {
608
- const parsed = extractListItem(lines[cursor] ?? "");
609
- const previous = chain[chain.length - 1];
610
- if (parsed === void 0 || previous !== void 0 && (previous.content.length > 0 || parsed.indent !== previous.marker)) {
611
- nested = false;
612
- break;
613
- }
614
- chain.push(parsed);
615
- }
616
- const remaining = 64 - depth;
617
- if (nested && remaining > 0 && chain.length > remaining) {
618
- const terminal = chain[remaining - 1];
619
- if (terminal !== void 0) {
620
- const source = [terminal.content];
621
- for (let cursor = start + remaining; cursor < lines.length; cursor += 1) source.push((lines[cursor] ?? "").slice(terminal.marker));
622
- let children = [{
623
- element: "paragraph",
624
- children: [{
625
- element: "text",
626
- value: source.join("\n")
627
- }]
628
- }];
629
- let node;
630
- for (let cursor = remaining - 1; cursor >= 0; cursor -= 1) {
631
- const parsed = chain[cursor];
632
- if (parsed === void 0) continue;
633
- node = {
634
- element: "list",
635
- ordered: parsed.ordered,
636
- start: parsed.start,
637
- items: [{
638
- element: "listItem",
639
- children
640
- }]
641
- };
642
- children = [node];
643
- }
644
- if (node !== void 0) return {
645
- node,
646
- next: lines.length
647
- };
648
- }
649
- }
650
- let index = start;
651
- while (index < lines.length) {
652
- const parsed = extractListItem(lines[index] ?? "");
653
- if (!parsed || parsed.indent > topIndent || parsed.ordered !== ordered) break;
654
- const itemLines = [parsed.content];
655
- const continuation = parsed.marker;
656
- index += 1;
657
- while (index < lines.length) {
658
- const next = lines[index] ?? "";
659
- if (isBlankLine(next)) {
660
- const after = lines[index + 1] ?? "";
661
- if (index + 1 < lines.length && !isBlankLine(after) && countIndent(after) >= continuation) {
662
- itemLines.push("");
663
- index += 1;
664
- continue;
665
- }
666
- break;
667
- }
668
- if (countIndent(next) >= continuation) {
669
- itemLines.push(next.slice(continuation));
670
- index += 1;
671
- continue;
672
- }
673
- if (extractListItem(next) || startsBlock(lines, index)) break;
674
- itemLines.push(next.trim());
675
- index += 1;
676
- }
677
- items.push({
678
- element: "listItem",
679
- children: parseBlocks(itemLines, depth + 1)
680
- });
681
- }
682
- return {
683
- node: {
684
- element: "list",
685
- ordered,
686
- start: startOrdinal,
687
- items
688
- },
689
- next: index
690
- };
691
- }
692
- /**
693
547
  * Parses a markdown string into a typed {@link MarkdownDocument} AST via the
694
548
  * block phase.
695
549
  *
@@ -1644,6 +1498,152 @@ function scanInline(source, from, to, depth = 0) {
1644
1498
  return nodes;
1645
1499
  }
1646
1500
  /**
1501
+ * Collects a GFM table starting at a header row, parsing the header, the
1502
+ * alignment row, and every contiguous body row that follows.
1503
+ *
1504
+ * @param lines - The markdown lines to scan.
1505
+ * @param start - The index of the header row.
1506
+ * @returns The parsed table node and the index of the first line after it.
1507
+ *
1508
+ * @example
1509
+ * ```ts
1510
+ * collectTable(['| a |', '| - |'], 0) // { node: { element: 'table', ... }, next: 2 }
1511
+ * ```
1512
+ */
1513
+ function collectTable(lines, start) {
1514
+ const headerCells = splitTableRow(lines[start] ?? "");
1515
+ const columns = headerCells.length;
1516
+ const header = headerCells.map((cell) => parseInline(cell.trim()));
1517
+ const align = delimiterToAlignments(lines[start + 1] ?? "");
1518
+ const padded = [];
1519
+ for (let column = 0; column < columns; column += 1) padded.push(align[column] ?? null);
1520
+ const rows = [];
1521
+ let index = start + 2;
1522
+ while (index < lines.length && !isBlankLine(lines[index] ?? "") && (lines[index] ?? "").includes("|")) {
1523
+ const cells = splitTableRow(lines[index] ?? "");
1524
+ const row = [];
1525
+ for (let column = 0; column < columns; column += 1) row.push(parseInline((cells[column] ?? "").trim()));
1526
+ rows.push(row);
1527
+ index += 1;
1528
+ }
1529
+ return {
1530
+ node: {
1531
+ element: "table",
1532
+ header,
1533
+ rows,
1534
+ align: padded
1535
+ },
1536
+ next: index
1537
+ };
1538
+ }
1539
+ /**
1540
+ * Collects a list starting at the first item, gathering sibling items at the
1541
+ * same indent/ordering and recursing into each item's own block content.
1542
+ *
1543
+ * @param lines - The markdown lines to scan.
1544
+ * @param start - The index of the first list item.
1545
+ * @param depth - The current recursion depth (each item recurses at `depth + 1`).
1546
+ * @returns The parsed list node and the index of the first line after it.
1547
+ *
1548
+ * @example
1549
+ * ```ts
1550
+ * collectList(['- item'], 0, 0) // { node: { element: 'list', ... }, next: 1 }
1551
+ * ```
1552
+ */
1553
+ function collectList(lines, start, depth) {
1554
+ const first = extractListItem(lines[start] ?? "");
1555
+ const ordered = first?.ordered ?? false;
1556
+ const startOrdinal = first?.start ?? 1;
1557
+ const topIndent = first?.indent ?? 0;
1558
+ const items = [];
1559
+ const chain = [];
1560
+ let nested = true;
1561
+ for (let cursor = start; cursor < lines.length; cursor += 1) {
1562
+ const parsed = extractListItem(lines[cursor] ?? "");
1563
+ const previous = chain[chain.length - 1];
1564
+ if (parsed === void 0 || previous !== void 0 && (previous.content.length > 0 || parsed.indent !== previous.marker)) {
1565
+ nested = false;
1566
+ break;
1567
+ }
1568
+ chain.push(parsed);
1569
+ }
1570
+ const remaining = 64 - depth;
1571
+ if (nested && remaining > 0 && chain.length > remaining) {
1572
+ const terminal = chain[remaining - 1];
1573
+ if (terminal !== void 0) {
1574
+ const source = [terminal.content];
1575
+ for (let cursor = start + remaining; cursor < lines.length; cursor += 1) source.push((lines[cursor] ?? "").slice(terminal.marker));
1576
+ let children = [{
1577
+ element: "paragraph",
1578
+ children: [{
1579
+ element: "text",
1580
+ value: source.join("\n")
1581
+ }]
1582
+ }];
1583
+ let node;
1584
+ for (let cursor = remaining - 1; cursor >= 0; cursor -= 1) {
1585
+ const parsed = chain[cursor];
1586
+ if (parsed === void 0) continue;
1587
+ node = {
1588
+ element: "list",
1589
+ ordered: parsed.ordered,
1590
+ start: parsed.start,
1591
+ items: [{
1592
+ element: "listItem",
1593
+ children
1594
+ }]
1595
+ };
1596
+ children = [node];
1597
+ }
1598
+ if (node !== void 0) return {
1599
+ node,
1600
+ next: lines.length
1601
+ };
1602
+ }
1603
+ }
1604
+ let index = start;
1605
+ while (index < lines.length) {
1606
+ const parsed = extractListItem(lines[index] ?? "");
1607
+ if (!parsed || parsed.indent > topIndent || parsed.ordered !== ordered) break;
1608
+ const itemLines = [parsed.content];
1609
+ const continuation = parsed.marker;
1610
+ index += 1;
1611
+ while (index < lines.length) {
1612
+ const next = lines[index] ?? "";
1613
+ if (isBlankLine(next)) {
1614
+ const after = lines[index + 1] ?? "";
1615
+ if (index + 1 < lines.length && !isBlankLine(after) && countIndent(after) >= continuation) {
1616
+ itemLines.push("");
1617
+ index += 1;
1618
+ continue;
1619
+ }
1620
+ break;
1621
+ }
1622
+ if (countIndent(next) >= continuation) {
1623
+ itemLines.push(next.slice(continuation));
1624
+ index += 1;
1625
+ continue;
1626
+ }
1627
+ if (extractListItem(next) || startsBlock(lines, index)) break;
1628
+ itemLines.push(next.trim());
1629
+ index += 1;
1630
+ }
1631
+ items.push({
1632
+ element: "listItem",
1633
+ children: parseBlocks(itemLines, depth + 1)
1634
+ });
1635
+ }
1636
+ return {
1637
+ node: {
1638
+ element: "list",
1639
+ ordered,
1640
+ start: startOrdinal,
1641
+ items
1642
+ },
1643
+ next: index
1644
+ };
1645
+ }
1646
+ /**
1647
1647
  * Project a {@link MarkdownNode} into an unsanitized {@link HTMLDocument}.
1648
1648
  *
1649
1649
  * @remarks
@@ -297,7 +297,7 @@ export declare function createThematicBreakContract(): ContractInterface<Themati
297
297
  * delimiterToAlignments('| :--- | ---: |') // ['left', 'right']
298
298
  * ```
299
299
  */
300
- export declare function delimiterToAlignments(delimiter: string): readonly (TableAlign | null)[];
300
+ export declare function delimiterToAlignments(delimiter: string): ReadonlyArray<TableAlign | null>;
301
301
 
302
302
  /**
303
303
  * Emphasized inline content - `*italic*` / `_italic_` (`strong: false`) or
@@ -1184,7 +1184,7 @@ export declare interface MarkdownProjection {
1184
1184
  /** The cells this node contributes to an enclosing row. */
1185
1185
  readonly cells: readonly MarkdownCell[];
1186
1186
  /** The rows this node contributes to an enclosing table - each its cells, in column order. */
1187
- readonly rows: readonly (readonly MarkdownCell[])[];
1187
+ readonly rows: ReadonlyArray<readonly MarkdownCell[]>;
1188
1188
  }
1189
1189
 
1190
1190
  /**
@@ -1701,16 +1701,16 @@ export declare const tableAlignShape: LiteralShape<readonly ["left", "right", "c
1701
1701
  export declare interface TableNode {
1702
1702
  readonly element: 'table';
1703
1703
  /** The header row - one cell of inline content per column. */
1704
- readonly header: readonly (readonly InlineNode[])[];
1704
+ readonly header: ReadonlyArray<readonly InlineNode[]>;
1705
1705
  /** The body rows - each a list of cells, each cell inline content. */
1706
- readonly rows: readonly (readonly (readonly InlineNode[])[])[];
1706
+ readonly rows: ReadonlyArray<ReadonlyArray<readonly InlineNode[]>>;
1707
1707
  /**
1708
1708
  * The per-column alignment from the delimiter row, in column order. `null`
1709
1709
  * represents a bare `---` delimiter because this positional array requires one
1710
1710
  * entry per column, JSON cannot carry `undefined` in an array, and the delimiter
1711
1711
  * is an explicit no-alignment marker rather than an omitted value.
1712
1712
  */
1713
- readonly align: readonly (TableAlign | null)[];
1713
+ readonly align: ReadonlyArray<TableAlign | null>;
1714
1714
  }
1715
1715
 
1716
1716
  /**
@@ -297,7 +297,7 @@ export declare function createThematicBreakContract(): ContractInterface<Themati
297
297
  * delimiterToAlignments('| :--- | ---: |') // ['left', 'right']
298
298
  * ```
299
299
  */
300
- export declare function delimiterToAlignments(delimiter: string): readonly (TableAlign | null)[];
300
+ export declare function delimiterToAlignments(delimiter: string): ReadonlyArray<TableAlign | null>;
301
301
 
302
302
  /**
303
303
  * Emphasized inline content - `*italic*` / `_italic_` (`strong: false`) or
@@ -1184,7 +1184,7 @@ export declare interface MarkdownProjection {
1184
1184
  /** The cells this node contributes to an enclosing row. */
1185
1185
  readonly cells: readonly MarkdownCell[];
1186
1186
  /** The rows this node contributes to an enclosing table - each its cells, in column order. */
1187
- readonly rows: readonly (readonly MarkdownCell[])[];
1187
+ readonly rows: ReadonlyArray<readonly MarkdownCell[]>;
1188
1188
  }
1189
1189
 
1190
1190
  /**
@@ -1701,16 +1701,16 @@ export declare const tableAlignShape: LiteralShape<readonly ["left", "right", "c
1701
1701
  export declare interface TableNode {
1702
1702
  readonly element: 'table';
1703
1703
  /** The header row - one cell of inline content per column. */
1704
- readonly header: readonly (readonly InlineNode[])[];
1704
+ readonly header: ReadonlyArray<readonly InlineNode[]>;
1705
1705
  /** The body rows - each a list of cells, each cell inline content. */
1706
- readonly rows: readonly (readonly (readonly InlineNode[])[])[];
1706
+ readonly rows: ReadonlyArray<ReadonlyArray<readonly InlineNode[]>>;
1707
1707
  /**
1708
1708
  * The per-column alignment from the delimiter row, in column order. `null`
1709
1709
  * represents a bare `---` delimiter because this positional array requires one
1710
1710
  * entry per column, JSON cannot carry `undefined` in an array, and the delimiter
1711
1711
  * is an explicit no-alignment marker rather than an omitted value.
1712
1712
  */
1713
- readonly align: readonly (TableAlign | null)[];
1713
+ readonly align: ReadonlyArray<TableAlign | null>;
1714
1714
  }
1715
1715
 
1716
1716
  /**
@@ -543,152 +543,6 @@ function parseBlocks(lines, depth) {
543
543
  return blocks;
544
544
  }
545
545
  /**
546
- * Collects a GFM table starting at a header row, parsing the header, the
547
- * alignment row, and every contiguous body row that follows.
548
- *
549
- * @param lines - The markdown lines to scan.
550
- * @param start - The index of the header row.
551
- * @returns The parsed table node and the index of the first line after it.
552
- *
553
- * @example
554
- * ```ts
555
- * collectTable(['| a |', '| - |'], 0) // { node: { element: 'table', ... }, next: 2 }
556
- * ```
557
- */
558
- function collectTable(lines, start) {
559
- const headerCells = splitTableRow(lines[start] ?? "");
560
- const columns = headerCells.length;
561
- const header = headerCells.map((cell) => parseInline(cell.trim()));
562
- const align = delimiterToAlignments(lines[start + 1] ?? "");
563
- const padded = [];
564
- for (let column = 0; column < columns; column += 1) padded.push(align[column] ?? null);
565
- const rows = [];
566
- let index = start + 2;
567
- while (index < lines.length && !isBlankLine(lines[index] ?? "") && (lines[index] ?? "").includes("|")) {
568
- const cells = splitTableRow(lines[index] ?? "");
569
- const row = [];
570
- for (let column = 0; column < columns; column += 1) row.push(parseInline((cells[column] ?? "").trim()));
571
- rows.push(row);
572
- index += 1;
573
- }
574
- return {
575
- node: {
576
- element: "table",
577
- header,
578
- rows,
579
- align: padded
580
- },
581
- next: index
582
- };
583
- }
584
- /**
585
- * Collects a list starting at the first item, gathering sibling items at the
586
- * same indent/ordering and recursing into each item's own block content.
587
- *
588
- * @param lines - The markdown lines to scan.
589
- * @param start - The index of the first list item.
590
- * @param depth - The current recursion depth (each item recurses at `depth + 1`).
591
- * @returns The parsed list node and the index of the first line after it.
592
- *
593
- * @example
594
- * ```ts
595
- * collectList(['- item'], 0, 0) // { node: { element: 'list', ... }, next: 1 }
596
- * ```
597
- */
598
- function collectList(lines, start, depth) {
599
- const first = extractListItem(lines[start] ?? "");
600
- const ordered = first?.ordered ?? false;
601
- const startOrdinal = first?.start ?? 1;
602
- const topIndent = first?.indent ?? 0;
603
- const items = [];
604
- const chain = [];
605
- let nested = true;
606
- for (let cursor = start; cursor < lines.length; cursor += 1) {
607
- const parsed = extractListItem(lines[cursor] ?? "");
608
- const previous = chain[chain.length - 1];
609
- if (parsed === void 0 || previous !== void 0 && (previous.content.length > 0 || parsed.indent !== previous.marker)) {
610
- nested = false;
611
- break;
612
- }
613
- chain.push(parsed);
614
- }
615
- const remaining = 64 - depth;
616
- if (nested && remaining > 0 && chain.length > remaining) {
617
- const terminal = chain[remaining - 1];
618
- if (terminal !== void 0) {
619
- const source = [terminal.content];
620
- for (let cursor = start + remaining; cursor < lines.length; cursor += 1) source.push((lines[cursor] ?? "").slice(terminal.marker));
621
- let children = [{
622
- element: "paragraph",
623
- children: [{
624
- element: "text",
625
- value: source.join("\n")
626
- }]
627
- }];
628
- let node;
629
- for (let cursor = remaining - 1; cursor >= 0; cursor -= 1) {
630
- const parsed = chain[cursor];
631
- if (parsed === void 0) continue;
632
- node = {
633
- element: "list",
634
- ordered: parsed.ordered,
635
- start: parsed.start,
636
- items: [{
637
- element: "listItem",
638
- children
639
- }]
640
- };
641
- children = [node];
642
- }
643
- if (node !== void 0) return {
644
- node,
645
- next: lines.length
646
- };
647
- }
648
- }
649
- let index = start;
650
- while (index < lines.length) {
651
- const parsed = extractListItem(lines[index] ?? "");
652
- if (!parsed || parsed.indent > topIndent || parsed.ordered !== ordered) break;
653
- const itemLines = [parsed.content];
654
- const continuation = parsed.marker;
655
- index += 1;
656
- while (index < lines.length) {
657
- const next = lines[index] ?? "";
658
- if (isBlankLine(next)) {
659
- const after = lines[index + 1] ?? "";
660
- if (index + 1 < lines.length && !isBlankLine(after) && countIndent(after) >= continuation) {
661
- itemLines.push("");
662
- index += 1;
663
- continue;
664
- }
665
- break;
666
- }
667
- if (countIndent(next) >= continuation) {
668
- itemLines.push(next.slice(continuation));
669
- index += 1;
670
- continue;
671
- }
672
- if (extractListItem(next) || startsBlock(lines, index)) break;
673
- itemLines.push(next.trim());
674
- index += 1;
675
- }
676
- items.push({
677
- element: "listItem",
678
- children: parseBlocks(itemLines, depth + 1)
679
- });
680
- }
681
- return {
682
- node: {
683
- element: "list",
684
- ordered,
685
- start: startOrdinal,
686
- items
687
- },
688
- next: index
689
- };
690
- }
691
- /**
692
546
  * Parses a markdown string into a typed {@link MarkdownDocument} AST via the
693
547
  * block phase.
694
548
  *
@@ -1643,6 +1497,152 @@ function scanInline(source, from, to, depth = 0) {
1643
1497
  return nodes;
1644
1498
  }
1645
1499
  /**
1500
+ * Collects a GFM table starting at a header row, parsing the header, the
1501
+ * alignment row, and every contiguous body row that follows.
1502
+ *
1503
+ * @param lines - The markdown lines to scan.
1504
+ * @param start - The index of the header row.
1505
+ * @returns The parsed table node and the index of the first line after it.
1506
+ *
1507
+ * @example
1508
+ * ```ts
1509
+ * collectTable(['| a |', '| - |'], 0) // { node: { element: 'table', ... }, next: 2 }
1510
+ * ```
1511
+ */
1512
+ function collectTable(lines, start) {
1513
+ const headerCells = splitTableRow(lines[start] ?? "");
1514
+ const columns = headerCells.length;
1515
+ const header = headerCells.map((cell) => parseInline(cell.trim()));
1516
+ const align = delimiterToAlignments(lines[start + 1] ?? "");
1517
+ const padded = [];
1518
+ for (let column = 0; column < columns; column += 1) padded.push(align[column] ?? null);
1519
+ const rows = [];
1520
+ let index = start + 2;
1521
+ while (index < lines.length && !isBlankLine(lines[index] ?? "") && (lines[index] ?? "").includes("|")) {
1522
+ const cells = splitTableRow(lines[index] ?? "");
1523
+ const row = [];
1524
+ for (let column = 0; column < columns; column += 1) row.push(parseInline((cells[column] ?? "").trim()));
1525
+ rows.push(row);
1526
+ index += 1;
1527
+ }
1528
+ return {
1529
+ node: {
1530
+ element: "table",
1531
+ header,
1532
+ rows,
1533
+ align: padded
1534
+ },
1535
+ next: index
1536
+ };
1537
+ }
1538
+ /**
1539
+ * Collects a list starting at the first item, gathering sibling items at the
1540
+ * same indent/ordering and recursing into each item's own block content.
1541
+ *
1542
+ * @param lines - The markdown lines to scan.
1543
+ * @param start - The index of the first list item.
1544
+ * @param depth - The current recursion depth (each item recurses at `depth + 1`).
1545
+ * @returns The parsed list node and the index of the first line after it.
1546
+ *
1547
+ * @example
1548
+ * ```ts
1549
+ * collectList(['- item'], 0, 0) // { node: { element: 'list', ... }, next: 1 }
1550
+ * ```
1551
+ */
1552
+ function collectList(lines, start, depth) {
1553
+ const first = extractListItem(lines[start] ?? "");
1554
+ const ordered = first?.ordered ?? false;
1555
+ const startOrdinal = first?.start ?? 1;
1556
+ const topIndent = first?.indent ?? 0;
1557
+ const items = [];
1558
+ const chain = [];
1559
+ let nested = true;
1560
+ for (let cursor = start; cursor < lines.length; cursor += 1) {
1561
+ const parsed = extractListItem(lines[cursor] ?? "");
1562
+ const previous = chain[chain.length - 1];
1563
+ if (parsed === void 0 || previous !== void 0 && (previous.content.length > 0 || parsed.indent !== previous.marker)) {
1564
+ nested = false;
1565
+ break;
1566
+ }
1567
+ chain.push(parsed);
1568
+ }
1569
+ const remaining = 64 - depth;
1570
+ if (nested && remaining > 0 && chain.length > remaining) {
1571
+ const terminal = chain[remaining - 1];
1572
+ if (terminal !== void 0) {
1573
+ const source = [terminal.content];
1574
+ for (let cursor = start + remaining; cursor < lines.length; cursor += 1) source.push((lines[cursor] ?? "").slice(terminal.marker));
1575
+ let children = [{
1576
+ element: "paragraph",
1577
+ children: [{
1578
+ element: "text",
1579
+ value: source.join("\n")
1580
+ }]
1581
+ }];
1582
+ let node;
1583
+ for (let cursor = remaining - 1; cursor >= 0; cursor -= 1) {
1584
+ const parsed = chain[cursor];
1585
+ if (parsed === void 0) continue;
1586
+ node = {
1587
+ element: "list",
1588
+ ordered: parsed.ordered,
1589
+ start: parsed.start,
1590
+ items: [{
1591
+ element: "listItem",
1592
+ children
1593
+ }]
1594
+ };
1595
+ children = [node];
1596
+ }
1597
+ if (node !== void 0) return {
1598
+ node,
1599
+ next: lines.length
1600
+ };
1601
+ }
1602
+ }
1603
+ let index = start;
1604
+ while (index < lines.length) {
1605
+ const parsed = extractListItem(lines[index] ?? "");
1606
+ if (!parsed || parsed.indent > topIndent || parsed.ordered !== ordered) break;
1607
+ const itemLines = [parsed.content];
1608
+ const continuation = parsed.marker;
1609
+ index += 1;
1610
+ while (index < lines.length) {
1611
+ const next = lines[index] ?? "";
1612
+ if (isBlankLine(next)) {
1613
+ const after = lines[index + 1] ?? "";
1614
+ if (index + 1 < lines.length && !isBlankLine(after) && countIndent(after) >= continuation) {
1615
+ itemLines.push("");
1616
+ index += 1;
1617
+ continue;
1618
+ }
1619
+ break;
1620
+ }
1621
+ if (countIndent(next) >= continuation) {
1622
+ itemLines.push(next.slice(continuation));
1623
+ index += 1;
1624
+ continue;
1625
+ }
1626
+ if (extractListItem(next) || startsBlock(lines, index)) break;
1627
+ itemLines.push(next.trim());
1628
+ index += 1;
1629
+ }
1630
+ items.push({
1631
+ element: "listItem",
1632
+ children: parseBlocks(itemLines, depth + 1)
1633
+ });
1634
+ }
1635
+ return {
1636
+ node: {
1637
+ element: "list",
1638
+ ordered,
1639
+ start: startOrdinal,
1640
+ items
1641
+ },
1642
+ next: index
1643
+ };
1644
+ }
1645
+ /**
1646
1646
  * Project a {@link MarkdownNode} into an unsanitized {@link HTMLDocument}.
1647
1647
  *
1648
1648
  * @remarks