asciidoc-abundant-tree 0.2.4 → 0.2.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.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { o as exportAnimationYaml } from "../src-8G5Sgsvr.mjs";
2
+ import { o as exportAnimationYaml } from "../src-COUYWnMz.mjs";
3
3
  import process from "node:process";
4
4
  //#region src/animation-yaml-export/cli.ts
5
5
  const USAGE = `Usage:
package/dist/browser.mjs CHANGED
@@ -407,6 +407,7 @@ function recoverSourceAwareSourceLayer(document, logicalSpan, options) {
407
407
  };
408
408
  const sourceSpan = options.logicalSourceSpan ? recoverSourceAwareSpan(document, options.logicalSourceSpan, false) : void 0;
409
409
  if (sourceSpan && !sourceSpan.ok) return sourceSpan;
410
+ const raw = options.raw === "lines" ? `${sourceLines(sourceFile.lineTable, lineSpan.startLine, lineSpan.endLine).join("\n")}\n` : options.raw === "sourceSpan" && sourceSpan?.sourceSpan ? sliceSourceSpan(sourceFile.lineTable, sourceSpan.sourceSpan) : void 0;
410
411
  return {
411
412
  ok: true,
412
413
  relativePath,
@@ -417,10 +418,13 @@ function recoverSourceAwareSourceLayer(document, logicalSpan, options) {
417
418
  line: lineSpan.startLine,
418
419
  span: lineSpan,
419
420
  ...sourceSpan?.sourceSpan ? { sourceSpan: sourceSpan.sourceSpan } : {},
420
- ...options.raw ? { raw: `${sourceLines(sourceFile.lineTable, lineSpan.startLine, lineSpan.endLine).join("\n")}\n` } : {}
421
+ ...raw === void 0 ? {} : { raw }
421
422
  }
422
423
  };
423
424
  }
425
+ function sliceSourceSpan(lineTable, span) {
426
+ return sourceLines(lineTable, span.start.line, span.end.line).map((text, index, lines) => Array.from(text).slice(index === 0 ? span.start.column - 1 : 0, index === lines.length - 1 ? span.end.column - 1 : void 0).join("")).join("\n");
427
+ }
424
428
  function recoverSourceAwarePointSourceLayer(document, logicalSourceSpan, raw) {
425
429
  const recovered = recoverSourceAwareSpan(document, logicalSourceSpan, true);
426
430
  if (!recovered.ok) {
@@ -787,12 +791,7 @@ function trimBlankEdges(lines) {
787
791
  return lines.slice(first, last);
788
792
  }
789
793
  function descriptionMetadataTermKey(term) {
790
- const raw = term.source?.raw;
791
- const sourceSpan = term.sourceSpan;
792
- if (!raw || !sourceSpan || sourceSpan.start.line !== sourceSpan.end.line) return term.text;
793
- const [line] = raw.split(/\r?\n/u);
794
- if (line === void 0) return term.text;
795
- return Array.from(line).slice(sourceSpan.start.column - 1, sourceSpan.end.column - 1).join("");
794
+ return term.source?.raw || term.text;
796
795
  }
797
796
  function mergeRunSource(run) {
798
797
  const sources = run.map((list) => list.source);
@@ -848,12 +847,12 @@ function sourcesHaveContiguousLineSpans(sources) {
848
847
  return true;
849
848
  }
850
849
  function earliestPosition(positions) {
851
- return positions.reduce((earliest, position) => comparePositions(position, earliest) < 0 ? position : earliest);
850
+ return positions.reduce((earliest, position) => comparePositions$1(position, earliest) < 0 ? position : earliest);
852
851
  }
853
852
  function latestPosition(positions) {
854
- return positions.reduce((latest, position) => comparePositions(position, latest) > 0 ? position : latest);
853
+ return positions.reduce((latest, position) => comparePositions$1(position, latest) > 0 ? position : latest);
855
854
  }
856
- function comparePositions(left, right) {
855
+ function comparePositions$1(left, right) {
857
856
  return left.line - right.line || left.column - right.column;
858
857
  }
859
858
  //#endregion
@@ -861,7 +860,6 @@ function comparePositions(left, right) {
861
860
  function officialBlockPolicy(block) {
862
861
  switch (block.getContext?.()) {
863
862
  case "admonition":
864
- case "dlist":
865
863
  case "list_item":
866
864
  case "paragraph":
867
865
  case "table":
@@ -872,6 +870,7 @@ function officialBlockPolicy(block) {
872
870
  case "open": return block.getContentModel?.() === "simple" ? "scan" : "recurse";
873
871
  case "olist":
874
872
  case "colist":
873
+ case "dlist":
875
874
  case "preamble":
876
875
  case "section":
877
876
  case "ulist": return "recurse";
@@ -939,6 +938,165 @@ function descriptionListItemFromRaw(rawItem) {
939
938
  };
940
939
  }
941
940
  //#endregion
941
+ //#region src/official-delimiter.ts
942
+ const DELIMITED_BLOCKS = {
943
+ "--": ["open", new Set([
944
+ "comment",
945
+ "example",
946
+ "literal",
947
+ "listing",
948
+ "pass",
949
+ "quote",
950
+ "sidebar",
951
+ "source",
952
+ "verse",
953
+ "admonition",
954
+ "abstract",
955
+ "partintro"
956
+ ])],
957
+ "----": ["listing", new Set(["literal", "source"])],
958
+ "....": ["literal", new Set(["listing", "source"])],
959
+ "====": ["example", new Set(["admonition"])],
960
+ "****": ["sidebar", /* @__PURE__ */ new Set()],
961
+ ____: ["quote", new Set(["verse"])],
962
+ "++++": ["pass", new Set([
963
+ "stem",
964
+ "latexmath",
965
+ "asciimath"
966
+ ])],
967
+ "|===": ["table", /* @__PURE__ */ new Set()],
968
+ ",===": ["table", /* @__PURE__ */ new Set()],
969
+ ":===": ["table", /* @__PURE__ */ new Set()],
970
+ "!===": ["table", /* @__PURE__ */ new Set()],
971
+ "~~~~": ["open", new Set(["abstract", "partintro"])],
972
+ "////": ["comment", /* @__PURE__ */ new Set()],
973
+ "```": ["fenced_code", /* @__PURE__ */ new Set()]
974
+ };
975
+ const DELIMITED_BLOCK_HEADS = new Set(Object.keys(DELIMITED_BLOCKS).map((delimiter) => delimiter.slice(0, 2)));
976
+ const DELIMITED_BLOCK_TAILS = Object.fromEntries(Object.keys(DELIMITED_BLOCKS).filter((delimiter) => delimiter.length === 4).map((delimiter) => [delimiter, delimiter.slice(-1)]));
977
+ function officialDelimiter(line) {
978
+ let candidate = line;
979
+ let lineLength = candidate.length;
980
+ if (lineLength < 2 || !DELIMITED_BLOCK_HEADS.has(candidate.slice(0, 2))) return;
981
+ let tip;
982
+ let tipLength;
983
+ if (lineLength === 2) {
984
+ tip = candidate;
985
+ tipLength = 2;
986
+ } else {
987
+ tipLength = lineLength < 5 ? lineLength : 4;
988
+ tip = candidate.slice(0, tipLength);
989
+ if (tip.startsWith("`")) {
990
+ if (tipLength === 4) {
991
+ if (tip === "````") return;
992
+ tip = tip.slice(0, 3);
993
+ if (tip !== "```") return;
994
+ candidate = tip;
995
+ lineLength = 3;
996
+ tipLength = 3;
997
+ } else if (tip !== "```") return;
998
+ } else if (tipLength === 3) return;
999
+ }
1000
+ const entry = DELIMITED_BLOCKS[tip];
1001
+ if (!entry) return;
1002
+ const tail = DELIMITED_BLOCK_TAILS[tip];
1003
+ if (!(lineLength === tipLength || tail !== void 0 && isUniform(candidate.slice(1), tail))) return;
1004
+ const [context, masq] = entry;
1005
+ return {
1006
+ context,
1007
+ masq,
1008
+ terminator: candidate
1009
+ };
1010
+ }
1011
+ function delimiterOpens(delimiter, context, style) {
1012
+ if (context === void 0) return false;
1013
+ if (delimiter.context === "fenced_code") return context === "listing";
1014
+ return delimiter.context === context || delimiter.masq.has(context) || style !== null && style !== void 0 && delimiter.masq.has(style);
1015
+ }
1016
+ function isUniform(text, character) {
1017
+ return [...text].every((each) => each === character);
1018
+ }
1019
+ //#endregion
1020
+ //#region src/official-paragraph.ts
1021
+ const CC_ALPHA = String.raw`\p{Alphabetic}`;
1022
+ const CC_WORD = String.raw`\p{Alphabetic}\p{N}\p{Pc}`;
1023
+ const BlockAttributeLineRx = new RegExp(String.raw`^\[(?:|[${CC_WORD}.#%{,"'].*|\[(?:|[${CC_ALPHA}_:][${CC_WORD}\-:.]*(?:, *.+)?)\])\]$`, "u");
1024
+ const AnyListRx = /^(?:[ \t]*(?:-|\*\**|\.\.*|•|\d+\.|[a-zA-Z]\.|[IVXivx]+\))[ \t]|(?!\/\/[^/])[ \t]*[^ \t].*?(?::::{0,2}|;;)(?:$|[ \t])|<(?:\d+|\.)>[ \t])/;
1025
+ const BlockAnchorRx = new RegExp(String.raw`^\[\[(?:|([${CC_ALPHA}_:][${CC_WORD}\-:.]*)(?:, *(.+))?)\]\]$`, "u");
1026
+ const BlockAttributeListRx = new RegExp(String.raw`^\[(|[${CC_WORD}.#%{,"'].*)\]$`, "u");
1027
+ const DescriptionListRx = /^(?!\/\/[^/])[ \t]*([^ \t].*?)(:::{0,2}|;;)(?:$|[ \t]+([\s\S]*)$)/;
1028
+ const BlockTitleRx = /^\.(\.?[^ \t.].*)$/;
1029
+ const AttributeEntryRx = new RegExp(String.raw`^:(!?[${CC_WORD}][^:]*):(?:[ \t]+(.*))?$`, "u");
1030
+ function paragraphEndLine(lineTable, startLine, breakAtList, skipsLineComments = true) {
1031
+ let last = startLine;
1032
+ for (let line = startLine + 1; line <= lineTable.lines.length; line += 1) {
1033
+ const text = lineText(lineTable, line).trimEnd();
1034
+ if (text === "" || text === "+" || terminatesParagraph(text, breakAtList)) break;
1035
+ if (!(skipsLineComments && isLineComment(text))) last = line;
1036
+ }
1037
+ return last;
1038
+ }
1039
+ function listItemTextEndLine(lineTable, markerLine) {
1040
+ let line = markerLine + 1;
1041
+ while (line <= lineTable.lines.length && isTextOnlyMetadata(lineText(lineTable, line).trimEnd())) line += 1;
1042
+ const text = lineText(lineTable, line).trimEnd();
1043
+ if (line > lineTable.lines.length || text === "" || text === "+" || terminatesParagraph(text, true)) return markerLine;
1044
+ return paragraphEndLine(lineTable, line, true);
1045
+ }
1046
+ function descriptionText(lineTable, termLine, occupied) {
1047
+ const termText = lineText(lineTable, termLine).trimEnd();
1048
+ const itemText = DescriptionListRx.exec(termText)?.[3];
1049
+ const hasText = Boolean(itemText);
1050
+ const termTextColumn = [...termText].length - [...itemText ?? ""].length + 1;
1051
+ const lastLine = lineTable.lines.length;
1052
+ let line = termLine + 1;
1053
+ if (!hasText) while (line <= lastLine && lineText(lineTable, line).trim() === "") line += 1;
1054
+ while (line <= lastLine && isDescriptionMetadata(lineText(lineTable, line).trimEnd(), !hasText)) line += 1;
1055
+ const text = lineText(lineTable, line).trimEnd();
1056
+ if (!(line <= lastLine && text !== "" && text !== "+" && !terminatesParagraph(text, true) && !occupied(line))) return hasText ? {
1057
+ span: {
1058
+ startLine: termLine,
1059
+ endLine: termLine
1060
+ },
1061
+ startColumn: termTextColumn,
1062
+ readsLineComments: false
1063
+ } : void 0;
1064
+ const readsLineComments = hasText && /^[ \t]/u.test(lineText(lineTable, line));
1065
+ return {
1066
+ span: {
1067
+ startLine: hasText ? termLine : line,
1068
+ endLine: paragraphEndLine(lineTable, line, true, !readsLineComments)
1069
+ },
1070
+ startColumn: hasText ? termTextColumn : 1,
1071
+ ...hasText && line > termLine + 1 ? { discardedSpan: {
1072
+ startLine: termLine + 1,
1073
+ endLine: line - 1
1074
+ } } : {},
1075
+ readsLineComments
1076
+ };
1077
+ }
1078
+ function isDescriptionMetadata(text, textOnly) {
1079
+ if (isLineComment(text)) return true;
1080
+ return !textOnly && (text.startsWith(".") && BlockTitleRx.test(text) || text.startsWith(":") && AttributeEntryRx.test(text));
1081
+ }
1082
+ function isTextOnlyMetadata(text) {
1083
+ if (text.startsWith("[[")) return text.endsWith("]]") && BlockAnchorRx.test(text);
1084
+ if (text.startsWith("[")) return text.endsWith("]") && BlockAttributeListRx.test(text);
1085
+ return isLineComment(text);
1086
+ }
1087
+ function descriptionListDelimiter(text) {
1088
+ const match = DescriptionListRx.exec(text);
1089
+ if (!match?.[1] || !match[2]) return;
1090
+ const indent = text.length - text.replace(/^[ \t]*/u, "").length;
1091
+ return {
1092
+ raw: match[2],
1093
+ index: indent + match[1].length
1094
+ };
1095
+ }
1096
+ function terminatesParagraph(text, breakAtList) {
1097
+ return officialDelimiter(text) !== void 0 || text.startsWith("[") && BlockAttributeLineRx.test(text) || breakAtList && AnyListRx.test(text);
1098
+ }
1099
+ //#endregion
942
1100
  //#region src/official-projector.ts
