asciidoc-abundant-tree 0.2.3 → 0.2.4

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-DuMegO5s.mjs";
2
+ import { o as exportAnimationYaml } from "../src-8G5Sgsvr.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
@@ -281,11 +281,14 @@ function quotedLineTable(lineTable, depth) {
281
281
  views.set(depth, view);
282
282
  return view;
283
283
  }
284
+ function isLineComment(text) {
285
+ return text.startsWith("//") && !text.startsWith("///");
286
+ }
284
287
  function paragraphLine(lineTable, startLine, n, skipsLineComments) {
285
288
  let counted = 0;
286
289
  for (let line = startLine; line <= lineTable.lines.length; line += 1) {
287
290
  const text = lineText(lineTable, line);
288
- if (skipsLineComments && text.startsWith("//") && !text.startsWith("///")) continue;
291
+ if (skipsLineComments && isLineComment(text)) continue;
289
292
  counted += 1;
290
293
  if (counted === n) return line;
291
294
  }
@@ -868,6 +871,7 @@ function officialBlockPolicy(block) {
868
871
  case "sidebar":
869
872
  case "open": return block.getContentModel?.() === "simple" ? "scan" : "recurse";
870
873
  case "olist":
874
+ case "colist":
871
875
  case "preamble":
872
876
  case "section":
873
877
  case "ulist": return "recurse";
@@ -875,6 +879,13 @@ function officialBlockPolicy(block) {
875
879
  case "literal":
876
880
  case "pass":
877
881
  case "stem": return "skip";
882
+ case "thematic_break":
883
+ case "page_break":
884
+ case "toc":
885
+ case "image":
886
+ case "audio":
887
+ case "video":
888
+ case "floating_title": return "skip";
878
889
  default: return "diagnostic";
879
890
  }
880
891
  }
@@ -976,16 +987,32 @@ function buildNode(block, context) {
976
987
  if (blockContext === "open" && officialLine !== void 0) return childBlocksOf(block).flatMap((child) => toNodes(buildNode(child, context)));
977
988
  if (officialBlockPolicy(block) === "diagnostic") return;
978
989
  if (officialLine !== void 0) {
990
+ const id = block.getId?.();
979
991
  registerOfficialBlockTarget(context, block, {
980
992
  targetType: "block",
993
+ idOrigin: blockContext === "floating_title" && !interval?.metadata.some((surface) => id && surface.ids.includes(id)) ? "asciidoctor-generated" : "source",
981
994
  sourceSpan: interval?.sourceSpan ?? sourceSpanFromLineSpan(context.lineTable, {
982
995
  startLine: officialLine,
983
996
  endLine: officialLine
984
997
  })
985
998
  });
999
+ requestTitleBindings(context, block);
986
1000
  return childBlocksOf(block).flatMap((child) => toNodes(buildNode(child, context)));
987
1001
  }
988
1002
  }
1003
+ function requestTitleBindings(context, block) {
1004
+ const blockContext = block.getContext?.();
1005
+ const line = context.intervalByBlock.get(block)?.blockStartLine;
1006
+ if (blockContext !== "section" && blockContext !== "floating_title" || line === void 0) return;
1007
+ const xrefs = collectXrefsInSpan(context, {
1008
+ startLine: line,
1009
+ endLine: line
1010
+ });
1011
+ if (xrefs.length > 0) context.bindingRequests.push({
1012
+ block,
1013
+ xrefs
1014
+ });
1015
+ }
989
1016
  function canProjectBlock(block, context) {
990
1017
  return context.projectableBlocks?.has(block) ?? true;
991
1018
  }
@@ -1010,6 +1037,7 @@ function buildSection(block, context) {
1010
1037
  source: section.source,
1011
1038
  asciidoctor: section.asciidoctor
1012
1039
  });
1040
+ requestTitleBindings(context, block);
1013
1041
  section.children = childBlocksOf(block).flatMap((child) => toNodes(buildNode(child, context)));
1014
1042
  return section;
1015
1043
  }
