@orkestrel/markdown 0.0.5 → 0.0.6

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.
@@ -863,15 +863,6 @@ function scanInline(source, from, to, depth = 0) {
863
863
  const nodes = [];
864
864
  let index = from;
865
865
  let pending = "";
866
- const flush = () => {
867
- if (pending.length > 0) {
868
- nodes.push({
869
- element: "text",
870
- value: pending
871
- });
872
- pending = "";
873
- }
874
- };
875
866
  while (index < to) {
876
867
  const character = source[index] ?? "";
877
868
  if (character === "\\" && index + 1 < to && isEscapable(source[index + 1] ?? "")) {
@@ -879,40 +870,51 @@ function scanInline(source, from, to, depth = 0) {
879
870
  index += 2;
880
871
  continue;
881
872
  }
873
+ let scanned;
874
+ let end = index;
882
875
  if (character === "`") {
883
876
  const span = scanCode(source, index, to);
884
877
  if (span) {
885
- flush();
886
- nodes.push({
878
+ scanned = {
887
879
  element: "codeSpan",
888
880
  value: span.value
889
- });
890
- index = span.end;
891
- continue;
881
+ };
882
+ end = span.end;
892
883
  }
893
884
  }
894
885
  if (character === "[") {
895
886
  const link = scanLink(source, index, to, depth);
896
887
  if (link) {
897
- flush();
898
- nodes.push(link.node);
899
- index = link.end;
900
- continue;
888
+ scanned = link.node;
889
+ end = link.end;
901
890
  }
902
891
  }
903
892
  if (character === "*" || character === "_") {
904
893
  const emphasis = scanEmphasis(source, index, to, depth);
905
894
  if (emphasis) {
906
- flush();
907
- nodes.push(emphasis.node);
908
- index = emphasis.end;
909
- continue;
895
+ scanned = emphasis.node;
896
+ end = emphasis.end;
910
897
  }
911
898
  }
899
+ if (scanned !== void 0) {
900
+ if (pending.length > 0) {
901
+ nodes.push({
902
+ element: "text",
903
+ value: pending
904
+ });
905
+ pending = "";
906
+ }
907
+ nodes.push(scanned);
908
+ index = end;
909
+ continue;
910
+ }
912
911
  pending += character;
913
912
  index += 1;
914
913
  }
915
- flush();
914
+ if (pending.length > 0) nodes.push({
915
+ element: "text",
916
+ value: pending
917
+ });
916
918
  return nodes;
917
919
  }
918
920
  /**
@@ -971,10 +973,7 @@ function sanitizeUrl(href) {
971
973
  * @remarks
972
974
  * Total: never throws. At {@link MAX_DEPTH} a value-bearing node (`text` / `codeSpan`)
973
975
  * degrades to its escaped `value`; any other node degrades to `''` instead of
974
- * recursing further, so pathologically deep input cannot exhaust the call stack. The
975
- * recursive engine and its per-shape sub-steps (inline concatenation, table cell,
976
- * tight list-item) are nested inner functions - the only exported surface is
977
- * `renderHTML` itself.
976
+ * recursing further, so pathologically deep input cannot exhaust the call stack.
978
977
  *
979
978
  * @param node - The AST node to render (a full document, or any sub-node)
980
979
  * @returns The rendered, XSS-safe HTML string
@@ -988,47 +987,158 @@ function sanitizeUrl(href) {
988
987
  * ```
989
988
  */
990
989
  function renderHTML(node) {
991
- function render(current, depth) {
992
- if (depth >= 64) return "value" in current && typeof current.value === "string" ? escapeHtml(current.value) : "";
990
+ const stack = [{
991
+ node,
992
+ depth: 0,
993
+ expanded: false,
994
+ count: 0
995
+ }];
996
+ const values = [];
997
+ while (stack.length > 0) {
998
+ const frame = stack.pop();
999
+ if (frame === void 0) continue;
1000
+ const current = frame.node;
1001
+ if (!frame.expanded) {
1002
+ if (frame.depth >= 64) {
1003
+ values.push("value" in current && typeof current.value === "string" ? escapeHtml(current.value) : "");
1004
+ continue;
1005
+ }
1006
+ const children = [];
1007
+ let depth = frame.depth + 1;
1008
+ switch (current.element) {
1009
+ case "document":
1010
+ case "heading":
1011
+ case "paragraph":
1012
+ case "blockquote":
1013
+ for (const child of current.children) if (child !== void 0) children.push(child);
1014
+ break;
1015
+ case "listItem": {
1016
+ const only = current.children[0];
1017
+ if (current.children.length === 1 && only !== void 0 && only.element === "paragraph") {
1018
+ for (const child of only.children) if (child !== void 0) children.push(child);
1019
+ } else for (const child of current.children) if (child !== void 0) children.push(child);
1020
+ break;
1021
+ }
1022
+ case "emphasis":
1023
+ case "link":
1024
+ for (const child of current.children) if (child !== void 0) children.push(child);
1025
+ depth += 1;
1026
+ break;
1027
+ case "list":
1028
+ for (const child of current.items) if (child !== void 0) children.push(child);
1029
+ break;
1030
+ case "table":
1031
+ for (const cell of current.header) if (cell !== void 0) {
1032
+ for (const child of cell) if (child !== void 0) children.push(child);
1033
+ }
1034
+ for (const row of current.rows) if (row !== void 0) {
1035
+ for (const cell of row) if (cell !== void 0) {
1036
+ for (const child of cell) if (child !== void 0) children.push(child);
1037
+ }
1038
+ }
1039
+ depth += 1;
1040
+ break;
1041
+ }
1042
+ stack.push({
1043
+ ...frame,
1044
+ expanded: true,
1045
+ count: children.length
1046
+ });
1047
+ for (let index = children.length - 1; index >= 0; index -= 1) {
1048
+ const child = children[index];
1049
+ if (child !== void 0) stack.push({
1050
+ node: child,
1051
+ depth,
1052
+ expanded: false,
1053
+ count: 0
1054
+ });
1055
+ }
1056
+ continue;
1057
+ }
1058
+ const children = frame.count === 0 ? [] : values.splice(values.length - frame.count, frame.count);
1059
+ let value = "";
993
1060
  switch (current.element) {
994
- case "document": return current.children.map((child) => render(child, depth + 1)).join("\n");
995
- case "heading": return `<h${current.level}>${renderInline(current.children, depth)}</h${current.level}>`;
996
- case "paragraph": return `<p>${renderInline(current.children, depth)}</p>`;
997
- case "thematicBreak": return "<hr>";
998
- case "blockquote": return `<blockquote>\n${current.children.map((child) => render(child, depth + 1)).join("\n")}\n</blockquote>`;
999
- case "codeBlock": return `<pre>${current.lang === void 0 ? "<code>" : `<code class="language-${escapeHtml(current.lang)}">`}${escapeHtml(current.code)}</code></pre>`;
1061
+ case "document":
1062
+ value = children.join("\n");
1063
+ break;
1064
+ case "heading":
1065
+ value = `<h${current.level}>${children.join("")}</h${current.level}>`;
1066
+ break;
1067
+ case "paragraph":
1068
+ value = `<p>${children.join("")}</p>`;
1069
+ break;
1070
+ case "thematicBreak":
1071
+ value = "<hr>";
1072
+ break;
1073
+ case "blockquote":
1074
+ value = `<blockquote>\n${children.join("\n")}\n</blockquote>`;
1075
+ break;
1076
+ case "codeBlock":
1077
+ value = `<pre>${current.lang === void 0 ? "<code>" : `<code class="language-${escapeHtml(current.lang)}">`}${escapeHtml(current.code)}</code></pre>`;
1078
+ break;
1000
1079
  case "list": {
1001
- const items = current.items.map((item) => render(item, depth + 1)).join("\n");
1002
- if (!current.ordered) return `<ul>\n${items}\n</ul>`;
1003
- return `<ol${current.start !== 1 ? ` start="${current.start}"` : ""}>\n${items}\n</ol>`;
1080
+ const items = children.join("\n");
1081
+ if (!current.ordered) {
1082
+ value = `<ul>\n${items}\n</ul>`;
1083
+ break;
1084
+ }
1085
+ value = `<ol${current.start !== 1 ? ` start="${current.start}"` : ""}>\n${items}\n</ol>`;
1086
+ break;
1004
1087
  }
1005
- case "listItem": return `<li>${renderItem(current.children, depth)}</li>`;
1088
+ case "listItem":
1089
+ value = `<li>${children.join(current.children.length === 1 && current.children[0]?.element === "paragraph" ? "" : "\n")}</li>`;
1090
+ break;
1006
1091
  case "table": {
1007
- const head = `<tr>${current.header.map((cell, column) => renderCell("th", cell, current.align[column], depth)).join("")}</tr>`;
1008
- const body = current.rows.map((row) => `<tr>${row.map((cell, column) => renderCell("td", cell, current.align[column], depth)).join("")}</tr>`).join("\n");
1009
- return `<table>\n<thead>\n${head}\n</thead>${(0, _orkestrel_contract.isNonEmptyArray)(current.rows) ? `\n<tbody>\n${body}\n</tbody>` : ""}\n</table>`;
1092
+ let offset = 0;
1093
+ const header = [];
1094
+ for (const [column, cell] of current.header.entries()) {
1095
+ if (cell === void 0) continue;
1096
+ const align = current.align[column];
1097
+ const style = align === "left" || align === "right" || align === "center" ? ` style="text-align:${align}"` : "";
1098
+ let count = 0;
1099
+ for (const child of cell) if (child !== void 0) count += 1;
1100
+ header.push(`<th${style}>${children.slice(offset, offset + count).join("")}</th>`);
1101
+ offset += count;
1102
+ }
1103
+ const rows = [];
1104
+ for (const row of current.rows) {
1105
+ const cells = [];
1106
+ for (const [column, cell] of row.entries()) {
1107
+ if (cell === void 0) continue;
1108
+ const align = current.align[column];
1109
+ const style = align === "left" || align === "right" || align === "center" ? ` style="text-align:${align}"` : "";
1110
+ let count = 0;
1111
+ for (const child of cell) if (child !== void 0) count += 1;
1112
+ cells.push(`<td${style}>${children.slice(offset, offset + count).join("")}</td>`);
1113
+ offset += count;
1114
+ }
1115
+ rows.push(`<tr>${cells.join("")}</tr>`);
1116
+ }
1117
+ const body = rows.join("\n");
1118
+ const bodyHtml = (0, _orkestrel_contract.isNonEmptyArray)(current.rows) ? `\n<tbody>\n${body}\n</tbody>` : "";
1119
+ value = `<table>\n<thead>\n<tr>${header.join("")}</tr>\n</thead>${bodyHtml}\n</table>`;
1120
+ break;
1010
1121
  }
1011
- case "text": return escapeHtml(current.value);
1012
- case "emphasis": return current.strong ? `<strong>${renderInline(current.children, depth + 1)}</strong>` : `<em>${renderInline(current.children, depth + 1)}</em>`;
1013
- case "codeSpan": return `<code>${escapeHtml(current.value)}</code>`;
1014
- case "link": return `<a href="${sanitizeUrl(current.href)}">${renderInline(current.children, depth + 1)}</a>`;
1015
- default: return "";
1016
- }
1017
- }
1018
- function renderInline(nodes, depth) {
1019
- return nodes.map((child) => render(child, depth + 1)).join("");
1020
- }
1021
- function renderCell(tag, cell, align, depth) {
1022
- return `<${tag}${align === "left" || align === "right" || align === "center" ? ` style="text-align:${align}"` : ""}>${renderInline(cell, depth + 1)}</${tag}>`;
1023
- }
1024
- function renderItem(children, depth) {
1025
- if (children.length === 1) {
1026
- const only = children[0];
1027
- if (only !== void 0 && only.element === "paragraph") return renderInline(only.children, depth);
1122
+ case "text":
1123
+ value = escapeHtml(current.value);
1124
+ break;
1125
+ case "emphasis":
1126
+ value = current.strong ? `<strong>${children.join("")}</strong>` : `<em>${children.join("")}</em>`;
1127
+ break;
1128
+ case "codeSpan":
1129
+ value = `<code>${escapeHtml(current.value)}</code>`;
1130
+ break;
1131
+ case "link":
1132
+ value = `<a href="${sanitizeUrl(current.href)}">${children.join("")}</a>`;
1133
+ break;
1134
+ default:
1135
+ value = "";
1136
+ break;
1028
1137
  }
1029
- return children.map((child) => render(child, depth + 1)).join("\n");
1138
+ if (stack.length === 0) return value;
1139
+ values.push(value);
1030
1140
  }
1031
- return render(node, 0);
1141
+ return "";
1032
1142
  }
1033
1143
  /**
1034
1144
  * Render a {@link MarkdownNode} to its CANONICAL markdown source - the inverse
@@ -1058,125 +1168,220 @@ function renderHTML(node) {
1058
1168
  * ```
1059
1169
  */
1060
1170
  function renderMarkdown(node) {
1061
- function escapeText(value) {
1062
- let out = "";
1063
- for (let index = 0; index < value.length; index += 1) {
1064
- const character = value[index] ?? "";
1065
- const atLineStart = index === 0 || value[index - 1] === "\n";
1066
- if (character === "\\" || character === "*" || character === "_" || character === "`" || character === "[" || character === "]") {
1067
- out += `\\${character}`;
1068
- continue;
1069
- }
1070
- if (atLineStart) {
1071
- if (character === "#" || character === ">") {
1072
- out += `\\${character}`;
1171
+ const stack = [{
1172
+ node,
1173
+ depth: 0,
1174
+ expanded: false,
1175
+ count: 0,
1176
+ escaped: ""
1177
+ }];
1178
+ const values = [];
1179
+ while (stack.length > 0) {
1180
+ const frame = stack.pop();
1181
+ if (frame === void 0) continue;
1182
+ const current = frame.node;
1183
+ if (!frame.expanded) {
1184
+ let escaped = "";
1185
+ if ((frame.depth >= 64 || current.element === "text") && "value" in current && typeof current.value === "string") for (let index = 0; index < current.value.length; index += 1) {
1186
+ const character = current.value[index] ?? "";
1187
+ const atLineStart = index === 0 || current.value[index - 1] === "\n";
1188
+ if (character === "\\" || character === "*" || character === "_" || character === "`" || character === "[" || character === "]") {
1189
+ escaped += `\\${character}`;
1073
1190
  continue;
1074
1191
  }
1075
- if ((character === "-" || character === "+") && (value[index + 1] ?? " ") === " ") {
1076
- out += `\\${character}`;
1077
- continue;
1078
- }
1079
- if (/[0-9]/.test(character)) {
1080
- let end = index;
1081
- while (end < value.length && /[0-9]/.test(value[end] ?? "")) end += 1;
1082
- const marker = value[end];
1083
- if ((marker === "." || marker === ")") && value[end + 1] === " ") {
1084
- out += `${value.slice(index, end)}\\${marker}`;
1085
- index = end;
1192
+ if (atLineStart) {
1193
+ if (character === "#" || character === ">") {
1194
+ escaped += `\\${character}`;
1195
+ continue;
1196
+ }
1197
+ if ((character === "-" || character === "+") && (current.value[index + 1] ?? " ") === " ") {
1198
+ escaped += `\\${character}`;
1086
1199
  continue;
1087
1200
  }
1201
+ if (/[0-9]/.test(character)) {
1202
+ let end = index;
1203
+ while (end < current.value.length && /[0-9]/.test(current.value[end] ?? "")) end += 1;
1204
+ const marker = current.value[end];
1205
+ if ((marker === "." || marker === ")") && current.value[end + 1] === " ") {
1206
+ escaped += `${current.value.slice(index, end)}\\${marker}`;
1207
+ index = end;
1208
+ continue;
1209
+ }
1210
+ }
1088
1211
  }
1212
+ escaped += character;
1213
+ }
1214
+ if (frame.depth >= 64) {
1215
+ values.push(escaped);
1216
+ continue;
1217
+ }
1218
+ const children = [];
1219
+ let depth = frame.depth + 1;
1220
+ switch (current.element) {
1221
+ case "document":
1222
+ case "heading":
1223
+ case "paragraph":
1224
+ case "blockquote":
1225
+ case "listItem":
1226
+ case "emphasis":
1227
+ case "link":
1228
+ for (const child of current.children) if (child !== void 0) children.push(child);
1229
+ break;
1230
+ case "list":
1231
+ for (const child of current.items) if (child !== void 0) children.push(child);
1232
+ break;
1233
+ case "table":
1234
+ for (const cell of current.header) if (cell !== void 0) {
1235
+ for (const child of cell) if (child !== void 0) children.push(child);
1236
+ }
1237
+ for (const row of current.rows) {
1238
+ if (row === void 0) continue;
1239
+ for (let column = 0; column < current.header.length; column += 1) {
1240
+ const cell = row[column];
1241
+ if (cell !== void 0) {
1242
+ for (const child of cell) if (child !== void 0) children.push(child);
1243
+ }
1244
+ }
1245
+ }
1246
+ depth += 1;
1247
+ break;
1248
+ }
1249
+ stack.push({
1250
+ ...frame,
1251
+ expanded: true,
1252
+ count: children.length,
1253
+ escaped
1254
+ });
1255
+ for (let index = children.length - 1; index >= 0; index -= 1) {
1256
+ const child = children[index];
1257
+ if (child !== void 0) stack.push({
1258
+ node: child,
1259
+ depth,
1260
+ expanded: false,
1261
+ count: 0,
1262
+ escaped: ""
1263
+ });
1089
1264
  }
1090
- out += character;
1265
+ continue;
1091
1266
  }
1092
- return out;
1093
- }
1094
- function fenceFor(body, minimum) {
1095
- let longest = 0;
1096
- let run = 0;
1097
- for (const character of body) if (character === "`") {
1098
- run += 1;
1099
- longest = Math.max(longest, run);
1100
- } else run = 0;
1101
- return "`".repeat(Math.max(minimum, longest + 1));
1102
- }
1103
- function renderInline(nodes, depth) {
1104
- return nodes.map((child) => render(child, depth + 1)).join("");
1105
- }
1106
- function renderBlocks(blocks, depth) {
1107
- return blocks.map((block) => render(block, depth + 1)).join("\n\n");
1108
- }
1109
- function renderItem(item, marker, depth) {
1110
- const body = renderBlocks(item.children, depth + 1);
1111
- const pad = " ".repeat(marker.length);
1112
- return body.split("\n").map((line, index) => index === 0 ? marker + line : line === "" ? "" : pad + line).join("\n");
1113
- }
1114
- function renderCell(cell, depth) {
1115
- return renderInline(cell, depth + 1).replace(/\|/g, "\\|");
1116
- }
1117
- function renderTable(current, depth) {
1118
- const columns = current.header.length;
1119
- return [
1120
- `| ${current.header.map((cell) => renderCell(cell, depth)).join(" | ")} |`,
1121
- `| ${current.align.map((align) => {
1122
- if (align === "left") return ":--";
1123
- if (align === "right") return "--:";
1124
- if (align === "center") return ":-:";
1125
- return "---";
1126
- }).join(" | ")} |`,
1127
- ...current.rows.map((row) => {
1128
- const cells = [];
1129
- for (let column = 0; column < columns; column += 1) {
1130
- const cell = row[column];
1131
- cells.push(cell === void 0 ? "" : renderCell(cell, depth));
1132
- }
1133
- return `| ${cells.join(" | ")} |`;
1134
- })
1135
- ].join("\n");
1136
- }
1137
- function render(current, depth) {
1138
- if (depth >= 64) return "value" in current && typeof current.value === "string" ? escapeText(current.value) : "";
1267
+ const children = frame.count === 0 ? [] : values.splice(values.length - frame.count, frame.count);
1268
+ let value = "";
1139
1269
  switch (current.element) {
1140
- case "document": return renderBlocks(current.children, depth);
1270
+ case "codeBlock":
1271
+ case "codeSpan": {
1272
+ const body = current.element === "codeBlock" ? current.code : current.value;
1273
+ let longest = 0;
1274
+ let run = 0;
1275
+ for (const character of body) if (character === "`") {
1276
+ run += 1;
1277
+ longest = Math.max(longest, run);
1278
+ } else run = 0;
1279
+ const fence = "`".repeat(Math.max(current.element === "codeBlock" ? 3 : 1, longest + 1));
1280
+ if (current.element === "codeBlock") {
1281
+ value = `${fence}${current.lang === void 0 ? "" : current.lang}\n${current.code}\n${fence}`;
1282
+ break;
1283
+ }
1284
+ const pad = current.value.startsWith("`") || current.value.endsWith("`") ? " " : "";
1285
+ value = `${fence}${pad}${current.value}${pad}${fence}`;
1286
+ break;
1287
+ }
1288
+ case "document":
1289
+ value = children.join("\n\n");
1290
+ break;
1141
1291
  case "heading": {
1142
- const escaped = renderInline(current.children, depth).replace(/(^|[^\\])(#+)$/, (_match, pre, hashes) => {
1143
- return `${pre}\\${hashes[0] ?? ""}${hashes.slice(1)}`;
1292
+ const escaped = children.join("").replace(/(^|[^\\])(#+)$/, (_match, before, hashes) => {
1293
+ return `${before}\\${hashes[0] ?? ""}${hashes.slice(1)}`;
1144
1294
  });
1145
- return `${"#".repeat(current.level)} ${escaped}`;
1146
- }
1147
- case "paragraph": return renderInline(current.children, depth);
1148
- case "thematicBreak": return "---";
1149
- case "blockquote": return renderBlocks(current.children, depth).split("\n").map((line) => line === "" ? ">" : `> ${line}`).join("\n");
1150
- case "codeBlock": {
1151
- const fence = fenceFor(current.code, 3);
1152
- return `${fence}${current.lang === void 0 ? "" : current.lang}\n${current.code}\n${fence}`;
1295
+ value = `${"#".repeat(current.level)} ${escaped}`;
1296
+ break;
1153
1297
  }
1298
+ case "paragraph":
1299
+ value = children.join("");
1300
+ break;
1301
+ case "thematicBreak":
1302
+ value = "---";
1303
+ break;
1304
+ case "blockquote":
1305
+ value = children.join("\n\n").split("\n").map((line) => line === "" ? ">" : `> ${line}`).join("\n");
1306
+ break;
1154
1307
  case "list": {
1308
+ const items = [];
1155
1309
  let ordinal = current.start;
1156
- return current.items.map((item) => {
1157
- return renderItem(item, current.ordered ? `${ordinal++}. ` : "- ", depth);
1158
- }).join("\n");
1310
+ for (const body of children) {
1311
+ const marker = current.ordered ? `${ordinal}. ` : "- ";
1312
+ ordinal += 1;
1313
+ const pad = " ".repeat(marker.length);
1314
+ items.push(body.split("\n").map((line, index) => index === 0 ? marker + line : line === "" ? "" : pad + line).join("\n"));
1315
+ }
1316
+ value = items.join("\n");
1317
+ break;
1318
+ }
1319
+ case "listItem":
1320
+ value = children.join("\n\n");
1321
+ break;
1322
+ case "table": {
1323
+ let offset = 0;
1324
+ const header = [];
1325
+ for (const cell of current.header) {
1326
+ if (cell === void 0) {
1327
+ header.push("");
1328
+ continue;
1329
+ }
1330
+ let count = 0;
1331
+ for (const child of cell) if (child !== void 0) count += 1;
1332
+ header.push(children.slice(offset, offset + count).join("").replace(/\|/g, "\\|"));
1333
+ offset += count;
1334
+ }
1335
+ const delimiter = current.align.map((align) => {
1336
+ if (align === "left") return ":--";
1337
+ if (align === "right") return "--:";
1338
+ if (align === "center") return ":-:";
1339
+ return "---";
1340
+ });
1341
+ const rows = [];
1342
+ for (const row of current.rows) {
1343
+ const cells = [];
1344
+ for (let column = 0; column < current.header.length; column += 1) {
1345
+ const cell = row[column];
1346
+ if (cell === void 0) {
1347
+ cells.push("");
1348
+ continue;
1349
+ }
1350
+ let count = 0;
1351
+ for (const child of cell) if (child !== void 0) count += 1;
1352
+ cells.push(children.slice(offset, offset + count).join("").replace(/\|/g, "\\|"));
1353
+ offset += count;
1354
+ }
1355
+ rows.push(`| ${cells.join(" | ")} |`);
1356
+ }
1357
+ value = [
1358
+ `| ${header.join(" | ")} |`,
1359
+ `| ${delimiter.join(" | ")} |`,
1360
+ ...rows
1361
+ ].join("\n");
1362
+ break;
1159
1363
  }
1160
- case "listItem": return renderBlocks(current.children, depth);
1161
- case "table": return renderTable(current, depth);
1162
- case "text": return escapeText(current.value);
1364
+ case "text":
1365
+ value = frame.escaped;
1366
+ break;
1163
1367
  case "emphasis": {
1164
1368
  const marker = current.strong ? "**" : "*";
1165
- return `${marker}${renderInline(current.children, depth)}${marker}`;
1166
- }
1167
- case "codeSpan": {
1168
- const fence = fenceFor(current.value, 1);
1169
- const pad = current.value.startsWith("`") || current.value.endsWith("`") ? " " : "";
1170
- return `${fence}${pad}${current.value}${pad}${fence}`;
1369
+ value = `${marker}${children.join("")}${marker}`;
1370
+ break;
1171
1371
  }
1172
1372
  case "link": {
1173
1373
  const href = current.href.replace(/[\\()]/g, (character) => `\\${character}`);
1174
- return `[${renderInline(current.children, depth)}](${href})`;
1374
+ value = `[${children.join("")}](${href})`;
1375
+ break;
1175
1376
  }
1176
- default: return "";
1377
+ default:
1378
+ value = "";
1379
+ break;
1177
1380
  }
1381
+ if (stack.length === 0) return value;
1382
+ values.push(value);
1178
1383
  }
1179
- return render(node, 0);
1384
+ return "";
1180
1385
  }
1181
1386
  /**
1182
1387
  * Depth-first, pre-order, root-inclusive traversal of a {@link MarkdownNode} - yields
@@ -1198,10 +1403,17 @@ function renderMarkdown(node) {
1198
1403
  * ```
1199
1404
  */
1200
1405
  function* walkNodes(node) {
1201
- function* walk(current, depth) {
1202
- yield current;
1203
- if (depth >= 64) return;
1204
- switch (current.element) {
1406
+ const stack = [{
1407
+ node,
1408
+ depth: 0
1409
+ }];
1410
+ while (stack.length > 0) {
1411
+ const frame = stack.pop();
1412
+ if (frame === void 0) continue;
1413
+ yield frame.node;
1414
+ if (frame.depth >= 64) continue;
1415
+ const children = [];
1416
+ switch (frame.node.element) {
1205
1417
  case "document":
1206
1418
  case "heading":
1207
1419
  case "paragraph":
@@ -1209,19 +1421,30 @@ function* walkNodes(node) {
1209
1421
  case "listItem":
1210
1422
  case "emphasis":
1211
1423
  case "link":
1212
- for (const child of current.children) yield* walk(child, depth + 1);
1213
- return;
1424
+ for (const child of frame.node.children) if (child !== void 0) children.push(child);
1425
+ break;
1214
1426
  case "list":
1215
- for (const item of current.items) yield* walk(item, depth + 1);
1216
- return;
1427
+ for (const child of frame.node.items) if (child !== void 0) children.push(child);
1428
+ break;
1217
1429
  case "table":
1218
- for (const cell of current.header) for (const inline of cell) yield* walk(inline, depth + 1);
1219
- for (const row of current.rows) for (const cell of row) for (const inline of cell) yield* walk(inline, depth + 1);
1220
- return;
1221
- default: return;
1430
+ for (const cell of frame.node.header) if (cell !== void 0) {
1431
+ for (const child of cell) if (child !== void 0) children.push(child);
1432
+ }
1433
+ for (const row of frame.node.rows) if (row !== void 0) {
1434
+ for (const cell of row) if (cell !== void 0) {
1435
+ for (const child of cell) if (child !== void 0) children.push(child);
1436
+ }
1437
+ }
1438
+ break;
1439
+ }
1440
+ for (let index = children.length - 1; index >= 0; index -= 1) {
1441
+ const child = children[index];
1442
+ if (child !== void 0) stack.push({
1443
+ node: child,
1444
+ depth: frame.depth + 1
1445
+ });
1222
1446
  }
1223
1447
  }
1224
- yield* walk(node, 0);
1225
1448
  }
1226
1449
  /**
1227
1450
  * Fold a {@link MarkdownNode} into a `T` via a total catamorphism - children are
@@ -1255,46 +1478,119 @@ function* walkNodes(node) {
1255
1478
  * ```
1256
1479
  */
1257
1480
  function foldNode(node, handlers, depth) {
1258
- function dispatch(current, children) {
1259
- switch (current.element) {
1260
- case "document": return handlers.document(current, children);
1261
- case "heading": return handlers.heading(current, children);
1262
- case "paragraph": return handlers.paragraph(current, children);
1263
- case "thematicBreak": return handlers.thematicBreak(current, children);
1264
- case "blockquote": return handlers.blockquote(current, children);
1265
- case "codeBlock": return handlers.codeBlock(current, children);
1266
- case "list": return handlers.list(current, children);
1267
- case "listItem": return handlers.listItem(current, children);
1268
- case "table": return handlers.table(current, children);
1269
- case "text": return handlers.text(current, children);
1270
- case "emphasis": return handlers.emphasis(current, children);
1271
- case "codeSpan": return handlers.codeSpan(current, children);
1272
- case "link": return handlers.link(current, children);
1481
+ const stack = [{
1482
+ node,
1483
+ depth,
1484
+ expanded: false,
1485
+ count: 0
1486
+ }];
1487
+ const values = [];
1488
+ while (stack.length > 0) {
1489
+ const frame = stack.pop();
1490
+ if (frame === void 0) continue;
1491
+ if (!frame.expanded) {
1492
+ const children = [];
1493
+ if (frame.depth < 64) switch (frame.node.element) {
1494
+ case "document":
1495
+ case "heading":
1496
+ case "paragraph":
1497
+ case "blockquote":
1498
+ case "listItem":
1499
+ case "emphasis":
1500
+ case "link":
1501
+ for (const child of frame.node.children) if (child !== void 0) children.push(child);
1502
+ break;
1503
+ case "list":
1504
+ for (const child of frame.node.items) if (child !== void 0) children.push(child);
1505
+ break;
1506
+ case "table":
1507
+ for (const cell of frame.node.header) if (cell !== void 0) {
1508
+ for (const child of cell) if (child !== void 0) children.push(child);
1509
+ }
1510
+ for (const row of frame.node.rows) if (row !== void 0) {
1511
+ for (const cell of row) if (cell !== void 0) {
1512
+ for (const child of cell) if (child !== void 0) children.push(child);
1513
+ }
1514
+ }
1515
+ break;
1516
+ }
1517
+ stack.push({
1518
+ ...frame,
1519
+ expanded: true,
1520
+ count: children.length
1521
+ });
1522
+ for (let index = children.length - 1; index >= 0; index -= 1) {
1523
+ const child = children[index];
1524
+ if (child !== void 0) stack.push({
1525
+ node: child,
1526
+ depth: frame.depth + 1,
1527
+ expanded: false,
1528
+ count: 0
1529
+ });
1530
+ }
1531
+ continue;
1273
1532
  }
1274
- }
1275
- function childNodes(current) {
1276
- switch (current.element) {
1533
+ const children = frame.count === 0 ? [] : values.splice(values.length - frame.count, frame.count);
1534
+ let value;
1535
+ switch (frame.node.element) {
1277
1536
  case "document":
1537
+ value = handlers.document(frame.node, children);
1538
+ break;
1278
1539
  case "heading":
1540
+ value = handlers.heading(frame.node, children);
1541
+ break;
1279
1542
  case "paragraph":
1543
+ value = handlers.paragraph(frame.node, children);
1544
+ break;
1545
+ case "thematicBreak":
1546
+ value = handlers.thematicBreak(frame.node, children);
1547
+ break;
1280
1548
  case "blockquote":
1549
+ value = handlers.blockquote(frame.node, children);
1550
+ break;
1551
+ case "codeBlock":
1552
+ value = handlers.codeBlock(frame.node, children);
1553
+ break;
1554
+ case "list":
1555
+ value = handlers.list(frame.node, children);
1556
+ break;
1281
1557
  case "listItem":
1558
+ value = handlers.listItem(frame.node, children);
1559
+ break;
1560
+ case "table":
1561
+ value = handlers.table(frame.node, children);
1562
+ break;
1563
+ case "text":
1564
+ value = handlers.text(frame.node, children);
1565
+ break;
1282
1566
  case "emphasis":
1283
- case "link": return current.children;
1284
- case "list": return current.items;
1285
- case "table": {
1286
- const header = current.header.flatMap((cell) => cell);
1287
- const rows = current.rows.flatMap((row) => row.flatMap((cell) => cell));
1288
- return [...header, ...rows];
1289
- }
1290
- default: return [];
1567
+ value = handlers.emphasis(frame.node, children);
1568
+ break;
1569
+ case "codeSpan":
1570
+ value = handlers.codeSpan(frame.node, children);
1571
+ break;
1572
+ case "link":
1573
+ value = handlers.link(frame.node, children);
1574
+ break;
1291
1575
  }
1576
+ if (stack.length === 0) return value;
1577
+ values.push(value);
1292
1578
  }
1293
- function fold(current, level) {
1294
- if (level >= 64) return dispatch(current, []);
1295
- return dispatch(current, childNodes(current).map((child) => fold(child, level + 1)));
1579
+ switch (node.element) {
1580
+ case "document": return handlers.document(node, []);
1581
+ case "heading": return handlers.heading(node, []);
1582
+ case "paragraph": return handlers.paragraph(node, []);
1583
+ case "thematicBreak": return handlers.thematicBreak(node, []);
1584
+ case "blockquote": return handlers.blockquote(node, []);
1585
+ case "codeBlock": return handlers.codeBlock(node, []);
1586
+ case "list": return handlers.list(node, []);
1587
+ case "listItem": return handlers.listItem(node, []);
1588
+ case "table": return handlers.table(node, []);
1589
+ case "text": return handlers.text(node, []);
1590
+ case "emphasis": return handlers.emphasis(node, []);
1591
+ case "codeSpan": return handlers.codeSpan(node, []);
1592
+ case "link": return handlers.link(node, []);
1296
1593
  }
1297
- return fold(node, depth);
1298
1594
  }
1299
1595
  /**
1300
1596
  * Rewrite a {@link MarkdownDocument} bottom-up (copy-on-write) - each node's children
@@ -1329,71 +1625,227 @@ function foldNode(node, handlers, depth) {
1329
1625
  * ```
1330
1626
  */
1331
1627
  function rewriteDocument(document, rewrite) {
1332
- function rewriteInline(node, depth) {
1333
- if (depth >= 64) return node;
1334
- const rebuilt = rebuildInline(node, depth);
1335
- const result = rewrite(rebuilt);
1336
- return isInlineNode(result) ? result : rebuilt;
1337
- }
1338
- function rewriteBlock(node, depth) {
1339
- if (depth >= 64) return node;
1340
- const rebuilt = rebuildBlock(node, depth);
1341
- const result = rewrite(rebuilt);
1342
- return isBlockNode(result) ? result : rebuilt;
1343
- }
1344
- function rewriteItem(item, depth) {
1345
- if (depth >= 64) return item;
1346
- const rebuilt = {
1347
- element: "listItem",
1348
- children: item.children.map((child) => rewriteBlock(child, depth + 1))
1349
- };
1628
+ const stack = [{
1629
+ node: document,
1630
+ depth: -1,
1631
+ expanded: false,
1632
+ count: 0
1633
+ }];
1634
+ const values = [];
1635
+ while (stack.length > 0) {
1636
+ const frame = stack.pop();
1637
+ if (frame === void 0) continue;
1638
+ const current = frame.node;
1639
+ if (!frame.expanded) {
1640
+ if (current.element !== "document" && frame.depth >= 64) {
1641
+ values.push(current);
1642
+ continue;
1643
+ }
1644
+ const children = [];
1645
+ switch (current.element) {
1646
+ case "document":
1647
+ case "heading":
1648
+ case "paragraph":
1649
+ case "blockquote":
1650
+ case "listItem":
1651
+ case "emphasis":
1652
+ case "link":
1653
+ for (const child of current.children) if (child !== void 0) children.push(child);
1654
+ break;
1655
+ case "list":
1656
+ for (const child of current.items) if (child !== void 0) children.push(child);
1657
+ break;
1658
+ case "table":
1659
+ for (const cell of current.header) if (cell !== void 0) {
1660
+ for (const child of cell) if (child !== void 0) children.push(child);
1661
+ }
1662
+ for (const row of current.rows) if (row !== void 0) {
1663
+ for (const cell of row) if (cell !== void 0) {
1664
+ for (const child of cell) if (child !== void 0) children.push(child);
1665
+ }
1666
+ }
1667
+ break;
1668
+ }
1669
+ stack.push({
1670
+ ...frame,
1671
+ expanded: true,
1672
+ count: children.length
1673
+ });
1674
+ const depth = current.element === "document" ? 0 : frame.depth + 1;
1675
+ for (let index = children.length - 1; index >= 0; index -= 1) {
1676
+ const child = children[index];
1677
+ if (child !== void 0) stack.push({
1678
+ node: child,
1679
+ depth,
1680
+ expanded: false,
1681
+ count: 0
1682
+ });
1683
+ }
1684
+ continue;
1685
+ }
1686
+ const children = frame.count === 0 ? [] : values.splice(values.length - frame.count, frame.count);
1687
+ let rebuilt = current;
1688
+ switch (current.element) {
1689
+ case "document": {
1690
+ const blocks = [];
1691
+ let offset = 0;
1692
+ for (const block of current.children) {
1693
+ if (block === void 0) continue;
1694
+ const child = children[offset];
1695
+ blocks.push(child !== void 0 && isBlockNode(child) ? child : block);
1696
+ offset += 1;
1697
+ }
1698
+ const result = {
1699
+ element: "document",
1700
+ children: blocks
1701
+ };
1702
+ if (stack.length === 0) return result;
1703
+ values.push(result);
1704
+ continue;
1705
+ }
1706
+ case "heading":
1707
+ case "paragraph": {
1708
+ const inlines = [];
1709
+ let offset = 0;
1710
+ for (const inline of current.children) {
1711
+ if (inline === void 0) continue;
1712
+ const child = children[offset];
1713
+ inlines.push(child !== void 0 && isInlineNode(child) ? child : inline);
1714
+ offset += 1;
1715
+ }
1716
+ rebuilt = {
1717
+ ...current,
1718
+ children: inlines
1719
+ };
1720
+ break;
1721
+ }
1722
+ case "blockquote": {
1723
+ const blocks = [];
1724
+ let offset = 0;
1725
+ for (const block of current.children) {
1726
+ if (block === void 0) continue;
1727
+ const child = children[offset];
1728
+ blocks.push(child !== void 0 && isBlockNode(child) ? child : block);
1729
+ offset += 1;
1730
+ }
1731
+ rebuilt = {
1732
+ ...current,
1733
+ children: blocks
1734
+ };
1735
+ break;
1736
+ }
1737
+ case "listItem": {
1738
+ const blocks = [];
1739
+ let offset = 0;
1740
+ for (const block of current.children) {
1741
+ if (block === void 0) continue;
1742
+ const child = children[offset];
1743
+ blocks.push(child !== void 0 && isBlockNode(child) ? child : block);
1744
+ offset += 1;
1745
+ }
1746
+ rebuilt = {
1747
+ element: "listItem",
1748
+ children: blocks
1749
+ };
1750
+ break;
1751
+ }
1752
+ case "emphasis":
1753
+ case "link": {
1754
+ const inlines = [];
1755
+ let offset = 0;
1756
+ for (const inline of current.children) {
1757
+ if (inline === void 0) continue;
1758
+ const child = children[offset];
1759
+ inlines.push(child !== void 0 && isInlineNode(child) ? child : inline);
1760
+ offset += 1;
1761
+ }
1762
+ rebuilt = {
1763
+ ...current,
1764
+ children: inlines
1765
+ };
1766
+ break;
1767
+ }
1768
+ case "list": {
1769
+ const items = [];
1770
+ let offset = 0;
1771
+ for (const item of current.items) {
1772
+ if (item === void 0) continue;
1773
+ const child = children[offset];
1774
+ items.push(child?.element === "listItem" ? child : item);
1775
+ offset += 1;
1776
+ }
1777
+ rebuilt = {
1778
+ ...current,
1779
+ items
1780
+ };
1781
+ break;
1782
+ }
1783
+ case "table": {
1784
+ let offset = 0;
1785
+ const header = [];
1786
+ for (const cell of current.header) {
1787
+ if (cell === void 0) continue;
1788
+ const inlines = [];
1789
+ for (const inline of cell) {
1790
+ if (inline === void 0) continue;
1791
+ const child = children[offset];
1792
+ inlines.push(child !== void 0 && isInlineNode(child) ? child : inline);
1793
+ offset += 1;
1794
+ }
1795
+ header.push(inlines);
1796
+ }
1797
+ const rows = [];
1798
+ for (const row of current.rows) {
1799
+ if (row === void 0) continue;
1800
+ const cells = [];
1801
+ for (const cell of row) {
1802
+ if (cell === void 0) continue;
1803
+ const inlines = [];
1804
+ for (const inline of cell) {
1805
+ if (inline === void 0) continue;
1806
+ const child = children[offset];
1807
+ inlines.push(child !== void 0 && isInlineNode(child) ? child : inline);
1808
+ offset += 1;
1809
+ }
1810
+ cells.push(inlines);
1811
+ }
1812
+ rows.push(cells);
1813
+ }
1814
+ rebuilt = {
1815
+ ...current,
1816
+ header,
1817
+ rows
1818
+ };
1819
+ break;
1820
+ }
1821
+ }
1350
1822
  const result = rewrite(rebuilt);
1351
- return result.element === "listItem" ? result : rebuilt;
1352
- }
1353
- function rebuildInline(node, depth) {
1354
- switch (node.element) {
1355
- case "emphasis": return {
1356
- ...node,
1357
- children: node.children.map((child) => rewriteInline(child, depth + 1))
1358
- };
1359
- case "link": return {
1360
- ...node,
1361
- children: node.children.map((child) => rewriteInline(child, depth + 1))
1362
- };
1823
+ let accepted = rebuilt;
1824
+ switch (current.element) {
1363
1825
  case "text":
1364
- case "codeSpan": return node;
1365
- }
1366
- }
1367
- function rebuildBlock(node, depth) {
1368
- switch (node.element) {
1369
- case "heading": return {
1370
- ...node,
1371
- children: node.children.map((child) => rewriteInline(child, depth + 1))
1372
- };
1373
- case "paragraph": return {
1374
- ...node,
1375
- children: node.children.map((child) => rewriteInline(child, depth + 1))
1376
- };
1377
- case "blockquote": return {
1378
- ...node,
1379
- children: node.children.map((child) => rewriteBlock(child, depth + 1))
1380
- };
1381
- case "list": return {
1382
- ...node,
1383
- items: node.items.map((item) => rewriteItem(item, depth + 1))
1384
- };
1385
- case "table": return {
1386
- ...node,
1387
- header: node.header.map((cell) => cell.map((inline) => rewriteInline(inline, depth + 1))),
1388
- rows: node.rows.map((row) => row.map((cell) => cell.map((inline) => rewriteInline(inline, depth + 1))))
1389
- };
1826
+ case "emphasis":
1827
+ case "codeSpan":
1828
+ case "link":
1829
+ if (isInlineNode(result)) accepted = result;
1830
+ break;
1831
+ case "heading":
1832
+ case "paragraph":
1833
+ case "list":
1834
+ case "table":
1390
1835
  case "codeBlock":
1391
- case "thematicBreak": return node;
1836
+ case "blockquote":
1837
+ case "thematicBreak":
1838
+ if (isBlockNode(result)) accepted = result;
1839
+ break;
1840
+ case "listItem":
1841
+ if (result.element === "listItem") accepted = result;
1842
+ break;
1392
1843
  }
1844
+ values.push(accepted);
1393
1845
  }
1394
1846
  return {
1395
1847
  element: "document",
1396
- children: document.children.map((child) => rewriteBlock(child, 0))
1848
+ children: [...document.children]
1397
1849
  };
1398
1850
  }
1399
1851
  /**
@@ -1418,26 +1870,55 @@ function rewriteDocument(document, rewrite) {
1418
1870
  * ```
1419
1871
  */
1420
1872
  function flattenText(node) {
1421
- function flatten(current, depth) {
1422
- if (depth >= 64) return "";
1423
- switch (current.element) {
1424
- case "text": return current.value;
1425
- case "codeSpan": return current.value;
1426
- case "codeBlock": return current.code;
1873
+ const stack = [{
1874
+ node,
1875
+ depth: 0
1876
+ }];
1877
+ let value = "";
1878
+ while (stack.length > 0) {
1879
+ const frame = stack.pop();
1880
+ if (frame === void 0 || frame.depth >= 64) continue;
1881
+ const children = [];
1882
+ switch (frame.node.element) {
1883
+ case "text":
1884
+ case "codeSpan":
1885
+ value += frame.node.value;
1886
+ break;
1887
+ case "codeBlock":
1888
+ value += frame.node.code;
1889
+ break;
1427
1890
  case "document":
1428
1891
  case "heading":
1429
1892
  case "paragraph":
1430
1893
  case "blockquote":
1431
1894
  case "listItem":
1432
1895
  case "emphasis":
1433
- case "link": return current.children.map((child) => flatten(child, depth + 1)).join("");
1434
- case "list": return current.items.map((item) => flatten(item, depth + 1)).join("");
1435
- case "table": return current.header.map((cell) => cell.map((inline) => flatten(inline, depth + 1)).join("")).join("") + current.rows.map((row) => row.map((cell) => cell.map((inline) => flatten(inline, depth + 1)).join("")).join("")).join("");
1436
- case "thematicBreak": return "";
1437
- default: return "";
1896
+ case "link":
1897
+ for (const child of frame.node.children) if (child !== void 0) children.push(child);
1898
+ break;
1899
+ case "list":
1900
+ for (const child of frame.node.items) if (child !== void 0) children.push(child);
1901
+ break;
1902
+ case "table":
1903
+ for (const cell of frame.node.header) if (cell !== void 0) {
1904
+ for (const child of cell) if (child !== void 0) children.push(child);
1905
+ }
1906
+ for (const row of frame.node.rows) if (row !== void 0) {
1907
+ for (const cell of row) if (cell !== void 0) {
1908
+ for (const child of cell) if (child !== void 0) children.push(child);
1909
+ }
1910
+ }
1911
+ break;
1912
+ }
1913
+ for (let index = children.length - 1; index >= 0; index -= 1) {
1914
+ const child = children[index];
1915
+ if (child !== void 0) stack.push({
1916
+ node: child,
1917
+ depth: frame.depth + 1
1918
+ });
1438
1919
  }
1439
1920
  }
1440
- return flatten(node, 0);
1921
+ return value;
1441
1922
  }
1442
1923
  //#endregion
1443
1924
  //#region src/core/parsers.ts
@@ -1596,6 +2077,51 @@ function collectList(lines, start, depth) {
1596
2077
  const startOrdinal = first?.start ?? 1;
1597
2078
  const topIndent = first?.indent ?? 0;
1598
2079
  const items = [];
2080
+ const chain = [];
2081
+ let nested = true;
2082
+ for (let cursor = start; cursor < lines.length; cursor += 1) {
2083
+ const parsed = extractListItem(lines[cursor] ?? "");
2084
+ const previous = chain[chain.length - 1];
2085
+ if (parsed === void 0 || previous !== void 0 && (previous.content.length > 0 || parsed.indent !== previous.marker)) {
2086
+ nested = false;
2087
+ break;
2088
+ }
2089
+ chain.push(parsed);
2090
+ }
2091
+ const remaining = 64 - depth;
2092
+ if (nested && remaining > 0 && chain.length > remaining) {
2093
+ const terminal = chain[remaining - 1];
2094
+ if (terminal !== void 0) {
2095
+ const source = [terminal.content];
2096
+ for (let cursor = start + remaining; cursor < lines.length; cursor += 1) source.push((lines[cursor] ?? "").slice(terminal.marker));
2097
+ let children = [{
2098
+ element: "paragraph",
2099
+ children: [{
2100
+ element: "text",
2101
+ value: source.join("\n")
2102
+ }]
2103
+ }];
2104
+ let node;
2105
+ for (let cursor = remaining - 1; cursor >= 0; cursor -= 1) {
2106
+ const parsed = chain[cursor];
2107
+ if (parsed === void 0) continue;
2108
+ node = {
2109
+ element: "list",
2110
+ ordered: parsed.ordered,
2111
+ start: parsed.start,
2112
+ items: [{
2113
+ element: "listItem",
2114
+ children
2115
+ }]
2116
+ };
2117
+ children = [node];
2118
+ }
2119
+ if (node !== void 0) return {
2120
+ node,
2121
+ next: lines.length
2122
+ };
2123
+ }
2124
+ }
1599
2125
  let index = start;
1600
2126
  while (index < lines.length) {
1601
2127
  const parsed = extractListItem(lines[index] ?? "");
@@ -1878,7 +2404,12 @@ var Markdown = class Markdown {
1878
2404
  let index = 0;
1879
2405
  return new ReadableStream({ pull(controller) {
1880
2406
  if (index < blocks.length) {
1881
- controller.enqueue(blocks[index]);
2407
+ const block = blocks[index];
2408
+ if (block === void 0) {
2409
+ controller.close();
2410
+ return;
2411
+ }
2412
+ controller.enqueue(block);
1882
2413
  index += 1;
1883
2414
  } else controller.close();
1884
2415
  } });