@wdprlib/parser 3.1.2 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (419) hide show
  1. package/dist/index.cjs +10456 -8230
  2. package/dist/index.d.cts +313 -337
  3. package/dist/index.d.ts +313 -337
  4. package/dist/index.js +10460 -8234
  5. package/package.json +5 -3
  6. package/src/index.ts +170 -0
  7. package/src/lexer/anchor.ts +48 -0
  8. package/src/lexer/index.ts +21 -0
  9. package/src/lexer/lexer.ts +201 -0
  10. package/src/lexer/options.ts +19 -0
  11. package/src/lexer/punctuation.ts +70 -0
  12. package/src/lexer/quoted-string.ts +16 -0
  13. package/src/lexer/runs.ts +85 -0
  14. package/src/lexer/spacing-actions.ts +24 -0
  15. package/src/lexer/state.ts +103 -0
  16. package/src/lexer/syntax-actions.ts +80 -0
  17. package/src/lexer/text-actions.ts +41 -0
  18. package/src/lexer/token-actions.ts +136 -0
  19. package/src/lexer/token-factory.ts +62 -0
  20. package/src/lexer/tokenize.ts +18 -0
  21. package/src/lexer/tokens.ts +141 -0
  22. package/src/parser/constants.ts +175 -0
  23. package/src/parser/depth/index.ts +111 -0
  24. package/src/parser/depth/stack.ts +82 -0
  25. package/src/parser/index.ts +18 -0
  26. package/src/parser/parse/block.ts +42 -0
  27. package/src/parser/parse/context.ts +26 -0
  28. package/src/parser/parse/footnotes.ts +25 -0
  29. package/src/parser/parse/index.ts +42 -0
  30. package/src/parser/parse/options.ts +34 -0
  31. package/src/parser/parse/parser.ts +79 -0
  32. package/src/parser/parse/plain-non-ascii.ts +129 -0
  33. package/src/parser/parse/result.ts +57 -0
  34. package/src/parser/parse/source.ts +11 -0
  35. package/src/parser/postprocess/divAdjacentParagraph.ts +76 -0
  36. package/src/parser/postprocess/index.ts +15 -0
  37. package/src/parser/postprocess/spanStrip/clean-element.ts +168 -0
  38. package/src/parser/postprocess/spanStrip/cleanup.ts +25 -0
  39. package/src/parser/postprocess/spanStrip/empty-spans.ts +36 -0
  40. package/src/parser/postprocess/spanStrip/escaped.ts +78 -0
  41. package/src/parser/postprocess/spanStrip/factory.ts +23 -0
  42. package/src/parser/postprocess/spanStrip/index.ts +8 -0
  43. package/src/parser/postprocess/spanStrip/merge.ts +117 -0
  44. package/src/parser/postprocess/spanStrip/predicates.ts +59 -0
  45. package/src/parser/postprocess/spanStrip/split.ts +67 -0
  46. package/src/parser/preprocess/expr/chars.ts +15 -0
  47. package/src/parser/preprocess/expr/evaluate.ts +22 -0
  48. package/src/parser/preprocess/expr/index.ts +45 -0
  49. package/src/parser/preprocess/expr/kind.ts +19 -0
  50. package/src/parser/preprocess/expr/parse.ts +103 -0
  51. package/src/parser/preprocess/expr/scan.ts +34 -0
  52. package/src/parser/preprocess/expr/types.ts +14 -0
  53. package/src/parser/preprocess/index.ts +38 -0
  54. package/src/parser/preprocess/typography.ts +132 -0
  55. package/src/parser/preprocess/utils/bracket-depths.ts +98 -0
  56. package/src/parser/preprocess/utils/index.ts +13 -0
  57. package/src/parser/preprocess/utils/raw-regions.ts +153 -0
  58. package/src/parser/preprocess/whitespace/detection.ts +39 -0
  59. package/src/parser/preprocess/whitespace/index.ts +79 -0
  60. package/src/parser/preprocess/whitespace/leading-spaces.ts +11 -0
  61. package/src/parser/preprocess/whitespace/patterns.ts +23 -0
  62. package/src/parser/rules/block/align/body.ts +46 -0
  63. package/src/parser/rules/block/align/element.ts +13 -0
  64. package/src/parser/rules/block/align/index.ts +90 -0
  65. package/src/parser/rules/block/align/syntax.ts +113 -0
  66. package/src/parser/rules/block/bibliography/body.ts +81 -0
  67. package/src/parser/rules/block/bibliography/entries.ts +49 -0
  68. package/src/parser/rules/block/bibliography/entry-content.ts +73 -0
  69. package/src/parser/rules/block/bibliography/entry-key.ts +83 -0
  70. package/src/parser/rules/block/bibliography/index.ts +90 -0
  71. package/src/parser/rules/block/bibliography/open.ts +53 -0
  72. package/src/parser/rules/block/block-list/bare-content.ts +105 -0
  73. package/src/parser/rules/block/block-list/bare-paragraph.ts +60 -0
  74. package/src/parser/rules/block/block-list/index.ts +51 -0
  75. package/src/parser/rules/block/block-list/item-content.ts +132 -0
  76. package/src/parser/rules/block/block-list/li-content.ts +107 -0
  77. package/src/parser/rules/block/block-list/li-item.ts +77 -0
  78. package/src/parser/rules/block/block-list/list-block.ts +100 -0
  79. package/src/parser/rules/block/block-list/open.ts +51 -0
  80. package/src/parser/rules/block/block-list/tags.ts +50 -0
  81. package/src/parser/rules/block/blockquote/build.ts +62 -0
  82. package/src/parser/rules/block/blockquote/index.ts +80 -0
  83. package/src/parser/rules/block/blockquote/line.ts +79 -0
  84. package/src/parser/rules/block/blockquote/lines.ts +39 -0
  85. package/src/parser/rules/block/center/index.ts +72 -0
  86. package/src/parser/rules/block/center/open.ts +27 -0
  87. package/src/parser/rules/block/clear-float/index.ts +51 -0
  88. package/src/parser/rules/block/clear-float/syntax.ts +43 -0
  89. package/src/parser/rules/block/code/attributes.ts +30 -0
  90. package/src/parser/rules/block/code/content.ts +57 -0
  91. package/src/parser/rules/block/code/index.ts +100 -0
  92. package/src/parser/rules/block/collapsible/attributes.ts +95 -0
  93. package/src/parser/rules/block/collapsible/body.ts +69 -0
  94. package/src/parser/rules/block/collapsible/index.ts +117 -0
  95. package/src/parser/rules/block/collapsible/open.ts +51 -0
  96. package/src/parser/rules/block/collapsible/orphans.ts +31 -0
  97. package/src/parser/rules/block/collapsible/tags.ts +17 -0
  98. package/src/parser/rules/block/comment/consume.ts +37 -0
  99. package/src/parser/rules/block/comment/index.ts +47 -0
  100. package/src/parser/rules/block/content-separator/index.ts +49 -0
  101. package/src/parser/rules/block/content-separator/syntax.ts +33 -0
  102. package/src/parser/rules/block/definition-list/collect.ts +40 -0
  103. package/src/parser/rules/block/definition-list/index.ts +63 -0
  104. package/src/parser/rules/block/definition-list/item-key.ts +95 -0
  105. package/src/parser/rules/block/definition-list/item-value.ts +56 -0
  106. package/src/parser/rules/block/definition-list/items.ts +54 -0
  107. package/src/parser/rules/block/div/body.ts +41 -0
  108. package/src/parser/rules/block/div/close.ts +41 -0
  109. package/src/parser/rules/block/div/failed.ts +117 -0
  110. package/src/parser/rules/block/div/index.ts +112 -0
  111. package/src/parser/rules/block/div/nesting.ts +37 -0
  112. package/src/parser/rules/block/div/open.ts +59 -0
  113. package/src/parser/rules/block/div/paragraph-strip.ts +44 -0
  114. package/src/parser/rules/block/embed-block/content.ts +53 -0
  115. package/src/parser/rules/block/embed-block/index.ts +91 -0
  116. package/src/parser/rules/block/embed-block/open.ts +52 -0
  117. package/src/parser/rules/block/embed-block/tags.ts +5 -0
  118. package/src/parser/rules/block/footnoteblock/attributes.ts +73 -0
  119. package/src/parser/rules/block/footnoteblock/index.ts +82 -0
  120. package/src/parser/rules/block/footnoteblock/open.ts +53 -0
  121. package/src/parser/rules/block/heading/index.ts +87 -0
  122. package/src/parser/rules/block/heading/open.ts +50 -0
  123. package/src/parser/rules/block/heading/toc-text.ts +26 -0
  124. package/src/parser/rules/block/horizontal-rule/index.ts +44 -0
  125. package/src/parser/rules/block/horizontal-rule/syntax.ts +21 -0
  126. package/src/parser/rules/block/html/body.ts +114 -0
  127. package/src/parser/rules/block/html/diagnostics.ts +11 -0
  128. package/src/parser/rules/block/html/index.ts +95 -0
  129. package/src/parser/rules/block/html/open.ts +36 -0
  130. package/src/parser/rules/block/iframe/attributes.ts +106 -0
  131. package/src/parser/rules/block/iframe/index.ts +73 -0
  132. package/src/parser/rules/block/iframe/open.ts +58 -0
  133. package/src/parser/rules/block/iframe/source.ts +24 -0
  134. package/src/parser/rules/block/iframe/url.ts +38 -0
  135. package/src/parser/rules/block/iftags/body.ts +48 -0
  136. package/src/parser/rules/block/iftags/condition.ts +24 -0
  137. package/src/parser/rules/block/iftags/index.ts +108 -0
  138. package/src/parser/rules/block/include/arguments.ts +48 -0
  139. package/src/parser/rules/block/include/index.ts +75 -0
  140. package/src/parser/rules/block/include/location.ts +24 -0
  141. package/src/parser/rules/block/include/variables.ts +37 -0
  142. package/src/parser/rules/block/index.ts +127 -0
  143. package/src/parser/rules/block/list/index.ts +73 -0
  144. package/src/parser/rules/block/list/line.ts +77 -0
  145. package/src/parser/rules/block/list/native.ts +89 -0
  146. package/src/parser/rules/block/math/content.ts +54 -0
  147. package/src/parser/rules/block/math/index.ts +106 -0
  148. package/src/parser/rules/block/math/name.ts +35 -0
  149. package/src/parser/rules/block/module/backlinks/index.ts +31 -0
  150. package/src/parser/rules/block/module/backlinks/types.ts +21 -0
  151. package/src/parser/rules/block/module/body.ts +92 -0
  152. package/src/parser/rules/block/module/categories/index.ts +34 -0
  153. package/src/parser/rules/block/module/categories/types.ts +21 -0
  154. package/src/parser/rules/block/module/css/index.ts +37 -0
  155. package/src/parser/rules/block/module/element.ts +33 -0
  156. package/src/parser/rules/block/module/iftags/condition.ts +109 -0
  157. package/src/parser/rules/block/module/iftags/index.ts +26 -0
  158. package/src/parser/rules/block/module/iftags/preprocess.ts +140 -0
  159. package/src/parser/rules/block/module/iftags/resolve.ts +73 -0
  160. package/src/parser/rules/block/module/iftags/types.ts +63 -0
  161. package/src/parser/rules/block/module/include/directive.ts +91 -0
  162. package/src/parser/rules/block/module/include/index.ts +29 -0
  163. package/src/parser/rules/block/module/include/references.ts +42 -0
  164. package/src/parser/rules/block/module/include/resolve/cache.ts +44 -0
  165. package/src/parser/rules/block/module/include/resolve/index.ts +106 -0
  166. package/src/parser/rules/block/module/include/resolve/iterate.ts +202 -0
  167. package/src/parser/rules/block/module/include/resolve/replace.ts +31 -0
  168. package/src/parser/rules/block/module/include/resolve/types.ts +105 -0
  169. package/src/parser/rules/block/module/include/scanner.ts +121 -0
  170. package/src/parser/rules/block/module/index.ts +134 -0
  171. package/src/parser/rules/block/module/join/index.ts +34 -0
  172. package/src/parser/rules/block/module/join/types.ts +23 -0
  173. package/src/parser/rules/block/module/listpages/compiler.ts +73 -0
  174. package/src/parser/rules/block/module/listpages/extract.ts +76 -0
  175. package/src/parser/rules/block/module/listpages/extraction/listpages.ts +42 -0
  176. package/src/parser/rules/block/module/listpages/extraction/listusers.ts +30 -0
  177. package/src/parser/rules/block/module/listpages/extraction/query.ts +51 -0
  178. package/src/parser/rules/block/module/listpages/extraction/result.ts +18 -0
  179. package/src/parser/rules/block/module/listpages/extraction/template.ts +96 -0
  180. package/src/parser/rules/block/module/listpages/extraction/variables.ts +58 -0
  181. package/src/parser/rules/block/module/listpages/index.ts +83 -0
  182. package/src/parser/rules/block/module/listpages/normalization/date-selector.ts +53 -0
  183. package/src/parser/rules/block/module/listpages/normalization/numeric-selector.ts +32 -0
  184. package/src/parser/rules/block/module/listpages/normalization/order-parent.ts +82 -0
  185. package/src/parser/rules/block/module/listpages/normalization/selectors.ts +2 -0
  186. package/src/parser/rules/block/module/listpages/normalization/tags-category.ts +86 -0
  187. package/src/parser/rules/block/module/listpages/normalize.ts +74 -0
  188. package/src/parser/rules/block/module/listpages/parser.ts +106 -0
  189. package/src/parser/rules/block/module/listpages/resolution/items.ts +43 -0
  190. package/src/parser/rules/block/module/listpages/resolution/wrapper.ts +42 -0
  191. package/src/parser/rules/block/module/listpages/resolve.ts +60 -0
  192. package/src/parser/rules/block/module/listpages/template/format/content.ts +41 -0
  193. package/src/parser/rules/block/module/listpages/template/format/date.ts +116 -0
  194. package/src/parser/rules/block/module/listpages/template/format/index.ts +4 -0
  195. package/src/parser/rules/block/module/listpages/template/format/tags.ts +7 -0
  196. package/src/parser/rules/block/module/listpages/template/format/user.ts +9 -0
  197. package/src/parser/rules/block/module/listpages/template/getters/index.ts +36 -0
  198. package/src/parser/rules/block/module/listpages/template/getters/parameterized.ts +60 -0
  199. package/src/parser/rules/block/module/listpages/template/getters/simple.ts +65 -0
  200. package/src/parser/rules/block/module/listpages/template/getters/types.ts +3 -0
  201. package/src/parser/rules/block/module/listpages/template/syntax.ts +97 -0
  202. package/src/parser/rules/block/module/listpages/types/data-fetcher.ts +15 -0
  203. package/src/parser/rules/block/module/listpages/types/data-requirements.ts +52 -0
  204. package/src/parser/rules/block/module/listpages/types/external-data.ts +77 -0
  205. package/src/parser/rules/block/module/listpages/types/index.ts +17 -0
  206. package/src/parser/rules/block/module/listpages/types/normalized-query.ts +120 -0
  207. package/src/parser/rules/block/module/listpages/types/query.ts +67 -0
  208. package/src/parser/rules/block/module/listpages/types/template.ts +17 -0
  209. package/src/parser/rules/block/module/listpages/types/variables.ts +69 -0
  210. package/src/parser/rules/block/module/listpages/url-resolution/fields.ts +48 -0
  211. package/src/parser/rules/block/module/listpages/url-resolution/params.ts +19 -0
  212. package/src/parser/rules/block/module/listpages/url-resolution/query.ts +24 -0
  213. package/src/parser/rules/block/module/listpages/url-resolution/resolve.ts +53 -0
  214. package/src/parser/rules/block/module/listpages/url-resolution/value.ts +25 -0
  215. package/src/parser/rules/block/module/listpages/url-resolver.ts +29 -0
  216. package/src/parser/rules/block/module/listusers/compiler.ts +56 -0
  217. package/src/parser/rules/block/module/listusers/extract.ts +40 -0
  218. package/src/parser/rules/block/module/listusers/getters.ts +21 -0
  219. package/src/parser/rules/block/module/listusers/index.ts +36 -0
  220. package/src/parser/rules/block/module/listusers/parser.ts +54 -0
  221. package/src/parser/rules/block/module/listusers/resolve.ts +58 -0
  222. package/src/parser/rules/block/module/listusers/types.ts +93 -0
  223. package/src/parser/rules/block/module/listusers/variables.ts +15 -0
  224. package/src/parser/rules/block/module/mapping.ts +61 -0
  225. package/src/parser/rules/block/module/open.ts +57 -0
  226. package/src/parser/rules/block/module/page-tree/index.ts +38 -0
  227. package/src/parser/rules/block/module/page-tree/types.ts +29 -0
  228. package/src/parser/rules/block/module/rate/index.ts +28 -0
  229. package/src/parser/rules/block/module/rate/types.ts +19 -0
  230. package/src/parser/rules/block/module/resolution/contexts.ts +78 -0
  231. package/src/parser/rules/block/module/resolution/data-maps.ts +39 -0
  232. package/src/parser/rules/block/module/resolution/dynamic-modules.ts +93 -0
  233. package/src/parser/rules/block/module/resolution/styles.ts +53 -0
  234. package/src/parser/rules/block/module/resolution/walk-resolve.ts +107 -0
  235. package/src/parser/rules/block/module/resolve.ts +198 -0
  236. package/src/parser/rules/block/module/rule.ts +56 -0
  237. package/src/parser/rules/block/module/types-common.ts +70 -0
  238. package/src/parser/rules/block/module/types.ts +61 -0
  239. package/src/parser/rules/block/module/utils.ts +43 -0
  240. package/src/parser/rules/block/module/walk/children.ts +35 -0
  241. package/src/parser/rules/block/module/walk/index.ts +9 -0
  242. package/src/parser/rules/block/module/walk/map/index.ts +2 -0
  243. package/src/parser/rules/block/module/walk/map/stateful-definition-list.ts +25 -0
  244. package/src/parser/rules/block/module/walk/map/stateful-list.ts +40 -0
  245. package/src/parser/rules/block/module/walk/map/stateful-table.ts +23 -0
  246. package/src/parser/rules/block/module/walk/map/stateful-tabs.ts +19 -0
  247. package/src/parser/rules/block/module/walk/map/stateful.ts +71 -0
  248. package/src/parser/rules/block/module/walk/map/stateless-definition-list.ts +12 -0
  249. package/src/parser/rules/block/module/walk/map/stateless-list.ts +29 -0
  250. package/src/parser/rules/block/module/walk/map/stateless-table.ts +11 -0
  251. package/src/parser/rules/block/module/walk/map/stateless-tabs.ts +5 -0
  252. package/src/parser/rules/block/module/walk/map/stateless.ts +51 -0
  253. package/src/parser/rules/block/module/walk/map/types.ts +6 -0
  254. package/src/parser/rules/block/module/walk/traverse.ts +65 -0
  255. package/src/parser/rules/block/orphan-li/content.ts +60 -0
  256. package/src/parser/rules/block/orphan-li/index.ts +75 -0
  257. package/src/parser/rules/block/orphan-li/open.ts +25 -0
  258. package/src/parser/rules/block/orphan-li/tags.ts +40 -0
  259. package/src/parser/rules/block/paragraph/content.ts +12 -0
  260. package/src/parser/rules/block/paragraph/index.ts +60 -0
  261. package/src/parser/rules/block/paragraph/normalize.ts +52 -0
  262. package/src/parser/rules/block/paragraph/span-markers.ts +52 -0
  263. package/src/parser/rules/block/parsing/attributes/index.ts +32 -0
  264. package/src/parser/rules/block/parsing/attributes/names.ts +93 -0
  265. package/src/parser/rules/block/parsing/attributes/scanner.ts +75 -0
  266. package/src/parser/rules/block/parsing/attributes/values.ts +26 -0
  267. package/src/parser/rules/block/parsing/block-item.ts +29 -0
  268. package/src/parser/rules/block/parsing/content.ts +127 -0
  269. package/src/parser/rules/block/parsing/end-condition.ts +51 -0
  270. package/src/parser/rules/block/parsing/inline-content.ts +105 -0
  271. package/src/parser/rules/block/parsing/inline-newline.ts +41 -0
  272. package/src/parser/rules/block/parsing/non-boundary.ts +24 -0
  273. package/src/parser/rules/block/parsing/rule-dispatch.ts +44 -0
  274. package/src/parser/rules/block/table/index.ts +80 -0
  275. package/src/parser/rules/block/table/pipe/cell-start.ts +69 -0
  276. package/src/parser/rules/block/table/pipe/cell.ts +106 -0
  277. package/src/parser/rules/block/table/pipe/index.ts +2 -0
  278. package/src/parser/rules/block/table/pipe/row.ts +88 -0
  279. package/src/parser/rules/block/table/pipe/tokens.ts +14 -0
  280. package/src/parser/rules/block/table/pipe/trim.ts +50 -0
  281. package/src/parser/rules/block/table-block/body.ts +79 -0
  282. package/src/parser/rules/block/table-block/cell-attributes.ts +33 -0
  283. package/src/parser/rules/block/table-block/cell-boundary.ts +99 -0
  284. package/src/parser/rules/block/table-block/cell-content/index.ts +88 -0
  285. package/src/parser/rules/block/table-block/cell-content/segments.ts +134 -0
  286. package/src/parser/rules/block/table-block/cell-newline.ts +47 -0
  287. package/src/parser/rules/block/table-block/cell.ts +64 -0
  288. package/src/parser/rules/block/table-block/index.ts +113 -0
  289. package/src/parser/rules/block/table-block/row-boundary.ts +75 -0
  290. package/src/parser/rules/block/table-block/structure.ts +80 -0
  291. package/src/parser/rules/block/tabview/body.ts +64 -0
  292. package/src/parser/rules/block/tabview/index.ts +90 -0
  293. package/src/parser/rules/block/tabview/open.ts +50 -0
  294. package/src/parser/rules/block/tabview/tab.ts +92 -0
  295. package/src/parser/rules/block/tabview/tags.ts +30 -0
  296. package/src/parser/rules/block/toc/element.ts +11 -0
  297. package/src/parser/rules/block/toc/index.ts +44 -0
  298. package/src/parser/rules/block/toc/open.ts +84 -0
  299. package/src/parser/rules/block/utils.ts +15 -0
  300. package/src/parser/rules/common/attribute-safety.ts +109 -0
  301. package/src/parser/rules/common/block-name.ts +33 -0
  302. package/src/parser/rules/common/index.ts +2 -0
  303. package/src/parser/rules/contracts/index.ts +3 -0
  304. package/src/parser/rules/contracts/parse-context.ts +38 -0
  305. package/src/parser/rules/contracts/rule.ts +43 -0
  306. package/src/parser/rules/contracts/scope.ts +31 -0
  307. package/src/parser/rules/index.ts +49 -0
  308. package/src/parser/rules/inline/anchor/attributes.ts +54 -0
  309. package/src/parser/rules/inline/anchor/child.ts +26 -0
  310. package/src/parser/rules/inline/anchor/close.ts +34 -0
  311. package/src/parser/rules/inline/anchor/content.ts +59 -0
  312. package/src/parser/rules/inline/anchor/index.ts +103 -0
  313. package/src/parser/rules/inline/anchor/newline.ts +26 -0
  314. package/src/parser/rules/inline/anchor/open.ts +47 -0
  315. package/src/parser/rules/inline/anchor/paragraph-strip.ts +14 -0
  316. package/src/parser/rules/inline/anchor/syntax.ts +40 -0
  317. package/src/parser/rules/inline/anchor-name/index.ts +38 -0
  318. package/src/parser/rules/inline/anchor-name/name.ts +39 -0
  319. package/src/parser/rules/inline/anchor-name/syntax.ts +46 -0
  320. package/src/parser/rules/inline/bibcite/element.ts +14 -0
  321. package/src/parser/rules/inline/bibcite/index.ts +34 -0
  322. package/src/parser/rules/inline/bibcite/syntax.ts +64 -0
  323. package/src/parser/rules/inline/bold.ts +49 -0
  324. package/src/parser/rules/inline/color/index.ts +35 -0
  325. package/src/parser/rules/inline/color/syntax.ts +69 -0
  326. package/src/parser/rules/inline/comment/consume.ts +31 -0
  327. package/src/parser/rules/inline/comment/index.ts +64 -0
  328. package/src/parser/rules/inline/equation-ref/element.ts +8 -0
  329. package/src/parser/rules/inline/equation-ref/index.ts +34 -0
  330. package/src/parser/rules/inline/equation-ref/syntax.ts +45 -0
  331. package/src/parser/rules/inline/expr/branch.ts +104 -0
  332. package/src/parser/rules/inline/expr/conditional-branch.ts +27 -0
  333. package/src/parser/rules/inline/expr/conditional.ts +80 -0
  334. package/src/parser/rules/inline/expr/depth.ts +25 -0
  335. package/src/parser/rules/inline/expr/elements.ts +39 -0
  336. package/src/parser/rules/inline/expr/index.ts +84 -0
  337. package/src/parser/rules/inline/expr/syntax.ts +45 -0
  338. package/src/parser/rules/inline/footnote/child.ts +22 -0
  339. package/src/parser/rules/inline/footnote/close.ts +33 -0
  340. package/src/parser/rules/inline/footnote/content.ts +54 -0
  341. package/src/parser/rules/inline/footnote/elements.ts +38 -0
  342. package/src/parser/rules/inline/footnote/index.ts +54 -0
  343. package/src/parser/rules/inline/footnote/newline.ts +27 -0
  344. package/src/parser/rules/inline/footnote/open.ts +38 -0
  345. package/src/parser/rules/inline/formatting/container.ts +50 -0
  346. package/src/parser/rules/inline/guillemet/index.ts +56 -0
  347. package/src/parser/rules/inline/guillemet/text.ts +11 -0
  348. package/src/parser/rules/inline/html/gate.ts +64 -0
  349. package/src/parser/rules/inline/html/index.ts +81 -0
  350. package/src/parser/rules/inline/html/open.ts +37 -0
  351. package/src/parser/rules/inline/image/attributes.ts +22 -0
  352. package/src/parser/rules/inline/image/body.ts +36 -0
  353. package/src/parser/rules/inline/image/index.ts +89 -0
  354. package/src/parser/rules/inline/image/open.ts +56 -0
  355. package/src/parser/rules/inline/image/source.ts +62 -0
  356. package/src/parser/rules/inline/image/syntax.ts +76 -0
  357. package/src/parser/rules/inline/index.ts +150 -0
  358. package/src/parser/rules/inline/italic.ts +46 -0
  359. package/src/parser/rules/inline/line-break/backslash.ts +58 -0
  360. package/src/parser/rules/inline/line-break/elements.ts +9 -0
  361. package/src/parser/rules/inline/line-break/index.ts +3 -0
  362. package/src/parser/rules/inline/line-break/newline.ts +82 -0
  363. package/src/parser/rules/inline/line-break/underscore.ts +45 -0
  364. package/src/parser/rules/inline/link-anchor.ts +72 -0
  365. package/src/parser/rules/inline/link-bracket/anchor.ts +3 -0
  366. package/src/parser/rules/inline/link-bracket/direct-url.ts +5 -0
  367. package/src/parser/rules/inline/link-bracket/parsed.ts +81 -0
  368. package/src/parser/rules/inline/link-bracket/parts.ts +64 -0
  369. package/src/parser/rules/inline/link-bracket/prefix.ts +15 -0
  370. package/src/parser/rules/inline/link-single.ts +73 -0
  371. package/src/parser/rules/inline/link-star.ts +72 -0
  372. package/src/parser/rules/inline/link-triple/fallback.ts +10 -0
  373. package/src/parser/rules/inline/link-triple/index.ts +62 -0
  374. package/src/parser/rules/inline/link-triple/interwiki.ts +11 -0
  375. package/src/parser/rules/inline/link-triple/label.ts +35 -0
  376. package/src/parser/rules/inline/link-triple/syntax.ts +72 -0
  377. package/src/parser/rules/inline/link-triple/target.ts +36 -0
  378. package/src/parser/rules/inline/math-inline/index.ts +40 -0
  379. package/src/parser/rules/inline/math-inline/syntax.ts +55 -0
  380. package/src/parser/rules/inline/monospace.ts +50 -0
  381. package/src/parser/rules/inline/parsing/block-boundary.ts +42 -0
  382. package/src/parser/rules/inline/parsing/block-start-predicates.ts +117 -0
  383. package/src/parser/rules/inline/parsing/collect.ts +23 -0
  384. package/src/parser/rules/inline/parsing/inline-content.ts +115 -0
  385. package/src/parser/rules/inline/parsing/paragraph-boundary.ts +47 -0
  386. package/src/parser/rules/inline/parsing/plain-text.ts +69 -0
  387. package/src/parser/rules/inline/parsing/preserved-line-break.ts +11 -0
  388. package/src/parser/rules/inline/parsing/rules.ts +34 -0
  389. package/src/parser/rules/inline/parsing/simple-token.ts +26 -0
  390. package/src/parser/rules/inline/raw/angle.ts +40 -0
  391. package/src/parser/rules/inline/raw/double-at.ts +78 -0
  392. package/src/parser/rules/inline/raw/index.ts +26 -0
  393. package/src/parser/rules/inline/raw/result.ts +26 -0
  394. package/src/parser/rules/inline/size/content.ts +65 -0
  395. package/src/parser/rules/inline/size/index.ts +55 -0
  396. package/src/parser/rules/inline/size/open.ts +43 -0
  397. package/src/parser/rules/inline/size/value.ts +45 -0
  398. package/src/parser/rules/inline/span/content.ts +97 -0
  399. package/src/parser/rules/inline/span/elements.ts +108 -0
  400. package/src/parser/rules/inline/span/index.ts +79 -0
  401. package/src/parser/rules/inline/span/newline.ts +50 -0
  402. package/src/parser/rules/inline/span/syntax.ts +70 -0
  403. package/src/parser/rules/inline/strikethrough/index.ts +60 -0
  404. package/src/parser/rules/inline/strikethrough/parse.ts +14 -0
  405. package/src/parser/rules/inline/strikethrough/syntax.ts +24 -0
  406. package/src/parser/rules/inline/subscript.ts +47 -0
  407. package/src/parser/rules/inline/superscript.ts +49 -0
  408. package/src/parser/rules/inline/text/element.ts +5 -0
  409. package/src/parser/rules/inline/text/index.ts +85 -0
  410. package/src/parser/rules/inline/underline/child.ts +26 -0
  411. package/src/parser/rules/inline/underline/content.ts +29 -0
  412. package/src/parser/rules/inline/underline/index.ts +84 -0
  413. package/src/parser/rules/inline/user/element.ts +11 -0
  414. package/src/parser/rules/inline/user/index.ts +34 -0
  415. package/src/parser/rules/inline/user/syntax.ts +67 -0
  416. package/src/parser/rules/inline/utils.ts +4 -0
  417. package/src/parser/rules/tokens.ts +106 -0
  418. package/src/parser/rules/types.ts +9 -0
  419. package/src/parser/toc.ts +130 -0
