@wdprlib/parser 3.2.0 → 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 (433) hide show
  1. package/dist/index.cjs +10451 -8402
  2. package/dist/index.d.cts +313 -337
  3. package/dist/index.d.ts +313 -337
  4. package/dist/index.js +10438 -8389
  5. package/package.json +1 -1
  6. package/src/index.ts +7 -0
  7. package/src/lexer/anchor.ts +48 -0
  8. package/src/lexer/index.ts +3 -2
  9. package/src/lexer/lexer.ts +73 -559
  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/parser/constants.ts +2 -0
  22. package/src/parser/depth/index.ts +111 -0
  23. package/src/parser/depth/stack.ts +82 -0
  24. package/src/parser/parse/block.ts +42 -0
  25. package/src/parser/parse/context.ts +26 -0
  26. package/src/parser/parse/footnotes.ts +25 -0
  27. package/src/parser/parse/index.ts +42 -0
  28. package/src/parser/parse/options.ts +34 -0
  29. package/src/parser/parse/parser.ts +79 -0
  30. package/src/parser/parse/plain-non-ascii.ts +129 -0
  31. package/src/parser/parse/result.ts +57 -0
  32. package/src/parser/parse/source.ts +11 -0
  33. package/src/parser/postprocess/divAdjacentParagraph.ts +1 -1
  34. package/src/parser/postprocess/spanStrip/clean-element.ts +168 -0
  35. package/src/parser/postprocess/spanStrip/cleanup.ts +25 -0
  36. package/src/parser/postprocess/spanStrip/empty-spans.ts +36 -0
  37. package/src/parser/postprocess/spanStrip/escaped.ts +78 -0
  38. package/src/parser/postprocess/spanStrip/factory.ts +23 -0
  39. package/src/parser/postprocess/spanStrip/index.ts +8 -0
  40. package/src/parser/postprocess/spanStrip/merge.ts +117 -0
  41. package/src/parser/postprocess/spanStrip/predicates.ts +59 -0
  42. package/src/parser/postprocess/spanStrip/split.ts +67 -0
  43. package/src/parser/preprocess/expr/chars.ts +15 -0
  44. package/src/parser/preprocess/expr/evaluate.ts +22 -0
  45. package/src/parser/preprocess/expr/index.ts +45 -0
  46. package/src/parser/preprocess/expr/kind.ts +19 -0
  47. package/src/parser/preprocess/expr/parse.ts +103 -0
  48. package/src/parser/preprocess/expr/scan.ts +34 -0
  49. package/src/parser/preprocess/expr/types.ts +14 -0
  50. package/src/parser/preprocess/typography.ts +70 -5
  51. package/src/parser/preprocess/utils/bracket-depths.ts +98 -0
  52. package/src/parser/preprocess/utils/index.ts +13 -0
  53. package/src/parser/preprocess/utils/raw-regions.ts +153 -0
  54. package/src/parser/preprocess/whitespace/detection.ts +39 -0
  55. package/src/parser/preprocess/whitespace/index.ts +79 -0
  56. package/src/parser/preprocess/whitespace/leading-spaces.ts +11 -0
  57. package/src/parser/preprocess/whitespace/patterns.ts +23 -0
  58. package/src/parser/rules/block/align/body.ts +46 -0
  59. package/src/parser/rules/block/align/element.ts +13 -0
  60. package/src/parser/rules/block/align/index.ts +90 -0
  61. package/src/parser/rules/block/align/syntax.ts +113 -0
  62. package/src/parser/rules/block/bibliography/body.ts +81 -0
  63. package/src/parser/rules/block/bibliography/entries.ts +49 -0
  64. package/src/parser/rules/block/bibliography/entry-content.ts +73 -0
  65. package/src/parser/rules/block/bibliography/entry-key.ts +83 -0
  66. package/src/parser/rules/block/bibliography/index.ts +90 -0
  67. package/src/parser/rules/block/bibliography/open.ts +53 -0
  68. package/src/parser/rules/block/block-list/bare-content.ts +105 -0
  69. package/src/parser/rules/block/block-list/bare-paragraph.ts +60 -0
  70. package/src/parser/rules/block/block-list/index.ts +51 -0
  71. package/src/parser/rules/block/block-list/item-content.ts +132 -0
  72. package/src/parser/rules/block/block-list/li-content.ts +107 -0
  73. package/src/parser/rules/block/block-list/li-item.ts +77 -0
  74. package/src/parser/rules/block/block-list/list-block.ts +100 -0
  75. package/src/parser/rules/block/block-list/open.ts +51 -0
  76. package/src/parser/rules/block/block-list/tags.ts +50 -0
  77. package/src/parser/rules/block/blockquote/build.ts +62 -0
  78. package/src/parser/rules/block/blockquote/index.ts +80 -0
  79. package/src/parser/rules/block/blockquote/line.ts +79 -0
  80. package/src/parser/rules/block/blockquote/lines.ts +39 -0
  81. package/src/parser/rules/block/{center.ts → center/index.ts} +7 -22
  82. package/src/parser/rules/block/center/open.ts +27 -0
  83. package/src/parser/rules/block/{clear-float.ts → clear-float/index.ts} +6 -30
  84. package/src/parser/rules/block/clear-float/syntax.ts +43 -0
  85. package/src/parser/rules/block/code/attributes.ts +30 -0
  86. package/src/parser/rules/block/code/content.ts +57 -0
  87. package/src/parser/rules/block/code/index.ts +100 -0
  88. package/src/parser/rules/block/collapsible/attributes.ts +95 -0
  89. package/src/parser/rules/block/collapsible/body.ts +69 -0
  90. package/src/parser/rules/block/collapsible/index.ts +117 -0
  91. package/src/parser/rules/block/collapsible/open.ts +51 -0
  92. package/src/parser/rules/block/collapsible/orphans.ts +31 -0
  93. package/src/parser/rules/block/collapsible/tags.ts +17 -0
  94. package/src/parser/rules/block/comment/consume.ts +37 -0
  95. package/src/parser/rules/block/{comment.ts → comment/index.ts} +12 -38
  96. package/src/parser/rules/block/{content-separator.ts → content-separator/index.ts} +5 -35
  97. package/src/parser/rules/block/content-separator/syntax.ts +33 -0
  98. package/src/parser/rules/block/definition-list/collect.ts +40 -0
  99. package/src/parser/rules/block/definition-list/index.ts +63 -0
  100. package/src/parser/rules/block/definition-list/item-key.ts +95 -0
  101. package/src/parser/rules/block/definition-list/item-value.ts +56 -0
  102. package/src/parser/rules/block/definition-list/items.ts +54 -0
  103. package/src/parser/rules/block/div/body.ts +41 -0
  104. package/src/parser/rules/block/div/close.ts +41 -0
  105. package/src/parser/rules/block/div/failed.ts +117 -0
  106. package/src/parser/rules/block/div/index.ts +112 -0
  107. package/src/parser/rules/block/div/nesting.ts +37 -0
  108. package/src/parser/rules/block/div/open.ts +59 -0
  109. package/src/parser/rules/block/div/paragraph-strip.ts +44 -0
  110. package/src/parser/rules/block/embed-block/content.ts +53 -0
  111. package/src/parser/rules/block/embed-block/index.ts +91 -0
  112. package/src/parser/rules/block/embed-block/open.ts +52 -0
  113. package/src/parser/rules/block/embed-block/tags.ts +5 -0
  114. package/src/parser/rules/block/footnoteblock/attributes.ts +73 -0
  115. package/src/parser/rules/block/footnoteblock/index.ts +82 -0
  116. package/src/parser/rules/block/footnoteblock/open.ts +53 -0
  117. package/src/parser/rules/block/heading/index.ts +87 -0
  118. package/src/parser/rules/block/heading/open.ts +50 -0
  119. package/src/parser/rules/block/heading/toc-text.ts +26 -0
  120. package/src/parser/rules/block/{horizontal-rule.ts → horizontal-rule/index.ts} +4 -21
  121. package/src/parser/rules/block/horizontal-rule/syntax.ts +21 -0
  122. package/src/parser/rules/block/html/body.ts +114 -0
  123. package/src/parser/rules/block/html/diagnostics.ts +11 -0
  124. package/src/parser/rules/block/html/index.ts +95 -0
  125. package/src/parser/rules/block/html/open.ts +36 -0
  126. package/src/parser/rules/block/iframe/attributes.ts +106 -0
  127. package/src/parser/rules/block/iframe/index.ts +73 -0
  128. package/src/parser/rules/block/iframe/open.ts +58 -0
  129. package/src/parser/rules/block/iframe/source.ts +24 -0
  130. package/src/parser/rules/block/iframe/url.ts +38 -0
  131. package/src/parser/rules/block/iftags/body.ts +48 -0
  132. package/src/parser/rules/block/iftags/condition.ts +24 -0
  133. package/src/parser/rules/block/{iftags.ts → iftags/index.ts} +16 -58
  134. package/src/parser/rules/block/include/arguments.ts +48 -0
  135. package/src/parser/rules/block/include/index.ts +75 -0
  136. package/src/parser/rules/block/include/location.ts +24 -0
  137. package/src/parser/rules/block/include/variables.ts +37 -0
  138. package/src/parser/rules/block/list/index.ts +73 -0
  139. package/src/parser/rules/block/list/line.ts +77 -0
  140. package/src/parser/rules/block/list/native.ts +89 -0
  141. package/src/parser/rules/block/math/content.ts +54 -0
  142. package/src/parser/rules/block/math/index.ts +106 -0
  143. package/src/parser/rules/block/math/name.ts +35 -0
  144. package/src/parser/rules/block/module/body.ts +92 -0
  145. package/src/parser/rules/block/module/element.ts +33 -0
  146. package/src/parser/rules/block/module/include/directive.ts +91 -0
  147. package/src/parser/rules/block/module/include/index.ts +11 -2
  148. package/src/parser/rules/block/module/include/references.ts +42 -0
  149. package/src/parser/rules/block/module/include/resolve/cache.ts +44 -0
  150. package/src/parser/rules/block/module/include/resolve/index.ts +106 -0
  151. package/src/parser/rules/block/module/include/resolve/iterate.ts +202 -0
  152. package/src/parser/rules/block/module/include/resolve/replace.ts +31 -0
  153. package/src/parser/rules/block/module/include/resolve/types.ts +105 -0
  154. package/src/parser/rules/block/module/include/scanner.ts +121 -0
  155. package/src/parser/rules/block/module/index.ts +14 -2
  156. package/src/parser/rules/block/module/listpages/compiler.ts +12 -392
  157. package/src/parser/rules/block/module/listpages/extract.ts +25 -359
  158. package/src/parser/rules/block/module/listpages/extraction/listpages.ts +42 -0
  159. package/src/parser/rules/block/module/listpages/extraction/listusers.ts +30 -0
  160. package/src/parser/rules/block/module/listpages/extraction/query.ts +51 -0
  161. package/src/parser/rules/block/module/listpages/extraction/result.ts +18 -0
  162. package/src/parser/rules/block/module/listpages/extraction/template.ts +96 -0
  163. package/src/parser/rules/block/module/listpages/extraction/variables.ts +58 -0
  164. package/src/parser/rules/block/module/listpages/normalization/date-selector.ts +53 -0
  165. package/src/parser/rules/block/module/listpages/normalization/numeric-selector.ts +32 -0
  166. package/src/parser/rules/block/module/listpages/normalization/order-parent.ts +82 -0
  167. package/src/parser/rules/block/module/listpages/normalization/selectors.ts +2 -0
  168. package/src/parser/rules/block/module/listpages/normalization/tags-category.ts +86 -0
  169. package/src/parser/rules/block/module/listpages/normalize.ts +8 -324
  170. package/src/parser/rules/block/module/listpages/resolution/items.ts +43 -0
  171. package/src/parser/rules/block/module/listpages/resolution/wrapper.ts +42 -0
  172. package/src/parser/rules/block/module/listpages/resolve.ts +5 -75
  173. package/src/parser/rules/block/module/listpages/template/format/content.ts +41 -0
  174. package/src/parser/rules/block/module/listpages/template/format/date.ts +116 -0
  175. package/src/parser/rules/block/module/listpages/template/format/index.ts +4 -0
  176. package/src/parser/rules/block/module/listpages/template/format/tags.ts +7 -0
  177. package/src/parser/rules/block/module/listpages/template/format/user.ts +9 -0
  178. package/src/parser/rules/block/module/listpages/template/getters/index.ts +36 -0
  179. package/src/parser/rules/block/module/listpages/template/getters/parameterized.ts +60 -0
  180. package/src/parser/rules/block/module/listpages/template/getters/simple.ts +65 -0
  181. package/src/parser/rules/block/module/listpages/template/getters/types.ts +3 -0
  182. package/src/parser/rules/block/module/listpages/template/syntax.ts +97 -0
  183. package/src/parser/rules/block/module/listpages/types/data-fetcher.ts +15 -0
  184. package/src/parser/rules/block/module/listpages/types/data-requirements.ts +52 -0
  185. package/src/parser/rules/block/module/listpages/types/external-data.ts +77 -0
  186. package/src/parser/rules/block/module/listpages/types/index.ts +17 -0
  187. package/src/parser/rules/block/module/listpages/types/normalized-query.ts +120 -0
  188. package/src/parser/rules/block/module/listpages/types/query.ts +67 -0
  189. package/src/parser/rules/block/module/listpages/types/template.ts +17 -0
  190. package/src/parser/rules/block/module/listpages/types/variables.ts +69 -0
  191. package/src/parser/rules/block/module/listpages/url-resolution/fields.ts +48 -0
  192. package/src/parser/rules/block/module/listpages/url-resolution/params.ts +19 -0
  193. package/src/parser/rules/block/module/listpages/url-resolution/query.ts +24 -0
  194. package/src/parser/rules/block/module/listpages/url-resolution/resolve.ts +53 -0
  195. package/src/parser/rules/block/module/listpages/url-resolution/value.ts +25 -0
  196. package/src/parser/rules/block/module/listpages/url-resolver.ts +3 -160
  197. package/src/parser/rules/block/module/listusers/compiler.ts +4 -25
  198. package/src/parser/rules/block/module/listusers/extract.ts +4 -9
  199. package/src/parser/rules/block/module/listusers/getters.ts +21 -0
  200. package/src/parser/rules/block/module/listusers/variables.ts +15 -0
  201. package/src/parser/rules/block/module/open.ts +57 -0
  202. package/src/parser/rules/block/module/resolution/contexts.ts +78 -0
  203. package/src/parser/rules/block/module/resolution/data-maps.ts +39 -0
  204. package/src/parser/rules/block/module/resolution/dynamic-modules.ts +93 -0
  205. package/src/parser/rules/block/module/resolution/styles.ts +53 -0
  206. package/src/parser/rules/block/module/resolution/walk-resolve.ts +107 -0
  207. package/src/parser/rules/block/module/resolve.ts +79 -292
  208. package/src/parser/rules/block/module/rule.ts +56 -0
  209. package/src/parser/rules/block/module/types-common.ts +11 -0
  210. package/src/parser/rules/block/module/walk/children.ts +35 -0
  211. package/src/parser/rules/block/module/walk/index.ts +9 -0
  212. package/src/parser/rules/block/module/walk/map/index.ts +2 -0
  213. package/src/parser/rules/block/module/walk/map/stateful-definition-list.ts +25 -0
  214. package/src/parser/rules/block/module/walk/map/stateful-list.ts +40 -0
  215. package/src/parser/rules/block/module/walk/map/stateful-table.ts +23 -0
  216. package/src/parser/rules/block/module/walk/map/stateful-tabs.ts +19 -0
  217. package/src/parser/rules/block/module/walk/map/stateful.ts +71 -0
  218. package/src/parser/rules/block/module/walk/map/stateless-definition-list.ts +12 -0
  219. package/src/parser/rules/block/module/walk/map/stateless-list.ts +29 -0
  220. package/src/parser/rules/block/module/walk/map/stateless-table.ts +11 -0
  221. package/src/parser/rules/block/module/walk/map/stateless-tabs.ts +5 -0
  222. package/src/parser/rules/block/module/walk/map/stateless.ts +51 -0
  223. package/src/parser/rules/block/module/walk/map/types.ts +6 -0
  224. package/src/parser/rules/block/module/walk/traverse.ts +65 -0
  225. package/src/parser/rules/block/orphan-li/content.ts +60 -0
  226. package/src/parser/rules/block/orphan-li/index.ts +75 -0
  227. package/src/parser/rules/block/orphan-li/open.ts +25 -0
  228. package/src/parser/rules/block/orphan-li/tags.ts +40 -0
  229. package/src/parser/rules/block/paragraph/content.ts +12 -0
  230. package/src/parser/rules/block/paragraph/index.ts +60 -0
  231. package/src/parser/rules/block/paragraph/normalize.ts +52 -0
  232. package/src/parser/rules/block/paragraph/span-markers.ts +52 -0
  233. package/src/parser/rules/block/parsing/attributes/index.ts +32 -0
  234. package/src/parser/rules/block/parsing/attributes/names.ts +93 -0
  235. package/src/parser/rules/block/parsing/attributes/scanner.ts +75 -0
  236. package/src/parser/rules/block/parsing/attributes/values.ts +26 -0
  237. package/src/parser/rules/block/parsing/block-item.ts +29 -0
  238. package/src/parser/rules/block/parsing/content.ts +127 -0
  239. package/src/parser/rules/block/parsing/end-condition.ts +51 -0
  240. package/src/parser/rules/block/parsing/inline-content.ts +105 -0
  241. package/src/parser/rules/block/parsing/inline-newline.ts +41 -0
  242. package/src/parser/rules/block/parsing/non-boundary.ts +24 -0
  243. package/src/parser/rules/block/parsing/rule-dispatch.ts +44 -0
  244. package/src/parser/rules/block/table/index.ts +80 -0
  245. package/src/parser/rules/block/table/pipe/cell-start.ts +69 -0
  246. package/src/parser/rules/block/table/pipe/cell.ts +106 -0
  247. package/src/parser/rules/block/table/pipe/index.ts +2 -0
  248. package/src/parser/rules/block/table/pipe/row.ts +88 -0
  249. package/src/parser/rules/block/table/pipe/tokens.ts +14 -0
  250. package/src/parser/rules/block/table/pipe/trim.ts +50 -0
  251. package/src/parser/rules/block/table-block/body.ts +79 -0
  252. package/src/parser/rules/block/table-block/cell-attributes.ts +33 -0
  253. package/src/parser/rules/block/table-block/cell-boundary.ts +99 -0
  254. package/src/parser/rules/block/table-block/cell-content/index.ts +88 -0
  255. package/src/parser/rules/block/table-block/cell-content/segments.ts +134 -0
  256. package/src/parser/rules/block/table-block/cell-newline.ts +47 -0
  257. package/src/parser/rules/block/table-block/cell.ts +64 -0
  258. package/src/parser/rules/block/table-block/index.ts +113 -0
  259. package/src/parser/rules/block/table-block/row-boundary.ts +75 -0
  260. package/src/parser/rules/block/table-block/structure.ts +80 -0
  261. package/src/parser/rules/block/tabview/body.ts +64 -0
  262. package/src/parser/rules/block/tabview/index.ts +90 -0
  263. package/src/parser/rules/block/tabview/open.ts +50 -0
  264. package/src/parser/rules/block/tabview/tab.ts +92 -0
  265. package/src/parser/rules/block/tabview/tags.ts +30 -0
  266. package/src/parser/rules/block/toc/element.ts +11 -0
  267. package/src/parser/rules/block/toc/index.ts +44 -0
  268. package/src/parser/rules/block/toc/open.ts +84 -0
  269. package/src/parser/rules/block/utils.ts +10 -610
  270. package/src/parser/rules/{utils.ts → common/attribute-safety.ts} +3 -49
  271. package/src/parser/rules/common/block-name.ts +33 -0
  272. package/src/parser/rules/common/index.ts +2 -0
  273. package/src/parser/rules/contracts/index.ts +3 -0
  274. package/src/parser/rules/contracts/parse-context.ts +38 -0
  275. package/src/parser/rules/contracts/rule.ts +43 -0
  276. package/src/parser/rules/contracts/scope.ts +31 -0
  277. package/src/parser/rules/inline/anchor/attributes.ts +54 -0
  278. package/src/parser/rules/inline/anchor/child.ts +26 -0
  279. package/src/parser/rules/inline/anchor/close.ts +34 -0
  280. package/src/parser/rules/inline/anchor/content.ts +59 -0
  281. package/src/parser/rules/inline/anchor/index.ts +103 -0
  282. package/src/parser/rules/inline/anchor/newline.ts +26 -0
  283. package/src/parser/rules/inline/anchor/open.ts +47 -0
  284. package/src/parser/rules/inline/anchor/paragraph-strip.ts +14 -0
  285. package/src/parser/rules/inline/anchor/syntax.ts +40 -0
  286. package/src/parser/rules/inline/anchor-name/index.ts +38 -0
  287. package/src/parser/rules/inline/anchor-name/name.ts +39 -0
  288. package/src/parser/rules/inline/anchor-name/syntax.ts +46 -0
  289. package/src/parser/rules/inline/bibcite/element.ts +14 -0
  290. package/src/parser/rules/inline/bibcite/index.ts +34 -0
  291. package/src/parser/rules/inline/bibcite/syntax.ts +64 -0
  292. package/src/parser/rules/inline/bold.ts +2 -39
  293. package/src/parser/rules/inline/color/index.ts +35 -0
  294. package/src/parser/rules/inline/color/syntax.ts +69 -0
  295. package/src/parser/rules/inline/comment/consume.ts +31 -0
  296. package/src/parser/rules/inline/{comment.ts → comment/index.ts} +10 -36
  297. package/src/parser/rules/inline/equation-ref/element.ts +8 -0
  298. package/src/parser/rules/inline/equation-ref/index.ts +34 -0
  299. package/src/parser/rules/inline/equation-ref/syntax.ts +45 -0
  300. package/src/parser/rules/inline/expr/branch.ts +104 -0
  301. package/src/parser/rules/inline/expr/conditional-branch.ts +27 -0
  302. package/src/parser/rules/inline/expr/conditional.ts +80 -0
  303. package/src/parser/rules/inline/expr/depth.ts +25 -0
  304. package/src/parser/rules/inline/expr/elements.ts +39 -0
  305. package/src/parser/rules/inline/expr/index.ts +84 -0
  306. package/src/parser/rules/inline/expr/syntax.ts +45 -0
  307. package/src/parser/rules/inline/footnote/child.ts +22 -0
  308. package/src/parser/rules/inline/footnote/close.ts +33 -0
  309. package/src/parser/rules/inline/footnote/content.ts +54 -0
  310. package/src/parser/rules/inline/footnote/elements.ts +38 -0
  311. package/src/parser/rules/inline/footnote/index.ts +54 -0
  312. package/src/parser/rules/inline/footnote/newline.ts +27 -0
  313. package/src/parser/rules/inline/footnote/open.ts +38 -0
  314. package/src/parser/rules/inline/formatting/container.ts +50 -0
  315. package/src/parser/rules/inline/{guillemet.ts → guillemet/index.ts} +5 -13
  316. package/src/parser/rules/inline/guillemet/text.ts +11 -0
  317. package/src/parser/rules/inline/html/gate.ts +64 -0
  318. package/src/parser/rules/inline/{html.ts → html/index.ts} +9 -60
  319. package/src/parser/rules/inline/html/open.ts +37 -0
  320. package/src/parser/rules/inline/image/attributes.ts +22 -0
  321. package/src/parser/rules/inline/image/body.ts +36 -0
  322. package/src/parser/rules/inline/image/index.ts +89 -0
  323. package/src/parser/rules/inline/image/open.ts +56 -0
  324. package/src/parser/rules/inline/image/source.ts +62 -0
  325. package/src/parser/rules/inline/image/syntax.ts +76 -0
  326. package/src/parser/rules/inline/italic.ts +2 -30
  327. package/src/parser/rules/inline/line-break/backslash.ts +58 -0
  328. package/src/parser/rules/inline/line-break/elements.ts +9 -0
  329. package/src/parser/rules/inline/line-break/index.ts +3 -0
  330. package/src/parser/rules/inline/line-break/newline.ts +82 -0
  331. package/src/parser/rules/inline/line-break/underscore.ts +45 -0
  332. package/src/parser/rules/inline/link-anchor.ts +6 -81
  333. package/src/parser/rules/inline/link-bracket/anchor.ts +3 -0
  334. package/src/parser/rules/inline/link-bracket/direct-url.ts +5 -0
  335. package/src/parser/rules/inline/link-bracket/parsed.ts +81 -0
  336. package/src/parser/rules/inline/link-bracket/parts.ts +64 -0
  337. package/src/parser/rules/inline/link-bracket/prefix.ts +15 -0
  338. package/src/parser/rules/inline/link-single.ts +7 -98
  339. package/src/parser/rules/inline/link-star.ts +7 -69
  340. package/src/parser/rules/inline/link-triple/fallback.ts +10 -0
  341. package/src/parser/rules/inline/link-triple/index.ts +62 -0
  342. package/src/parser/rules/inline/link-triple/interwiki.ts +11 -0
  343. package/src/parser/rules/inline/link-triple/label.ts +35 -0
  344. package/src/parser/rules/inline/link-triple/syntax.ts +72 -0
  345. package/src/parser/rules/inline/link-triple/target.ts +36 -0
  346. package/src/parser/rules/inline/math-inline/index.ts +40 -0
  347. package/src/parser/rules/inline/math-inline/syntax.ts +55 -0
  348. package/src/parser/rules/inline/monospace.ts +2 -30
  349. package/src/parser/rules/inline/parsing/block-boundary.ts +42 -0
  350. package/src/parser/rules/inline/parsing/block-start-predicates.ts +117 -0
  351. package/src/parser/rules/inline/parsing/collect.ts +23 -0
  352. package/src/parser/rules/inline/parsing/inline-content.ts +115 -0
  353. package/src/parser/rules/inline/parsing/paragraph-boundary.ts +47 -0
  354. package/src/parser/rules/inline/parsing/plain-text.ts +69 -0
  355. package/src/parser/rules/inline/parsing/preserved-line-break.ts +11 -0
  356. package/src/parser/rules/inline/parsing/rules.ts +34 -0
  357. package/src/parser/rules/inline/parsing/simple-token.ts +26 -0
  358. package/src/parser/rules/inline/raw/angle.ts +40 -0
  359. package/src/parser/rules/inline/raw/double-at.ts +78 -0
  360. package/src/parser/rules/inline/raw/index.ts +26 -0
  361. package/src/parser/rules/inline/raw/result.ts +26 -0
  362. package/src/parser/rules/inline/size/content.ts +65 -0
  363. package/src/parser/rules/inline/size/index.ts +55 -0
  364. package/src/parser/rules/inline/size/open.ts +43 -0
  365. package/src/parser/rules/inline/size/value.ts +45 -0
  366. package/src/parser/rules/inline/span/content.ts +97 -0
  367. package/src/parser/rules/inline/span/elements.ts +108 -0
  368. package/src/parser/rules/inline/span/index.ts +79 -0
  369. package/src/parser/rules/inline/span/newline.ts +50 -0
  370. package/src/parser/rules/inline/span/syntax.ts +70 -0
  371. package/src/parser/rules/inline/{strikethrough.ts → strikethrough/index.ts} +5 -60
  372. package/src/parser/rules/inline/strikethrough/parse.ts +14 -0
  373. package/src/parser/rules/inline/strikethrough/syntax.ts +24 -0
  374. package/src/parser/rules/inline/subscript.ts +2 -39
  375. package/src/parser/rules/inline/superscript.ts +4 -39
  376. package/src/parser/rules/inline/text/element.ts +5 -0
  377. package/src/parser/rules/inline/{text.ts → text/index.ts} +5 -4
  378. package/src/parser/rules/inline/underline/child.ts +26 -0
  379. package/src/parser/rules/inline/underline/content.ts +29 -0
  380. package/src/parser/rules/inline/{underline.ts → underline/index.ts} +6 -49
  381. package/src/parser/rules/inline/user/element.ts +11 -0
  382. package/src/parser/rules/inline/user/index.ts +34 -0
  383. package/src/parser/rules/inline/user/syntax.ts +67 -0
  384. package/src/parser/rules/inline/utils.ts +4 -344
  385. package/src/parser/rules/tokens.ts +106 -0
  386. package/src/parser/rules/types.ts +9 -252
  387. package/src/parser/depth.ts +0 -251
  388. package/src/parser/parse.ts +0 -315
  389. package/src/parser/postprocess/spanStrip.ts +0 -697
  390. package/src/parser/preprocess/expr.ts +0 -265
  391. package/src/parser/preprocess/utils.ts +0 -250
  392. package/src/parser/preprocess/whitespace.ts +0 -111
  393. package/src/parser/rules/block/align.ts +0 -282
  394. package/src/parser/rules/block/bibliography.ts +0 -359
  395. package/src/parser/rules/block/block-list.ts +0 -689
  396. package/src/parser/rules/block/blockquote.ts +0 -238
  397. package/src/parser/rules/block/code.ts +0 -187
  398. package/src/parser/rules/block/collapsible.ts +0 -337
  399. package/src/parser/rules/block/definition-list.ts +0 -270
  400. package/src/parser/rules/block/div.ts +0 -400
  401. package/src/parser/rules/block/embed-block.ts +0 -153
  402. package/src/parser/rules/block/footnoteblock.ts +0 -200
  403. package/src/parser/rules/block/heading.ts +0 -142
  404. package/src/parser/rules/block/html.ts +0 -222
  405. package/src/parser/rules/block/iframe.ts +0 -239
  406. package/src/parser/rules/block/include.ts +0 -179
  407. package/src/parser/rules/block/list.ts +0 -244
  408. package/src/parser/rules/block/math.ts +0 -183
  409. package/src/parser/rules/block/module/include/resolve.ts +0 -556
  410. package/src/parser/rules/block/module/listpages/types.ts +0 -513
  411. package/src/parser/rules/block/module/walk.ts +0 -380
  412. package/src/parser/rules/block/module.ts +0 -164
  413. package/src/parser/rules/block/orphan-li.ts +0 -177
  414. package/src/parser/rules/block/paragraph.ts +0 -157
  415. package/src/parser/rules/block/table-block.ts +0 -726
  416. package/src/parser/rules/block/table.ts +0 -441
  417. package/src/parser/rules/block/tabview.ts +0 -331
  418. package/src/parser/rules/block/toc.ts +0 -129
  419. package/src/parser/rules/inline/anchor-name.ts +0 -154
  420. package/src/parser/rules/inline/anchor.ts +0 -327
  421. package/src/parser/rules/inline/bibcite.ts +0 -153
  422. package/src/parser/rules/inline/color.ts +0 -140
  423. package/src/parser/rules/inline/equation-ref.ts +0 -115
  424. package/src/parser/rules/inline/expr.ts +0 -526
  425. package/src/parser/rules/inline/footnote.ts +0 -223
  426. package/src/parser/rules/inline/image.ts +0 -328
  427. package/src/parser/rules/inline/line-break.ts +0 -326
  428. package/src/parser/rules/inline/link-triple.ts +0 -267
  429. package/src/parser/rules/inline/math-inline.ts +0 -126
  430. package/src/parser/rules/inline/raw.ts +0 -262
  431. package/src/parser/rules/inline/size.ts +0 -244
  432. package/src/parser/rules/inline/span.ts +0 -424
  433. package/src/parser/rules/inline/user.ts +0 -147