@@ -1518,14 +1546,17 @@ function complete(block, parent, lineTable, depth) {
1518
1546
  if (depth > 0) quoteDepths.set(block, depth);
1519
1547
  const location = block.getSourceLocation?.();
1520
1548
  const anchor = location?.getLineNumber?.();
1521
- if (location && anchor !== void 0 && opensMarkdownQuote(block, quotedLineTable(lineTable, depth))) {
1549
+ const view = quotedLineTable(lineTable, depth);
1550
+ if (location && anchor !== void 0 && opensMarkdownQuote(block, view)) {
1522
1551
  markdownQuotes.add(block);
1523
- relocateQuoted(block, location, anchor, lineTable, depth);
1552
+ relocateReader(block, location, anchor, numbering(lineTable, anchor, 1, (line) => !isLineComment(lineText(view, line))), quotedLineTable(lineTable, depth + 1));
1524
1553
  }
1554
+ if (location && anchor !== void 0 && block.getContext?.() === "table" && !cellLineMappers.has(block)) relocateReader(block, location, anchor, numbering(lineTable, anchor + 1, anchor + 1, (line) => !isLineComment(lineText(view, line))), view);
1525
1555
  const children = childBlocksOf(block);
1526
1556
  const childDepth = markdownQuotes.has(block) ? depth + 1 : depth;
1527
1557
  for (const child of children) complete(child, block, lineTable, childDepth);
1528
1558
  for (const cellBlock of cellBlocksOf(block)) complete(cellBlock, void 0, lineTable, childDepth);
1559
+ if (block.getContext?.() === "colist") locate(block, children[0]?.getSourceLocation?.());
1529
1560
  if (!block.getSourceLocation?.() && block.getContext?.() === "open") {
1530
1561
  const location = children.find((child) => child.getSourceLocation?.())?.getSourceLocation?.();
1531
1562
  if (location) {
@@ -1534,23 +1565,37 @@ function complete(block, parent, lineTable, depth) {
1534
1565
  }
1535
1566
  }
1536
1567
  }
1537
- function relocateQuoted(quote, location, anchor, lineTable, depth) {
1538
- const outer = quotedLineTable(lineTable, depth);
1539
- const inner = quotedLineTable(lineTable, depth + 1);
1540
- const toSource = (relative) => paragraphLine(outer, anchor, relative, true);
1568
+ function numbering(lineTable, from, first, visible) {
1569
+ return {
1570
+ visible,
1571
+ toSource: (line) => {
1572
+ let counted = first - 1;
1573
+ for (let source = from; source <= lineTable.lines.length; source += 1) if (visible(source)) {
1574
+ counted += 1;
1575
+ if (counted === line) return source;
1576
+ }
1577
+ return Math.max(from, lineTable.lines.length);
1578
+ }
1579
+ };
1580
+ }
1581
+ function relocateReader(container, location, anchor, reader, view) {
1582
+ if (container.getContext?.() === "table") cellLineMappers.set(container, reader.toSource);
1541
1583
  const relocate = (block) => {
1542
1584
  for (const child of [...childBlocksOf(block), ...cellBlocksOf(block)]) {
1543
1585
  const relative = child.getSourceLocation?.()?.getLineNumber?.();
1544
- if (relative !== void 0) {
1545
- const line = toSource(relative);
1586
+ const line = relative === void 0 ? void 0 : reader.toSource(relative);
1587
+ if (relative !== void 0 && line !== void 0) {
1546
1588
  locate(child, new Cursor(location.getFile?.(), location.getDirectory?.(), location.getPath?.(), line));
1547
1589
  if (line === anchor) takenFromParent.add(child);
1590
+ if (child.getContext?.() === "table") {
1591
+ relocateReader(child, location, line, numbering(view, line + 1, relative + 1, (source) => reader.visible(source) && !isLineComment(lineText(view, source))), view);
1592
+ continue;
1593
+ }
1548
1594
  }
1549
- if (child.getContext?.() === "table") cellLineMappers.set(child, toSource);
1550
- if (!opensMarkdownQuote(child, inner)) relocate(child);
1595
+ if (!opensMarkdownQuote(child, view)) relocate(child);
1551
1596
  }
1552
1597
  };
1553
- relocate(quote);
1598
+ relocate(container);
1554
1599
  }
1555
1600
  function cellBlocksOf(block) {
1556
1601
  return asciidocCellDocuments(block).flatMap(childBlocksOf);
@@ -1816,6 +1861,38 @@ function isUniform(text, character) {
1816
1861
  return [...text].every((each) => each === character);
1817
1862
  }
1818
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
1819
1896
  //#region src/source-interval-resolver.ts
1820
1897
  function resolveSourceInterval(surface, sourceTable) {
1821
1898
  if (surface.sourceLine === void 0) return;
@@ -1846,7 +1923,7 @@ function resolveSourceInterval(surface, sourceTable) {
1846
1923
  message: `Could not locate ${surface.context} block delimiter from official source line ${blockStartLine}.`,
1847
1924
  source: spanForLineText(sourceTable, blockStartLine, 1)
1848
1925
  });
1849
- const contentSpan = delimited?.contentSpan ?? undelimited?.contentSpan ?? sourceContentSpan ?? contentSpanForContext(surface, span);
1926
+ const contentSpan = delimited?.contentSpan ?? undelimited?.contentSpan ?? sourceContentSpan ?? contentSpanForContext(surface, span, lineTable);
1850
1927
  const sourceSpan = sourceSpanFromLineSpan(sourceTable, span);
1851
1928
  const titleSpan = titleSpanForSurface(surface, sourceTable);
1852
1929
  return {
@@ -1857,7 +1934,8 @@ function resolveSourceInterval(surface, sourceTable) {
1857
1934
  ...metadataSpan ? { metadataSpan } : {},
1858
1935
  ...contentSpan ? { contentSpan } : {},
1859
1936
  ...sourceSpan ? { sourceSpan } : {},
1860
- ...titleSpan ? { titleSpan } : {}
1937
+ ...titleSpan ? { titleSpan } : {},
1938
+ ...delimited ? { delimited: true } : {}
1861
1939
  };
1862
1940
  }
1863
1941
  function nextSiblingStartLine(surface, lineTable) {
@@ -1900,7 +1978,7 @@ function resolveDelimitedBlockSpan(lineTable, startLine, surface) {
1900
1978
  }
1901
1979
  function resolveUndelimitedBlockSpan(lineTable, sourceTable, startLine, surface) {
1902
1980
  const anchorText = lineText(lineTable, startLine);
1903
- if (isMarkdownQuote(surface.block)) return markdownQuoteSpan(lineTable, sourceTable, startLine, surface);
1981
+ if (isMarkdownQuote(surface.block)) return markdownQuoteSpan(lineTable, startLine);
1904
1982
  const firstLine = firstSourceLine(surface);
1905
1983
  if (firstLine === void 0) return;
1906
1984
  const official = withoutWhitespace(firstLine);
@@ -1944,18 +2022,10 @@ function isAirQuote(surface, anchorText, officialFirstLine) {
1944
2022
  const opened = anchorText.slice(1).trimEnd();
1945
2023
  return withoutWhitespace(surface.block.getSourceLines?.().length === 1 && opened.endsWith("\"") ? opened.slice(0, -1) : opened) === officialFirstLine;
1946
2024
  }
1947
- function markdownQuoteSpan(lineTable, sourceTable, startLine, surface) {
1948
- const contentEnd = lastChildIntervalEnd(sourceTable, startLine, surface);
1949
- let endLine = contentEnd;
1950
- for (let next = paragraphLine(lineTable, endLine, 2, true); next > endLine; next = paragraphLine(lineTable, endLine, 2, true)) {
1951
- const text = lineText(lineTable, next).trimEnd();
1952
- if (text === ">") {
1953
- endLine = next;
1954
- continue;
1955
- }
1956
- if (/^(?:> )?-- /u.test(text)) endLine = next;
1957
- break;
1958
- }
2025
+ function markdownQuoteSpan(lineTable, startLine) {
2026
+ const endLine = paragraphEndLine(lineTable, startLine, false);
2027
+ let contentEnd = endLine > startLine && /^(?:> )?-- /u.test(lineText(lineTable, endLine).trimEnd()) ? endLine - 1 : endLine;
2028
+ while (contentEnd > startLine && isEmptyQuotedLine(lineTable, contentEnd)) contentEnd -= 1;
1959
2029
  return {
1960
2030
  span: {
1961
2031
  startLine,
@@ -1967,6 +2037,10 @@ function markdownQuoteSpan(lineTable, sourceTable, startLine, surface) {
1967
2037
  }
1968
2038
  };
1969
2039
  }
2040
+ function isEmptyQuotedLine(lineTable, line) {
2041
+ const text = lineText(lineTable, line).trimEnd();
2042
+ return text === ">" || isLineComment(text);
2043
+ }
1970
2044
  function withoutWhitespace(text) {
1971
2045
  return text.replace(/\s+/gu, "");
1972
2046
  }
@@ -1979,7 +2053,7 @@ function firstSourceLine(surface) {
1979
2053
  const firstChild = surface.children[0];
1980
2054
  return firstChild ? firstSourceLine(firstChild) : void 0;
1981
2055
  }
1982
- function contentSpanForContext(surface, span) {
2056
+ function contentSpanForContext(surface, span, lineTable) {
1983
2057
  if (surface.context === "paragraph") return {
1984
2058
  startLine: surface.sourceLine ?? span.startLine,
1985
2059
  endLine: span.endLine
@@ -1988,7 +2062,7 @@ function contentSpanForContext(surface, span) {
1988
2062
  const line = surface.sourceLine ?? span.startLine;
1989
2063
  return {
1990
2064
  startLine: line,
1991
- endLine: line
2065
+ endLine: surface.parent?.context === "dlist" ? line : listItemTextEndLine(lineTable, line)
1992
2066
  };
1993
2067
  }
1994
2068
  }
@@ -2102,13 +2176,26 @@ function scanSurfaces(collected, surfaces, intervalByBlock) {
2102
2176
  continue;
2103
2177
  }
2104
2178
  if (interval.metadataSpan) scanMetadataRange(collected.lineTable, interval.metadataSpan.startLine, interval.metadataSpan.endLine, collected.xrefOccurrences, collected.anchorOccurrences);
2179
+ if (isHeading(surface) && surface.sourceLine !== void 0) {
2180
+ const line = collected.lineTable.lines[surface.sourceLine - 1];
2181
+ if (line) {
2182
+ scanXrefMatches(collected.lineTable, line, collected.xrefOccurrences);
2183
+ scanAnchorMatches(collected.lineTable, line, collected.anchorOccurrences);
2184
+ }
2185
+ }
2105
2186
  const span = interval.contentSpan ?? interval.span;
2106
2187
  if (officialBlockPolicy(surface.block) !== "scan") continue;
2107
2188
  if (!scansMacroSubstitutedContent(surface)) continue;
2108
2189
  if (surface.context === "table") scanTable(collected, surface.block);
2109
- else scanInlineRange(collected.lineTable, span.startLine, span.endLine, collected.xrefOccurrences, collected.anchorOccurrences, collected.headingInlineMetadataOccurrences, collected.toolDiagnostics, descendantUnscannableRanges(surface, intervalByBlock), isBibliographyList(surface));
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);
2110
2191
  }
2111
2192
  }
2193
+ function isHeading(surface) {
2194
+ return surface.context === "section" || surface.context === "floating_title";
2195
+ }
2196
+ function skipsLineComments(surface, interval) {
2197
+ return interval.delimited !== true || surface.block.getContentModel?.() === "compound";
2198
+ }
2112
2199
  function hasDiagnosticPolicyAncestor$1(surface) {
2113
2200
  let current = surface.parent;
2114
2201
  while (current) {
@@ -2163,11 +2250,11 @@ function parseMacroLabel(raw) {
2163
2250
  function compareSourceSpans(left, right) {
2164
2251
  return (left.sourceSpan?.start.line ?? 0) - (right.sourceSpan?.start.line ?? 0) || (left.sourceSpan?.start.column ?? 0) - (right.sourceSpan?.start.column ?? 0);
2165
2252
  }
2166
- function scanInlineRange(lineTable, startLine, endLine, xrefOccurrences, anchorOccurrences, headingInlineMetadataOccurrences, toolDiagnostics, skipRanges = [], bibliography = false) {
2253
+ function scanInlineRange(lineTable, startLine, endLine, xrefOccurrences, anchorOccurrences, headingInlineMetadataOccurrences, toolDiagnostics, skipRanges, bibliography, commentView) {
2167
2254
  for (let lineNumber = startLine; lineNumber <= endLine; lineNumber += 1) {
2168
2255
  if (isLineInRanges(lineNumber, skipRanges)) continue;
2169
2256
  const line = lineTable.lines[lineNumber - 1];
2170
- if (!line) continue;
2257
+ if (!line || commentView && isLineComment(lineText(commentView, lineNumber))) continue;
2171
2258
  scanXrefMatches(lineTable, line, xrefOccurrences);
2172
2259
  if (bibliography) scanBibliographyAnchor(lineTable, line, anchorOccurrences);
2173
2260
  scanAnchorMatches(lineTable, line, anchorOccurrences);
@@ -2200,7 +2287,7 @@ function scanXrefMatches(lineTable, line, xrefOccurrences) {
2200
2287
  }
2201
2288
  }
2202
2289
  function scanTable(collected, block) {
2203
- for (const range of mergeLineSpans(ordinaryCellRanges(block))) scanInlineRange(collected.lineTable, range.startLine, range.endLine, collected.xrefOccurrences, collected.anchorOccurrences, collected.headingInlineMetadataOccurrences, collected.toolDiagnostics);
2290
+ for (const range of mergeLineSpans(ordinaryCellRanges(block))) scanInlineRange(collected.lineTable, range.startLine, range.endLine, collected.xrefOccurrences, collected.anchorOccurrences, collected.headingInlineMetadataOccurrences, collected.toolDiagnostics, [], false, collected.lineTable);
2204
2291
  for (const document of asciidocCellDocuments(block)) {
2205
2292
  const surfaces = walkOfficialBlocks(document);
2206
2293
  const intervalByBlock = /* @__PURE__ */ new WeakMap();
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-DuMegO5s.mjs";
2
+ import { a as parseAbundantTree, i as serializeAbundantTreeToJson, n as formatAbundantTree, t as rdf12 } from "./src-8G5Sgsvr.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-DuMegO5s.mjs";
1
+ import { a as parseAbundantTree, i as serializeAbundantTreeToJson, n as formatAbundantTree, o as exportAnimationYaml, r as serializeAbundantTree, t as rdf12 } from "./src-8G5Sgsvr.mjs";
2
2
  export { exportAnimationYaml, formatAbundantTree, parseAbundantTree, rdf12, serializeAbundantTree, serializeAbundantTreeToJson };
@@ -1056,11 +1056,14 @@ function quotedLineTable(lineTable, depth) {
1056
1056
  views.set(depth, view);
1057
1057
  return view;
1058
1058
  }
1059
+ function isLineComment(text) {
1060
+ return text.startsWith("//") && !text.startsWith("///");
1061
+ }
1059
1062
  function paragraphLine(lineTable, startLine, n, skipsLineComments) {
1060
1063
  let counted = 0;
1061
1064
  for (let line = startLine; line <= lineTable.lines.length; line += 1) {
1062
1065
  const text = lineText(lineTable, line);
1063
- if (skipsLineComments && text.startsWith("//") && !text.startsWith("///")) continue;
1066
+ if (skipsLineComments && isLineComment(text)) continue;
1064
1067
  counted += 1;
1065
1068
  if (counted === n) return line;
1066
1069
  }
@@ -3870,6 +3873,7 @@ function officialBlockPolicy(block) {
3870
3873
  case "sidebar":
3871
3874
  case "open": return block.getContentModel?.() === "simple" ? "scan" : "recurse";
3872
3875
  case "olist":
3876
+ case "colist":
3873
3877
  case "preamble":
3874
3878
  case "section":
3875
3879
  case "ulist": return "recurse";
@@ -3877,6 +3881,13 @@ function officialBlockPolicy(block) {
3877
3881
  case "literal":
3878
3882
  case "pass":
3879
3883
  case "stem": return "skip";
3884
+ case "thematic_break":
3885
+ case "page_break":
3886
+ case "toc":
3887
+ case "image":
3888
+ case "audio":
3889
+ case "video":
3890
+ case "floating_title": return "skip";
3880
3891
  default: return "diagnostic";
3881
3892
  }
3882
3893
  }
@@ -3978,16 +3989,32 @@ function buildNode(block, context) {
3978
3989
  if (blockContext === "open" && officialLine !== void 0) return childBlocksOf(block).flatMap((child) => toNodes(buildNode(child, context)));
3979
3990
  if (officialBlockPolicy(block) === "diagnostic") return;
3980
3991
  if (officialLine !== void 0) {
3992
+ const id = block.getId?.();
3981
3993
  registerOfficialBlockTarget(context, block, {
3982
3994
  targetType: "block",
3995
+ idOrigin: blockContext === "floating_title" && !interval?.metadata.some((surface) => id && surface.ids.includes(id)) ? "asciidoctor-generated" : "source",
3983
3996
  sourceSpan: interval?.sourceSpan ?? sourceSpanFromLineSpan(context.lineTable, {
3984
3997
  startLine: officialLine,
3985
3998
  endLine: officialLine
3986
3999
  })
3987
4000
  });
4001
+ requestTitleBindings(context, block);
3988
4002
  return childBlocksOf(block).flatMap((child) => toNodes(buildNode(child, context)));
3989
4003
  }
3990
4004
  }
4005
+ function requestTitleBindings(context, block) {
4006
+ const blockContext = block.getContext?.();
4007
+ const line = context.intervalByBlock.get(block)?.blockStartLine;
4008
+ if (blockContext !== "section" && blockContext !== "floating_title" || line === void 0) return;
4009
+ const xrefs = collectXrefsInSpan(context, {
4010
+ startLine: line,
4011
+ endLine: line
4012
+ });
4013
+ if (xrefs.length > 0) context.bindingRequests.push({
4014
+ block,
4015
+ xrefs
4016
+ });
4017
+ }
3991
4018
  function canProjectBlock(block, context) {
3992
4019
  return context.projectableBlocks?.has(block) ?? true;
3993
4020
  }
@@ -4012,6 +4039,7 @@ function buildSection(block, context) {
4012
4039
  source: section.source,
4013
4040
  asciidoctor: section.asciidoctor
4014
4041
  });
4042
+ requestTitleBindings(context, block);
4015
4043
  section.children = childBlocksOf(block).flatMap((child) => toNodes(buildNode(child, context)));
4016
4044
  return section;
4017
4045
  }
@@ -4520,14 +4548,17 @@ function complete(block, parent, lineTable, depth) {
4520
4548
  if (depth > 0) quoteDepths.set(block, depth);
4521
4549
  const location = block.getSourceLocation?.();
4522
4550
  const anchor = location?.getLineNumber?.();
4523
- if (location && anchor !== void 0 && opensMarkdownQuote(block, quotedLineTable(lineTable, depth))) {
4551
+ const view = quotedLineTable(lineTable, depth);
4552
+ if (location && anchor !== void 0 && opensMarkdownQuote(block, view)) {
4524
4553
  markdownQuotes.add(block);
4525
- relocateQuoted(block, location, anchor, lineTable, depth);
4554
+ relocateReader(block, location, anchor, numbering(lineTable, anchor, 1, (line) => !isLineComment(lineText(view, line))), quotedLineTable(lineTable, depth + 1));
4526
4555
  }
4556
+ if (location && anchor !== void 0 && block.getContext?.() === "table" && !cellLineMappers.has(block)) relocateReader(block, location, anchor, numbering(lineTable, anchor + 1, anchor + 1, (line) => !isLineComment(lineText(view, line))), view);
4527
4557
  const children = childBlocksOf(block);
4528
4558
  const childDepth = markdownQuotes.has(block) ? depth + 1 : depth;
4529
4559
  for (const child of children) complete(child, block, lineTable, childDepth);
4530
4560
  for (const cellBlock of cellBlocksOf(block)) complete(cellBlock, void 0, lineTable, childDepth);
4561
+ if (block.getContext?.() === "colist") locate(block, children[0]?.getSourceLocation?.());
4531
4562
  if (!block.getSourceLocation?.() && block.getContext?.() === "open") {
4532
4563
  const location = children.find((child) => child.getSourceLocation?.())?.getSourceLocation?.();
4533
4564
  if (location) {
@@ -4536,23 +4567,37 @@ function complete(block, parent, lineTable, depth) {
4536
4567
  }
4537
4568
  }
4538
4569
  }
4539
- function relocateQuoted(quote, location, anchor, lineTable, depth) {
4540
- const outer = quotedLineTable(lineTable, depth);
4541
- const inner = quotedLineTable(lineTable, depth + 1);
4542
- const toSource = (relative) => paragraphLine(outer, anchor, relative, true);
4570
+ function numbering(lineTable, from, first, visible) {
4571
+ return {
4572
+ visible,
4573
+ toSource: (line) => {
4574
+ let counted = first - 1;
4575
+ for (let source = from; source <= lineTable.lines.length; source += 1) if (visible(source)) {
4576
+ counted += 1;
4577
+ if (counted === line) return source;
4578
+ }
4579
+ return Math.max(from, lineTable.lines.length);
4580
+ }
4581
+ };
4582
+ }
4583
+ function relocateReader(container, location, anchor, reader, view) {
4584
+ if (container.getContext?.() === "table") cellLineMappers.set(container, reader.toSource);
4543
4585
  const relocate = (block) => {
4544
4586
  for (const child of [...childBlocksOf(block), ...cellBlocksOf(block)]) {
4545
4587
  const relative = child.getSourceLocation?.()?.getLineNumber?.();
4546
- if (relative !== void 0) {
4547
- const line = toSource(relative);
4588
+ const line = relative === void 0 ? void 0 : reader.toSource(relative);
4589
+ if (relative !== void 0 && line !== void 0) {
4548
4590
  locate(child, new Cursor(location.getFile?.(), location.getDirectory?.(), location.getPath?.(), line));
4549
4591
  if (line === anchor) takenFromParent.add(child);
4592
+ if (child.getContext?.() === "table") {
4593
+ relocateReader(child, location, line, numbering(view, line + 1, relative + 1, (source) => reader.visible(source) && !isLineComment(lineText(view, source))), view);
4594
+ continue;
4595
+ }
4550
4596
  }
4551
- if (child.getContext?.() === "table") cellLineMappers.set(child, toSource);
4552
- if (!opensMarkdownQuote(child, inner)) relocate(child);
4597
+ if (!opensMarkdownQuote(child, view)) relocate(child);
4553
4598
  }
4554
4599
  };
4555
- relocate(quote);
4600
+ relocate(container);
4556
4601
  }
4557
4602
  function cellBlocksOf(block) {
4558
4603
  return asciidocCellDocuments(block).flatMap(childBlocksOf);
@@ -4818,6 +4863,38 @@ function isUniform(text, character) {
4818
4863
  return [...text].every((each) => each === character);
4819
4864
  }
4820
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
4821
4898
  //#region src/source-interval-resolver.ts
4822
4899
  function resolveSourceInterval(surface, sourceTable) {
4823
4900
  if (surface.sourceLine === void 0) return;
@@ -4848,7 +4925,7 @@ function resolveSourceInterval(surface, sourceTable) {
4848
4925
  message: `Could not locate ${surface.context} block delimiter from official source line ${blockStartLine}.`,
4849
4926
  source: spanForLineText(sourceTable, blockStartLine, 1)
4850
4927
  });
4851
- const contentSpan = delimited?.contentSpan ?? undelimited?.contentSpan ?? sourceContentSpan ?? contentSpanForContext(surface, span);
4928
+ const contentSpan = delimited?.contentSpan ?? undelimited?.contentSpan ?? sourceContentSpan ?? contentSpanForContext(surface, span, lineTable);
4852
4929
  const sourceSpan = sourceSpanFromLineSpan(sourceTable, span);
4853
4930
  const titleSpan = titleSpanForSurface(surface, sourceTable);
4854
4931
  return {
@@ -4859,7 +4936,8 @@ function resolveSourceInterval(surface, sourceTable) {
4859
4936
  ...metadataSpan ? { metadataSpan } : {},
4860
4937
  ...contentSpan ? { contentSpan } : {},
4861
4938
  ...sourceSpan ? { sourceSpan } : {},
4862
- ...titleSpan ? { titleSpan } : {}
4939
+ ...titleSpan ? { titleSpan } : {},
4940
+ ...delimited ? { delimited: true } : {}
4863
4941
  };
4864
4942
  }
4865
4943
  function nextSiblingStartLine(surface, lineTable) {
@@ -4902,7 +4980,7 @@ function resolveDelimitedBlockSpan(lineTable, startLine, surface) {
4902
4980
  }
4903
4981
  function resolveUndelimitedBlockSpan(lineTable, sourceTable, startLine, surface) {
4904
4982
  const anchorText = lineText(lineTable, startLine);
4905
- if (isMarkdownQuote(surface.block)) return markdownQuoteSpan(lineTable, sourceTable, startLine, surface);
4983
+ if (isMarkdownQuote(surface.block)) return markdownQuoteSpan(lineTable, startLine);
4906
4984
  const firstLine = firstSourceLine(surface);
4907
4985
  if (firstLine === void 0) return;
4908
4986
  const official = withoutWhitespace(firstLine);
@@ -4946,18 +5024,10 @@ function isAirQuote(surface, anchorText, officialFirstLine) {
4946
5024
  const opened = anchorText.slice(1).trimEnd();
4947
5025
  return withoutWhitespace(surface.block.getSourceLines?.().length === 1 && opened.endsWith("\"") ? opened.slice(0, -1) : opened) === officialFirstLine;
4948
5026
  }
4949
- function markdownQuoteSpan(lineTable, sourceTable, startLine, surface) {
4950
- const contentEnd = lastChildIntervalEnd(sourceTable, startLine, surface);
4951
- let endLine = contentEnd;
4952
- for (let next = paragraphLine(lineTable, endLine, 2, true); next > endLine; next = paragraphLine(lineTable, endLine, 2, true)) {
4953
- const text = lineText(lineTable, next).trimEnd();
4954
- if (text === ">") {
4955
- endLine = next;
4956
- continue;
4957
- }
4958
- if (/^(?:> )?-- /u.test(text)) endLine = next;
4959
- break;
4960
- }
5027
+ function markdownQuoteSpan(lineTable, startLine) {
5028
+ const endLine = paragraphEndLine(lineTable, startLine, false);
5029
+ let contentEnd = endLine > startLine && /^(?:> )?-- /u.test(lineText(lineTable, endLine).trimEnd()) ? endLine - 1 : endLine;
5030
+ while (contentEnd > startLine && isEmptyQuotedLine(lineTable, contentEnd)) contentEnd -= 1;
4961
5031
  return {
4962
5032
  span: {
4963
5033
  startLine,
@@ -4969,6 +5039,10 @@ function markdownQuoteSpan(lineTable, sourceTable, startLine, surface) {
4969
5039
  }
4970
5040
  };
4971
5041
  }
5042
+ function isEmptyQuotedLine(lineTable, line) {
5043
+ const text = lineText(lineTable, line).trimEnd();
5044
+ return text === ">" || isLineComment(text);
5045
+ }
4972
5046
  function withoutWhitespace(text) {
4973
5047
  return text.replace(/\s+/gu, "");
4974
5048
  }
@@ -4981,7 +5055,7 @@ function firstSourceLine(surface) {
4981
5055
  const firstChild = surface.children[0];
4982
5056
  return firstChild ? firstSourceLine(firstChild) : void 0;
4983
5057
  }
4984
- function contentSpanForContext(surface, span) {
5058
+ function contentSpanForContext(surface, span, lineTable) {
4985
5059
  if (surface.context === "paragraph") return {
4986
5060
  startLine: surface.sourceLine ?? span.startLine,
4987
5061
  endLine: span.endLine
@@ -4990,7 +5064,7 @@ function contentSpanForContext(surface, span) {
4990
5064
  const line = surface.sourceLine ?? span.startLine;
4991
5065
  return {
4992
5066
  startLine: line,
4993
- endLine: line
5067
+ endLine: surface.parent?.context === "dlist" ? line : listItemTextEndLine(lineTable, line)
4994
5068
  };
4995
5069
  }
4996
5070
  }
@@ -5104,13 +5178,26 @@ function scanSurfaces(collected, surfaces, intervalByBlock) {
5104
5178
  continue;
5105
5179
  }
5106
5180
  if (interval.metadataSpan) scanMetadataRange(collected.lineTable, interval.metadataSpan.startLine, interval.metadataSpan.endLine, collected.xrefOccurrences, collected.anchorOccurrences);
5181
+ if (isHeading(surface) && surface.sourceLine !== void 0) {
5182
+ const line = collected.lineTable.lines[surface.sourceLine - 1];
5183
+ if (line) {
5184
+ scanXrefMatches(collected.lineTable, line, collected.xrefOccurrences);
5185
+ scanAnchorMatches(collected.lineTable, line, collected.anchorOccurrences);
5186
+ }
5187
+ }
5107
5188
  const span = interval.contentSpan ?? interval.span;
5108
5189
  if (officialBlockPolicy(surface.block) !== "scan") continue;
5109
5190
  if (!scansMacroSubstitutedContent(surface)) continue;
5110
5191
  if (surface.context === "table") scanTable(collected, surface.block);
5111
- else scanInlineRange(collected.lineTable, span.startLine, span.endLine, collected.xrefOccurrences, collected.anchorOccurrences, collected.headingInlineMetadataOccurrences, collected.toolDiagnostics, descendantUnscannableRanges(surface, intervalByBlock), isBibliographyList(surface));
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);
5112
5193
  }
5113
5194
  }
5195
+ function isHeading(surface) {
5196
+ return surface.context === "section" || surface.context === "floating_title";
5197
+ }
5198
+ function skipsLineComments(surface, interval) {
5199
+ return interval.delimited !== true || surface.block.getContentModel?.() === "compound";
5200
+ }
5114
5201
  function hasDiagnosticPolicyAncestor$1(surface) {
5115
5202
  let current = surface.parent;
5116
5203
  while (current) {
@@ -5165,11 +5252,11 @@ function parseMacroLabel(raw) {
5165
5252
  function compareSourceSpans(left, right) {
5166
5253
  return (left.sourceSpan?.start.line ?? 0) - (right.sourceSpan?.start.line ?? 0) || (left.sourceSpan?.start.column ?? 0) - (right.sourceSpan?.start.column ?? 0);
5167
5254
  }
5168
- function scanInlineRange(lineTable, startLine, endLine, xrefOccurrences, anchorOccurrences, headingInlineMetadataOccurrences, toolDiagnostics, skipRanges = [], bibliography = false) {
5255
+ function scanInlineRange(lineTable, startLine, endLine, xrefOccurrences, anchorOccurrences, headingInlineMetadataOccurrences, toolDiagnostics, skipRanges, bibliography, commentView) {
5169
5256
  for (let lineNumber = startLine; lineNumber <= endLine; lineNumber += 1) {
5170
5257
  if (isLineInRanges(lineNumber, skipRanges)) continue;
5171
5258
  const line = lineTable.lines[lineNumber - 1];
5172
- if (!line) continue;
5259
+ if (!line || commentView && isLineComment(lineText(commentView, lineNumber))) continue;
5173
5260
  scanXrefMatches(lineTable, line, xrefOccurrences);
5174
5261
  if (bibliography) scanBibliographyAnchor(lineTable, line, anchorOccurrences);
5175
5262
  scanAnchorMatches(lineTable, line, anchorOccurrences);
@@ -5202,7 +5289,7 @@ function scanXrefMatches(lineTable, line, xrefOccurrences) {
5202
5289
  }
5203
5290
  }
5204
5291
  function scanTable(collected, block) {
5205
- for (const range of mergeLineSpans(ordinaryCellRanges(block))) scanInlineRange(collected.lineTable, range.startLine, range.endLine, collected.xrefOccurrences, collected.anchorOccurrences, collected.headingInlineMetadataOccurrences, collected.toolDiagnostics);
5292
+ for (const range of mergeLineSpans(ordinaryCellRanges(block))) scanInlineRange(collected.lineTable, range.startLine, range.endLine, collected.xrefOccurrences, collected.anchorOccurrences, collected.headingInlineMetadataOccurrences, collected.toolDiagnostics, [], false, collected.lineTable);
5206
5293
  for (const document of asciidocCellDocuments(block)) {
5207
5294
  const surfaces = walkOfficialBlocks(document);
5208
5295
  const intervalByBlock = /* @__PURE__ */ new WeakMap();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "asciidoc-abundant-tree",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
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": {