@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
@@ -1,327 +0,0 @@
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 { inlineRules } from "../index";
28
- import { sanitizeUrl as braintreeSanitizeUrl } from "@braintree/sanitize-url";
29
- import { parseAttributes } from "../block/utils";
30
- import { canApplyInlineRule } from "./utils";
31
-
32
- /**
33
- * Sanitizes a URL to prevent XSS attacks via dangerous URI schemes.
34
- *
35
- * Applies two layers of protection:
36
- * 1. Pre-checks the whitespace-normalized URL against known dangerous schemes
37
- * (`javascript:`, `data:`, `vbscript:`), catching evasion attempts like
38
- * `"java script:"` with embedded whitespace.
39
- * 2. Delegates to `@braintree/sanitize-url` for additional validation.
40
- *
41
- * Returns the original URL (not the normalized form) to avoid unintended
42
- * modifications such as trailing-slash addition.
43
- *
44
- * @param url - The raw URL string to sanitize
45
- * @returns The original URL if safe, or `"#invalid-url"` if the URL is deemed dangerous
46
- */
47
- function sanitizeUrl(url: string): string {
48
- // Pre-process: normalize whitespace to catch evasion attempts like "java script:"
49
- const normalizedForCheck = url.replace(/[\s\u0000-\u001f]/g, "").toLowerCase();
50
-
51
- // Check for dangerous schemes after whitespace normalization
52
- const dangerousSchemes = ["javascript:", "data:", "vbscript:"];
53
- for (const scheme of dangerousSchemes) {
54
- if (normalizedForCheck.startsWith(scheme)) {
55
- return "#invalid-url";
56
- }
57
- }
58
-
59
- // Use library for additional checks
60
- const sanitized = braintreeSanitizeUrl(url);
61
- if (sanitized === "about:blank") {
62
- return "#invalid-url";
63
- }
64
-
65
- // Return original URL to avoid unwanted normalization (e.g., trailing slash addition)
66
- return url;
67
- }
68
-
69
- /**
70
- * Parses the block name portion of an anchor open/close tag, handling the
71
- * optional underscore suffix that activates paragraph strip mode.
72
- *
73
- * Recognizes `a`, `anchor`, `a_`, and `anchor_` (case-insensitive).
74
- * The underscore suffix is reported via the `score` field so the caller
75
- * can decide how to handle newlines inside the anchor body.
76
- *
77
- * @param ctx - The current parse context containing the token stream
78
- * @param startPos - Token index at which to begin scanning
79
- * @returns An object with the lowercased name (including trailing `_` if present),
80
- * a `score` boolean indicating paragraph strip mode, and the number of
81
- * tokens consumed -- or `null` if no valid anchor block name was found
82
- */
83
- function parseAnchorBlockName(
84
- ctx: ParseContext,
85
- startPos: number,
86
- ): { name: string; score: boolean; consumed: number } | null {
87
- let pos = startPos;
88
- let consumed = 0;
89
-
90
- // Skip whitespace
91
- while (ctx.tokens[pos]?.type === "WHITESPACE") {
92
- pos++;
93
- consumed++;
94
- }
95
-
96
- const token = ctx.tokens[pos];
97
- if (!token || (token.type !== "TEXT" && token.type !== "IDENTIFIER")) {
98
- return null;
99
- }
100
-
101
- let name = token.value.toLowerCase();
102
- consumed++;
103
- pos++;
104
-
105
- // Check for underscore suffix (paragraph strip)
106
- let score = false;
107
- if (ctx.tokens[pos]?.type === "UNDERSCORE") {
108
- score = true;
109
- name += "_";
110
- consumed++;
111
- pos++;
112
- }
113
-
114
- return { name, score, consumed };
115
- }
116
-
117
- /**
118
- * Inline rule for parsing `[[a]]...[[/a]]` blocks.
119
- *
120
- * Triggered by a `BLOCK_OPEN` (`[[`) token. The rule verifies the block name
121
- * is `a` or `anchor` (optionally with `_` suffix), parses HTML attributes,
122
- * then recursively parses inline content until the matching closing tag.
123
- *
124
- * Produces an `"anchor"` AST element containing the parsed children, a
125
- * semantic `target` value, and the sanitized attribute map.
126
- *
127
- * Edge cases:
128
- * - If no matching closing tag is found, the rule fails (returns `{ success: false }`),
129
- * allowing the tokens to fall through to other rules or the text fallback.
130
- * - In paragraph strip mode, newlines within the body are consumed silently
131
- * rather than converted to line-break elements. After the closing tag,
132
- * at most one trailing newline is consumed to prevent a line-break between
133
- * consecutive `[[a_]]` blocks, but double newlines are preserved as
134
- * paragraph breaks.
135
- * - The `href` attribute is sanitized to block `javascript:`, `data:`, and
136
- * `vbscript:` schemes.
137
- */
138
- export const anchorRule: InlineRule = {
139
- name: "anchor",
140
- startTokens: ["BLOCK_OPEN"],
141
-
142
- /**
143
- * Attempts to parse an anchor block starting at the current position.
144
- *
145
- * @param ctx - Parse context with token stream and current position
146
- * @returns A successful result with an `"anchor"` element, or `{ success: false }`
147
- */
148
- parse(ctx: ParseContext): RuleResult<Element> {
149
- const openToken = currentToken(ctx);
150
- if (openToken.type !== "BLOCK_OPEN") {
151
- return { success: false };
152
- }
153
-
154
- let pos = ctx.pos + 1;
155
- let consumed = 1;
156
-
157
- // Parse block name with flags
158
- const nameResult = parseAnchorBlockName(ctx, pos);
159
- if (!nameResult) {
160
- return { success: false };
161
- }
162
-
163
- const baseName = nameResult.name.replace(/_$/, "");
164
- if (baseName !== "a" && baseName !== "anchor") {
165
- return { success: false };
166
- }
167
-
168
- const paragraphStrip = nameResult.score;
169
-
170
- pos += nameResult.consumed;
171
- consumed += nameResult.consumed;
172
-
173
- // Parse attributes
174
- const attrResult = parseAttributes(ctx, pos);
175
- pos += attrResult.consumed;
176
- consumed += attrResult.consumed;
177
-
178
- // Expect ]]
179
- if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
180
- return { success: false };
181
- }
182
- pos++;
183
- consumed++;
184
-
185
- // Parse content until [[/a]] or [[/anchor]]
186
- const children: Element[] = [];
187
- let foundClose = false;
188
-
189
- while (pos < ctx.tokens.length) {
190
- const token = ctx.tokens[pos];
191
- if (!token || token.type === "EOF") {
192
- break;
193
- }
194
-
195
- // Check for closing tag
196
- if (token.type === "BLOCK_END_OPEN") {
197
- const closeNameResult = parseAnchorBlockName(ctx, pos + 1);
198
- const closeBaseName = closeNameResult?.name.replace(/_$/, "");
199
- if (closeNameResult && (closeBaseName === "a" || closeBaseName === "anchor")) {
200
- pos++; // [[/
201
- consumed++;
202
- pos += closeNameResult.consumed;
203
- consumed += closeNameResult.consumed;
204
- if (ctx.tokens[pos]?.type === "BLOCK_CLOSE") {
205
- pos++;
206
- consumed++;
207
- }
208
- foundClose = true;
209
-
210
- // In paragraph strip mode, consume one trailing newline after close tag
211
- // This prevents a line-break between consecutive [[a_]] blocks
212
- // but preserves paragraph breaks (double newlines)
213
- if (
214
- paragraphStrip &&
215
- ctx.tokens[pos]?.type === "NEWLINE" &&
216
- ctx.tokens[pos + 1]?.type !== "NEWLINE"
217
- ) {
218
- pos++;
219
- consumed++;
220
- }
221
- break;
222
- }
223
- }
224
-
225
- // Handle NEWLINE
226
- if (token.type === "NEWLINE") {
227
- if (paragraphStrip) {
228
- // Skip newlines in paragraph strip mode
229
- pos++;
230
- consumed++;
231
- continue;
232
- }
233
- // Convert to line-break
234
- children.push({ element: "line-break" });
235
- pos++;
236
- consumed++;
237
- // Skip leading whitespace after newline
238
- while (ctx.tokens[pos]?.type === "WHITESPACE" && ctx.tokens[pos]?.lineStart) {
239
- pos++;
240
- consumed++;
241
- }
242
- continue;
243
- }
244
-
245
- // Skip whitespace at line start
246
- if (token.type === "WHITESPACE" && token.lineStart) {
247
- pos++;
248
- consumed++;
249
- continue;
250
- }
251
-
252
- // Try each inline rule
253
- let matched = false;
254
- const inlineCtx: ParseContext = { ...ctx, pos };
255
-
256
- for (const rule of inlineRules) {
257
- if (canApplyInlineRule(rule, token)) {
258
- const result = rule.parse(inlineCtx);
259
- if (result.success) {
260
- children.push(...result.elements);
261
- pos += result.consumed;
262
- consumed += result.consumed;
263
- matched = true;
264
- break;
265
- }
266
- }
267
- }
268
-
269
- if (!matched) {
270
- children.push({ element: "text", data: token.value });
271
- pos++;
272
- consumed++;
273
- }
274
- }
275
-
276
- if (!foundClose) {
277
- ctx.diagnostics.push({
278
- severity: "warning",
279
- code: "unclosed-block",
280
- message: `Missing closing tag [[/a]] for [[${nameResult.name}]]`,
281
- position: openToken.position,
282
- });
283
- return { success: false };
284
- }
285
-
286
- // Clean up children - remove leading/trailing line breaks if paragraph strip
287
- if (paragraphStrip) {
288
- while (children.length > 0 && children[0]?.element === "line-break") {
289
- children.shift();
290
- }
291
- while (children.length > 0 && children[children.length - 1]?.element === "line-break") {
292
- children.pop();
293
- }
294
- }
295
-
296
- // Determine target from attributes
297
- let target: "new-tab" | "parent" | "top" | "same" | null = null;
298
- const targetAttr = attrResult.attrs.target;
299
- if (targetAttr === "_blank") target = "new-tab";
300
- else if (targetAttr === "_parent") target = "parent";
301
- else if (targetAttr === "_top") target = "top";
302
- else if (targetAttr === "_self") target = "same";
303
-
304
- // Remove target from attributes (href stays in attributes)
305
- const { target: _t, ...cleanAttrs } = attrResult.attrs;
306
-
307
- // Sanitize href to prevent XSS
308
- if (cleanAttrs.href) {
309
- cleanAttrs.href = sanitizeUrl(cleanAttrs.href);
310
- }
311
-
312
- return {
313
- success: true,
314
- elements: [
315
- {
316
- element: "anchor",
317
- data: {
318
- target,
319
- attributes: cleanAttrs,
320
- elements: children,
321
- },
322
- },
323
- ],
324
- consumed,
325
- };
326
- },
327
- };
@@ -1,153 +0,0 @@
1
- /**
2
- *
3
- * Parses the Wikidot bibliography citation syntax: `((bibcite label))`.
4
- *
5
- * A bibcite creates a numbered inline reference (similar to footnotes)
6
- * that links to a corresponding entry in a `[[bibliography]]` block
7
- * elsewhere on the page. The `label` string is used to match the
8
- * citation with its bibliography entry.
9
- *
10
- * Unlike most inline blocks that start with `[[`, bibcite uses double
11
- * parentheses `((...))` as delimiters. The keyword `bibcite` must
12
- * appear (case-insensitive) between the opening `((` and the label.
13
- *
14
- * Produces a `"bibliography-cite"` AST element. The label is also
15
- * pushed into `ctx.bibcites` so the renderer can later resolve
16
- * citation numbers.
17
- *
18
- * Wikidot syntax examples:
19
- * - `((bibcite author2024))` -- cite with label "author2024"
20
- * - `((bibcite my-source))` -- cite with label "my-source"
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
-
28
- /**
29
- * Inline rule for parsing `((bibcite label))` bibliography citations.
30
- *
31
- * Triggered by a `TEXT` token (specifically the `(` character). The parser
32
- * looks for two consecutive `(` tokens, the keyword `bibcite`, the label
33
- * text, and then two consecutive `)` tokens.
34
- *
35
- * The label may span multiple tokens and is trimmed of surrounding whitespace.
36
- * Parsing fails if the label is empty or if a newline/EOF is encountered
37
- * before the closing `))`.
38
- *
39
- * Side effect: pushes the label into `ctx.bibcites` for later resolution
40
- * during rendering.
41
- */
42
- export const bibciteRule: InlineRule = {
43
- name: "bibcite",
44
- startTokens: ["TEXT"],
45
-
46
- /**
47
- * Attempts to parse a `((bibcite label))` citation at the current position.
48
- *
49
- * @param ctx - Parse context with token stream and current position
50
- * @returns A successful result with a `"bibliography-cite"` element, or `{ success: false }`
51
- */
52
- parse(ctx: ParseContext): RuleResult<Element> {
53
- const token = currentToken(ctx);
54
-
55
- // Must start with (
56
- if (token.type !== "TEXT" || token.value !== "(") {
57
- return { success: false };
58
- }
59
-
60
- // Check for second (
61
- const nextToken = ctx.tokens[ctx.pos + 1];
62
- if (!nextToken || nextToken.type !== "TEXT" || nextToken.value !== "(") {
63
- return { success: false };
64
- }
65
-
66
- // Check for "bibcite" identifier
67
- let pos = ctx.pos + 2;
68
- let consumed = 2;
69
-
70
- // Skip whitespace
71
- while (ctx.tokens[pos]?.type === "WHITESPACE") {
72
- pos++;
73
- consumed++;
74
- }
75
-
76
- const nameToken = ctx.tokens[pos];
77
- if (
78
- !nameToken ||
79
- nameToken.type !== "IDENTIFIER" ||
80
- nameToken.value.toLowerCase() !== "bibcite"
81
- ) {
82
- return { success: false };
83
- }
84
- pos++;
85
- consumed++;
86
-
87
- // Skip whitespace
88
- while (ctx.tokens[pos]?.type === "WHITESPACE") {
89
- pos++;
90
- consumed++;
91
- }
92
-
93
- // Parse label (identifier or text)
94
- const labelToken = ctx.tokens[pos];
95
- if (!labelToken || (labelToken.type !== "IDENTIFIER" && labelToken.type !== "TEXT")) {
96
- return { success: false };
97
- }
98
-
99
- // Collect label (may span multiple tokens until ))
100
- let label = "";
101
- let foundClose = false;
102
- while (pos < ctx.tokens.length) {
103
- const t = ctx.tokens[pos];
104
- if (!t) break;
105
-
106
- // Check for ))
107
- if (t.type === "TEXT" && t.value === ")") {
108
- const nextT = ctx.tokens[pos + 1];
109
- if (nextT?.type === "TEXT" && nextT.value === ")") {
110
- // Found closing ))
111
- consumed += 2;
112
- foundClose = true;
113
- break;
114
- }
115
- }
116
-
117
- // Stop at newline or EOF
118
- if (t.type === "NEWLINE" || t.type === "EOF") {
119
- return { success: false };
120
- }
121
-
122
- label += t.value;
123
- pos++;
124
- consumed++;
125
- }
126
-
127
- if (!foundClose) {
128
- return { success: false };
129
- }
130
-
131
- label = label.trim();
132
- if (!label) {
133
- return { success: false };
134
- }
135
-
136
- // Store bibcite reference in context for later resolution
137
- ctx.bibcites.push(label);
138
-
139
- return {
140
- success: true,
141
- elements: [
142
- {
143
- element: "bibliography-cite",
144
- data: {
145
- label,
146
- brackets: false, // Wikidot adds brackets in output but they're not in the AST
147
- },
148
- },
149
- ],
150
- consumed,
151
- };
152
- },
153
- };
@@ -1,140 +0,0 @@
1
- /**
2
- *
3
- * Parses the Wikidot inline color syntax: `##color|text##`.
4
- *
5
- * This syntax applies a CSS color to inline text. The color specifier
6
- * and the text content are separated by a pipe (`|`). Both parts are
7
- * required; an empty color or empty content causes the parse to fail.
8
- *
9
- * Supported color formats:
10
- * - 3-digit hex (e.g. `c00`) -- automatically prefixed with `#`
11
- * - 6-digit hex (e.g. `cc0000`) -- automatically prefixed with `#`
12
- * - Named CSS colors (e.g. `blue`, `red`)
13
- * - CSS color functions (e.g. `rgb(255,0,0)`)
14
- *
15
- * Wikidot syntax examples:
16
- * - `##c00|Apple##` -- red text reading "Apple"
17
- * - `##blue|Ocean##` -- blue text reading "Ocean"
18
- * - `##rgb(0,128,0)|Green text##` -- CSS function color
19
- *
20
- * Produces a `"color"` AST element with the resolved color value and
21
- * nested inline elements.
22
- *
23
- * @module
24
- */
25
- import type { Element } from "@wdprlib/ast";
26
- import type { InlineRule, ParseContext, RuleResult } from "../types";
27
- import { hasClosingMarkerBeforeNewline } from "../types";
28
- import { parseInlineUntil } from "./utils";
29
-
30
- /**
31
- * Inline rule for parsing `##color|text##` color formatting.
32
- *
33
- * Triggered by a `COLOR_MARKER` token (`##`). The rule collects the
34
- * color specifier until a `PIPE` token, then recursively parses inline
35
- * content until the closing `##`.
36
- *
37
- * Fails if:
38
- * - No closing `##` is found on the same line
39
- * - No pipe separator is present
40
- * - The color specifier or content is empty
41
- */
42
- export const colorRule: InlineRule = {
43
- name: "color",
44
- startTokens: ["COLOR_MARKER"],
45
-
46
- /**
47
- * Attempts to parse color formatting at the current position.
48
- *
49
- * @param ctx - Parse context with token stream and current position
50
- * @returns A successful result with a `"color"` element, or `{ success: false }`
51
- */
52
- parse(ctx: ParseContext): RuleResult<Element> {
53
- // Check if closing marker exists
54
- if (!hasClosingMarkerBeforeNewline({ ...ctx, pos: ctx.pos + 1 }, "COLOR_MARKER")) {
55
- return { success: false };
56
- }
57
-
58
- let pos = ctx.pos + 1;
59
- let consumed = 1; // ##
60
-
61
- // Collect color specification until PIPE
62
- let colorSpec = "";
63
- while (pos < ctx.tokens.length) {
64
- const token = ctx.tokens[pos];
65
- if (
66
- !token ||
67
- token.type === "PIPE" ||
68
- token.type === "COLOR_MARKER" ||
69
- token.type === "NEWLINE" ||
70
- token.type === "EOF"
71
- ) {
72
- break;
73
- }
74
- colorSpec += token.value;
75
- pos++;
76
- consumed++;
77
- }
78
-
79
- // Must have a PIPE separator
80
- if (ctx.tokens[pos]?.type !== "PIPE") {
81
- return { success: false };
82
- }
83
- pos++;
84
- consumed++;
85
-
86
- // Parse inline content until closing ##
87
- const contentResult = parseInlineUntil({ ...ctx, pos }, "COLOR_MARKER");
88
- pos += contentResult.consumed;
89
- consumed += contentResult.consumed;
90
-
91
- // Consume closing ##
92
- if (ctx.tokens[pos]?.type === "COLOR_MARKER") {
93
- pos++;
94
- consumed++;
95
- } else {
96
- return { success: false };
97
- }
98
-
99
- const textChildren = contentResult.elements;
100
-
101
- const trimmedColor = colorSpec.trim();
102
-
103
- // Wikidot requires non-empty color spec and non-empty content
104
- if (trimmedColor === "" || textChildren.length === 0) {
105
- return { success: false };
106
- }
107
-
108
- return {
109
- success: true,
110
- elements: [
111
- {
112
- element: "color",
113
- data: {
114
- color: hexifyColor(trimmedColor),
115
- elements: textChildren,
116
- },
117
- },
118
- ],
119
- consumed,
120
- };
121
- },
122
- };
123
-
124
- /**
125
- * Normalizes shorthand hex color values by prepending a `#` sign.
126
- *
127
- * Wikidot allows users to write hex colors without the `#` prefix
128
- * (e.g. `c00` or `ff0000`). This function detects 3- or 6-character
129
- * hex strings and adds the prefix. Non-hex color values (named colors,
130
- * CSS functions) are returned unchanged.
131
- *
132
- * @param color - The trimmed color string from the markup
133
- * @returns The color string, with `#` prepended if it was a bare hex value
134
- */
135
- function hexifyColor(color: string): string {
136
- if (/^[a-fA-F0-9]{3}$/.test(color) || /^[a-fA-F0-9]{6}$/.test(color)) {
137
- return `#${color}`;
138
- }
139
- return color;
140
- }