943
1101
  function projectOfficialDocument(options) {
944
1102
  const targets = [];
@@ -997,6 +1155,7 @@ function buildNode(block, context) {
997
1155
  })
998
1156
  });
999
1157
  requestTitleBindings(context, block);
1158
+ requestListItemBindings(context, block);
1000
1159
  return childBlocksOf(block).flatMap((child) => toNodes(buildNode(child, context)));
1001
1160
  }
1002
1161
  }
@@ -1013,6 +1172,15 @@ function requestTitleBindings(context, block) {
1013
1172
  xrefs
1014
1173
  });
1015
1174
  }
1175
+ function requestListItemBindings(context, block) {
1176
+ if (block.getContext?.() !== "list_item") return;
1177
+ const span = context.intervalByBlock.get(block)?.contentSpan;
1178
+ const xrefs = span ? collectXrefsInSpan(context, span) : [];
1179
+ if (xrefs.length > 0) context.bindingRequests.push({
1180
+ block,
1181
+ xrefs
1182
+ });
1183
+ }
1016
1184
  function canProjectBlock(block, context) {
1017
1185
  return context.projectableBlocks?.has(block) ?? true;
1018
1186
  }
@@ -1097,15 +1265,16 @@ function buildDescriptionTerm(block, context) {
1097
1265
  const span = interval?.contentSpan ?? interval?.span;
1098
1266
  const sourceSpan = line === void 0 ? void 0 : descriptionTermSourceSpan(context.lineTable, line);
1099
1267
  const source = span && sourceSpan ? descriptionPartSourceLayer(context, span, sourceSpan, "description term") : span ? blockSourceLayer(context, interval, span, "description term") : void 0;
1100
- const xrefs = span ? collectXrefsInSpan(context, span).filter((xref) => isOccurrenceInsideSourceSpan(xref, sourceSpan)) : [];
1268
+ const occurrenceSpan = occurrenceSpanOf(context, source, sourceSpan);
1269
+ const xrefs = span ? collectXrefsInSpan(context, span).filter((xref) => isOccurrenceInsideSourceSpan(xref, occurrenceSpan)) : [];
1101
1270
  const anchors = span ? collectAnchorsInSpan(context, span).filter((anchor) => {
1102
- if (!isOccurrenceInsideSourceSpan(anchor, sourceSpan)) return false;
1271
+ if (!isOccurrenceInsideSourceSpan(anchor, occurrenceSpan)) return false;
1103
1272
  const key = anchorKey(anchor);
1104
1273
  if (context.usedAnchorKeys.has(key)) return false;
1105
1274
  context.usedAnchorKeys.add(key);
1106
1275
  return true;
1107
1276
  }) : [];
1108
- const headingInlineMetadata = span ? collectHeadingInlineMetadataInSpan(context, span).filter((occurrence) => isOccurrenceInsideSourceSpan(occurrence, sourceSpan)) : [];
1277
+ const headingInlineMetadata = span ? collectHeadingInlineMetadataInSpan(context, span).filter((occurrence) => isOccurrenceInsideSourceSpan(occurrence, occurrenceSpan)) : [];
1109
1278
  context.bindingRequests.push({
1110
1279
  block,
1111
1280
  xrefs
@@ -1131,17 +1300,18 @@ function buildDescription(block, context) {
1131
1300
  const line = block.getSourceLocation?.()?.getLineNumber?.();
1132
1301
  const interval = context.intervalByBlock.get(block);
1133
1302
  const span = interval?.contentSpan ?? interval?.span;
1134
- const sourceSpan = line === void 0 ? void 0 : descriptionTextSourceSpan(context.lineTable, line);
1303
+ const sourceSpan = interval?.contentSourceSpan;
1135
1304
  const source = span && sourceSpan ? descriptionPartSourceLayer(context, span, sourceSpan, "description item") : span ? blockSourceLayer(context, interval, span, "description item") : void 0;
1136
- const xrefs = span ? collectXrefsInSpan(context, span).filter((xref) => isOccurrenceInsideSourceSpan(xref, sourceSpan)) : [];
1305
+ const occurrenceSpan = occurrenceSpanOf(context, source, sourceSpan);
1306
+ const xrefs = span ? collectXrefsInSpan(context, span).filter((xref) => isOccurrenceInsideSourceSpan(xref, occurrenceSpan)) : [];
1137
1307
  const anchors = span ? collectAnchorsInSpan(context, span).filter((anchor) => {
1138
- if (!isOccurrenceInsideSourceSpan(anchor, sourceSpan)) return false;
1308
+ if (!isOccurrenceInsideSourceSpan(anchor, occurrenceSpan)) return false;
1139
1309
  const key = anchorKey(anchor);
1140
1310
  if (context.usedAnchorKeys.has(key)) return false;
1141
1311
  context.usedAnchorKeys.add(key);
1142
1312
  return true;
1143
1313
  }) : [];
1144
- const headingInlineMetadata = span ? collectHeadingInlineMetadataInSpan(context, span).filter((occurrence) => isOccurrenceInsideSourceSpan(occurrence, sourceSpan)) : [];
1314
+ const headingInlineMetadata = span ? collectHeadingInlineMetadataInSpan(context, span).filter((occurrence) => isOccurrenceInsideSourceSpan(occurrence, occurrenceSpan)) : [];
1145
1315
  context.bindingRequests.push({
1146
1316
  block,
1147
1317
  xrefs
@@ -1188,31 +1358,13 @@ function descriptionTermSourceSpan(lineTable, line) {
1188
1358
  }
1189
1359
  };
1190
1360
  }
1191
- function descriptionTextSourceSpan(lineTable, line) {
1192
- const delimiter = descriptionListDelimiterMatch(lineTable, line);
1193
- if (!delimiter) return;
1194
- const text = lineText(lineTable, line);
1195
- const afterDelimiterIndex = delimiter.index + delimiter.raw.length;
1196
- const firstTextIndex = /\S/u.exec(text.slice(afterDelimiterIndex))?.index ?? 0;
1197
- return {
1198
- start: {
1199
- line,
1200
- column: [...text.slice(0, afterDelimiterIndex + firstTextIndex)].length + 1
1201
- },
1202
- end: {
1203
- line,
1204
- column: [...text].length + 1
1205
- }
1206
- };
1207
- }
1208
1361
  function descriptionListDelimiterMatch(lineTable, line) {
1209
1362
  const text = lineText(lineTable, line);
1210
- const match = /:{2,4}|;;/u.exec(text);
1211
- if (!match || match.index === void 0) return;
1363
+ const delimiter = descriptionListDelimiter(text);
1364
+ if (!delimiter) return;
1212
1365
  return {
1213
- raw: match[0],
1214
- index: match.index,
1215
- column: [...text.slice(0, match.index)].length + 1
1366
+ ...delimiter,
1367
+ column: [...text.slice(0, delimiter.index)].length + 1
1216
1368
  };
1217
1369
  }
1218
1370
  function descriptionPartSourceLayer(context, span, sourceSpan, diagnosticContext) {
@@ -1223,20 +1375,28 @@ function descriptionPartSourceLayer(context, span, sourceSpan, diagnosticContext
1223
1375
  });
1224
1376
  const recovered = recoverSourceAwareSourceLayer(context.sourceAwareDocument, span, {
1225
1377
  logicalSourceSpan: sourceSpan,
1378
+ raw: "sourceSpan",
1226
1379
  diagnosticContext
1227
1380
  });
1228
1381
  return recovered.ok ? recovered.sourceLayer : void 0;
1229
1382
  }
1230
1383
  function sourceTextForSpan(context, sourceSpan) {
1231
- if (sourceSpan.start.line !== sourceSpan.end.line) return;
1232
- return Array.from(lineText(context.lineTable, sourceSpan.start.line)).slice(sourceSpan.start.column - 1, sourceSpan.end.column - 1).join("");
1384
+ const lines = [];
1385
+ for (let line = sourceSpan.start.line; line <= sourceSpan.end.line; line += 1) {
1386
+ const chars = Array.from(lineText(context.lineTable, line));
1387
+ lines.push(chars.slice(line === sourceSpan.start.line ? sourceSpan.start.column - 1 : 0, line === sourceSpan.end.line ? sourceSpan.end.column - 1 : void 0).join(""));
1388
+ }
1389
+ return lines.join("\n");
1390
+ }
1391
+ function occurrenceSpanOf(context, source, sourceSpan) {
1392
+ return context.sourceAwareDocument ? source?.sourceSpan : sourceSpan;
1233
1393
  }
1234
1394
  function isOccurrenceInsideSourceSpan(occurrence, sourceSpan) {
1235
1395
  if (!sourceSpan || !occurrence.sourceSpan) return true;
1236
- const start = occurrence.sourceSpan.start;
1237
- const end = occurrence.sourceSpan.end;
1238
- if (start.line !== sourceSpan.start.line || end.line !== sourceSpan.end.line) return false;
1239
- return start.column >= sourceSpan.start.column && end.column <= sourceSpan.end.column;
1396
+ return comparePositions(occurrence.sourceSpan.start, sourceSpan.start) >= 0 && comparePositions(occurrence.sourceSpan.end, sourceSpan.end) <= 0;
1397
+ }
1398
+ function comparePositions(left, right) {
1399
+ return left.line - right.line || left.column - right.column;
1240
1400
  }
1241
1401
  function mergeNodeLineSpans(spans) {
1242
1402
  const present = spans.filter(isLineSpan);
@@ -1453,7 +1613,7 @@ function blockSourceLayer(context, interval, fallbackSpan, diagnosticContext) {
1453
1613
  const logicalSourceSpan = sameLineSpan(fallbackSpan, interval.span) ? interval.sourceSpan : void 0;
1454
1614
  const recovered = recoverSourceAwareSourceLayer(context.sourceAwareDocument, fallbackSpan, {
1455
1615
  logicalSourceSpan,
1456
- raw: true,
1616
+ raw: "lines",
1457
1617
  diagnosticContext
1458
1618
  });
1459
1619
  return recovered.ok ? recovered.sourceLayer : void 0;
@@ -1782,117 +1942,6 @@ function parseStyleIdRoles(part) {
1782
1942
  });
1783
1943
  }
1784
1944
  //#endregion
1785
- //#region src/official-delimiter.ts
1786
- const DELIMITED_BLOCKS = {
1787
- "--": ["open", new Set([
1788
- "comment",
1789
- "example",
1790
- "literal",
1791
- "listing",
1792
- "pass",
1793
- "quote",
1794
- "sidebar",
1795
- "source",
1796
- "verse",
1797
- "admonition",
1798
- "abstract",
1799
- "partintro"
1800
- ])],
1801
- "----": ["listing", new Set(["literal", "source"])],
1802
- "....": ["literal", new Set(["listing", "source"])],
1803
- "====": ["example", new Set(["admonition"])],
1804
- "****": ["sidebar", /* @__PURE__ */ new Set()],
1805
- ____: ["quote", new Set(["verse"])],
1806
- "++++": ["pass", new Set([
1807
- "stem",
1808
- "latexmath",
1809
- "asciimath"
1810
- ])],
1811
- "|===": ["table", /* @__PURE__ */ new Set()],
1812
- ",===": ["table", /* @__PURE__ */ new Set()],
1813
- ":===": ["table", /* @__PURE__ */ new Set()],
1814
- "!===": ["table", /* @__PURE__ */ new Set()],
1815
- "~~~~": ["open", new Set(["abstract", "partintro"])],
1816
- "////": ["comment", /* @__PURE__ */ new Set()],
1817
- "```": ["fenced_code", /* @__PURE__ */ new Set()]
1818
- };
1819
- const DELIMITED_BLOCK_HEADS = new Set(Object.keys(DELIMITED_BLOCKS).map((delimiter) => delimiter.slice(0, 2)));
1820
- const DELIMITED_BLOCK_TAILS = Object.fromEntries(Object.keys(DELIMITED_BLOCKS).filter((delimiter) => delimiter.length === 4).map((delimiter) => [delimiter, delimiter.slice(-1)]));
1821
- function officialDelimiter(line) {
1822
- let candidate = line;
1823
- let lineLength = candidate.length;
1824
- if (lineLength < 2 || !DELIMITED_BLOCK_HEADS.has(candidate.slice(0, 2))) return;
1825
- let tip;
1826
- let tipLength;
1827
- if (lineLength === 2) {
1828
- tip = candidate;
1829
- tipLength = 2;
1830
- } else {
1831
- tipLength = lineLength < 5 ? lineLength : 4;
1832
- tip = candidate.slice(0, tipLength);
1833
- if (tip.startsWith("`")) {
1834
- if (tipLength === 4) {
1835
- if (tip === "````") return;
1836
- tip = tip.slice(0, 3);
1837
- if (tip !== "```") return;
1838
- candidate = tip;
1839
- lineLength = 3;
1840
- tipLength = 3;
1841
- } else if (tip !== "```") return;
1842
- } else if (tipLength === 3) return;
1843
- }
1844
- const entry = DELIMITED_BLOCKS[tip];
1845
- if (!entry) return;
1846
- const tail = DELIMITED_BLOCK_TAILS[tip];
1847
- if (!(lineLength === tipLength || tail !== void 0 && isUniform(candidate.slice(1), tail))) return;
1848
- const [context, masq] = entry;
1849
- return {
1850
- context,
1851
- masq,
1852
- terminator: candidate
1853
- };
1854
- }
1855
- function delimiterOpens(delimiter, context, style) {
1856
- if (context === void 0) return false;
1857
- if (delimiter.context === "fenced_code") return context === "listing";
1858
- return delimiter.context === context || delimiter.masq.has(context) || style !== null && style !== void 0 && delimiter.masq.has(style);
1859
- }
1860
- function isUniform(text, character) {
1861
- return [...text].every((each) => each === character);
1862
- }
1863
- //#endregion
1864
- //#region src/official-paragraph.ts
1865
- const CC_ALPHA = String.raw`\p{Alphabetic}`;
1866
- const CC_WORD = String.raw`\p{Alphabetic}\p{N}\p{Pc}`;
1867
- const BlockAttributeLineRx = new RegExp(String.raw`^\[(?:|[${CC_WORD}.#%{,"'].*|\[(?:|[${CC_ALPHA}_:][${CC_WORD}\-:.]*(?:, *.+)?)\])\]$`, "u");
1868
- const AnyListRx = /^(?:[ \t]*(?:-|\*\**|\.\.*|•|\d+\.|[a-zA-Z]\.|[IVXivx]+\))[ \t]|(?!\/\/[^/])[ \t]*[^ \t].*?(?::::{0,2}|;;)(?:$|[ \t])|<(?:\d+|\.)>[ \t])/;
1869
- const BlockAnchorRx = new RegExp(String.raw`^\[\[(?:|([${CC_ALPHA}_:][${CC_WORD}\-:.]*)(?:, *(.+))?)\]\]$`, "u");
1870
- const BlockAttributeListRx = new RegExp(String.raw`^\[(|[${CC_WORD}.#%{,"'].*)\]$`, "u");
1871
- function paragraphEndLine(lineTable, startLine, breakAtList) {
1872
- let last = startLine;
1873
- for (let line = startLine + 1; line <= lineTable.lines.length; line += 1) {
1874
- const text = lineText(lineTable, line).trimEnd();
1875
- if (text === "" || text === "+" || terminatesParagraph(text, breakAtList)) break;
1876
- if (!isLineComment(text)) last = line;
1877
- }
1878
- return last;
1879
- }
1880
- function listItemTextEndLine(lineTable, markerLine) {
1881
- let line = markerLine + 1;
1882
- while (line <= lineTable.lines.length && isTextOnlyMetadata(lineText(lineTable, line).trimEnd())) line += 1;
1883
- const text = lineText(lineTable, line).trimEnd();
1884
- if (line > lineTable.lines.length || text === "" || text === "+" || terminatesParagraph(text, true)) return markerLine;
1885
- return paragraphEndLine(lineTable, line, true);
1886
- }
1887
- function isTextOnlyMetadata(text) {
1888
- if (text.startsWith("[[")) return text.endsWith("]]") && BlockAnchorRx.test(text);
1889
- if (text.startsWith("[")) return text.endsWith("]") && BlockAttributeListRx.test(text);
1890
- return isLineComment(text);
1891
- }
1892
- function terminatesParagraph(text, breakAtList) {
1893
- return officialDelimiter(text) !== void 0 || text.startsWith("[") && BlockAttributeLineRx.test(text) || breakAtList && AnyListRx.test(text);
1894
- }
1895
- //#endregion
1896
1945
  //#region src/source-interval-resolver.ts
1897
1946
  function resolveSourceInterval(surface, sourceTable) {
1898
1947
  if (surface.sourceLine === void 0) return;
@@ -1902,12 +1951,13 @@ function resolveSourceInterval(surface, sourceTable) {
1902
1951
  const startLine = metadata.at(0)?.line ?? blockStartLine;
1903
1952
  const diagnostics = [];
1904
1953
  const delimitedContext = isDelimitedContext(surface.context);
1954
+ const description = isDescription(surface) ? descriptionTextOf(surface, lineTable) : void 0;
1905
1955
  const synthesized = borrowsChildSourceLocation(surface.block);
1906
1956
  const delimited = delimitedContext ? resolveDelimitedBlockSpan(lineTable, blockStartLine, surface) : void 0;
1907
1957
  const undelimited = delimitedContext && delimited === void 0 && !synthesized ? resolveUndelimitedBlockSpan(lineTable, sourceTable, blockStartLine, surface) : void 0;
1908
1958
  const sourceContentSpan = sourceContentSpanForContext(surface, lineTable, blockStartLine);
1909
1959
  const nextSiblingStart = nextSiblingStartLine(surface, lineTable);
1910
- const childEndLine = surface.context === "dlist" ? lastChildEndLine(surface, lineTable) : void 0;
1960
+ const childEndLine = surface.context === "dlist" ? lastChildEndLine(surface, sourceTable) : void 0;
1911
1961
  const endLine = delimited?.span.endLine ?? undelimited?.span.endLine ?? sourceContentSpan?.endLine ?? childEndLine ?? (nextSiblingStart !== void 0 ? nextSiblingStart - 1 : void 0) ?? parentEndLine(surface, sourceTable) ?? lineTable.lines.length;
1912
1962
  const span = normalizeLineSpan({
1913
1963
  startLine,
@@ -1923,9 +1973,11 @@ function resolveSourceInterval(surface, sourceTable) {
1923
1973
  message: `Could not locate ${surface.context} block delimiter from official source line ${blockStartLine}.`,
1924
1974
  source: spanForLineText(sourceTable, blockStartLine, 1)
1925
1975
  });
1926
- const contentSpan = delimited?.contentSpan ?? undelimited?.contentSpan ?? sourceContentSpan ?? contentSpanForContext(surface, span, lineTable);
1976
+ const contentSpan = delimited?.contentSpan ?? undelimited?.contentSpan ?? sourceContentSpan ?? description?.span ?? contentSpanForContext(surface, span, lineTable);
1927
1977
  const sourceSpan = sourceSpanFromLineSpan(sourceTable, span);
1928
1978
  const titleSpan = titleSpanForSurface(surface, sourceTable);
1979
+ const contentSourceSpan = description ? descriptionSourceSpan(description, sourceTable, lineTable) : void 0;
1980
+ const readsLineComments = delimited !== void 0 || description?.readsLineComments === true;
1929
1981
  return {
1930
1982
  blockStartLine,
1931
1983
  metadata,
@@ -1933,9 +1985,33 @@ function resolveSourceInterval(surface, sourceTable) {
1933
1985
  diagnostics,
1934
1986
  ...metadataSpan ? { metadataSpan } : {},
1935
1987
  ...contentSpan ? { contentSpan } : {},
1988
+ ...contentSourceSpan ? { contentSourceSpan } : {},
1989
+ ...description?.discardedSpan ? { discardedSpan: description.discardedSpan } : {},
1936
1990
  ...sourceSpan ? { sourceSpan } : {},
1937
1991
  ...titleSpan ? { titleSpan } : {},
1938
- ...delimited ? { delimited: true } : {}
1992
+ ...readsLineComments ? { readsLineComments: true } : {}
1993
+ };
1994
+ }
1995
+ function isDescription(surface) {
1996
+ const list = surface.parent;
1997
+ return list?.context === "dlist" && descriptionListItemsFromBlock(list.block).some((item) => item.description === surface.block);
1998
+ }
1999
+ function descriptionTextOf(surface, lineTable) {
2000
+ const termLine = surface.parent?.children[surface.indexInParent - 1]?.sourceLine;
2001
+ if (termLine === void 0) return;
2002
+ return descriptionText(lineTable, termLine, (line) => surface.children.some((child) => child.sourceLine === line));
2003
+ }
2004
+ function descriptionSourceSpan(description, sourceTable, lineTable) {
2005
+ const { startLine, endLine } = description.span;
2006
+ return {
2007
+ start: {
2008
+ line: startLine,
2009
+ column: [...lineText(sourceTable, startLine)].length - [...lineText(lineTable, startLine)].length + description.startColumn
2010
+ },
2011
+ end: {
2012
+ line: endLine,
2013
+ column: [...lineText(sourceTable, endLine)].length + 1
2014
+ }
1939
2015
  };
1940
2016
  }
1941
2017
  function nextSiblingStartLine(surface, lineTable) {
@@ -1949,13 +2025,24 @@ function metadataForSurface(surface, lineTable, blockStartLine) {
1949
2025
  if (takesParentSourceLocation(surface.block)) return [];
1950
2026
  return collectPrecedingMetadata(lineTable, blockStartLine);
1951
2027
  }
1952
- function lastChildEndLine(surface, lineTable) {
1953
- const childLines = surface.children.flatMap((child) => descendantSourceLines(child));
2028
+ function lastChildEndLine(surface, sourceTable) {
2029
+ const childLines = surface.children.map((child) => enclosedEndLine(child, sourceTable)).filter((line) => line !== void 0);
1954
2030
  if (childLines.length === 0) return;
1955
- return Math.min(Math.max(...childLines), lastContentLine(lineTable));
2031
+ return Math.min(Math.max(...childLines), lastContentLine(sourceTable));
2032
+ }
2033
+ function enclosedEndLine(surface, sourceTable) {
2034
+ const ends = [surface.sourceLine === void 0 ? void 0 : ownEndLine(surface, sourceTable, surface.sourceLine), ...surface.children.map((child) => enclosedEndLine(child, sourceTable))].filter((line) => line !== void 0);
2035
+ return ends.length > 0 ? Math.max(...ends) : void 0;
1956
2036
  }
1957
- function descendantSourceLines(surface) {
1958
- return [...surface.sourceLine === void 0 ? [] : [surface.sourceLine], ...surface.children.flatMap((child) => descendantSourceLines(child))];
2037
+ function ownEndLine(surface, sourceTable, startLine) {
2038
+ const lineTable = quotedLineTable(sourceTable, markdownQuoteDepth(surface.block));
2039
+ const delimited = isDelimitedContext(surface.context) && !borrowsChildSourceLocation(surface.block) ? resolveDelimitedBlockSpan(lineTable, startLine, surface) ?? resolveUndelimitedBlockSpan(lineTable, sourceTable, startLine, surface) : void 0;
2040
+ if (delimited) return delimited.span.endLine;
2041
+ const paragraph = sourceContentSpanForContext(surface, lineTable, startLine);
2042
+ if (paragraph) return paragraph.endLine;
2043
+ if (isDescription(surface)) return descriptionTextOf(surface, lineTable)?.span.endLine ?? startLine;
2044
+ if (surface.context === "list_item" && surface.parent?.context !== "dlist") return listItemTextEndLine(lineTable, startLine);
2045
+ return startLine;
1959
2046
  }
1960
2047
  function parentEndLine(surface, lineTable) {
1961
2048
  const parent = surface.parent;
@@ -2187,15 +2274,12 @@ function scanSurfaces(collected, surfaces, intervalByBlock) {
2187
2274
  if (officialBlockPolicy(surface.block) !== "scan") continue;
2188
2275
  if (!scansMacroSubstitutedContent(surface)) continue;
2189
2276
  if (surface.context === "table") scanTable(collected, surface.block);
2190
- else scanInlineRange(collected.lineTable, span.startLine, span.endLine, collected.xrefOccurrences, collected.anchorOccurrences, collected.headingInlineMetadataOccurrences, collected.toolDiagnostics, descendantUnscannableRanges(surface, intervalByBlock), isBibliographyList(surface), skipsLineComments(surface, interval) ? quotedLineTable(collected.lineTable, markdownQuoteDepth(surface.block)) : null);
2277
+ else scanInlineRange(collected.lineTable, span.startLine, span.endLine, collected.xrefOccurrences, collected.anchorOccurrences, collected.headingInlineMetadataOccurrences, collected.toolDiagnostics, [...descendantUnscannableRanges(surface, intervalByBlock), ...interval.discardedSpan ? [interval.discardedSpan] : []], isBibliographyList(surface), interval.readsLineComments ? null : quotedLineTable(collected.lineTable, markdownQuoteDepth(surface.block)));
2191
2278
  }
2192
2279
  }
2193
2280
  function isHeading(surface) {
2194
2281
  return surface.context === "section" || surface.context === "floating_title";
2195
2282
  }
2196
- function skipsLineComments(surface, interval) {
2197
- return interval.delimited !== true || surface.block.getContentModel?.() === "compound";
2198
- }
2199
2283
  function hasDiagnosticPolicyAncestor$1(surface) {
2200
2284
  let current = surface.parent;
2201
2285
  while (current) {
@@ -2208,7 +2292,7 @@ function isPreambleParagraph(surface) {
2208
2292
  return surface.context === "paragraph" && surface.parent?.context === "preamble";
2209
2293
  }
2210
2294
  function scansMacroSubstitutedContent(surface) {
2211
- if (surface.context === "dlist" || surface.context === "table") return true;
2295
+ if (surface.context === "table") return true;
2212
2296
  const substitutions = surface.block.getSubstitutions?.();
2213
2297
  return !Array.isArray(substitutions) || substitutions.includes("macros");
2214
2298
  }
@@ -2505,7 +2589,7 @@ function projectSourceSurfaces(options) {
2505
2589
  ].includes(surface.context ?? "")) {
2506
2590
  const recovered = recoverSourceAwareSourceLayer(sourceAwareDocument, interval.span, {
2507
2591
  logicalSourceSpan: interval.sourceSpan,
2508
- raw: true,
2592
+ raw: "lines",
2509
2593
  diagnosticContext: `${surface.context} block`
2510
2594
  });
2511
2595
  if (!recovered.ok) toolDiagnostics.push(recovered.diagnostic);
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as parseAbundantTree, i as serializeAbundantTreeToJson, n as formatAbundantTree, t as rdf12 } from "./src-8G5Sgsvr.mjs";
2
+ import { a as parseAbundantTree, i as serializeAbundantTreeToJson, n as formatAbundantTree, t as rdf12 } from "./src-COUYWnMz.mjs";
3
3
  import { relative, resolve, sep } from "node:path";
4
4
  import { existsSync } from "node:fs";
5
5
  import process from "node:process";
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { a as parseAbundantTree, i as serializeAbundantTreeToJson, n as formatAbundantTree, o as exportAnimationYaml, r as serializeAbundantTree, t as rdf12 } from "./src-8G5Sgsvr.mjs";
1
+ import { a as parseAbundantTree, i as serializeAbundantTreeToJson, n as formatAbundantTree, o as exportAnimationYaml, r as serializeAbundantTree, t as rdf12 } from "./src-COUYWnMz.mjs";
2
2
  export { exportAnimationYaml, formatAbundantTree, parseAbundantTree, rdf12, serializeAbundantTree, serializeAbundantTreeToJson };
@@ -780,6 +780,7 @@ function recoverSourceAwareSourceLayer(document, logicalSpan, options) {
780
780
  };
781
781
  const sourceSpan = options.logicalSourceSpan ? recoverSourceAwareSpan(document, options.logicalSourceSpan, false) : void 0;
782
782
  if (sourceSpan && !sourceSpan.ok) return sourceSpan;
783
+ const raw = options.raw === "lines" ? `${sourceLines(sourceFile.lineTable, lineSpan.startLine, lineSpan.endLine).join("\n")}\n` : options.raw === "sourceSpan" && sourceSpan?.sourceSpan ? sliceSourceSpan(sourceFile.lineTable, sourceSpan.sourceSpan) : void 0;
783
784
  return {
784
785
  ok: true,
785
786
  relativePath,
@@ -790,10 +791,13 @@ function recoverSourceAwareSourceLayer(document, logicalSpan, options) {
790
791
  line: lineSpan.startLine,
791
792
  span: lineSpan,
792
793
  ...sourceSpan?.sourceSpan ? { sourceSpan: sourceSpan.sourceSpan } : {},
793
- ...options.raw ? { raw: `${sourceLines(sourceFile.lineTable, lineSpan.startLine, lineSpan.endLine).join("\n")}\n` } : {}
794
+ ...raw === void 0 ? {} : { raw }
794
795
  }
795
796
  };
796
797
  }
798
+ function sliceSourceSpan(lineTable, span) {
799
+ return sourceLines(lineTable, span.start.line, span.end.line).map((text, index, lines) => Array.from(text).slice(index === 0 ? span.start.column - 1 : 0, index === lines.length - 1 ? span.end.column - 1 : void 0).join("")).join("\n");
800
+ }
797
801
  function recoverSourceAwarePointSourceLayer(document, logicalSourceSpan, raw) {
798
802
  const recovered = recoverSourceAwareSpan(document, logicalSourceSpan, true);
799
803
  if (!recovered.ok) {
@@ -3789,12 +3793,7 @@ function trimBlankEdges(lines) {
3789
3793
  return lines.slice(first, last);
3790
3794
  }
3791
3795
  function descriptionMetadataTermKey(term) {
3792
- const raw = term.source?.raw;
3793
- const sourceSpan = term.sourceSpan;
3794
- if (!raw || !sourceSpan || sourceSpan.start.line !== sourceSpan.end.line) return term.text;
3795
- const [line] = raw.split(/\r?\n/u);
3796
- if (line === void 0) return term.text;
3797
- return Array.from(line).slice(sourceSpan.start.column - 1, sourceSpan.end.column - 1).join("");
3796
+ return term.source?.raw || term.text;
3798
3797
  }
3799
3798
  function mergeRunSource(run) {
3800
3799
  const sources = run.map((list) => list.source);
@@ -3850,12 +3849,12 @@ function sourcesHaveContiguousLineSpans(sources) {
3850
3849
  return true;
3851
3850
  }
3852
3851
  function earliestPosition(positions) {
3853
- return positions.reduce((earliest, position) => comparePositions(position, earliest) < 0 ? position : earliest);
3852
+ return positions.reduce((earliest, position) => comparePositions$1(position, earliest) < 0 ? position : earliest);
3854
3853
  }
3855
3854
  function latestPosition(positions) {
3856
- return positions.reduce((latest, position) => comparePositions(position, latest) > 0 ? position : latest);
3855
+ return positions.reduce((latest, position) => comparePositions$1(position, latest) > 0 ? position : latest);
3857
3856
  }
3858
- function comparePositions(left, right) {
3857
+ function comparePositions$1(left, right) {
3859
3858
  return left.line - right.line || left.column - right.column;
3860
3859
  }
3861
3860
  //#endregion
@@ -3863,7 +3862,6 @@ function comparePositions(left, right) {
3863
3862
  function officialBlockPolicy(block) {
3864
3863
  switch (block.getContext?.()) {
3865
3864
  case "admonition":
3866
- case "dlist":
3867
3865
  case "list_item":
3868
3866
  case "paragraph":
3869
3867
  case "table":
@@ -3874,6 +3872,7 @@ function officialBlockPolicy(block) {
3874
3872
  case "open": return block.getContentModel?.() === "simple" ? "scan" : "recurse";
3875
3873
  case "olist":
3876
3874
  case "colist":
3875
+ case "dlist":
3877
3876
  case "preamble":
3878
3877
  case "section":
3879
3878
  case "ulist": return "recurse";
@@ -3941,6 +3940,165 @@ function descriptionListItemFromRaw(rawItem) {
3941
3940
  };
3942
3941
  }
3943
3942
  //#endregion
3943
+ //#region src/official-delimiter.ts
3944
+ const DELIMITED_BLOCKS = {
3945
+ "--": ["open", new Set([
3946
+ "comment",
3947
+ "example",
3948
+ "literal",
3949
+ "listing",
3950
+ "pass",
3951
+ "quote",
3952
+ "sidebar",
3953
+ "source",
3954
+ "verse",
3955
+ "admonition",
3956
+ "abstract",
3957
+ "partintro"
3958
+ ])],
3959
+ "----": ["listing", new Set(["literal", "source"])],
3960
+ "....": ["literal", new Set(["listing", "source"])],
3961
+ "====": ["example", new Set(["admonition"])],
3962
+ "****": ["sidebar", /* @__PURE__ */ new Set()],
3963
+ ____: ["quote", new Set(["verse"])],
3964
+ "++++": ["pass", new Set([
3965
+ "stem",
3966
+ "latexmath",
3967
+ "asciimath"
3968
+ ])],
3969
+ "|===": ["table", /* @__PURE__ */ new Set()],
3970
+ ",===": ["table", /* @__PURE__ */ new Set()],
3971
+ ":===": ["table", /* @__PURE__ */ new Set()],
3972
+ "!===": ["table", /* @__PURE__ */ new Set()],
3973
+ "~~~~": ["open", new Set(["abstract", "partintro"])],
3974
+ "////": ["comment", /* @__PURE__ */ new Set()],
3975
+ "```": ["fenced_code", /* @__PURE__ */ new Set()]
3976
+ };
3977
+ const DELIMITED_BLOCK_HEADS = new Set(Object.keys(DELIMITED_BLOCKS).map((delimiter) => delimiter.slice(0, 2)));
3978
+ const DELIMITED_BLOCK_TAILS = Object.fromEntries(Object.keys(DELIMITED_BLOCKS).filter((delimiter) => delimiter.length === 4).map((delimiter) => [delimiter, delimiter.slice(-1)]));
3979
+ function officialDelimiter(line) {
3980
+ let candidate = line;
3981
+ let lineLength = candidate.length;
3982
+ if (lineLength < 2 || !DELIMITED_BLOCK_HEADS.has(candidate.slice(0, 2))) return;
3983
+ let tip;
3984
+ let tipLength;
3985
+ if (lineLength === 2) {
3986
+ tip = candidate;
3987
+ tipLength = 2;
3988
+ } else {
3989
+ tipLength = lineLength < 5 ? lineLength : 4;
3990
+ tip = candidate.slice(0, tipLength);
3991
+ if (tip.startsWith("`")) {
3992
+ if (tipLength === 4) {
3993
+ if (tip === "````") return;
3994
+ tip = tip.slice(0, 3);
3995
+ if (tip !== "```") return;
3996
+ candidate = tip;
3997
+ lineLength = 3;
3998
+ tipLength = 3;
3999
+ } else if (tip !== "```") return;
4000
+ } else if (tipLength === 3) return;
4001
+ }
4002
+ const entry = DELIMITED_BLOCKS[tip];
4003
+ if (!entry) return;
4004
+ const tail = DELIMITED_BLOCK_TAILS[tip];
4005
+ if (!(lineLength === tipLength || tail !== void 0 && isUniform(candidate.slice(1), tail))) return;
4006
+ const [context, masq] = entry;
4007
+ return {
4008
+ context,
4009
+ masq,
4010
+ terminator: candidate
4011
+ };
4012
+ }
4013
+ function delimiterOpens(delimiter, context, style) {
4014
+ if (context === void 0) return false;
4015
+ if (delimiter.context === "fenced_code") return context === "listing";
4016
+ return delimiter.context === context || delimiter.masq.has(context) || style !== null && style !== void 0 && delimiter.masq.has(style);
4017
+ }
4018
+ function isUniform(text, character) {
4019
+ return [...text].every((each) => each === character);
4020
+ }
4021
+ //#endregion
4022
+ //#region src/official-paragraph.ts
4023
+ const CC_ALPHA = String.raw`\p{Alphabetic}`;
4024
+ const CC_WORD = String.raw`\p{Alphabetic}\p{N}\p{Pc}`;
4025
+ const BlockAttributeLineRx = new RegExp(String.raw`^\[(?:|[${CC_WORD}.#%{,"'].*|\[(?:|[${CC_ALPHA}_:][${CC_WORD}\-:.]*(?:, *.+)?)\])\]$`, "u");
4026
+ const AnyListRx = /^(?:[ \t]*(?:-|\*\**|\.\.*|•|\d+\.|[a-zA-Z]\.|[IVXivx]+\))[ \t]|(?!\/\/[^/])[ \t]*[^ \t].*?(?::::{0,2}|;;)(?:$|[ \t])|<(?:\d+|\.)>[ \t])/;
4027
+ const BlockAnchorRx = new RegExp(String.raw`^\[\[(?:|([${CC_ALPHA}_:][${CC_WORD}\-:.]*)(?:, *(.+))?)\]\]$`, "u");
4028
+ const BlockAttributeListRx = new RegExp(String.raw`^\[(|[${CC_WORD}.#%{,"'].*)\]$`, "u");
4029
+ const DescriptionListRx = /^(?!\/\/[^/])[ \t]*([^ \t].*?)(:::{0,2}|;;)(?:$|[ \t]+([\s\S]*)$)/;
4030
+ const BlockTitleRx = /^\.(\.?[^ \t.].*)$/;
4031
+ const AttributeEntryRx = new RegExp(String.raw`^:(!?[${CC_WORD}][^:]*):(?:[ \t]+(.*))?$`, "u");
4032
+ function paragraphEndLine(lineTable, startLine, breakAtList, skipsLineComments = true) {
4033
+ let last = startLine;
4034
+ for (let line = startLine + 1; line <= lineTable.lines.length; line += 1) {
4035
+ const text = lineText(lineTable, line).trimEnd();
4036
+ if (text === "" || text === "+" || terminatesParagraph(text, breakAtList)) break;
4037
+ if (!(skipsLineComments && isLineComment(text))) last = line;
4038
+ }
4039
+ return last;
4040
+ }
4041
+ function listItemTextEndLine(lineTable, markerLine) {
4042
+ let line = markerLine + 1;
4043
+ while (line <= lineTable.lines.length && isTextOnlyMetadata(lineText(lineTable, line).trimEnd())) line += 1;
4044
+ const text = lineText(lineTable, line).trimEnd();
4045
+ if (line > lineTable.lines.length || text === "" || text === "+" || terminatesParagraph(text, true)) return markerLine;
4046
+ return paragraphEndLine(lineTable, line, true);
4047
+ }
4048
+ function descriptionText(lineTable, termLine, occupied) {
4049
+ const termText = lineText(lineTable, termLine).trimEnd();
4050
+ const itemText = DescriptionListRx.exec(termText)?.[3];
4051
+ const hasText = Boolean(itemText);
4052
+ const termTextColumn = [...termText].length - [...itemText ?? ""].length + 1;
4053
+ const lastLine = lineTable.lines.length;
4054
+ let line = termLine + 1;
4055
+ if (!hasText) while (line <= lastLine && lineText(lineTable, line).trim() === "") line += 1;
4056
+ while (line <= lastLine && isDescriptionMetadata(lineText(lineTable, line).trimEnd(), !hasText)) line += 1;
4057
+ const text = lineText(lineTable, line).trimEnd();
4058
+ if (!(line <= lastLine && text !== "" && text !== "+" && !terminatesParagraph(text, true) && !occupied(line))) return hasText ? {
4059
+ span: {
4060
+ startLine: termLine,
4061
+ endLine: termLine
4062
+ },
4063
+ startColumn: termTextColumn,
4064
+ readsLineComments: false
4065
+ } : void 0;
4066
+ const readsLineComments = hasText && /^[ \t]/u.test(lineText(lineTable, line));
4067
+ return {
4068
+ span: {
4069
+ startLine: hasText ? termLine : line,
4070
+ endLine: paragraphEndLine(lineTable, line, true, !readsLineComments)
4071
+ },
4072
+ startColumn: hasText ? termTextColumn : 1,
4073
+ ...hasText && line > termLine + 1 ? { discardedSpan: {
4074
+ startLine: termLine + 1,
4075
+ endLine: line - 1
4076
+ } } : {},
4077
+ readsLineComments
4078
+ };
4079
+ }
4080
+ function isDescriptionMetadata(text, textOnly) {
4081
+ if (isLineComment(text)) return true;
4082
+ return !textOnly && (text.startsWith(".") && BlockTitleRx.test(text) || text.startsWith(":") && AttributeEntryRx.test(text));
4083
+ }
4084
+ function isTextOnlyMetadata(text) {
4085
+ if (text.startsWith("[[")) return text.endsWith("]]") && BlockAnchorRx.test(text);
4086
+ if (text.startsWith("[")) return text.endsWith("]") && BlockAttributeListRx.test(text);
4087
+ return isLineComment(text);
4088
+ }
4089
+ function descriptionListDelimiter(text) {
4090
+ const match = DescriptionListRx.exec(text);
4091
+ if (!match?.[1] || !match[2]) return;
4092
+ const indent = text.length - text.replace(/^[ \t]*/u, "").length;
4093
+ return {
4094
+ raw: match[2],
4095
+ index: indent + match[1].length
4096
+ };
4097
+ }
4098
+ function terminatesParagraph(text, breakAtList) {
4099
+ return officialDelimiter(text) !== void 0 || text.startsWith("[") && BlockAttributeLineRx.test(text) || breakAtList && AnyListRx.test(text);
4100
+ }
4101
+ //#endregion
3944
4102
  //#region src/official-projector.ts
3945
4103
  function projectOfficialDocument(options) {
3946
4104
  const targets = [];
@@ -3999,6 +4157,7 @@ function buildNode(block, context) {
3999
4157
  })
4000
4158
  });
4001
4159
  requestTitleBindings(context, block);
4160
+ requestListItemBindings(context, block);
4002
4161
  return childBlocksOf(block).flatMap((child) => toNodes(buildNode(child, context)));
4003
4162
  }
4004
4163
  }
@@ -4015,6 +4174,15 @@ function requestTitleBindings(context, block) {
4015
4174
  xrefs
4016
4175
  });
4017
4176
  }
4177
+ function requestListItemBindings(context, block) {
4178
+ if (block.getContext?.() !== "list_item") return;
4179
+ const span = context.intervalByBlock.get(block)?.contentSpan;
4180
+ const xrefs = span ? collectXrefsInSpan(context, span) : [];
4181
+ if (xrefs.length > 0) context.bindingRequests.push({
4182
+ block,
4183
+ xrefs
4184
+ });
4185
+ }
4018
4186
  function canProjectBlock(block, context) {
4019
4187
  return context.projectableBlocks?.has(block) ?? true;
4020
4188
  }
@@ -4099,15 +4267,16 @@ function buildDescriptionTerm(block, context) {
4099
4267
  const span = interval?.contentSpan ?? interval?.span;
4100
4268
  const sourceSpan = line === void 0 ? void 0 : descriptionTermSourceSpan(context.lineTable, line);
4101
4269
  const source = span && sourceSpan ? descriptionPartSourceLayer(context, span, sourceSpan, "description term") : span ? blockSourceLayer(context, interval, span, "description term") : void 0;
4102
- const xrefs = span ? collectXrefsInSpan(context, span).filter((xref) => isOccurrenceInsideSourceSpan(xref, sourceSpan)) : [];
4270
+ const occurrenceSpan = occurrenceSpanOf(context, source, sourceSpan);
4271
+ const xrefs = span ? collectXrefsInSpan(context, span).filter((xref) => isOccurrenceInsideSourceSpan(xref, occurrenceSpan)) : [];
4103
4272
  const anchors = span ? collectAnchorsInSpan(context, span).filter((anchor) => {
4104
- if (!isOccurrenceInsideSourceSpan(anchor, sourceSpan)) return false;
4273
+ if (!isOccurrenceInsideSourceSpan(anchor, occurrenceSpan)) return false;
4105
4274
  const key = anchorKey(anchor);
4106
4275
  if (context.usedAnchorKeys.has(key)) return false;
4107
4276
  context.usedAnchorKeys.add(key);
4108
4277
  return true;
4109
4278
  }) : [];
4110
- const headingInlineMetadata = span ? collectHeadingInlineMetadataInSpan(context, span).filter((occurrence) => isOccurrenceInsideSourceSpan(occurrence, sourceSpan)) : [];
4279
+ const headingInlineMetadata = span ? collectHeadingInlineMetadataInSpan(context, span).filter((occurrence) => isOccurrenceInsideSourceSpan(occurrence, occurrenceSpan)) : [];
4111
4280
  context.bindingRequests.push({
4112
4281
  block,
4113
4282
  xrefs
@@ -4133,17 +4302,18 @@ function buildDescription(block, context) {
4133
4302
  const line = block.getSourceLocation?.()?.getLineNumber?.();
4134
4303
  const interval = context.intervalByBlock.get(block);
4135
4304
  const span = interval?.contentSpan ?? interval?.span;
4136
- const sourceSpan = line === void 0 ? void 0 : descriptionTextSourceSpan(context.lineTable, line);
4305
+ const sourceSpan = interval?.contentSourceSpan;
4137
4306
  const source = span && sourceSpan ? descriptionPartSourceLayer(context, span, sourceSpan, "description item") : span ? blockSourceLayer(context, interval, span, "description item") : void 0;
4138
- const xrefs = span ? collectXrefsInSpan(context, span).filter((xref) => isOccurrenceInsideSourceSpan(xref, sourceSpan)) : [];
4307
+ const occurrenceSpan = occurrenceSpanOf(context, source, sourceSpan);
4308
+ const xrefs = span ? collectXrefsInSpan(context, span).filter((xref) => isOccurrenceInsideSourceSpan(xref, occurrenceSpan)) : [];
4139
4309
  const anchors = span ? collectAnchorsInSpan(context, span).filter((anchor) => {
4140
- if (!isOccurrenceInsideSourceSpan(anchor, sourceSpan)) return false;
4310
+ if (!isOccurrenceInsideSourceSpan(anchor, occurrenceSpan)) return false;
4141
4311
  const key = anchorKey(anchor);
4142
4312
  if (context.usedAnchorKeys.has(key)) return false;
4143
4313
  context.usedAnchorKeys.add(key);
4144
4314
  return true;
4145
4315
  }) : [];
4146
- const headingInlineMetadata = span ? collectHeadingInlineMetadataInSpan(context, span).filter((occurrence) => isOccurrenceInsideSourceSpan(occurrence, sourceSpan)) : [];
4316
+ const headingInlineMetadata = span ? collectHeadingInlineMetadataInSpan(context, span).filter((occurrence) => isOccurrenceInsideSourceSpan(occurrence, occurrenceSpan)) : [];
4147
4317
  context.bindingRequests.push({
4148
4318
  block,
4149
4319
  xrefs
@@ -4190,31 +4360,13 @@ function descriptionTermSourceSpan(lineTable, line) {
4190
4360
  }
4191
4361
  };
4192
4362
  }
4193
- function descriptionTextSourceSpan(lineTable, line) {
4194
- const delimiter = descriptionListDelimiterMatch(lineTable, line);
4195
- if (!delimiter) return;
4196
- const text = lineText(lineTable, line);
4197
- const afterDelimiterIndex = delimiter.index + delimiter.raw.length;
4198
- const firstTextIndex = /\S/u.exec(text.slice(afterDelimiterIndex))?.index ?? 0;
4199
- return {
4200
- start: {
4201
- line,
4202
- column: [...text.slice(0, afterDelimiterIndex + firstTextIndex)].length + 1
4203
- },
4204
- end: {
4205
- line,
4206
- column: [...text].length + 1
4207
- }
4208
- };
4209
- }
4210
4363
  function descriptionListDelimiterMatch(lineTable, line) {
4211
4364
  const text = lineText(lineTable, line);
4212
- const match = /:{2,4}|;;/u.exec(text);
4213
- if (!match || match.index === void 0) return;
4365
+ const delimiter = descriptionListDelimiter(text);
4366
+ if (!delimiter) return;
4214
4367
  return {
4215
- raw: match[0],
4216
- index: match.index,
4217
- column: [...text.slice(0, match.index)].length + 1
4368
+ ...delimiter,
4369
+ column: [...text.slice(0, delimiter.index)].length + 1
4218
4370
  };
4219
4371
  }
4220
4372
  function descriptionPartSourceLayer(context, span, sourceSpan, diagnosticContext) {
@@ -4225,20 +4377,28 @@ function descriptionPartSourceLayer(context, span, sourceSpan, diagnosticContext
4225
4377
  });
4226
4378
  const recovered = recoverSourceAwareSourceLayer(context.sourceAwareDocument, span, {
4227
4379
  logicalSourceSpan: sourceSpan,
4380
+ raw: "sourceSpan",
4228
4381
  diagnosticContext
4229
4382
  });
4230
4383
  return recovered.ok ? recovered.sourceLayer : void 0;
4231
4384
  }
4232
4385
  function sourceTextForSpan(context, sourceSpan) {
4233
- if (sourceSpan.start.line !== sourceSpan.end.line) return;
4234
- return Array.from(lineText(context.lineTable, sourceSpan.start.line)).slice(sourceSpan.start.column - 1, sourceSpan.end.column - 1).join("");
4386
+ const lines = [];
4387
+ for (let line = sourceSpan.start.line; line <= sourceSpan.end.line; line += 1) {
4388
+ const chars = Array.from(lineText(context.lineTable, line));
4389
+ lines.push(chars.slice(line === sourceSpan.start.line ? sourceSpan.start.column - 1 : 0, line === sourceSpan.end.line ? sourceSpan.end.column - 1 : void 0).join(""));
4390
+ }
4391
+ return lines.join("\n");
4392
+ }
4393
+ function occurrenceSpanOf(context, source, sourceSpan) {
4394
+ return context.sourceAwareDocument ? source?.sourceSpan : sourceSpan;
4235
4395
  }
4236
4396
  function isOccurrenceInsideSourceSpan(occurrence, sourceSpan) {
4237
4397
  if (!sourceSpan || !occurrence.sourceSpan) return true;
4238
- const start = occurrence.sourceSpan.start;
4239
- const end = occurrence.sourceSpan.end;
4240
- if (start.line !== sourceSpan.start.line || end.line !== sourceSpan.end.line) return false;
4241
- return start.column >= sourceSpan.start.column && end.column <= sourceSpan.end.column;
4398
+ return comparePositions(occurrence.sourceSpan.start, sourceSpan.start) >= 0 && comparePositions(occurrence.sourceSpan.end, sourceSpan.end) <= 0;
4399
+ }
4400
+ function comparePositions(left, right) {
4401
+ return left.line - right.line || left.column - right.column;
4242
4402
  }
4243
4403
  function mergeNodeLineSpans(spans) {
4244
4404
  const present = spans.filter(isLineSpan);
@@ -4455,7 +4615,7 @@ function blockSourceLayer(context, interval, fallbackSpan, diagnosticContext) {
4455
4615
  const logicalSourceSpan = sameLineSpan(fallbackSpan, interval.span) ? interval.sourceSpan : void 0;
4456
4616
  const recovered = recoverSourceAwareSourceLayer(context.sourceAwareDocument, fallbackSpan, {
4457
4617
  logicalSourceSpan,
4458
- raw: true,
4618
+ raw: "lines",
4459
4619
  diagnosticContext
4460
4620
  });
4461
4621
  return recovered.ok ? recovered.sourceLayer : void 0;
@@ -4784,117 +4944,6 @@ function parseStyleIdRoles(part) {
4784
4944
  });
4785
4945
  }
4786
4946
  //#endregion
4787
- //#region src/official-delimiter.ts
4788
- const DELIMITED_BLOCKS = {
4789
- "--": ["open", new Set([
4790
- "comment",
4791
- "example",
4792
- "literal",
4793
- "listing",
4794
- "pass",
4795
- "quote",
4796
- "sidebar",
4797
- "source",
4798
- "verse",
4799
- "admonition",
4800
- "abstract",
4801
- "partintro"
4802
- ])],
4803
- "----": ["listing", new Set(["literal", "source"])],
4804
- "....": ["literal", new Set(["listing", "source"])],
4805
- "====": ["example", new Set(["admonition"])],
4806
- "****": ["sidebar", /* @__PURE__ */ new Set()],
4807
- ____: ["quote", new Set(["verse"])],
4808
- "++++": ["pass", new Set([
4809
- "stem",
4810
- "latexmath",
4811
- "asciimath"
4812
- ])],
4813
- "|===": ["table", /* @__PURE__ */ new Set()],
4814
- ",===": ["table", /* @__PURE__ */ new Set()],
4815
- ":===": ["table", /* @__PURE__ */ new Set()],
4816
- "!===": ["table", /* @__PURE__ */ new Set()],
4817
- "~~~~": ["open", new Set(["abstract", "partintro"])],
4818
- "////": ["comment", /* @__PURE__ */ new Set()],
4819
- "```": ["fenced_code", /* @__PURE__ */ new Set()]
4820
- };
4821
- const DELIMITED_BLOCK_HEADS = new Set(Object.keys(DELIMITED_BLOCKS).map((delimiter) => delimiter.slice(0, 2)));
4822
- const DELIMITED_BLOCK_TAILS = Object.fromEntries(Object.keys(DELIMITED_BLOCKS).filter((delimiter) => delimiter.length === 4).map((delimiter) => [delimiter, delimiter.slice(-1)]));
4823
- function officialDelimiter(line) {
4824
- let candidate = line;
4825
- let lineLength = candidate.length;
4826
- if (lineLength < 2 || !DELIMITED_BLOCK_HEADS.has(candidate.slice(0, 2))) return;
4827
- let tip;
4828
- let tipLength;
4829
- if (lineLength === 2) {
4830
- tip = candidate;
4831
- tipLength = 2;
4832
- } else {
4833
- tipLength = lineLength < 5 ? lineLength : 4;
4834
- tip = candidate.slice(0, tipLength);
4835
- if (tip.startsWith("`")) {
4836
- if (tipLength === 4) {
4837
- if (tip === "````") return;
4838
- tip = tip.slice(0, 3);
4839
- if (tip !== "```") return;
4840
- candidate = tip;
4841
- lineLength = 3;
4842
- tipLength = 3;
4843
- } else if (tip !== "```") return;
4844
- } else if (tipLength === 3) return;
4845
- }
4846
- const entry = DELIMITED_BLOCKS[tip];
4847
- if (!entry) return;
4848
- const tail = DELIMITED_BLOCK_TAILS[tip];
4849
- if (!(lineLength === tipLength || tail !== void 0 && isUniform(candidate.slice(1), tail))) return;
4850
- const [context, masq] = entry;
4851
- return {
4852
- context,
4853
- masq,
4854
- terminator: candidate
4855
- };
4856
- }
4857
- function delimiterOpens(delimiter, context, style) {
4858
- if (context === void 0) return false;
4859
- if (delimiter.context === "fenced_code") return context === "listing";
4860
- return delimiter.context === context || delimiter.masq.has(context) || style !== null && style !== void 0 && delimiter.masq.has(style);
4861
- }
4862
- function isUniform(text, character) {
4863
- return [...text].every((each) => each === character);
4864
- }
4865
- //#endregion
4866
- //#region src/official-paragraph.ts
4867
- const CC_ALPHA = String.raw`\p{Alphabetic}`;
4868
- const CC_WORD = String.raw`\p{Alphabetic}\p{N}\p{Pc}`;
4869
- const BlockAttributeLineRx = new RegExp(String.raw`^\[(?:|[${CC_WORD}.#%{,"'].*|\[(?:|[${CC_ALPHA}_:][${CC_WORD}\-:.]*(?:, *.+)?)\])\]$`, "u");
4870
- const AnyListRx = /^(?:[ \t]*(?:-|\*\**|\.\.*|•|\d+\.|[a-zA-Z]\.|[IVXivx]+\))[ \t]|(?!\/\/[^/])[ \t]*[^ \t].*?(?::::{0,2}|;;)(?:$|[ \t])|<(?:\d+|\.)>[ \t])/;
4871
- const BlockAnchorRx = new RegExp(String.raw`^\[\[(?:|([${CC_ALPHA}_:][${CC_WORD}\-:.]*)(?:, *(.+))?)\]\]$`, "u");
4872
- const BlockAttributeListRx = new RegExp(String.raw`^\[(|[${CC_WORD}.#%{,"'].*)\]$`, "u");
4873
- function paragraphEndLine(lineTable, startLine, breakAtList) {
4874
- let last = startLine;
4875
- for (let line = startLine + 1; line <= lineTable.lines.length; line += 1) {
4876
- const text = lineText(lineTable, line).trimEnd();
4877
- if (text === "" || text === "+" || terminatesParagraph(text, breakAtList)) break;
4878
- if (!isLineComment(text)) last = line;
4879
- }
4880
- return last;
4881
- }
4882
- function listItemTextEndLine(lineTable, markerLine) {
4883
- let line = markerLine + 1;
4884
- while (line <= lineTable.lines.length && isTextOnlyMetadata(lineText(lineTable, line).trimEnd())) line += 1;
4885
- const text = lineText(lineTable, line).trimEnd();
4886
- if (line > lineTable.lines.length || text === "" || text === "+" || terminatesParagraph(text, true)) return markerLine;
4887
- return paragraphEndLine(lineTable, line, true);
4888
- }
4889
- function isTextOnlyMetadata(text) {
4890
- if (text.startsWith("[[")) return text.endsWith("]]") && BlockAnchorRx.test(text);
4891
- if (text.startsWith("[")) return text.endsWith("]") && BlockAttributeListRx.test(text);
4892
- return isLineComment(text);
4893
- }
4894
- function terminatesParagraph(text, breakAtList) {
4895
- return officialDelimiter(text) !== void 0 || text.startsWith("[") && BlockAttributeLineRx.test(text) || breakAtList && AnyListRx.test(text);
4896
- }
4897
- //#endregion
4898
4947
  //#region src/source-interval-resolver.ts
4899
4948
  function resolveSourceInterval(surface, sourceTable) {
4900
4949
  if (surface.sourceLine === void 0) return;
@@ -4904,12 +4953,13 @@ function resolveSourceInterval(surface, sourceTable) {
4904
4953
  const startLine = metadata.at(0)?.line ?? blockStartLine;
4905
4954
  const diagnostics = [];
4906
4955
  const delimitedContext = isDelimitedContext(surface.context);
4956
+ const description = isDescription(surface) ? descriptionTextOf(surface, lineTable) : void 0;
4907
4957
  const synthesized = borrowsChildSourceLocation(surface.block);
4908
4958
  const delimited = delimitedContext ? resolveDelimitedBlockSpan(lineTable, blockStartLine, surface) : void 0;
4909
4959
  const undelimited = delimitedContext && delimited === void 0 && !synthesized ? resolveUndelimitedBlockSpan(lineTable, sourceTable, blockStartLine, surface) : void 0;
4910
4960
  const sourceContentSpan = sourceContentSpanForContext(surface, lineTable, blockStartLine);
4911
4961
  const nextSiblingStart = nextSiblingStartLine(surface, lineTable);
4912
- const childEndLine = surface.context === "dlist" ? lastChildEndLine(surface, lineTable) : void 0;
4962
+ const childEndLine = surface.context === "dlist" ? lastChildEndLine(surface, sourceTable) : void 0;
4913
4963
  const endLine = delimited?.span.endLine ?? undelimited?.span.endLine ?? sourceContentSpan?.endLine ?? childEndLine ?? (nextSiblingStart !== void 0 ? nextSiblingStart - 1 : void 0) ?? parentEndLine(surface, sourceTable) ?? lineTable.lines.length;
4914
4964
  const span = normalizeLineSpan({
4915
4965
  startLine,
@@ -4925,9 +4975,11 @@ function resolveSourceInterval(surface, sourceTable) {
4925
4975
  message: `Could not locate ${surface.context} block delimiter from official source line ${blockStartLine}.`,
4926
4976
  source: spanForLineText(sourceTable, blockStartLine, 1)
4927
4977
  });
4928
- const contentSpan = delimited?.contentSpan ?? undelimited?.contentSpan ?? sourceContentSpan ?? contentSpanForContext(surface, span, lineTable);
4978
+ const contentSpan = delimited?.contentSpan ?? undelimited?.contentSpan ?? sourceContentSpan ?? description?.span ?? contentSpanForContext(surface, span, lineTable);
4929
4979
  const sourceSpan = sourceSpanFromLineSpan(sourceTable, span);
4930
4980
  const titleSpan = titleSpanForSurface(surface, sourceTable);
4981
+ const contentSourceSpan = description ? descriptionSourceSpan(description, sourceTable, lineTable) : void 0;
4982
+ const readsLineComments = delimited !== void 0 || description?.readsLineComments === true;
4931
4983
  return {
4932
4984
  blockStartLine,
4933
4985
  metadata,
@@ -4935,9 +4987,33 @@ function resolveSourceInterval(surface, sourceTable) {
4935
4987
  diagnostics,
4936
4988
  ...metadataSpan ? { metadataSpan } : {},
4937
4989
  ...contentSpan ? { contentSpan } : {},
4990
+ ...contentSourceSpan ? { contentSourceSpan } : {},
4991
+ ...description?.discardedSpan ? { discardedSpan: description.discardedSpan } : {},
4938
4992
  ...sourceSpan ? { sourceSpan } : {},
4939
4993
  ...titleSpan ? { titleSpan } : {},
4940
- ...delimited ? { delimited: true } : {}
4994
+ ...readsLineComments ? { readsLineComments: true } : {}
4995
+ };
4996
+ }
4997
+ function isDescription(surface) {
4998
+ const list = surface.parent;
4999
+ return list?.context === "dlist" && descriptionListItemsFromBlock(list.block).some((item) => item.description === surface.block);
5000
+ }
5001
+ function descriptionTextOf(surface, lineTable) {
5002
+ const termLine = surface.parent?.children[surface.indexInParent - 1]?.sourceLine;
5003
+ if (termLine === void 0) return;
5004
+ return descriptionText(lineTable, termLine, (line) => surface.children.some((child) => child.sourceLine === line));
5005
+ }
5006
+ function descriptionSourceSpan(description, sourceTable, lineTable) {
5007
+ const { startLine, endLine } = description.span;
5008
+ return {
5009
+ start: {
5010
+ line: startLine,
5011
+ column: [...lineText(sourceTable, startLine)].length - [...lineText(lineTable, startLine)].length + description.startColumn
5012
+ },
5013
+ end: {
5014
+ line: endLine,
5015
+ column: [...lineText(sourceTable, endLine)].length + 1
5016
+ }
4941
5017
  };
4942
5018
  }
4943
5019
  function nextSiblingStartLine(surface, lineTable) {
@@ -4951,13 +5027,24 @@ function metadataForSurface(surface, lineTable, blockStartLine) {
4951
5027
  if (takesParentSourceLocation(surface.block)) return [];
4952
5028
  return collectPrecedingMetadata(lineTable, blockStartLine);
4953
5029
  }
4954
- function lastChildEndLine(surface, lineTable) {
4955
- const childLines = surface.children.flatMap((child) => descendantSourceLines(child));
5030
+ function lastChildEndLine(surface, sourceTable) {
5031
+ const childLines = surface.children.map((child) => enclosedEndLine(child, sourceTable)).filter((line) => line !== void 0);
4956
5032
  if (childLines.length === 0) return;
4957
- return Math.min(Math.max(...childLines), lastContentLine(lineTable));
5033
+ return Math.min(Math.max(...childLines), lastContentLine(sourceTable));
5034
+ }
5035
+ function enclosedEndLine(surface, sourceTable) {
5036
+ const ends = [surface.sourceLine === void 0 ? void 0 : ownEndLine(surface, sourceTable, surface.sourceLine), ...surface.children.map((child) => enclosedEndLine(child, sourceTable))].filter((line) => line !== void 0);
5037
+ return ends.length > 0 ? Math.max(...ends) : void 0;
4958
5038
  }
4959
- function descendantSourceLines(surface) {
4960
- return [...surface.sourceLine === void 0 ? [] : [surface.sourceLine], ...surface.children.flatMap((child) => descendantSourceLines(child))];
5039
+ function ownEndLine(surface, sourceTable, startLine) {
5040
+ const lineTable = quotedLineTable(sourceTable, markdownQuoteDepth(surface.block));
5041
+ const delimited = isDelimitedContext(surface.context) && !borrowsChildSourceLocation(surface.block) ? resolveDelimitedBlockSpan(lineTable, startLine, surface) ?? resolveUndelimitedBlockSpan(lineTable, sourceTable, startLine, surface) : void 0;
5042
+ if (delimited) return delimited.span.endLine;
5043
+ const paragraph = sourceContentSpanForContext(surface, lineTable, startLine);
5044
+ if (paragraph) return paragraph.endLine;
5045
+ if (isDescription(surface)) return descriptionTextOf(surface, lineTable)?.span.endLine ?? startLine;
5046
+ if (surface.context === "list_item" && surface.parent?.context !== "dlist") return listItemTextEndLine(lineTable, startLine);
5047
+ return startLine;
4961
5048
  }
4962
5049
  function parentEndLine(surface, lineTable) {
4963
5050
  const parent = surface.parent;
@@ -5189,15 +5276,12 @@ function scanSurfaces(collected, surfaces, intervalByBlock) {
5189
5276
  if (officialBlockPolicy(surface.block) !== "scan") continue;
5190
5277
  if (!scansMacroSubstitutedContent(surface)) continue;
5191
5278
  if (surface.context === "table") scanTable(collected, surface.block);
5192
- else scanInlineRange(collected.lineTable, span.startLine, span.endLine, collected.xrefOccurrences, collected.anchorOccurrences, collected.headingInlineMetadataOccurrences, collected.toolDiagnostics, descendantUnscannableRanges(surface, intervalByBlock), isBibliographyList(surface), skipsLineComments(surface, interval) ? quotedLineTable(collected.lineTable, markdownQuoteDepth(surface.block)) : null);
5279
+ else scanInlineRange(collected.lineTable, span.startLine, span.endLine, collected.xrefOccurrences, collected.anchorOccurrences, collected.headingInlineMetadataOccurrences, collected.toolDiagnostics, [...descendantUnscannableRanges(surface, intervalByBlock), ...interval.discardedSpan ? [interval.discardedSpan] : []], isBibliographyList(surface), interval.readsLineComments ? null : quotedLineTable(collected.lineTable, markdownQuoteDepth(surface.block)));
5193
5280
  }
5194
5281
  }
5195
5282
  function isHeading(surface) {
5196
5283
  return surface.context === "section" || surface.context === "floating_title";
5197
5284
  }
5198
- function skipsLineComments(surface, interval) {
5199
- return interval.delimited !== true || surface.block.getContentModel?.() === "compound";
5200
- }
5201
5285
  function hasDiagnosticPolicyAncestor$1(surface) {
5202
5286
  let current = surface.parent;
5203
5287
  while (current) {
@@ -5210,7 +5294,7 @@ function isPreambleParagraph(surface) {
5210
5294
  return surface.context === "paragraph" && surface.parent?.context === "preamble";
5211
5295
  }
5212
5296
  function scansMacroSubstitutedContent(surface) {
5213
- if (surface.context === "dlist" || surface.context === "table") return true;
5297
+ if (surface.context === "table") return true;
5214
5298
  const substitutions = surface.block.getSubstitutions?.();
5215
5299
  return !Array.isArray(substitutions) || substitutions.includes("macros");
5216
5300
  }
@@ -5507,7 +5591,7 @@ function projectSourceSurfaces(options) {
5507
5591
  ].includes(surface.context ?? "")) {
5508
5592
  const recovered = recoverSourceAwareSourceLayer(sourceAwareDocument, interval.span, {
5509
5593
  logicalSourceSpan: interval.sourceSpan,
5510
- raw: true,
5594
+ raw: "lines",
5511
5595
  diagnosticContext: `${surface.context} block`
5512
5596
  });
5513
5597
  if (!recovered.ok) toolDiagnostics.push(recovered.diagnostic);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "asciidoc-abundant-tree",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "description": "Recover a source-aware, analysis-ready tree from AsciiDoc files and explicit book-entry include graphs.",
5
5
  "license": "Apache-2.0",
6
6
  "author": {