@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,41 @@
1
+ import type { Element } from "@wdprlib/ast";
2
+ import type { ParseContext } from "../../types";
3
+ import { parseBlocksUntil } from "../utils";
4
+ import { isDivClose } from "./close";
5
+ import { countDivCloses } from "./nesting";
6
+ import { unwrapEdgeParagraphs } from "./paragraph-strip";
7
+
8
+ export interface DivBodyResult {
9
+ elements: Element[];
10
+ consumed: number;
11
+ }
12
+
13
+ export function parseDivBody(
14
+ ctx: ParseContext,
15
+ startPos: number,
16
+ paragraphStrip: boolean,
17
+ ): DivBodyResult {
18
+ const bodyBudget = resolveDivBodyBudget(ctx, startPos);
19
+ const bodyCtx: ParseContext = {
20
+ ...ctx,
21
+ pos: startPos,
22
+ scope: { ...ctx.scope, divClosesBudget: bodyBudget },
23
+ };
24
+
25
+ const bodyResult = parseBlocksUntil(bodyCtx, isDivClose);
26
+ const elements = paragraphStrip ? unwrapEdgeParagraphs(bodyResult.elements) : bodyResult.elements;
27
+
28
+ return {
29
+ elements,
30
+ consumed: bodyResult.consumed,
31
+ };
32
+ }
33
+
34
+ function resolveDivBodyBudget(ctx: ParseContext, startPos: number): number {
35
+ if (ctx.scope.divClosesBudget !== undefined) {
36
+ return ctx.scope.divClosesBudget - 1;
37
+ }
38
+
39
+ const closesInScope = countDivCloses(ctx, startPos);
40
+ return closesInScope > 0 ? closesInScope - 1 : 0;
41
+ }
@@ -0,0 +1,41 @@
1
+ import type { ParseContext } from "../../types";
2
+ import { parseBlockName } from "../utils";
3
+
4
+ export function isDivClose(ctx: ParseContext): boolean {
5
+ const token = ctx.tokens[ctx.pos];
6
+ if (token?.type !== "BLOCK_END_OPEN") return false;
7
+
8
+ const closeNameResult = parseBlockName(ctx, ctx.pos + 1);
9
+ return closeNameResult?.name === "div";
10
+ }
11
+
12
+ export function consumeDivClose(
13
+ ctx: ParseContext,
14
+ startPos: number,
15
+ ): { pos: number; consumed: number } {
16
+ let pos = startPos;
17
+ let consumed = 0;
18
+
19
+ if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
20
+ return { pos, consumed };
21
+ }
22
+
23
+ pos++;
24
+ consumed++;
25
+
26
+ const closeNameResult = parseBlockName(ctx, pos);
27
+ if (closeNameResult) {
28
+ pos += closeNameResult.consumed;
29
+ consumed += closeNameResult.consumed;
30
+ }
31
+ if (ctx.tokens[pos]?.type === "BLOCK_CLOSE") {
32
+ pos++;
33
+ consumed++;
34
+ }
35
+ if (ctx.tokens[pos]?.type === "NEWLINE") {
36
+ pos++;
37
+ consumed++;
38
+ }
39
+
40
+ return { pos, consumed };
41
+ }
@@ -0,0 +1,117 @@
1
+ import type { Element } from "@wdprlib/ast";
2
+ import type { ParseContext, RuleResult } from "../../types";
3
+ import { parseAttributes, parseBlockName } from "../utils";
4
+
5
+ /**
6
+ * Handles the case where `[[div]]` fails as a block element because
7
+ * the closing `]]` is not followed by a NEWLINE.
8
+ */
9
+ export function consumeFailedDiv(ctx: ParseContext): RuleResult<Element> {
10
+ const elements: Element[] = [];
11
+ let pos = ctx.pos;
12
+ let consumed = 0;
13
+ let lastClosePos = -1;
14
+ let lastCloseConsumed = 0;
15
+
16
+ let scanPos = pos;
17
+ while (scanPos < ctx.tokens.length) {
18
+ const t = ctx.tokens[scanPos];
19
+ if (!t || t.type === "EOF") break;
20
+
21
+ if (t.type === "BLOCK_OPEN" && t.lineStart && scanPos > pos) {
22
+ const nameResult = parseBlockName(ctx, scanPos + 1);
23
+ if (nameResult?.name === "div" || nameResult?.name === "div_") {
24
+ let checkPos = scanPos + 1 + nameResult.consumed;
25
+ const attrResult = parseAttributes(ctx, checkPos);
26
+ checkPos += attrResult.consumed;
27
+ if (ctx.tokens[checkPos]?.type === "BLOCK_CLOSE") {
28
+ checkPos++;
29
+ if (ctx.tokens[checkPos]?.type === "NEWLINE" || ctx.tokens[checkPos]?.type === "EOF") {
30
+ break;
31
+ }
32
+ }
33
+ }
34
+ }
35
+
36
+ if (t.type === "BLOCK_END_OPEN") {
37
+ const nameResult = parseBlockName(ctx, scanPos + 1);
38
+ if (nameResult?.name === "div") {
39
+ lastClosePos = scanPos;
40
+ lastCloseConsumed = 1 + nameResult.consumed;
41
+ const closeToken = ctx.tokens[scanPos + 1 + nameResult.consumed];
42
+ if (closeToken?.type === "BLOCK_CLOSE") {
43
+ lastCloseConsumed++;
44
+ }
45
+ }
46
+ }
47
+ scanPos++;
48
+ }
49
+
50
+ if (lastClosePos === -1) {
51
+ return { success: false };
52
+ }
53
+
54
+ const endPosForDiag = lastClosePos;
55
+ for (let diagPos = ctx.pos; diagPos < endPosForDiag; diagPos++) {
56
+ const t = ctx.tokens[diagPos];
57
+ if (t?.type === "BLOCK_OPEN") {
58
+ const nameResult = parseBlockName(ctx, diagPos + 1);
59
+ if (nameResult?.name === "div" || nameResult?.name === "div_") {
60
+ if (t.position) {
61
+ ctx.diagnostics.push({
62
+ severity: "error",
63
+ code: "inline-block-element",
64
+ message: `[[${nameResult.name}]] must be followed by a newline to be a block element`,
65
+ position: t.position,
66
+ });
67
+ }
68
+ }
69
+ }
70
+ }
71
+
72
+ const endPos = lastClosePos + lastCloseConsumed;
73
+ while (pos < endPos && pos < ctx.tokens.length) {
74
+ const t = ctx.tokens[pos];
75
+ if (!t || t.type === "EOF") break;
76
+
77
+ if (t.type === "NEWLINE") {
78
+ let peekPos = pos + 1;
79
+ while (ctx.tokens[peekPos]?.type === "WHITESPACE") peekPos++;
80
+ if (ctx.tokens[peekPos]?.type === "NEWLINE") {
81
+ while (ctx.tokens[pos]?.type === "NEWLINE" || ctx.tokens[pos]?.type === "WHITESPACE") {
82
+ pos++;
83
+ consumed++;
84
+ }
85
+ continue;
86
+ }
87
+ elements.push({ element: "line-break" });
88
+ pos++;
89
+ consumed++;
90
+ continue;
91
+ }
92
+
93
+ elements.push({ element: "text", data: t.value });
94
+ pos++;
95
+ consumed++;
96
+ }
97
+
98
+ if (ctx.tokens[pos]?.type === "NEWLINE") {
99
+ pos++;
100
+ consumed++;
101
+ }
102
+
103
+ return {
104
+ success: true,
105
+ elements: [
106
+ {
107
+ element: "container",
108
+ data: {
109
+ type: "paragraph",
110
+ attributes: {},
111
+ elements,
112
+ },
113
+ },
114
+ ],
115
+ consumed,
116
+ };
117
+ }
@@ -0,0 +1,112 @@
1
+ /**
2
+ *
3
+ * Block rule for Wikidot `[[div]]` and `[[div_]]` container blocks.
4
+ *
5
+ * `[[div]]` wraps its body content in a `<div>` element, with full
6
+ * paragraph processing for the body. `[[div_]]` (paragraph strip mode)
7
+ * unwraps the first and last paragraphs so their content appears directly
8
+ * inside the `<div>`, while middle paragraphs keep their `<p>` wrappers.
9
+ *
10
+ * Both variants accept HTML attributes (class, style, id, etc.) on the
11
+ * opening tag.
12
+ *
13
+ * Wikidot-specific edge cases:
14
+ * - The opening `]]` MUST be followed by a NEWLINE for the block to be
15
+ * recognised. `[[div]]inline[[/div]]` is NOT a valid div -- it becomes
16
+ * a failed div (see `consumeFailedDiv()`).
17
+ * - When a div fails, everything from the opening `[[div]]` through the
18
+ * last `[[/div]]` is collected as a single paragraph of text/line-break
19
+ * elements. Blank lines within that span are silently removed.
20
+ * - `[[div_]]` uses `unwrapEdgeParagraphs()` to strip paragraph
21
+ * wrappers from the first and last elements.
22
+ *
23
+ * @module
24
+ */
25
+ import type { Element } from "@wdprlib/ast";
26
+ import type { BlockRule, ParseContext, RuleResult } from "../../types";
27
+ import { currentToken } from "../../types";
28
+ import { parseDivBody } from "./body";
29
+ import { consumeDivClose } from "./close";
30
+ import { consumeFailedDiv } from "./failed";
31
+ import { parseDivOpen } from "./open";
32
+
33
+ /**
34
+ * Block rule for `[[div]]`/`[[div_]]` container blocks.
35
+ *
36
+ * `requiresLineStart` is `false` because nested `[[div_]]` inside another
37
+ * `[[div_]]` may appear after inline content.
38
+ */
39
+ export const divRule: BlockRule = {
40
+ name: "div",
41
+ startTokens: ["BLOCK_OPEN"],
42
+ requiresLineStart: false, // Allow nested [[div_]] inside [[div_]]
43
+
44
+ parse(ctx: ParseContext): RuleResult<Element> {
45
+ const openToken = currentToken(ctx);
46
+ if (openToken.type !== "BLOCK_OPEN") {
47
+ return { success: false };
48
+ }
49
+
50
+ const openResult = parseDivOpen(ctx);
51
+ if (!openResult) {
52
+ return { success: false };
53
+ }
54
+
55
+ // Wikidot: [[div]] must be followed by newline to be recognized as block
56
+ // [[div]]inline[[/div]] is NOT recognized as div
57
+ // When this fails, Wikidot consumes everything up to the last [[/div]]
58
+ // as text in a single paragraph (blank lines are ignored)
59
+ if (!openResult.hasRequiredNewline) {
60
+ return consumeFailedDiv(ctx);
61
+ }
62
+
63
+ // Wikidot matches [[div]]/[[/div]] pairs from outside-in. When there are
64
+ // more opens than closes, the innermost excess opens become text. We enforce
65
+ // this with a "closes budget": the number of additional nested divs that can
66
+ // open. When budget reaches 0, this div cannot open.
67
+ if (ctx.scope.divClosesBudget === 0) {
68
+ return { success: false };
69
+ }
70
+
71
+ // Record opening tag position for diagnostics
72
+ const openPosition = openToken.position;
73
+
74
+ let pos = openResult.bodyStart;
75
+ let consumed = openResult.consumed;
76
+ const bodyResult = parseDivBody(ctx, pos, openResult.paragraphStrip);
77
+ consumed += bodyResult.consumed;
78
+ pos += bodyResult.consumed;
79
+
80
+ // Check for missing close tag
81
+ if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
82
+ ctx.diagnostics.push({
83
+ severity: "warning",
84
+ code: "unclosed-block",
85
+ message: `Missing closing tag [[/div]] for [[${openResult.blockName}]]`,
86
+ position: openPosition,
87
+ });
88
+ }
89
+
90
+ // Consume [[/div]]
91
+ if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
92
+ const closeResult = consumeDivClose(ctx, pos);
93
+ pos = closeResult.pos;
94
+ consumed += closeResult.consumed;
95
+ }
96
+
97
+ return {
98
+ success: true,
99
+ elements: [
100
+ {
101
+ element: "container",
102
+ data: {
103
+ type: "div",
104
+ attributes: openResult.attributes,
105
+ elements: bodyResult.elements,
106
+ },
107
+ },
108
+ ],
109
+ consumed,
110
+ };
111
+ },
112
+ };
@@ -0,0 +1,37 @@
1
+ import type { ParseContext } from "../../types";
2
+
3
+ const divCloseCountCache = new WeakMap<ParseContext["tokens"], Uint32Array>();
4
+
5
+ /**
6
+ * Counts `[[/div]]` close tags from a given position to the end of the
7
+ * token stream. Used to calculate the nesting budget for div blocks.
8
+ */
9
+ export function countDivCloses(ctx: ParseContext, startPos: number): number {
10
+ let counts = divCloseCountCache.get(ctx.tokens);
11
+ if (!counts) {
12
+ counts = new Uint32Array(ctx.tokens.length + 1);
13
+ for (let i = ctx.tokens.length - 1; i >= 0; i--) {
14
+ let count = counts[i + 1]!;
15
+ if (isDivCloseToken(ctx, i)) {
16
+ count++;
17
+ }
18
+ counts[i] = count;
19
+ }
20
+ divCloseCountCache.set(ctx.tokens, counts);
21
+ }
22
+ return counts[startPos] ?? 0;
23
+ }
24
+
25
+ function isDivCloseToken(ctx: ParseContext, pos: number): boolean {
26
+ if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") return false;
27
+ const name = ctx.tokens[pos + 1];
28
+ if (!name || (name.type !== "TEXT" && name.type !== "IDENTIFIER")) return false;
29
+ if (name.value.length !== 3) return false;
30
+ const d = name.value.charCodeAt(0);
31
+ const i = name.value.charCodeAt(1);
32
+ const v = name.value.charCodeAt(2);
33
+ if (!((d === 100 || d === 68) && (i === 105 || i === 73) && (v === 118 || v === 86))) {
34
+ return false;
35
+ }
36
+ return ctx.tokens[pos + 2]?.type !== "UNDERSCORE";
37
+ }
@@ -0,0 +1,59 @@
1
+ import type { AttributeMap } from "@wdprlib/ast";
2
+ import type { ParseContext } from "../../types";
3
+ import { parseAttributes, parseBlockName } from "../utils";
4
+
5
+ export interface DivOpenResult {
6
+ blockName: "div" | "div_";
7
+ paragraphStrip: boolean;
8
+ attributes: AttributeMap;
9
+ bodyStart: number;
10
+ consumed: number;
11
+ hasRequiredNewline: boolean;
12
+ }
13
+
14
+ export function parseDivOpen(ctx: ParseContext): DivOpenResult | null {
15
+ if (ctx.tokens[ctx.pos]?.type !== "BLOCK_OPEN") {
16
+ return null;
17
+ }
18
+
19
+ let pos = ctx.pos + 1;
20
+ let consumed = 1;
21
+
22
+ const nameResult = parseBlockName(ctx, pos);
23
+ if (!nameResult || !isDivBlockName(nameResult.name)) {
24
+ return null;
25
+ }
26
+
27
+ pos += nameResult.consumed;
28
+ consumed += nameResult.consumed;
29
+
30
+ const attrResult = parseAttributes(ctx, pos);
31
+ pos += attrResult.consumed;
32
+ consumed += attrResult.consumed;
33
+
34
+ if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
35
+ return null;
36
+ }
37
+
38
+ pos++;
39
+ consumed++;
40
+
41
+ const hasRequiredNewline = ctx.tokens[pos]?.type === "NEWLINE";
42
+ if (hasRequiredNewline) {
43
+ pos++;
44
+ consumed++;
45
+ }
46
+
47
+ return {
48
+ blockName: nameResult.name,
49
+ paragraphStrip: nameResult.name === "div_",
50
+ attributes: attrResult.attrs,
51
+ bodyStart: pos,
52
+ consumed,
53
+ hasRequiredNewline,
54
+ };
55
+ }
56
+
57
+ function isDivBlockName(name: string): name is "div" | "div_" {
58
+ return name === "div" || name === "div_";
59
+ }
@@ -0,0 +1,44 @@
1
+ import type { ContainerData, Element } from "@wdprlib/ast";
2
+
3
+ /**
4
+ * Implements the `[[div_]]` paragraph-strip behaviour.
5
+ *
6
+ * In Wikidot's `div_` mode, the first and last paragraph containers have
7
+ * their `<p>` wrappers removed, leaving the inner elements bare. Any
8
+ * middle paragraphs retain their wrapping.
9
+ */
10
+ export function unwrapEdgeParagraphs(elements: Element[]): Element[] {
11
+ if (elements.length === 0) return elements;
12
+
13
+ const result = [...elements];
14
+
15
+ const first = result[0];
16
+ if (isParagraphContainer(first)) {
17
+ const inner = first.data.elements;
18
+ result.splice(0, 1, ...inner);
19
+ }
20
+
21
+ const lastIdx = result.length - 1;
22
+ const last = result[lastIdx];
23
+ if (lastIdx >= 0 && isParagraphContainer(last)) {
24
+ const inner = last.data.elements;
25
+ result.splice(lastIdx, 1, ...inner);
26
+ }
27
+
28
+ return result;
29
+ }
30
+
31
+ type ParagraphContainer = Extract<Element, { element: "container" }> & {
32
+ data: ContainerData & { type: "paragraph" };
33
+ };
34
+
35
+ function isParagraphContainer(el: Element | undefined): el is ParagraphContainer {
36
+ return (
37
+ el !== undefined &&
38
+ el.element === "container" &&
39
+ typeof el.data === "object" &&
40
+ el.data !== null &&
41
+ "type" in el.data &&
42
+ el.data.type === "paragraph"
43
+ );
44
+ }
@@ -0,0 +1,53 @@
1
+ import type { ParseContext } from "../../types";
2
+ import { parseBlockName } from "../utils";
3
+ import { isEmbedBlockName } from "./tags";
4
+
5
+ export interface EmbedContentResult {
6
+ contents: string;
7
+ consumed: number;
8
+ foundClose: boolean;
9
+ }
10
+
11
+ export function collectEmbedContent(ctx: ParseContext, startPos: number): EmbedContentResult {
12
+ const contentParts: string[] = [];
13
+ let pos = startPos;
14
+ let consumed = 0;
15
+
16
+ while (pos < ctx.tokens.length) {
17
+ const token = ctx.tokens[pos];
18
+ if (!token) break;
19
+
20
+ if (token.type === "BLOCK_END_OPEN") {
21
+ const closeNameResult = parseBlockName(ctx, pos + 1);
22
+ if (closeNameResult && isEmbedBlockName(closeNameResult.name.toLowerCase())) {
23
+ return { contents: contentParts.join(""), consumed, foundClose: true };
24
+ }
25
+ }
26
+
27
+ contentParts.push(token.value);
28
+ pos++;
29
+ consumed++;
30
+ }
31
+
32
+ return { contents: contentParts.join(""), consumed, foundClose: false };
33
+ }
34
+
35
+ export function consumeEmbedClose(ctx: ParseContext, startPos: number): number {
36
+ let pos = startPos + 1;
37
+ let consumed = 1;
38
+
39
+ const closeNameResult = parseBlockName(ctx, pos);
40
+ if (closeNameResult) {
41
+ pos += closeNameResult.consumed;
42
+ consumed += closeNameResult.consumed;
43
+ }
44
+ if (ctx.tokens[pos]?.type === "BLOCK_CLOSE") {
45
+ pos++;
46
+ consumed++;
47
+ }
48
+ if (ctx.tokens[pos]?.type === "NEWLINE") {
49
+ consumed++;
50
+ }
51
+
52
+ return consumed;
53
+ }
@@ -0,0 +1,91 @@
1
+ /**
2
+ *
3
+ * Block rule for Wikidot embed blocks: `[[embed]]`, `[[embedvideo]]`,
4
+ * and `[[embedaudio]]` (each with a matching closing tag).
5
+ *
6
+ * In original Wikidot, only HTML that matches a server-side allow-list is
7
+ * rendered. This parser does not perform that filtering -- the raw content
8
+ * between the tags is stored verbatim as an `embed-block` element. Validation
9
+ * and sanitisation are expected to happen at rendering time or on the server.
10
+ *
11
+ * The embed block is wrapped in a paragraph container in the AST, matching
12
+ * Wikidot's rendering behaviour where embeds sit inside `<p>` tags.
13
+ *
14
+ * If no closing tag is found, the rule fails to prevent consuming the rest
15
+ * of the document.
16
+ *
17
+ * @module
18
+ */
19
+ import type { Element } from "@wdprlib/ast";
20
+ import type { BlockRule, ParseContext, RuleResult } from "../../types";
21
+ import { currentToken } from "../../types";
22
+ import { collectEmbedContent, consumeEmbedClose } from "./content";
23
+ import { parseEmbedBlockOpen } from "./open";
24
+
25
+ /**
26
+ * Block rule for `[[embed]]`, `[[embedvideo]]`, and `[[embedaudio]]`.
27
+ *
28
+ * Content between the opening and closing tags is captured as raw text.
29
+ * The block name matching is case-insensitive; the closing tag may use
30
+ * any of the three names (`embed`, `embedvideo`, `embedaudio`) regardless
31
+ * of which was used to open.
32
+ */
33
+ export const embedBlockRule: BlockRule = {
34
+ name: "embed-block",
35
+ startTokens: ["BLOCK_OPEN"],
36
+ requiresLineStart: false,
37
+
38
+ parse(ctx: ParseContext): RuleResult<Element> {
39
+ const openToken = currentToken(ctx);
40
+ if (openToken.type !== "BLOCK_OPEN") {
41
+ return { success: false };
42
+ }
43
+
44
+ const openResult = parseEmbedBlockOpen(ctx, ctx.pos);
45
+ if (!openResult) {
46
+ return { success: false };
47
+ }
48
+
49
+ let pos = openResult.pos;
50
+ let consumed = openResult.consumed;
51
+ const contentResult = collectEmbedContent(ctx, pos);
52
+ pos += contentResult.consumed;
53
+ consumed += contentResult.consumed;
54
+
55
+ if (!contentResult.foundClose) {
56
+ ctx.diagnostics.push({
57
+ severity: "warning",
58
+ code: "unclosed-block",
59
+ message: `Missing closing tag [[/${openResult.blockName}]] for [[${openResult.blockName}]]`,
60
+ position: openToken.position,
61
+ });
62
+ return { success: false };
63
+ }
64
+
65
+ const closeConsumed = consumeEmbedClose(ctx, pos);
66
+ pos += closeConsumed;
67
+ consumed += closeConsumed;
68
+
69
+ return {
70
+ success: true,
71
+ elements: [
72
+ {
73
+ element: "container",
74
+ data: {
75
+ type: "paragraph",
76
+ attributes: {},
77
+ elements: [
78
+ {
79
+ element: "embed-block",
80
+ data: {
81
+ contents: contentResult.contents.trim(),
82
+ },
83
+ },
84
+ ],
85
+ },
86
+ },
87
+ ],
88
+ consumed,
89
+ };
90
+ },
91
+ };
@@ -0,0 +1,52 @@
1
+ import type { ParseContext } from "../../types";
2
+ import { parseBlockName } from "../utils";
3
+ import { isEmbedBlockName } from "./tags";
4
+
5
+ export interface EmbedBlockOpenResult {
6
+ blockName: string;
7
+ pos: number;
8
+ consumed: number;
9
+ }
10
+
11
+ export function parseEmbedBlockOpen(
12
+ ctx: ParseContext,
13
+ startPos: number,
14
+ ): EmbedBlockOpenResult | null {
15
+ let pos = startPos;
16
+ let consumed = 0;
17
+
18
+ if (ctx.tokens[pos]?.type !== "BLOCK_OPEN") {
19
+ return null;
20
+ }
21
+ pos++;
22
+ consumed++;
23
+
24
+ const nameResult = parseBlockName(ctx, pos);
25
+ if (!nameResult) {
26
+ return null;
27
+ }
28
+
29
+ const blockName = nameResult.name.toLowerCase();
30
+ if (!isEmbedBlockName(blockName)) {
31
+ return null;
32
+ }
33
+ pos += nameResult.consumed;
34
+ consumed += nameResult.consumed;
35
+
36
+ while (ctx.tokens[pos]?.type === "WHITESPACE") {
37
+ pos++;
38
+ consumed++;
39
+ }
40
+
41
+ if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
42
+ return null;
43
+ }
44
+ pos++;
45
+ consumed++;
46
+
47
+ return {
48
+ blockName,
49
+ pos,
50
+ consumed,
51
+ };
52
+ }
@@ -0,0 +1,5 @@
1
+ const EMBED_BLOCK_NAMES = new Set(["embed", "embedvideo", "embedaudio"]);
2
+
3
+ export function isEmbedBlockName(name: string): boolean {
4
+ return EMBED_BLOCK_NAMES.has(name);
5
+ }