@@ -0,0 +1,85 @@
1
+ /**
2
+ *
3
+ * Provides the two lowest-priority inline rules: `textRule` and `fallbackRule`.
4
+ *
5
+ * These rules act as catch-alls that convert unrecognized tokens into
6
+ * plain `"text"` AST elements, ensuring no token is ever silently dropped
7
+ * during inline parsing.
8
+ *
9
+ * `textRule` handles `TEXT` and `WHITESPACE` tokens specifically and is
10
+ * included in the main `inlineRules` array as the last entry before
11
+ * the fallback.
12
+ *
13
+ * `fallbackRule` has an empty `startTokens` array, which means it matches
14
+ * ANY token type. It is exported separately as `inlineFallbackRule` and
15
+ * is NOT included in the `inlineRules` array to prevent it from
16
+ * short-circuiting more specific rules. Instead, it is invoked explicitly
17
+ * by the parser when no other rule matches.
18
+ *
19
+ * @module
20
+ */
21
+ import type { Element } from "@wdprlib/ast";
22
+ import type { InlineRule, ParseContext, RuleResult } from "../../types";
23
+ import { currentToken } from "../../types";
24
+ import { textElement } from "./element";
25
+
26
+ /**
27
+ * Inline rule for plain text and whitespace tokens.
28
+ *
29
+ * Matches `TEXT` and `WHITESPACE` token types and converts them
30
+ * directly to `"text"` AST elements. This rule always succeeds.
31
+ *
32
+ * Placed last (before the fallback) in the inline rules array so
33
+ * that all formatting and structural rules are tried first.
34
+ */
35
+ export const textRule: InlineRule = {
36
+ name: "text",
37
+ startTokens: ["TEXT", "WHITESPACE"],
38
+
39
+ /**
40
+ * Converts a TEXT or WHITESPACE token into a text element.
41
+ *
42
+ * @param ctx - Parse context with token stream and current position
43
+ * @returns Always returns `{ success: true }` with a single `"text"` element
44
+ */
45
+ parse(ctx: ParseContext): RuleResult<Element> {
46
+ const token = currentToken(ctx);
47
+
48
+ return {
49
+ success: true,
50
+ elements: [textElement(token.value)],
51
+ consumed: 1,
52
+ };
53
+ },
54
+ };
55
+
56
+ /**
57
+ * Universal fallback rule for any token type not matched by other rules.
58
+ *
59
+ * The empty `startTokens` array signals to the parser that this rule
60
+ * can match any token. It converts the token's value to a `"text"`
61
+ * element, ensuring no token is silently dropped.
62
+ *
63
+ * This rule is used as a last-resort handler and is intentionally
64
+ * excluded from the main `inlineRules` array.
65
+ */
66
+ export const fallbackRule: InlineRule = {
67
+ name: "fallback",
68
+ startTokens: [], // matches anything not matched by other rules
69
+
70
+ /**
71
+ * Converts any unrecognized token into a text element.
72
+ *
73
+ * @param ctx - Parse context with token stream and current position
74
+ * @returns Always returns `{ success: true }` with a single `"text"` element
75
+ */
76
+ parse(ctx: ParseContext): RuleResult<Element> {
77
+ const token = currentToken(ctx);
78
+
79
+ return {
80
+ success: true,
81
+ elements: [textElement(token.value)],
82
+ consumed: 1,
83
+ };
84
+ },
85
+ };
@@ -0,0 +1,26 @@
1
+ import type { Element } from "@wdprlib/ast";
2
+ import type { ParseContext } from "../../types";
3
+ import { parseInlineUntil } from "../utils";
4
+
5
+ export interface UnderlineChildResult {
6
+ elements: Element[];
7
+ consumed: number;
8
+ }
9
+
10
+ export function parseUnderlineChild(ctx: ParseContext, pos: number): UnderlineChildResult {
11
+ const token = ctx.tokens[pos];
12
+ if (!token) {
13
+ return { elements: [], consumed: 0 };
14
+ }
15
+
16
+ if (token.type === "NEWLINE") {
17
+ return { elements: [{ element: "line-break" }], consumed: 1 };
18
+ }
19
+
20
+ const result = parseInlineUntil({ ...ctx, pos }, "UNDERLINE_MARKER");
21
+ if (result.elements.length > 0) {
22
+ return { elements: result.elements, consumed: result.consumed };
23
+ }
24
+
25
+ return { elements: [{ element: "text", data: token.value }], consumed: 1 };
26
+ }
@@ -0,0 +1,29 @@
1
+ import type { Element } from "@wdprlib/ast";
2
+ import type { ParseContext } from "../../types";
3
+ import { parseUnderlineChild } from "./child";
4
+
5
+ export function parseUnderlineContent(
6
+ ctx: ParseContext,
7
+ startPos: number,
8
+ ): { children: Element[]; consumed: number } {
9
+ const children: Element[] = [];
10
+ let pos = startPos;
11
+ let consumed = 1;
12
+
13
+ while (pos < ctx.tokens.length) {
14
+ const token = ctx.tokens[pos];
15
+ if (!token || token.type === "EOF") break;
16
+
17
+ if (token.type === "UNDERLINE_MARKER") {
18
+ consumed++;
19
+ break;
20
+ }
21
+
22
+ const child = parseUnderlineChild(ctx, pos);
23
+ children.push(...child.elements);
24
+ pos += child.consumed;
25
+ consumed += child.consumed;
26
+ }
27
+
28
+ return { children, consumed };
29
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ *
3
+ * Parses the Wikidot underline formatting syntax: `__text__`.
4
+ *
5
+ * Underline text is delimited by double underscores. Unlike most
6
+ * inline formatting markers (bold, italic, etc.) which require the
7
+ * closing marker on the same line, underline markers can span
8
+ * multiple lines within the same paragraph. The closing marker
9
+ * must appear before a paragraph break (blank line).
10
+ *
11
+ * Single newlines within underlined content are converted to
12
+ * `<br />` elements, matching Wikidot's multiline underline behavior.
13
+ *
14
+ * If no closing `__` is found before a paragraph break, the opening
15
+ * marker is emitted as literal text.
16
+ *
17
+ * Empty underline (`____`) is silently discarded by Wikidot (produces
18
+ * no output).
19
+ *
20
+ * Renders as a `<u>` element in HTML.
21
+ *
22
+ * Produces a `"container"` AST element with `type: "underline"`.
23
+ *
24
+ * @module
25
+ */
26
+ import type { Element } from "@wdprlib/ast";
27
+ import type { InlineRule, ParseContext, RuleResult } from "../../types";
28
+ import { currentToken, hasClosingMarkerBeforeParagraphBreak } from "../../types";
29
+ import { createInlineContainer } from "../formatting/container";
30
+ import { parseUnderlineContent } from "./content";
31
+
32
+ /**
33
+ * Inline rule for parsing `__underline__` formatting.
34
+ *
35
+ * Triggered by an `UNDERLINE_MARKER` token (`__`). Uses
36
+ * {@link hasClosingMarkerBeforeParagraphBreak} instead of the
37
+ * single-line variant because Wikidot allows underline to span
38
+ * multiple lines within a paragraph.
39
+ *
40
+ * When no closing marker is found before a paragraph break, the
41
+ * opening `__` is treated as literal text.
42
+ */
43
+ export const underlineRule: InlineRule = {
44
+ name: "underline",
45
+ startTokens: ["UNDERLINE_MARKER"],
46
+
47
+ /**
48
+ * Attempts to parse underline formatting at the current position.
49
+ *
50
+ * @param ctx - Parse context with token stream and current position
51
+ * @returns A successful result containing either a `"container"` element
52
+ * with `type: "underline"`, an empty array (for `____`), or a
53
+ * text fallback for unmatched markers
54
+ */
55
+ parse(ctx: ParseContext): RuleResult<Element> {
56
+ const startToken = currentToken(ctx);
57
+
58
+ // Check if closing marker exists before paragraph break
59
+ if (!hasClosingMarkerBeforeParagraphBreak({ ...ctx, pos: ctx.pos + 1 }, "UNDERLINE_MARKER")) {
60
+ return {
61
+ success: true,
62
+ elements: [{ element: "text", data: startToken.value }],
63
+ consumed: 1,
64
+ };
65
+ }
66
+
67
+ const { children, consumed } = parseUnderlineContent(ctx, ctx.pos + 1);
68
+
69
+ // Empty underline (____) is discarded entirely in Wikidot
70
+ if (children.length === 0) {
71
+ return {
72
+ success: true,
73
+ elements: [],
74
+ consumed,
75
+ };
76
+ }
77
+
78
+ return {
79
+ success: true,
80
+ elements: [createInlineContainer("underline", children)],
81
+ consumed,
82
+ };
83
+ },
84
+ };
@@ -0,0 +1,11 @@
1
+ import type { Element } from "@wdprlib/ast";
2
+
3
+ export function userElement(name: string, showAvatar: boolean): Element {
4
+ return {
5
+ element: "user",
6
+ data: {
7
+ name,
8
+ "show-avatar": showAvatar,
9
+ },
10
+ };
11
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ *
3
+ * Parses the Wikidot user reference syntax: `[[user name]]` and `[[*user name]]`.
4
+ *
5
+ * @module
6
+ */
7
+ import type { Element } from "@wdprlib/ast";
8
+ import type { InlineRule, ParseContext, RuleResult } from "../../types";
9
+ import { currentToken } from "../../types";
10
+ import { userElement } from "./element";
11
+ import { parseUserReference } from "./syntax";
12
+
13
+ export const userRule: InlineRule = {
14
+ name: "user",
15
+ startTokens: ["BLOCK_OPEN"],
16
+
17
+ parse(ctx: ParseContext): RuleResult<Element> {
18
+ const openToken = currentToken(ctx);
19
+ if (openToken.type !== "BLOCK_OPEN") {
20
+ return { success: false };
21
+ }
22
+
23
+ const parsed = parseUserReference(ctx, ctx.pos + 1);
24
+ if (!parsed) {
25
+ return { success: false };
26
+ }
27
+
28
+ return {
29
+ success: true,
30
+ elements: [userElement(parsed.name, parsed.showAvatar)],
31
+ consumed: 1 + parsed.consumed,
32
+ };
33
+ },
34
+ };
@@ -0,0 +1,67 @@
1
+ import type { ParseContext } from "../../types";
2
+
3
+ export function parseUserReference(
4
+ ctx: ParseContext,
5
+ startPos: number,
6
+ ): { name: string; showAvatar: boolean; consumed: number } | null {
7
+ let pos = startPos;
8
+ let consumed = 0;
9
+
10
+ if (ctx.tokens[pos]?.type === "WHITESPACE") {
11
+ return null;
12
+ }
13
+
14
+ let showAvatar = false;
15
+ if (ctx.tokens[pos]?.type === "STAR") {
16
+ showAvatar = true;
17
+ pos++;
18
+ consumed++;
19
+ }
20
+
21
+ while (ctx.tokens[pos]?.type === "WHITESPACE") {
22
+ pos++;
23
+ consumed++;
24
+ }
25
+
26
+ const nameToken = ctx.tokens[pos];
27
+ if (!nameToken || (nameToken.type !== "TEXT" && nameToken.type !== "IDENTIFIER")) {
28
+ return null;
29
+ }
30
+ if (nameToken.value.toLowerCase() !== "user") {
31
+ return null;
32
+ }
33
+ pos++;
34
+ consumed++;
35
+
36
+ while (ctx.tokens[pos]?.type === "WHITESPACE") {
37
+ pos++;
38
+ consumed++;
39
+ }
40
+
41
+ let username = "";
42
+ while (pos < ctx.tokens.length) {
43
+ const token = ctx.tokens[pos];
44
+ if (
45
+ !token ||
46
+ token.type === "BLOCK_CLOSE" ||
47
+ token.type === "NEWLINE" ||
48
+ token.type === "EOF"
49
+ ) {
50
+ break;
51
+ }
52
+ username += token.value;
53
+ pos++;
54
+ consumed++;
55
+ }
56
+
57
+ username = username.trim();
58
+ if (!username || ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
59
+ return null;
60
+ }
61
+
62
+ return {
63
+ name: username,
64
+ showAvatar,
65
+ consumed: consumed + 1,
66
+ };
67
+ }
@@ -0,0 +1,4 @@
1
+ export { canApplyInlineRule } from "./parsing/rules";
2
+ export { collectUntilNewline } from "./parsing/collect";
3
+ export { getCandidateInlineRules } from "./parsing/rules";
4
+ export { parseInlineUntil, type InlineParseResult } from "./parsing/inline-content";
@@ -0,0 +1,106 @@
1
+ import type { Token, TokenType } from "../../lexer";
2
+ import type { ParseContext } from "./contracts";
3
+
4
+ /**
5
+ * Helper to get current token
6
+ */
7
+ export function currentToken(ctx: ParseContext): Token {
8
+ return ctx.tokens[ctx.pos] ?? eofToken();
9
+ }
10
+
11
+ /**
12
+ * Helper to peek ahead
13
+ */
14
+ export function peekToken(ctx: ParseContext, n = 1): Token {
15
+ return ctx.tokens[ctx.pos + n] ?? eofToken();
16
+ }
17
+
18
+ /**
19
+ * Helper to check token type
20
+ */
21
+ export function checkToken(ctx: ParseContext, type: TokenType): boolean {
22
+ return currentToken(ctx).type === type;
23
+ }
24
+
25
+ /**
26
+ * Helper to check if at end
27
+ */
28
+ export function isAtEnd(ctx: ParseContext): boolean {
29
+ return ctx.pos >= ctx.tokens.length || currentToken(ctx).type === "EOF";
30
+ }
31
+
32
+ /**
33
+ * Create EOF token
34
+ */
35
+ function eofToken(): Token {
36
+ return {
37
+ type: "EOF",
38
+ value: "",
39
+ position: { start: { line: 0, column: 0, offset: 0 }, end: { line: 0, column: 0, offset: 0 } },
40
+ lineStart: false,
41
+ };
42
+ }
43
+
44
+ /**
45
+ * Check if closing marker exists before newline.
46
+ * If markerValue is provided, also check that the token value matches.
47
+ */
48
+ export function hasClosingMarkerBeforeNewline(
49
+ ctx: ParseContext,
50
+ markerType: TokenType,
51
+ markerValue?: string,
52
+ ): boolean {
53
+ let pos = ctx.pos;
54
+ while (pos < ctx.tokens.length) {
55
+ const token = ctx.tokens[pos];
56
+ if (!token || token.type === "NEWLINE" || token.type === "EOF") {
57
+ return false;
58
+ }
59
+ if (token.type === markerType) {
60
+ if (markerValue === undefined || token.value === markerValue) {
61
+ return true;
62
+ }
63
+ }
64
+ pos++;
65
+ }
66
+ return false;
67
+ }
68
+
69
+ /**
70
+ * Check if closing marker exists before paragraph break (double newline).
71
+ * Allows inline formatting to span multiple lines within a paragraph.
72
+ */
73
+ export function hasClosingMarkerBeforeParagraphBreak(
74
+ ctx: ParseContext,
75
+ markerType: TokenType,
76
+ markerValue?: string,
77
+ ): boolean {
78
+ let pos = ctx.pos;
79
+ while (pos < ctx.tokens.length) {
80
+ const token = ctx.tokens[pos];
81
+ if (!token || token.type === "EOF") {
82
+ return false;
83
+ }
84
+ // Check for paragraph break (NEWLINE followed by NEWLINE after optional whitespace)
85
+ if (token.type === "NEWLINE") {
86
+ let lookAhead = 1;
87
+ while (ctx.tokens[pos + lookAhead]?.type === "WHITESPACE") {
88
+ lookAhead++;
89
+ }
90
+ if (
91
+ ctx.tokens[pos + lookAhead]?.type === "NEWLINE" ||
92
+ ctx.tokens[pos + lookAhead]?.type === "EOF" ||
93
+ !ctx.tokens[pos + lookAhead]
94
+ ) {
95
+ return false;
96
+ }
97
+ }
98
+ if (token.type === markerType) {
99
+ if (markerValue === undefined || token.value === markerValue) {
100
+ return true;
101
+ }
102
+ }
103
+ pos++;
104
+ }
105
+ return false;
106
+ }
@@ -0,0 +1,9 @@
1
+ export type { BlockRule, InlineRule, ParseContext, RuleResult, ScopeContext } from "./contracts";
2
+ export {
3
+ checkToken,
4
+ currentToken,
5
+ hasClosingMarkerBeforeNewline,
6
+ hasClosingMarkerBeforeParagraphBreak,
7
+ isAtEnd,
8
+ peekToken,
9
+ } from "./tokens";
@@ -0,0 +1,130 @@
1
+ /**
2
+ *
3
+ * Table of Contents (TOC) generation for Wikidot markup.
4
+ *
5
+ * Converts a flat array of `TocEntry` items (collected from heading elements
6
+ * during parsing) into nested bullet-list `Element` nodes suitable for rendering
7
+ * as `[[toc]]`. Uses the depth module to transform flat heading levels (h1-h6)
8
+ * into a properly nested list hierarchy.
9
+ *
10
+ * Each TOC entry becomes an anchor link (`#toc0`, `#toc1`, ...) pointing to the
11
+ * corresponding heading in the rendered page, matching Wikidot's original
12
+ * anchor naming scheme.
13
+ *
14
+ * @module
15
+ */
16
+
17
+ import type { Element, TocEntry, ListItem } from "@wdprlib/ast";
18
+ import { processDepths, type DepthList, type DepthItem } from "./depth";
19
+
20
+ /**
21
+ * Sequential counter for generating unique TOC anchor IDs.
22
+ *
23
+ * Wikidot assigns sequential `#toc0`, `#toc1`, ... anchors to headings in
24
+ * document order. This class maintains a monotonically increasing counter
25
+ * that is shared across all TOC trees to ensure globally unique anchors.
26
+ */
27
+ class TocIndexer {
28
+ private index = 0;
29
+
30
+ /**
31
+ * Returns the next sequential index and advances the counter.
32
+ * @returns The current index value (0-based) before incrementing
33
+ */
34
+ next(): number {
35
+ return this.index++;
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Build a nested bullet-list Element from depth-processed TOC items.
41
+ *
42
+ * Each item in the depth list is converted to a `ListItem`, with nested lists
43
+ * becoming sub-list items and leaf items becoming anchor links.
44
+ *
45
+ * @param indexer - Shared counter for generating sequential `#tocN` anchors
46
+ * @param items - Depth-processed list of heading text strings
47
+ * @returns A `list` Element with type "bullet" containing the TOC hierarchy
48
+ */
49
+ function buildTocList(indexer: TocIndexer, items: DepthList<null, string>): Element {
50
+ const listItems: ListItem[] = items.map((item) => buildTocListItem(indexer, item));
51
+
52
+ return {
53
+ element: "list",
54
+ data: {
55
+ type: "bullet",
56
+ attributes: {},
57
+ items: listItems,
58
+ },
59
+ };
60
+ }
61
+
62
+ /**
63
+ * Build a single TOC list item from a depth item.
64
+ *
65
+ * For leaf items, creates an anchor link element with a `#tocN` href.
66
+ * For nested list items, recursively builds a sub-list.
67
+ *
68
+ * @param indexer - Shared counter for generating sequential `#tocN` anchors
69
+ * @param item - A single depth item (either a leaf heading or a nested list)
70
+ * @returns A `ListItem` for inclusion in the TOC list
71
+ */
72
+ function buildTocListItem(indexer: TocIndexer, item: DepthItem<null, string>): ListItem {
73
+ if (item.kind === "list") {
74
+ return {
75
+ "item-type": "sub-list",
76
+ element: "list",
77
+ data: {
78
+ type: "bullet",
79
+ attributes: {},
80
+ items: item.children.map((child) => buildTocListItem(indexer, child)),
81
+ },
82
+ };
83
+ }
84
+
85
+ // item.kind === "item"
86
+ const anchor = `#toc${indexer.next()}`;
87
+ const linkElement: Element = {
88
+ element: "link",
89
+ data: {
90
+ type: "table-of-contents",
91
+ link: anchor,
92
+ extra: null,
93
+ label: { text: item.value },
94
+ target: null,
95
+ },
96
+ };
97
+
98
+ return {
99
+ "item-type": "elements",
100
+ attributes: {},
101
+ elements: [linkElement],
102
+ };
103
+ }
104
+
105
+ /**
106
+ * Convert flat TocEntry[] to nested List elements
107
+ *
108
+ * @param entries - Flat list of TOC entries with level and text
109
+ * @returns Array of List elements (usually one, but can be multiple if levels reset)
110
+ */
111
+ export function buildTableOfContents(entries: TocEntry[]): Element[] {
112
+ if (entries.length === 0) {
113
+ return [];
114
+ }
115
+
116
+ // Convert entries to depth-annotated items
117
+ // level is 1-based (h1=1, h2=2, ...), convert to 0-based depth
118
+ const depthItems = entries.map((entry) => ({
119
+ depth: entry.level - 1,
120
+ ltype: null as null, // We don't differentiate list types for TOC
121
+ value: entry.text,
122
+ }));
123
+
124
+ // Process into nested structure
125
+ const trees = processDepths<null, string>(null, depthItems);
126
+
127
+ // Build List elements from each tree
128
+ const indexer = new TocIndexer();
129
+ return trees.map((tree) => buildTocList(indexer, tree.list));
130
+ }