@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,98 @@
1
+ /**
2
+ * Compute the unmatched-`[[` depth at each character offset of `source`.
3
+ * Mirrors the lexer's `blockOpenerDepth`. Returns `Int32Array` of length
4
+ * `source.length + 1`; `depths[k]` is the depth immediately before the
5
+ * character at offset `k` is consumed.
6
+ */
7
+ export function computeBracketDepths(source: string): Int32Array {
8
+ const n = source.length;
9
+ const depths = new Int32Array(n + 1);
10
+ let depth = 0;
11
+ let i = 0;
12
+
13
+ while (i < n) {
14
+ depths[i] = depth;
15
+ const c = source.charCodeAt(i);
16
+ const c1 = i + 1 < n ? source.charCodeAt(i + 1) : -1;
17
+ const c2 = i + 2 < n ? source.charCodeAt(i + 2) : -1;
18
+
19
+ if (depth > 0 && c === 0x22 /* " */ && precededByEqualsAttr(source, i)) {
20
+ const end = findQuoteEnd(source, i + 1);
21
+ for (let k = i; k <= end; k++) depths[k] = depth;
22
+ i = end + 1;
23
+ continue;
24
+ }
25
+
26
+ if (c === 0x5b /* [ */ && c1 === 0x5b && c2 === 0x5b) {
27
+ const end = findTripleLinkEnd(source, i + 3);
28
+ for (let k = i; k <= end; k++) depths[k] = depth;
29
+ i = end + 1;
30
+ continue;
31
+ }
32
+
33
+ if (c === 0x5b && c1 === 0x5b) {
34
+ depth++;
35
+ depths[i + 1] = depth;
36
+ i += 2;
37
+ continue;
38
+ }
39
+
40
+ if (c === 0x5d /* ] */ && c1 === 0x5d) {
41
+ depth = Math.max(0, depth - 1);
42
+ depths[i + 1] = depth;
43
+ i += 2;
44
+ continue;
45
+ }
46
+
47
+ if (c === 0x0a /* \n */) {
48
+ depth = 0;
49
+ }
50
+
51
+ i++;
52
+ }
53
+
54
+ depths[n] = depth;
55
+ return depths;
56
+ }
57
+
58
+ function precededByEqualsAttr(source: string, pos: number): boolean {
59
+ let j = pos - 1;
60
+ while (j >= 0) {
61
+ const ch = source.charCodeAt(j);
62
+ if (ch === 0x20 /* space */ || ch === 0x09 /* tab */) {
63
+ j--;
64
+ continue;
65
+ }
66
+ return ch === 0x3d; /* = */
67
+ }
68
+ return false;
69
+ }
70
+
71
+ function findQuoteEnd(source: string, from: number): number {
72
+ for (let i = from; i < source.length; i++) {
73
+ const ch = source.charCodeAt(i);
74
+ if (ch === 0x22 /* " */ || ch === 0x0a /* \n */) return i;
75
+ }
76
+ return source.length - 1;
77
+ }
78
+
79
+ function findTripleLinkEnd(source: string, from: number): number {
80
+ for (let i = from; i < source.length; i++) {
81
+ if (
82
+ source.charCodeAt(i) === 0x5d &&
83
+ i + 2 < source.length &&
84
+ source.charCodeAt(i + 1) === 0x5d &&
85
+ source.charCodeAt(i + 2) === 0x5d
86
+ ) {
87
+ return i + 2;
88
+ }
89
+ if (
90
+ source.charCodeAt(i) === 0x0a &&
91
+ i + 1 < source.length &&
92
+ source.charCodeAt(i + 1) === 0x0a
93
+ ) {
94
+ return i;
95
+ }
96
+ }
97
+ return source.length - 1;
98
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ *
3
+ * Shared helper facade for source-level preprocess passes.
4
+ *
5
+ * Raw-region masking and bracket-depth tracking are implemented in separate
6
+ * files so preprocess passes can depend on a small stable import surface.
7
+ *
8
+ * @module
9
+ */
10
+
11
+ export type { Sentinels } from "./raw-regions";
12
+ export { makeUniqueSentinels, maskRawRegions, restorePlaceholders } from "./raw-regions";
13
+ export { computeBracketDepths } from "./bracket-depths";
@@ -0,0 +1,153 @@
1
+ const BASE_PLACEHOLDER_OPEN = "\uE000";
2
+ const BASE_PLACEHOLDER_CLOSE = "\uE001";
3
+
4
+ const RAW_BLOCK_OPEN_PATTERN = /\[\[\s*(code|html)\b[^\]]*\]\]/iy;
5
+
6
+ /** Unique sentinel characters used to wrap raw-region placeholders. */
7
+ export interface Sentinels {
8
+ open: string;
9
+ close: string;
10
+ }
11
+
12
+ /**
13
+ * Choose sentinel strings that are guaranteed not to appear in `source`.
14
+ * The placeholders we splice into the masked source have the form
15
+ * `<open><digits><close>`, so the restore pass must not confuse them
16
+ * with content. Extends both sentinel characters until neither appears.
17
+ */
18
+ export function makeUniqueSentinels(source: string): Sentinels {
19
+ let open = BASE_PLACEHOLDER_OPEN;
20
+ let close = BASE_PLACEHOLDER_CLOSE;
21
+ while (source.includes(open) || source.includes(close)) {
22
+ open += BASE_PLACEHOLDER_OPEN;
23
+ close += BASE_PLACEHOLDER_CLOSE;
24
+ }
25
+ return { open, close };
26
+ }
27
+
28
+ /**
29
+ * Walk `source` and replace each raw region with a placeholder token so
30
+ * downstream passes do not transform their bodies.
31
+ */
32
+ export function maskRawRegions(
33
+ source: string,
34
+ sentinels: Sentinels,
35
+ ): { masked: string; placeholders: string[] } {
36
+ const placeholders: string[] = [];
37
+ let masked = "";
38
+ let i = 0;
39
+
40
+ while (i < source.length) {
41
+ const rawBlock = tryMaskRawBlock(source, i, placeholders, sentinels);
42
+ if (rawBlock) {
43
+ masked += rawBlock.placeholder;
44
+ i = rawBlock.end;
45
+ continue;
46
+ }
47
+
48
+ const rawInline = tryMaskRawInline(source, i, placeholders, sentinels);
49
+ if (rawInline) {
50
+ masked += rawInline.placeholder;
51
+ i = rawInline.end;
52
+ continue;
53
+ }
54
+
55
+ masked += source[i];
56
+ i++;
57
+ }
58
+
59
+ return { masked, placeholders };
60
+ }
61
+
62
+ /** Inverse of {@link maskRawRegions}: replace placeholders with originals. */
63
+ export function restorePlaceholders(
64
+ source: string,
65
+ placeholders: string[],
66
+ sentinels: Sentinels,
67
+ ): string {
68
+ const pattern = new RegExp(
69
+ `${escapeRegex(sentinels.open)}(\\d+)${escapeRegex(sentinels.close)}`,
70
+ "g",
71
+ );
72
+ return source.replace(pattern, (_, idx: string) => placeholders[Number(idx)] ?? "");
73
+ }
74
+
75
+ function tryMaskRawBlock(
76
+ source: string,
77
+ pos: number,
78
+ placeholders: string[],
79
+ sentinels: Sentinels,
80
+ ): { placeholder: string; end: number } | null {
81
+ if (source[pos] !== "[" || source[pos + 1] !== "[") return null;
82
+
83
+ RAW_BLOCK_OPEN_PATTERN.lastIndex = pos;
84
+ const openMatch = RAW_BLOCK_OPEN_PATTERN.exec(source);
85
+ if (!openMatch) return null;
86
+
87
+ const name = openMatch[1]!.toLowerCase();
88
+ const openLen = openMatch[0].length;
89
+ const closePattern = new RegExp(`\\[\\[\\/\\s*${name}\\s*\\]\\]`, "ig");
90
+ closePattern.lastIndex = pos + openLen;
91
+ const closeMatch = closePattern.exec(source);
92
+
93
+ if (closeMatch) {
94
+ const end = closeMatch.index + closeMatch[0].length;
95
+ return {
96
+ placeholder: pushPlaceholder(placeholders, source.slice(pos, end), sentinels),
97
+ end,
98
+ };
99
+ }
100
+
101
+ if (name !== "code") return null;
102
+
103
+ return {
104
+ placeholder: pushPlaceholder(placeholders, source.slice(pos), sentinels),
105
+ end: source.length,
106
+ };
107
+ }
108
+
109
+ function tryMaskRawInline(
110
+ source: string,
111
+ pos: number,
112
+ placeholders: string[],
113
+ sentinels: Sentinels,
114
+ ): { placeholder: string; end: number } | null {
115
+ if (source[pos] === "@" && source[pos + 1] === "<") {
116
+ return tryMaskSingleLineRaw(source, pos, 2, ">@", placeholders, sentinels);
117
+ }
118
+
119
+ if (source[pos] === "@" && source[pos + 1] === "@") {
120
+ return tryMaskSingleLineRaw(source, pos, 2, "@@", placeholders, sentinels);
121
+ }
122
+
123
+ return null;
124
+ }
125
+
126
+ function tryMaskSingleLineRaw(
127
+ source: string,
128
+ pos: number,
129
+ openerLength: number,
130
+ close: string,
131
+ placeholders: string[],
132
+ sentinels: Sentinels,
133
+ ): { placeholder: string; end: number } | null {
134
+ const closePos = source.indexOf(close, pos + openerLength);
135
+ const newline = source.indexOf("\n", pos + openerLength);
136
+ if (closePos === -1 || (newline !== -1 && newline < closePos)) return null;
137
+
138
+ const end = closePos + close.length;
139
+ return {
140
+ placeholder: pushPlaceholder(placeholders, source.slice(pos, end), sentinels),
141
+ end,
142
+ };
143
+ }
144
+
145
+ function pushPlaceholder(placeholders: string[], text: string, sentinels: Sentinels): string {
146
+ const idx = placeholders.length;
147
+ placeholders.push(text);
148
+ return `${sentinels.open}${idx}${sentinels.close}`;
149
+ }
150
+
151
+ function escapeRegex(str: string): string {
152
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
153
+ }
@@ -0,0 +1,39 @@
1
+ export function needsWhitespaceSubstitution(text: string): boolean {
2
+ if (text.length === 0) return false;
3
+
4
+ if (text[0] === "\n" || text[0] === " " || text[text.length - 1] === "\n") {
5
+ return true;
6
+ }
7
+
8
+ return (
9
+ text.indexOf("\r") !== -1 ||
10
+ text.indexOf("\t") !== -1 ||
11
+ text.indexOf("\0") !== -1 ||
12
+ text.indexOf("\u00a0") !== -1 ||
13
+ text.indexOf("\u2007") !== -1 ||
14
+ text.indexOf("\\\n") !== -1 ||
15
+ text.indexOf("\n\n\n") !== -1 ||
16
+ text.indexOf("\n ") !== -1
17
+ );
18
+ }
19
+
20
+ export function mayContainWhitespaceOnlyLine(text: string): boolean {
21
+ const first = text[0];
22
+ if (
23
+ first === " " ||
24
+ first === "\t" ||
25
+ first === "\n" ||
26
+ first === "\u00a0" ||
27
+ first === "\u2007"
28
+ ) {
29
+ return true;
30
+ }
31
+
32
+ return (
33
+ text.indexOf("\n ") !== -1 ||
34
+ text.indexOf("\n\n") !== -1 ||
35
+ text.indexOf("\n\t") !== -1 ||
36
+ text.indexOf("\n\u00a0") !== -1 ||
37
+ text.indexOf("\n\u2007") !== -1
38
+ );
39
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ *
3
+ * Whitespace normalization preprocessing for Wikidot markup.
4
+ *
5
+ * This module ensures the lexer and parser receive input with consistent
6
+ * whitespace conventions. It handles platform differences (DOS/Mac newlines),
7
+ * normalizes exotic whitespace characters that users may paste from external
8
+ * sources, and applies Wikidot-specific behaviors like backslash line continuation.
9
+ *
10
+ * @module
11
+ */
12
+
13
+ import { needsWhitespaceSubstitution, mayContainWhitespaceOnlyLine } from "./detection";
14
+ import { replaceLeadingSpaces } from "./leading-spaces";
15
+ import { CONCAT_LINES, DOS_MAC_NEWLINES, NULL_CHARS, TABS, WHITESPACE_ONLY_LINE } from "./patterns";
16
+
17
+ /**
18
+ * Apply all whitespace normalization substitutions to the given text.
19
+ *
20
+ * Substitutions are applied in a specific order that avoids interference
21
+ * between steps (e.g., DOS newlines must be normalized before backslash
22
+ * continuation can be detected).
23
+ */
24
+ export function substitute(text: string): string {
25
+ if (!needsWhitespaceSubstitution(text)) {
26
+ return text;
27
+ }
28
+
29
+ let result = text;
30
+
31
+ if (result.indexOf("\r") !== -1) {
32
+ result = result.replace(DOS_MAC_NEWLINES, "\n");
33
+ }
34
+
35
+ if (result.indexOf("\u00a0") !== -1 || result.indexOf("\u2007") !== -1) {
36
+ result = replaceLeadingSpaces(result);
37
+ }
38
+
39
+ if (mayContainWhitespaceOnlyLine(result)) {
40
+ result = result.replace(WHITESPACE_ONLY_LINE, "");
41
+ }
42
+
43
+ if (result.indexOf("\\\n") !== -1) {
44
+ result = result.replace(CONCAT_LINES, String.fromCharCode(0xe000));
45
+ }
46
+
47
+ if (result.indexOf("\t") !== -1) {
48
+ result = result.replace(TABS, " ");
49
+ }
50
+
51
+ if (result.indexOf("\0") !== -1) {
52
+ result = result.replace(NULL_CHARS, " ");
53
+ }
54
+
55
+ if (result[0] === "\n") {
56
+ result = trimLeadingNewlines(result);
57
+ }
58
+ if (result[result.length - 1] === "\n") {
59
+ result = trimTrailingNewlines(result);
60
+ }
61
+
62
+ return result;
63
+ }
64
+
65
+ function trimLeadingNewlines(text: string): string {
66
+ let index = 0;
67
+ while (text[index] === "\n") {
68
+ index++;
69
+ }
70
+ return index === 0 ? text : text.slice(index);
71
+ }
72
+
73
+ function trimTrailingNewlines(text: string): string {
74
+ let end = text.length;
75
+ while (end > 0 && text[end - 1] === "\n") {
76
+ end--;
77
+ }
78
+ return end === text.length ? text : text.slice(0, end);
79
+ }
@@ -0,0 +1,11 @@
1
+ import { LEADING_NONSTANDARD_WHITESPACE } from "./patterns";
2
+
3
+ /**
4
+ * Replace non-standard whitespace characters at the start of each line
5
+ * with the same number of regular ASCII spaces.
6
+ */
7
+ export function replaceLeadingSpaces(text: string): string {
8
+ return text.replace(LEADING_NONSTANDARD_WHITESPACE, (match) => {
9
+ return " ".repeat(match.length);
10
+ });
11
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Matches non-standard whitespace characters (non-breaking space U+00A0,
3
+ * figure space U+2007) at the start of lines.
4
+ */
5
+ export const LEADING_NONSTANDARD_WHITESPACE: RegExp = /^[\u00a0\u2007]+/gm;
6
+
7
+ /** Matches lines containing only whitespace (collapsed to empty lines). */
8
+ export const WHITESPACE_ONLY_LINE: RegExp = /^\s+$/gm;
9
+
10
+ /** Matches DOS (`\r\n`) and legacy Mac (`\r`) line endings. */
11
+ export const DOS_MAC_NEWLINES: RegExp = /\r\n?/g;
12
+
13
+ /**
14
+ * Matches a backslash immediately followed by a newline.
15
+ * In Wikidot, `\` at end of line acts as an explicit line break (`<br />`).
16
+ */
17
+ export const CONCAT_LINES: RegExp = /\\\n/g;
18
+
19
+ /** Matches tab characters (expanded to four spaces). */
20
+ export const TABS: RegExp = /\t/g;
21
+
22
+ /** Matches null (NUL) characters (replaced with spaces). */
23
+ export const NULL_CHARS: RegExp = new RegExp(String.fromCharCode(0), "g");
@@ -0,0 +1,46 @@
1
+ import type { Element } from "@wdprlib/ast";
2
+ import type { ParseContext } from "../../types";
3
+ import { parseBlocksUntil } from "../utils";
4
+ import { type AlignDirection, parseAlignClose } from "./syntax";
5
+
6
+ export interface AlignBodyResult {
7
+ elements: Element[];
8
+ consumed: number;
9
+ foundClose: boolean;
10
+ }
11
+
12
+ export function parseAlignBody(
13
+ ctx: ParseContext,
14
+ startPos: number,
15
+ direction: AlignDirection,
16
+ ): AlignBodyResult {
17
+ const bodyCtx: ParseContext = { ...ctx, pos: startPos };
18
+ const bodyResult = parseBlocksUntil(bodyCtx, (checkCtx) => {
19
+ return parseAlignClose(checkCtx, direction).match;
20
+ });
21
+
22
+ let pos = startPos + bodyResult.consumed;
23
+ let consumed = bodyResult.consumed;
24
+
25
+ const closeCheck = parseAlignClose({ ...ctx, pos }, direction);
26
+ if (!closeCheck.match) {
27
+ return {
28
+ elements: bodyResult.elements,
29
+ consumed,
30
+ foundClose: false,
31
+ };
32
+ }
33
+
34
+ consumed += closeCheck.consumed;
35
+ pos += closeCheck.consumed;
36
+
37
+ if (ctx.tokens[pos]?.type === "NEWLINE") {
38
+ consumed++;
39
+ }
40
+
41
+ return {
42
+ elements: bodyResult.elements,
43
+ consumed,
44
+ foundClose: true,
45
+ };
46
+ }
@@ -0,0 +1,13 @@
1
+ import type { Element } from "@wdprlib/ast";
2
+ import type { AlignDirection } from "./syntax";
3
+
4
+ export function createAlignElement(direction: AlignDirection, elements: Element[]): Element {
5
+ return {
6
+ element: "container",
7
+ data: {
8
+ type: { align: direction },
9
+ attributes: {},
10
+ elements,
11
+ },
12
+ };
13
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ *
3
+ * Block rule for Wikidot alignment containers.
4
+ *
5
+ * Wikidot provides a shorthand bracket syntax for wrapping content in a
6
+ * directional alignment container:
7
+ *
8
+ * ```
9
+ * [[>]] ... [[/>]] right-aligned
10
+ * [[<]] ... [[/<]] left-aligned
11
+ * [[=]] ... [[/=]] center-aligned
12
+ * [[==]] ... [[/==]] justify-aligned
13
+ * ```
14
+ *
15
+ * Each pair acts as a block-level wrapper. The opening tag must appear at
16
+ * the start of a line and be followed by a newline. Body content is parsed
17
+ * recursively as block-level markup, and the matching closing tag terminates
18
+ * the container.
19
+ *
20
+ * @module
21
+ */
22
+ import type { Element } from "@wdprlib/ast";
23
+ import type { BlockRule, ParseContext, RuleResult } from "../../types";
24
+ import { currentToken } from "../../types";
25
+ import { parseAlignBody } from "./body";
26
+ import { createAlignElement } from "./element";
27
+ import { alignDirectionSymbol, parseAlignOpen } from "./syntax";
28
+
29
+ /**
30
+ * Block rule that matches Wikidot directional alignment containers.
31
+ *
32
+ * `preservesPrecedingLineBreak` is `true` because, unlike most block
33
+ * constructs, an alignment block does not suppress a preceding `\n` from
34
+ * becoming a `<br />` in Wikidot's output.
35
+ */
36
+ export const alignRule: BlockRule = {
37
+ name: "align",
38
+ startTokens: ["BLOCK_OPEN"],
39
+ requiresLineStart: true,
40
+ preservesPrecedingLineBreak: true,
41
+
42
+ isStartPattern(ctx: ParseContext, pos: number): boolean {
43
+ if (ctx.tokens[pos]?.type !== "BLOCK_OPEN") return false;
44
+ return parseAlignOpen(ctx, pos + 1) !== null;
45
+ },
46
+
47
+ parse(ctx: ParseContext): RuleResult<Element> {
48
+ const openToken = currentToken(ctx);
49
+ if (openToken.type !== "BLOCK_OPEN") {
50
+ return { success: false };
51
+ }
52
+
53
+ let pos = ctx.pos + 1;
54
+ let consumed = 1;
55
+
56
+ const alignResult = parseAlignOpen(ctx, pos);
57
+ if (!alignResult) {
58
+ return { success: false };
59
+ }
60
+
61
+ const { direction } = alignResult;
62
+ pos += alignResult.consumed;
63
+ consumed += alignResult.consumed;
64
+
65
+ if (ctx.tokens[pos]?.type !== "NEWLINE") {
66
+ return { success: false };
67
+ }
68
+ pos++;
69
+ consumed++;
70
+
71
+ const bodyResult = parseAlignBody(ctx, pos, direction);
72
+ consumed += bodyResult.consumed;
73
+
74
+ if (!bodyResult.foundClose) {
75
+ const directionSymbol = alignDirectionSymbol(direction);
76
+ ctx.diagnostics.push({
77
+ severity: "warning",
78
+ code: "unclosed-block",
79
+ message: `Missing closing tag [[/${directionSymbol}]] for [[${directionSymbol}]]`,
80
+ position: openToken.position,
81
+ });
82
+ }
83
+
84
+ return {
85
+ success: true,
86
+ elements: [createAlignElement(direction, bodyResult.elements)],
87
+ consumed,
88
+ };
89
+ },
90
+ };
@@ -0,0 +1,113 @@
1
+ import type { ParseContext } from "../../types";
2
+
3
+ /** The four text-alignment directions Wikidot supports. */
4
+ export type AlignDirection = "left" | "right" | "center" | "justify";
5
+
6
+ /**
7
+ * Attempts to parse the interior of an align opening tag starting after
8
+ * the BLOCK_OPEN (`[[`) token.
9
+ */
10
+ export function parseAlignOpen(
11
+ ctx: ParseContext,
12
+ pos: number,
13
+ ): { direction: AlignDirection; consumed: number } | null {
14
+ const tokens = ctx.tokens;
15
+ const firstToken = tokens[pos];
16
+ if (!firstToken) return null;
17
+
18
+ if (
19
+ firstToken.type === "BLOCKQUOTE_MARKER" &&
20
+ firstToken.value === ">" &&
21
+ tokens[pos + 1]?.type === "BLOCK_CLOSE"
22
+ ) {
23
+ return { direction: "right", consumed: 2 };
24
+ }
25
+
26
+ if (
27
+ firstToken.type === "TEXT" &&
28
+ firstToken.value === ">" &&
29
+ tokens[pos + 1]?.type === "BLOCK_CLOSE"
30
+ ) {
31
+ return { direction: "right", consumed: 2 };
32
+ }
33
+
34
+ if (
35
+ firstToken.type === "TEXT" &&
36
+ firstToken.value === "<" &&
37
+ tokens[pos + 1]?.type === "BLOCK_CLOSE"
38
+ ) {
39
+ return { direction: "left", consumed: 2 };
40
+ }
41
+
42
+ if (firstToken.type === "EQUALS" && tokens[pos + 1]?.type === "BLOCK_CLOSE") {
43
+ return { direction: "center", consumed: 2 };
44
+ }
45
+
46
+ if (
47
+ firstToken.type === "EQUALS" &&
48
+ tokens[pos + 1]?.type === "EQUALS" &&
49
+ tokens[pos + 2]?.type === "BLOCK_CLOSE"
50
+ ) {
51
+ return { direction: "justify", consumed: 3 };
52
+ }
53
+
54
+ return null;
55
+ }
56
+
57
+ /**
58
+ * Tests whether the tokens at the current position form a closing align tag.
59
+ */
60
+ export function parseAlignClose(
61
+ ctx: ParseContext,
62
+ direction: AlignDirection,
63
+ ): { match: boolean; consumed: number } {
64
+ const tokens = ctx.tokens;
65
+ let pos = ctx.pos;
66
+
67
+ if (tokens[pos]?.type !== "BLOCK_END_OPEN") {
68
+ return { match: false, consumed: 0 };
69
+ }
70
+ pos++;
71
+
72
+ if (direction === "right") {
73
+ if (
74
+ (tokens[pos]?.type === "BLOCKQUOTE_MARKER" || tokens[pos]?.type === "TEXT") &&
75
+ tokens[pos]?.value === ">" &&
76
+ tokens[pos + 1]?.type === "BLOCK_CLOSE"
77
+ ) {
78
+ return { match: true, consumed: 3 };
79
+ }
80
+ }
81
+
82
+ if (direction === "left") {
83
+ if (
84
+ tokens[pos]?.type === "TEXT" &&
85
+ tokens[pos]?.value === "<" &&
86
+ tokens[pos + 1]?.type === "BLOCK_CLOSE"
87
+ ) {
88
+ return { match: true, consumed: 3 };
89
+ }
90
+ }
91
+
92
+ if (direction === "center") {
93
+ if (tokens[pos]?.type === "EQUALS" && tokens[pos + 1]?.type === "BLOCK_CLOSE") {
94
+ return { match: true, consumed: 3 };
95
+ }
96
+ }
97
+
98
+ if (direction === "justify") {
99
+ if (
100
+ tokens[pos]?.type === "EQUALS" &&
101
+ tokens[pos + 1]?.type === "EQUALS" &&
102
+ tokens[pos + 2]?.type === "BLOCK_CLOSE"
103
+ ) {
104
+ return { match: true, consumed: 4 };
105
+ }
106
+ }
107
+
108
+ return { match: false, consumed: 0 };
109
+ }
110
+
111
+ export function alignDirectionSymbol(direction: AlignDirection): string {
112
+ return { left: "<", right: ">", center: "=", justify: "==" }[direction];
113
+ }