@@ -0,0 +1,33 @@
1
+ import type { ParseContext } from "../types";
2
+
3
+ /**
4
+ * Parse block name from tokens (handles [[name or [[/name).
5
+ *
6
+ * Handles underscore suffix like "div_" which may be tokenized as
7
+ * [IDENTIFIER "div"] [UNDERSCORE "_"].
8
+ */
9
+ export function parseBlockName(
10
+ ctx: ParseContext,
11
+ startPos: number,
12
+ ): { name: string; consumed: number } | null {
13
+ let pos = startPos;
14
+ let consumed = 0;
15
+
16
+ // Wikidot does NOT allow whitespace between [[ and block name.
17
+ // e.g. [[ code ]] is treated as plain text, not a code block.
18
+ const token = ctx.tokens[pos];
19
+ if (!token || (token.type !== "TEXT" && token.type !== "IDENTIFIER")) {
20
+ return null;
21
+ }
22
+
23
+ let name = token.value.toLowerCase();
24
+ consumed++;
25
+ pos++;
26
+
27
+ if (ctx.tokens[pos]?.type === "UNDERSCORE") {
28
+ name += "_";
29
+ consumed++;
30
+ }
31
+
32
+ return { name, consumed };
33
+ }
@@ -0,0 +1,2 @@
1
+ export { filterUnsafeAttributes } from "./attribute-safety";
2
+ export { parseBlockName } from "./block-name";
@@ -0,0 +1,3 @@
1
+ export type { ParseContext } from "./parse-context";
2
+ export type { BlockRule, InlineRule, RuleResult } from "./rule";
3
+ export type { ScopeContext } from "./scope";
@@ -0,0 +1,38 @@
1
+ import type { Token } from "../../../lexer";
2
+ import type {
3
+ CodeBlockData,
4
+ Diagnostic,
5
+ Element,
6
+ TocEntry,
7
+ Version,
8
+ WikitextSettings,
9
+ } from "@wdprlib/ast";
10
+ import type { BlockRule, InlineRule } from "./rule";
11
+ import type { ScopeContext } from "./scope";
12
+
13
+ /**
14
+ * Parser context passed to rules.
15
+ *
16
+ * Fields are grouped by lifecycle:
17
+ * - Static config (`tokens`, `version`, `trackPositions`, `settings`, rule arrays).
18
+ * - `pos`: per-scope cursor; kept top-level because every rule spread overrides it.
19
+ * - Accumulators (`footnotes`, `tocEntries`, ..., `diagnostics`): shared by array identity.
20
+ * - `scope`: per-scope state with immutable-replace semantics.
21
+ */
22
+ export interface ParseContext {
23
+ tokens: Token[];
24
+ pos: number;
25
+ version: Version;
26
+ trackPositions: boolean;
27
+ settings: WikitextSettings;
28
+ footnotes: Element[][];
29
+ tocEntries: TocEntry[];
30
+ codeBlocks: CodeBlockData[];
31
+ htmlBlocks: string[];
32
+ bibcites: string[];
33
+ blockRules: BlockRule[];
34
+ blockFallbackRule: BlockRule;
35
+ inlineRules: InlineRule[];
36
+ diagnostics: Diagnostic[];
37
+ scope: ScopeContext;
38
+ }
@@ -0,0 +1,43 @@
1
+ import type { Element } from "@wdprlib/ast";
2
+ import type { TokenType } from "../../../lexer";
3
+ import type { ParseContext } from "./parse-context";
4
+
5
+ /**
6
+ * Result of a rule attempt.
7
+ */
8
+ export type RuleResult<T> = { success: true; elements: T[]; consumed: number } | { success: false };
9
+
10
+ /**
11
+ * Block rule interface.
12
+ */
13
+ export interface BlockRule {
14
+ /** Rule name for debugging. */
15
+ name: string;
16
+ /** Token types that can start this rule. */
17
+ startTokens: TokenType[];
18
+ /** Whether this rule requires line start. */
19
+ requiresLineStart: boolean;
20
+ /** Try to parse this block. */
21
+ parse(ctx: ParseContext): RuleResult<Element>;
22
+ /**
23
+ * Check if tokens at the given position match this rule's start pattern.
24
+ * Used by inline parser to determine behavior before a block boundary.
25
+ */
26
+ isStartPattern?(ctx: ParseContext, pos: number): boolean;
27
+ /**
28
+ * When true, a single newline before this block becomes a line-break.
29
+ */
30
+ preservesPrecedingLineBreak?: boolean;
31
+ }
32
+
33
+ /**
34
+ * Inline rule interface.
35
+ */
36
+ export interface InlineRule {
37
+ /** Rule name for debugging. */
38
+ name: string;
39
+ /** Token types that can start this rule. */
40
+ startTokens: TokenType[];
41
+ /** Try to parse this inline element. */
42
+ parse(ctx: ParseContext): RuleResult<Element>;
43
+ }
@@ -0,0 +1,31 @@
1
+ import type { ParseContext } from "./parse-context";
2
+
3
+ /**
4
+ * Per-scope state propagated by spread + override semantics.
5
+ *
6
+ * Every field is `readonly` so a rule cannot accidentally mutate the
7
+ * parent scope by writing through a shared reference. Updates must be
8
+ * expressed as a replacement: `ctx.scope = { ...ctx.scope, X: ... }`.
9
+ */
10
+ export interface ScopeContext {
11
+ /**
12
+ * Close condition for the current block. The paragraph parser calls
13
+ * it to decide when to stop collecting inline content.
14
+ */
15
+ readonly blockCloseCondition?: (ctx: ParseContext) => boolean;
16
+ /**
17
+ * Block names excluded from paragraph-boundary detection.
18
+ */
19
+ readonly excludedBlockNames?: ReadonlySet<string>;
20
+ /**
21
+ * Budget for div nesting: tracks how many more nested divs can open.
22
+ */
23
+ readonly divClosesBudget?: number;
24
+ /**
25
+ * Used by the footnote-block rule to reject duplicate top-level occurrences.
26
+ *
27
+ * Scope is per spread copy of `ParseContext`, not document-global. This keeps
28
+ * the original primitive semantics while avoiding rollback-unsafe shared state.
29
+ */
30
+ readonly footnoteBlockParsed: boolean;
31
+ }
@@ -0,0 +1,54 @@
1
+ import { sanitizeUrl as braintreeSanitizeUrl } from "@braintree/sanitize-url";
2
+
3
+ export type AnchorTarget = "new-tab" | "parent" | "top" | "same";
4
+
5
+ export interface AnchorAttributes {
6
+ target: AnchorTarget | null;
7
+ attributes: Record<string, string>;
8
+ }
9
+
10
+ export function buildAnchorAttributes(attrs: Record<string, string>): AnchorAttributes {
11
+ const target = parseAnchorTarget(attrs.target);
12
+ const { target: _target, ...cleanAttrs } = attrs;
13
+
14
+ if (cleanAttrs.href) {
15
+ cleanAttrs.href = sanitizeUrl(cleanAttrs.href);
16
+ }
17
+
18
+ return { target, attributes: cleanAttrs };
19
+ }
20
+
21
+ function parseAnchorTarget(targetAttr: string | undefined): AnchorTarget | null {
22
+ if (targetAttr === "_blank") return "new-tab";
23
+ if (targetAttr === "_parent") return "parent";
24
+ if (targetAttr === "_top") return "top";
25
+ if (targetAttr === "_self") return "same";
26
+ return null;
27
+ }
28
+
29
+ function sanitizeUrl(url: string): string {
30
+ const normalizedForCheck = stripControlAndWhitespace(url).toLowerCase();
31
+ const dangerousSchemes = ["javascript:", "data:", "vbscript:"];
32
+ for (const scheme of dangerousSchemes) {
33
+ if (normalizedForCheck.startsWith(scheme)) {
34
+ return "#invalid-url";
35
+ }
36
+ }
37
+
38
+ const sanitized = braintreeSanitizeUrl(url);
39
+ return sanitized === "about:blank" ? "#invalid-url" : url;
40
+ }
41
+
42
+ const WHITESPACE = /\s/;
43
+
44
+ function stripControlAndWhitespace(value: string): string {
45
+ let result = "";
46
+ for (const char of value) {
47
+ const code = char.charCodeAt(0);
48
+ if (WHITESPACE.test(char) || code <= 0x1f) {
49
+ continue;
50
+ }
51
+ result += char;
52
+ }
53
+ return result;
54
+ }
@@ -0,0 +1,26 @@
1
+ import type { Element } from "@wdprlib/ast";
2
+ import type { ParseContext } from "../../types";
3
+ import { inlineRules } from "../index";
4
+ import { getCandidateInlineRules } from "../utils";
5
+
6
+ export interface AnchorChildResult {
7
+ elements: Element[];
8
+ consumed: number;
9
+ }
10
+
11
+ export function parseAnchorChild(ctx: ParseContext, pos: number): AnchorChildResult {
12
+ const token = ctx.tokens[pos];
13
+ if (!token) {
14
+ return { elements: [], consumed: 0 };
15
+ }
16
+
17
+ const inlineCtx: ParseContext = { ...ctx, pos };
18
+ for (const rule of getCandidateInlineRules(inlineRules, token.type)) {
19
+ const result = rule.parse(inlineCtx);
20
+ if (result.success) {
21
+ return { elements: result.elements, consumed: result.consumed };
22
+ }
23
+ }
24
+
25
+ return { elements: [{ element: "text", data: token.value }], consumed: 1 };
26
+ }
@@ -0,0 +1,34 @@
1
+ import type { ParseContext } from "../../types";
2
+ import { isAnchorBlockName, parseAnchorBlockName } from "./syntax";
3
+
4
+ export function tryConsumeAnchorClose(
5
+ ctx: ParseContext,
6
+ pos: number,
7
+ paragraphStrip: boolean,
8
+ ): { consumed: number } | null {
9
+ if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
10
+ return null;
11
+ }
12
+
13
+ const closeNameResult = parseAnchorBlockName(ctx, pos + 1);
14
+ if (!closeNameResult || !isAnchorBlockName(closeNameResult.name)) {
15
+ return null;
16
+ }
17
+
18
+ let consumed = 1 + closeNameResult.consumed;
19
+ let closePos = pos + consumed;
20
+ if (ctx.tokens[closePos]?.type === "BLOCK_CLOSE") {
21
+ closePos++;
22
+ consumed++;
23
+ }
24
+
25
+ if (
26
+ paragraphStrip &&
27
+ ctx.tokens[closePos]?.type === "NEWLINE" &&
28
+ ctx.tokens[closePos + 1]?.type !== "NEWLINE"
29
+ ) {
30
+ consumed++;
31
+ }
32
+
33
+ return { consumed };
34
+ }
@@ -0,0 +1,59 @@
1
+ import type { Element } from "@wdprlib/ast";
2
+ import type { ParseContext } from "../../types";
3
+ import { parseAnchorChild } from "./child";
4
+ import { tryConsumeAnchorClose } from "./close";
5
+ import { consumeAnchorNewline } from "./newline";
6
+ import { trimParagraphStripLineBreaks } from "./paragraph-strip";
7
+
8
+ export interface AnchorContentResult {
9
+ children: Element[];
10
+ consumed: number;
11
+ foundClose: boolean;
12
+ }
13
+
14
+ export function parseAnchorContent(
15
+ ctx: ParseContext,
16
+ startPos: number,
17
+ paragraphStrip: boolean,
18
+ ): AnchorContentResult {
19
+ const children: Element[] = [];
20
+ let pos = startPos;
21
+ let consumed = 0;
22
+
23
+ while (pos < ctx.tokens.length) {
24
+ const token = ctx.tokens[pos];
25
+ if (!token || token.type === "EOF") {
26
+ break;
27
+ }
28
+
29
+ const closeResult = tryConsumeAnchorClose(ctx, pos, paragraphStrip);
30
+ if (closeResult !== null) {
31
+ trimParagraphStripLineBreaks(children, paragraphStrip);
32
+ return {
33
+ children,
34
+ consumed: consumed + closeResult.consumed,
35
+ foundClose: true,
36
+ };
37
+ }
38
+
39
+ if (token.type === "NEWLINE") {
40
+ const newline = consumeAnchorNewline(ctx, pos, paragraphStrip, children);
41
+ pos += newline.consumed;
42
+ consumed += newline.consumed;
43
+ continue;
44
+ }
45
+
46
+ if (token.type === "WHITESPACE" && token.lineStart) {
47
+ pos++;
48
+ consumed++;
49
+ continue;
50
+ }
51
+
52
+ const child = parseAnchorChild(ctx, pos);
53
+ children.push(...child.elements);
54
+ pos += child.consumed;
55
+ consumed += child.consumed;
56
+ }
57
+
58
+ return { children, consumed, foundClose: false };
59
+ }
@@ -0,0 +1,103 @@
1
+ /**
2
+ *
3
+ * Parses the Wikidot anchor inline block syntax: `[[a]]...[[/a]]`.
4
+ *
5
+ * An anchor wraps inline content in an HTML `<a>` element, allowing
6
+ * href, target, and other HTML attributes to be specified.
7
+ *
8
+ * Wikidot syntax variants:
9
+ * - `[[a href="url"]]text[[/a]]` -- basic anchor with href
10
+ * - `[[a_ href="url"]]text[[/a]]` -- paragraph strip mode (trailing underscore)
11
+ *
12
+ * Paragraph strip mode (`[[a_]]`) suppresses newlines within the anchor
13
+ * body and strips at most one trailing newline after the closing tag
14
+ * (preserving double newlines as paragraph breaks). This prevents
15
+ * unwanted `<br>` elements when consecutive anchor blocks are placed on
16
+ * separate lines.
17
+ *
18
+ * The `target` attribute is extracted and mapped to a semantic enum value
19
+ * (`"new-tab"`, `"parent"`, `"top"`, `"same"`), while the remaining
20
+ * attributes (including `href`) are passed through after URL sanitization.
21
+ *
22
+ * @module
23
+ */
24
+ import type { Element } from "@wdprlib/ast";
25
+ import type { InlineRule, ParseContext, RuleResult } from "../../types";
26
+ import { currentToken } from "../../types";
27
+ import { buildAnchorAttributes } from "./attributes";
28
+ import { parseAnchorContent } from "./content";
29
+ import { parseAnchorOpen } from "./open";
30
+
31
+ /**
32
+ * Inline rule for parsing `[[a]]...[[/a]]` blocks.
33
+ *
34
+ * Triggered by a `BLOCK_OPEN` (`[[`) token. The rule verifies the block name
35
+ * is `a` or `anchor` (optionally with `_` suffix), parses HTML attributes,
36
+ * then recursively parses inline content until the matching closing tag.
37
+ *
38
+ * Produces an `"anchor"` AST element containing the parsed children, a
39
+ * semantic `target` value, and the sanitized attribute map.
40
+ *
41
+ * Edge cases:
42
+ * - If no matching closing tag is found, the rule fails (returns `{ success: false }`),
43
+ * allowing the tokens to fall through to other rules or the text fallback.
44
+ * - In paragraph strip mode, newlines within the body are consumed silently
45
+ * rather than converted to line-break elements. After the closing tag,
46
+ * at most one trailing newline is consumed to prevent a line-break between
47
+ * consecutive `[[a_]]` blocks, but double newlines are preserved as
48
+ * paragraph breaks.
49
+ * - The `href` attribute is sanitized to block `javascript:`, `data:`, and
50
+ * `vbscript:` schemes.
51
+ */
52
+ export const anchorRule: InlineRule = {
53
+ name: "anchor",
54
+ startTokens: ["BLOCK_OPEN"],
55
+
56
+ /**
57
+ * Attempts to parse an anchor block starting at the current position.
58
+ *
59
+ * @param ctx - Parse context with token stream and current position
60
+ * @returns A successful result with an `"anchor"` element, or `{ success: false }`
61
+ */
62
+ parse(ctx: ParseContext): RuleResult<Element> {
63
+ const openToken = currentToken(ctx);
64
+ if (openToken.type !== "BLOCK_OPEN") {
65
+ return { success: false };
66
+ }
67
+
68
+ const openResult = parseAnchorOpen(ctx);
69
+ if (!openResult) {
70
+ return { success: false };
71
+ }
72
+
73
+ const contentResult = parseAnchorContent(ctx, openResult.bodyStart, openResult.paragraphStrip);
74
+ const consumed = openResult.consumed + contentResult.consumed;
75
+
76
+ if (!contentResult.foundClose) {
77
+ ctx.diagnostics.push({
78
+ severity: "warning",
79
+ code: "unclosed-block",
80
+ message: `Missing closing tag [[/a]] for [[${openResult.name}]]`,
81
+ position: openToken.position,
82
+ });
83
+ return { success: false };
84
+ }
85
+
86
+ const anchorAttrs = buildAnchorAttributes(openResult.attributes);
87
+
88
+ return {
89
+ success: true,
90
+ elements: [
91
+ {
92
+ element: "anchor",
93
+ data: {
94
+ target: anchorAttrs.target,
95
+ attributes: anchorAttrs.attributes,
96
+ elements: contentResult.children,
97
+ },
98
+ },
99
+ ],
100
+ consumed,
101
+ };
102
+ },
103
+ };
@@ -0,0 +1,26 @@
1
+ import type { Element } from "@wdprlib/ast";
2
+ import type { ParseContext } from "../../types";
3
+
4
+ export interface AnchorNewlineResult {
5
+ consumed: number;
6
+ }
7
+
8
+ export function consumeAnchorNewline(
9
+ ctx: ParseContext,
10
+ pos: number,
11
+ paragraphStrip: boolean,
12
+ children: Element[],
13
+ ): AnchorNewlineResult {
14
+ let consumed = 1;
15
+ let nextPos = pos + 1;
16
+
17
+ if (!paragraphStrip) {
18
+ children.push({ element: "line-break" });
19
+ while (ctx.tokens[nextPos]?.type === "WHITESPACE" && ctx.tokens[nextPos]?.lineStart) {
20
+ nextPos++;
21
+ consumed++;
22
+ }
23
+ }
24
+
25
+ return { consumed };
26
+ }
@@ -0,0 +1,47 @@
1
+ import type { ParseContext } from "../../types";
2
+ import { parseAttributes } from "../../block/utils";
3
+ import { isAnchorBlockName, parseAnchorBlockName } from "./syntax";
4
+
5
+ export interface AnchorOpenResult {
6
+ name: string;
7
+ paragraphStrip: boolean;
8
+ attributes: Record<string, string>;
9
+ bodyStart: number;
10
+ consumed: number;
11
+ }
12
+
13
+ export function parseAnchorOpen(ctx: ParseContext): AnchorOpenResult | null {
14
+ if (ctx.tokens[ctx.pos]?.type !== "BLOCK_OPEN") {
15
+ return null;
16
+ }
17
+
18
+ let pos = ctx.pos + 1;
19
+ let consumed = 1;
20
+
21
+ const nameResult = parseAnchorBlockName(ctx, pos);
22
+ if (!nameResult || !isAnchorBlockName(nameResult.name)) {
23
+ return null;
24
+ }
25
+
26
+ pos += nameResult.consumed;
27
+ consumed += nameResult.consumed;
28
+
29
+ const attrResult = parseAttributes(ctx, pos);
30
+ pos += attrResult.consumed;
31
+ consumed += attrResult.consumed;
32
+
33
+ if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
34
+ return null;
35
+ }
36
+
37
+ pos++;
38
+ consumed++;
39
+
40
+ return {
41
+ name: nameResult.name,
42
+ paragraphStrip: nameResult.paragraphStrip,
43
+ attributes: attrResult.attrs,
44
+ bodyStart: pos,
45
+ consumed,
46
+ };
47
+ }
@@ -0,0 +1,14 @@
1
+ import type { Element } from "@wdprlib/ast";
2
+
3
+ export function trimParagraphStripLineBreaks(children: Element[], paragraphStrip: boolean): void {
4
+ if (!paragraphStrip) {
5
+ return;
6
+ }
7
+
8
+ while (children.length > 0 && children[0]?.element === "line-break") {
9
+ children.shift();
10
+ }
11
+ while (children.length > 0 && children[children.length - 1]?.element === "line-break") {
12
+ children.pop();
13
+ }
14
+ }
@@ -0,0 +1,40 @@
1
+ import type { ParseContext } from "../../types";
2
+
3
+ export interface AnchorBlockName {
4
+ name: string;
5
+ paragraphStrip: boolean;
6
+ consumed: number;
7
+ }
8
+
9
+ export function parseAnchorBlockName(ctx: ParseContext, startPos: number): AnchorBlockName | null {
10
+ let pos = startPos;
11
+ let consumed = 0;
12
+
13
+ while (ctx.tokens[pos]?.type === "WHITESPACE") {
14
+ pos++;
15
+ consumed++;
16
+ }
17
+
18
+ const token = ctx.tokens[pos];
19
+ if (!token || (token.type !== "TEXT" && token.type !== "IDENTIFIER")) {
20
+ return null;
21
+ }
22
+
23
+ let name = token.value.toLowerCase();
24
+ consumed++;
25
+ pos++;
26
+
27
+ let paragraphStrip = false;
28
+ if (ctx.tokens[pos]?.type === "UNDERSCORE") {
29
+ paragraphStrip = true;
30
+ name += "_";
31
+ consumed++;
32
+ }
33
+
34
+ return { name, paragraphStrip, consumed };
35
+ }
36
+
37
+ export function isAnchorBlockName(name: string): boolean {
38
+ const baseName = name.replace(/_$/, "");
39
+ return baseName === "a" || baseName === "anchor";
40
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ *
3
+ * Parses the Wikidot named anchor syntax: `[[# 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 { parseAnchorNameTarget } from "./syntax";
11
+
12
+ export const anchorNameRule: InlineRule = {
13
+ name: "anchorName",
14
+ startTokens: ["BLOCK_OPEN"],
15
+
16
+ parse(ctx: ParseContext): RuleResult<Element> {
17
+ const openToken = currentToken(ctx);
18
+ if (openToken.type !== "BLOCK_OPEN") {
19
+ return { success: false };
20
+ }
21
+
22
+ const target = parseAnchorNameTarget(ctx, ctx.pos + 1);
23
+ if (!target) {
24
+ return { success: false };
25
+ }
26
+
27
+ return {
28
+ success: true,
29
+ elements: [
30
+ {
31
+ element: "anchor-name",
32
+ data: target.name,
33
+ },
34
+ ],
35
+ consumed: 1 + target.consumed,
36
+ };
37
+ },
38
+ };
@@ -0,0 +1,39 @@
1
+ import type { ParseContext } from "../../types";
2
+
3
+ export function collectAnchorName(
4
+ ctx: ParseContext,
5
+ startPos: number,
6
+ ): { name: string; consumed: number } | null {
7
+ let pos = startPos;
8
+ let consumed = 0;
9
+ let name = "";
10
+
11
+ while (pos < ctx.tokens.length) {
12
+ const token = ctx.tokens[pos];
13
+ if (
14
+ !token ||
15
+ token.type === "BLOCK_CLOSE" ||
16
+ token.type === "NEWLINE" ||
17
+ token.type === "EOF"
18
+ ) {
19
+ break;
20
+ }
21
+ if (!isValidAnchorNameToken(token.value)) {
22
+ break;
23
+ }
24
+ name += token.value;
25
+ pos++;
26
+ consumed++;
27
+ }
28
+
29
+ return name ? { name, consumed } : null;
30
+ }
31
+
32
+ function isValidAnchorNameToken(value: string): boolean {
33
+ for (const char of value) {
34
+ if (!/^[-_A-Za-z0-9.%]$/.test(char)) {
35
+ return false;
36
+ }
37
+ }
38
+ return true;
39
+ }