@rocket/js 0.0.0 → 0.1.1

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 (340) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +233 -2
  3. package/dist-types/exports/MainMenu.d.ts +2 -0
  4. package/dist-types/exports/MainMenu.d.ts.map +1 -0
  5. package/dist-types/exports/PageData.d.ts +2 -0
  6. package/dist-types/exports/PageData.d.ts.map +1 -0
  7. package/dist-types/exports/RocketCodeBlock.d.ts +2 -0
  8. package/dist-types/exports/RocketCodeBlock.d.ts.map +1 -0
  9. package/dist-types/exports/RocketIcon.d.ts +2 -0
  10. package/dist-types/exports/RocketIcon.d.ts.map +1 -0
  11. package/dist-types/exports/RocketJsDemo.d.ts +2 -0
  12. package/dist-types/exports/RocketJsDemo.d.ts.map +1 -0
  13. package/dist-types/exports/RocketRequestDemo.d.ts +2 -0
  14. package/dist-types/exports/RocketRequestDemo.d.ts.map +1 -0
  15. package/dist-types/exports/SocialPreviewPlayground.d.ts +2 -0
  16. package/dist-types/exports/SocialPreviewPlayground.d.ts.map +1 -0
  17. package/dist-types/exports/adapters/netlify.d.ts +2 -0
  18. package/dist-types/exports/adapters/netlify.d.ts.map +1 -0
  19. package/dist-types/exports/asyncMessage.d.ts +2 -0
  20. package/dist-types/exports/asyncMessage.d.ts.map +1 -0
  21. package/dist-types/exports/component-hydration.d.ts +2 -0
  22. package/dist-types/exports/component-hydration.d.ts.map +1 -0
  23. package/dist-types/exports/components/web-awesome.d.ts +3 -0
  24. package/dist-types/exports/components/web-awesome.d.ts.map +1 -0
  25. package/dist-types/exports/components.d.ts +2 -0
  26. package/dist-types/exports/components.d.ts.map +1 -0
  27. package/dist-types/exports/config.d.ts +2 -0
  28. package/dist-types/exports/config.d.ts.map +1 -0
  29. package/dist-types/exports/debounce.d.ts +2 -0
  30. package/dist-types/exports/debounce.d.ts.map +1 -0
  31. package/dist-types/exports/define/RocketCodeBlock.d.ts +2 -0
  32. package/dist-types/exports/define/RocketCodeBlock.d.ts.map +1 -0
  33. package/dist-types/exports/define/RocketIcon.d.ts +2 -0
  34. package/dist-types/exports/define/RocketIcon.d.ts.map +1 -0
  35. package/dist-types/exports/define/RocketJsDemo.d.ts +2 -0
  36. package/dist-types/exports/define/RocketJsDemo.d.ts.map +1 -0
  37. package/dist-types/exports/define/RocketRequestDemo.d.ts +2 -0
  38. package/dist-types/exports/define/RocketRequestDemo.d.ts.map +1 -0
  39. package/dist-types/exports/define/menus.d.ts +2 -0
  40. package/dist-types/exports/define/menus.d.ts.map +1 -0
  41. package/dist-types/exports/extractCode.d.ts +2 -0
  42. package/dist-types/exports/extractCode.d.ts.map +1 -0
  43. package/dist-types/exports/globalData.d.ts +2 -0
  44. package/dist-types/exports/globalData.d.ts.map +1 -0
  45. package/dist-types/exports/hydration/hydrationLoader.d.ts +2 -0
  46. package/dist-types/exports/hydration/hydrationLoader.d.ts.map +1 -0
  47. package/dist-types/exports/icons.d.ts +2 -0
  48. package/dist-types/exports/icons.d.ts.map +1 -0
  49. package/dist-types/exports/layout-helper.d.ts +2 -0
  50. package/dist-types/exports/layout-helper.d.ts.map +1 -0
  51. package/dist-types/exports/layout.d.ts +2 -0
  52. package/dist-types/exports/layout.d.ts.map +1 -0
  53. package/dist-types/exports/layouts/atlasDoc.d.ts +2 -0
  54. package/dist-types/exports/layouts/atlasDoc.d.ts.map +1 -0
  55. package/dist-types/exports/layouts/atlasHero.d.ts +2 -0
  56. package/dist-types/exports/layouts/atlasHero.d.ts.map +1 -0
  57. package/dist-types/exports/layouts/atlasNotFound.d.ts +2 -0
  58. package/dist-types/exports/layouts/atlasNotFound.d.ts.map +1 -0
  59. package/dist-types/exports/loaded-page-module.d.ts +2 -0
  60. package/dist-types/exports/loaded-page-module.d.ts.map +1 -0
  61. package/dist-types/exports/markdownHook.d.ts +2 -0
  62. package/dist-types/exports/markdownHook.d.ts.map +1 -0
  63. package/dist-types/exports/menu.d.ts +2 -0
  64. package/dist-types/exports/menu.d.ts.map +1 -0
  65. package/dist-types/exports/menus.d.ts +6 -0
  66. package/dist-types/exports/menus.d.ts.map +1 -0
  67. package/dist-types/exports/page-runtime.d.ts +2 -0
  68. package/dist-types/exports/page-runtime.d.ts.map +1 -0
  69. package/dist-types/exports/pages.d.ts +2 -0
  70. package/dist-types/exports/pages.d.ts.map +1 -0
  71. package/dist-types/exports/resolve.d.ts +2 -0
  72. package/dist-types/exports/resolve.d.ts.map +1 -0
  73. package/dist-types/exports/ssr.d.ts +2 -0
  74. package/dist-types/exports/ssr.d.ts.map +1 -0
  75. package/dist-types/exports/standalone-demo-url.d.ts +2 -0
  76. package/dist-types/exports/standalone-demo-url.d.ts.map +1 -0
  77. package/dist-types/exports/transform.d.ts +2 -0
  78. package/dist-types/exports/transform.d.ts.map +1 -0
  79. package/dist-types/exports/types/hydration.d.ts +23 -0
  80. package/dist-types/exports/types/hydration.d.ts.map +1 -0
  81. package/dist-types/exports/types/rocket.d.ts +504 -0
  82. package/dist-types/exports/types/rocket.d.ts.map +1 -0
  83. package/dist-types/exports/types.d.ts +3 -0
  84. package/dist-types/exports/types.d.ts.map +1 -0
  85. package/dist-types/exports/wds-plugin.d.ts +2 -0
  86. package/dist-types/exports/wds-plugin.d.ts.map +1 -0
  87. package/dist-types/src/PageData.d.ts +82 -0
  88. package/dist-types/src/PageData.d.ts.map +1 -0
  89. package/dist-types/src/RocketCodeBlock.d.ts +64 -0
  90. package/dist-types/src/RocketCodeBlock.d.ts.map +1 -0
  91. package/dist-types/src/RocketIcon.d.ts +35 -0
  92. package/dist-types/src/RocketIcon.d.ts.map +1 -0
  93. package/dist-types/src/RocketJsDemo.d.ts +59 -0
  94. package/dist-types/src/RocketJsDemo.d.ts.map +1 -0
  95. package/dist-types/src/RocketJsDemo.test-browser.d.ts +3 -0
  96. package/dist-types/src/RocketJsDemo.test-browser.d.ts.map +1 -0
  97. package/dist-types/src/RocketRequestDemo.d.ts +57 -0
  98. package/dist-types/src/RocketRequestDemo.d.ts.map +1 -0
  99. package/dist-types/src/RocketRequestDemo.test-browser.d.ts +3 -0
  100. package/dist-types/src/RocketRequestDemo.test-browser.d.ts.map +1 -0
  101. package/dist-types/src/SocialPreviewPlayground.d.ts +102 -0
  102. package/dist-types/src/SocialPreviewPlayground.d.ts.map +1 -0
  103. package/dist-types/src/adapters/netlify.d.ts +54 -0
  104. package/dist-types/src/adapters/netlify.d.ts.map +1 -0
  105. package/dist-types/src/asyncMessage.d.ts +14 -0
  106. package/dist-types/src/asyncMessage.d.ts.map +1 -0
  107. package/dist-types/src/cli/RocketBuild.d.ts +78 -0
  108. package/dist-types/src/cli/RocketBuild.d.ts.map +1 -0
  109. package/dist-types/src/cli/RocketCli.d.ts +17 -0
  110. package/dist-types/src/cli/RocketCli.d.ts.map +1 -0
  111. package/dist-types/src/cli/RocketInit.d.ts +22 -0
  112. package/dist-types/src/cli/RocketInit.d.ts.map +1 -0
  113. package/dist-types/src/cli/RocketStart.d.ts +45 -0
  114. package/dist-types/src/cli/RocketStart.d.ts.map +1 -0
  115. package/dist-types/src/cli/cli.d.ts +3 -0
  116. package/dist-types/src/cli/cli.d.ts.map +1 -0
  117. package/dist-types/src/component-hydration.d.ts +26 -0
  118. package/dist-types/src/component-hydration.d.ts.map +1 -0
  119. package/dist-types/src/components/FeatureList.d.ts +15 -0
  120. package/dist-types/src/components/FeatureList.d.ts.map +1 -0
  121. package/dist-types/src/components/Footer.d.ts +17 -0
  122. package/dist-types/src/components/Footer.d.ts.map +1 -0
  123. package/dist-types/src/components/Header.d.ts +6 -0
  124. package/dist-types/src/components/Header.d.ts.map +1 -0
  125. package/dist-types/src/components/RocketDrawer.d.ts +20 -0
  126. package/dist-types/src/components/RocketDrawer.d.ts.map +1 -0
  127. package/dist-types/src/components/RocketSocialLink.d.ts +30 -0
  128. package/dist-types/src/components/RocketSocialLink.d.ts.map +1 -0
  129. package/dist-types/src/components.d.ts +7 -0
  130. package/dist-types/src/components.d.ts.map +1 -0
  131. package/dist-types/src/config.d.ts +6 -0
  132. package/dist-types/src/config.d.ts.map +1 -0
  133. package/dist-types/src/debounce.d.ts +8 -0
  134. package/dist-types/src/debounce.d.ts.map +1 -0
  135. package/dist-types/src/defaultSocialPreviewTemplate.d.ts +31 -0
  136. package/dist-types/src/defaultSocialPreviewTemplate.d.ts.map +1 -0
  137. package/dist-types/src/development-page-module-loader.d.ts +15 -0
  138. package/dist-types/src/development-page-module-loader.d.ts.map +1 -0
  139. package/dist-types/src/extractCode.d.ts +5 -0
  140. package/dist-types/src/extractCode.d.ts.map +1 -0
  141. package/dist-types/src/hydration/evaluate.d.ts +20 -0
  142. package/dist-types/src/hydration/evaluate.d.ts.map +1 -0
  143. package/dist-types/src/hydration/extractStrategies.d.ts +5 -0
  144. package/dist-types/src/hydration/extractStrategies.d.ts.map +1 -0
  145. package/dist-types/src/hydration/hydrationLoader.d.ts +64 -0
  146. package/dist-types/src/hydration/hydrationLoader.d.ts.map +1 -0
  147. package/dist-types/src/icons.d.ts +182 -0
  148. package/dist-types/src/icons.d.ts.map +1 -0
  149. package/dist-types/src/layouts/atlas/atlasDocLayout.d.ts +45 -0
  150. package/dist-types/src/layouts/atlas/atlasDocLayout.d.ts.map +1 -0
  151. package/dist-types/src/layouts/atlas/atlasHeroLayout.d.ts +7 -0
  152. package/dist-types/src/layouts/atlas/atlasHeroLayout.d.ts.map +1 -0
  153. package/dist-types/src/layouts/atlas/atlasNotFoundLayout.d.ts +5 -0
  154. package/dist-types/src/layouts/atlas/atlasNotFoundLayout.d.ts.map +1 -0
  155. package/dist-types/src/layouts/layout-helper.d.ts +16 -0
  156. package/dist-types/src/layouts/layout-helper.d.ts.map +1 -0
  157. package/dist-types/src/layouts/layout.d.ts +7 -0
  158. package/dist-types/src/layouts/layout.d.ts.map +1 -0
  159. package/dist-types/src/loaded-page-module.d.ts +51 -0
  160. package/dist-types/src/loaded-page-module.d.ts.map +1 -0
  161. package/dist-types/src/main.d.ts +2 -0
  162. package/dist-types/src/main.d.ts.map +1 -0
  163. package/dist-types/src/markdownCompiler.d.ts +22 -0
  164. package/dist-types/src/markdownCompiler.d.ts.map +1 -0
  165. package/dist-types/src/markdownHook.d.ts +6 -0
  166. package/dist-types/src/markdownHook.d.ts.map +1 -0
  167. package/dist-types/src/menu.d.ts +22 -0
  168. package/dist-types/src/menu.d.ts.map +1 -0
  169. package/dist-types/src/menus/MainMenu.d.ts +23 -0
  170. package/dist-types/src/menus/MainMenu.d.ts.map +1 -0
  171. package/dist-types/src/menus/RocketMenu.d.ts +23 -0
  172. package/dist-types/src/menus/RocketMenu.d.ts.map +1 -0
  173. package/dist-types/src/menus/RocketNextPage.d.ts +18 -0
  174. package/dist-types/src/menus/RocketNextPage.d.ts.map +1 -0
  175. package/dist-types/src/menus/RocketPreviousPage.d.ts +18 -0
  176. package/dist-types/src/menus/RocketPreviousPage.d.ts.map +1 -0
  177. package/dist-types/src/menus/RocketToc.d.ts +54 -0
  178. package/dist-types/src/menus/RocketToc.d.ts.map +1 -0
  179. package/dist-types/src/menus/pageNavigation.d.ts +41 -0
  180. package/dist-types/src/menus/pageNavigation.d.ts.map +1 -0
  181. package/dist-types/src/page-pagination.d.ts +69 -0
  182. package/dist-types/src/page-pagination.d.ts.map +1 -0
  183. package/dist-types/src/page-runtime.d.ts +110 -0
  184. package/dist-types/src/page-runtime.d.ts.map +1 -0
  185. package/dist-types/src/pages.d.ts +10 -0
  186. package/dist-types/src/pages.d.ts.map +1 -0
  187. package/dist-types/src/publicAssets.d.ts +70 -0
  188. package/dist-types/src/publicAssets.d.ts.map +1 -0
  189. package/dist-types/src/requestDemoMetadata.d.ts +19 -0
  190. package/dist-types/src/requestDemoMetadata.d.ts.map +1 -0
  191. package/dist-types/src/resolve.d.ts +7 -0
  192. package/dist-types/src/resolve.d.ts.map +1 -0
  193. package/dist-types/src/siteDiscoverability.d.ts +33 -0
  194. package/dist-types/src/siteDiscoverability.d.ts.map +1 -0
  195. package/dist-types/src/siteHeadMetadata.d.ts +20 -0
  196. package/dist-types/src/siteHeadMetadata.d.ts.map +1 -0
  197. package/dist-types/src/socialPreviewImages.d.ts +186 -0
  198. package/dist-types/src/socialPreviewImages.d.ts.map +1 -0
  199. package/dist-types/src/socialPreviewTemplatePreview.d.ts +22 -0
  200. package/dist-types/src/socialPreviewTemplatePreview.d.ts.map +1 -0
  201. package/dist-types/src/ssr.d.ts +6 -0
  202. package/dist-types/src/ssr.d.ts.map +1 -0
  203. package/dist-types/src/standalone-demo-url.d.ts +60 -0
  204. package/dist-types/src/standalone-demo-url.d.ts.map +1 -0
  205. package/dist-types/src/static-page-module-loader.d.ts +15 -0
  206. package/dist-types/src/static-page-module-loader.d.ts.map +1 -0
  207. package/dist-types/src/transform.d.ts +10 -0
  208. package/dist-types/src/transform.d.ts.map +1 -0
  209. package/dist-types/src/urlLifecycle.d.ts +23 -0
  210. package/dist-types/src/urlLifecycle.d.ts.map +1 -0
  211. package/dist-types/src/wds-plugin.d.ts +15 -0
  212. package/dist-types/src/wds-plugin.d.ts.map +1 -0
  213. package/docs/assets/home-background.svg +1 -0
  214. package/docs/assets/prism-one-light.css +368 -0
  215. package/docs/assets/rocket-logo-dark-with-text-below.svg +8 -0
  216. package/docs/assets/rocket-logo-dark-with-text.svg +7 -0
  217. package/docs/assets/rocket-logo-dark.svg +7 -0
  218. package/docs/assets/rocket-logo-light-with-text-below.svg +14 -0
  219. package/docs/assets/rocket-logo-light-with-text.svg +13 -0
  220. package/docs/assets/rocket-logo-light.svg +12 -0
  221. package/docs/assets/rocket-text-no-logo.svg +3 -0
  222. package/exports/MainMenu.js +1 -0
  223. package/exports/PageData.js +1 -0
  224. package/exports/RocketCodeBlock.js +1 -0
  225. package/exports/RocketIcon.js +1 -0
  226. package/exports/RocketJsDemo.js +1 -0
  227. package/exports/RocketRequestDemo.js +1 -0
  228. package/exports/SocialPreviewPlayground.js +1 -0
  229. package/exports/adapters/netlify.js +1 -0
  230. package/exports/asyncMessage.js +1 -0
  231. package/exports/component-hydration.js +1 -0
  232. package/exports/components/web-awesome.js +63 -0
  233. package/exports/components.js +1 -0
  234. package/exports/config.js +1 -0
  235. package/exports/debounce.js +1 -0
  236. package/exports/define/RocketCodeBlock.js +2 -0
  237. package/exports/define/RocketIcon.js +3 -0
  238. package/exports/define/RocketJsDemo.js +5 -0
  239. package/exports/define/RocketRequestDemo.js +5 -0
  240. package/exports/define/menus.js +14 -0
  241. package/exports/extractCode.js +1 -0
  242. package/exports/globalData.js +1 -0
  243. package/exports/hydration/hydrationLoader.js +1 -0
  244. package/exports/icons.js +11 -0
  245. package/exports/layout-helper.js +1 -0
  246. package/exports/layout.js +1 -0
  247. package/exports/layouts/_atlas.css +3 -0
  248. package/exports/layouts/atlasDoc.js +5 -0
  249. package/exports/layouts/atlasHero.js +1 -0
  250. package/exports/layouts/atlasNotFound.js +4 -0
  251. package/exports/loaded-page-module.js +5 -0
  252. package/exports/markdownHook.js +4 -0
  253. package/exports/menu.js +4 -0
  254. package/exports/menus.js +5 -0
  255. package/exports/page-runtime.js +5 -0
  256. package/exports/pages.js +1 -0
  257. package/exports/resolve.js +1 -0
  258. package/exports/ssr.js +1 -0
  259. package/exports/standalone-demo-url.js +10 -0
  260. package/exports/transform.js +1 -0
  261. package/exports/types/hydration.ts +26 -0
  262. package/exports/types/rocket.ts +598 -0
  263. package/exports/types.ts +71 -0
  264. package/exports/wds-plugin.js +1 -0
  265. package/package.json +192 -9
  266. package/src/PageData.js +244 -0
  267. package/src/RocketCodeBlock.js +516 -0
  268. package/src/RocketIcon.js +291 -0
  269. package/src/RocketJsDemo.js +397 -0
  270. package/src/RocketJsDemo.test-browser.js +228 -0
  271. package/src/RocketRequestDemo.js +439 -0
  272. package/src/RocketRequestDemo.test-browser.js +301 -0
  273. package/src/SocialPreviewPlayground.js +573 -0
  274. package/src/adapters/netlify.js +814 -0
  275. package/src/asyncMessage.js +21 -0
  276. package/src/cli/RocketBuild.js +581 -0
  277. package/src/cli/RocketCli.js +47 -0
  278. package/src/cli/RocketInit.js +636 -0
  279. package/src/cli/RocketStart.js +145 -0
  280. package/src/cli/cli.js +7 -0
  281. package/src/component-hydration.js +86 -0
  282. package/src/components/FeatureList.js +114 -0
  283. package/src/components/Footer.js +116 -0
  284. package/src/components/Header.js +122 -0
  285. package/src/components/RocketDrawer.js +193 -0
  286. package/src/components/RocketSocialLink.js +128 -0
  287. package/src/components/assets/discord.svg +7 -0
  288. package/src/components/assets/github.svg +4 -0
  289. package/src/components/assets/gitlab.svg +1 -0
  290. package/src/components/assets/info.txt +1 -0
  291. package/src/components/assets/license.svg +3 -0
  292. package/src/components/assets/npm.svg +5 -0
  293. package/src/components/assets/slack.svg +5 -0
  294. package/src/components/assets/telegram.svg +4 -0
  295. package/src/components/assets/twitter.svg +1 -0
  296. package/src/components.js +34 -0
  297. package/src/config.js +319 -0
  298. package/src/debounce.js +21 -0
  299. package/src/defaultSocialPreviewTemplate.js +118 -0
  300. package/src/development-page-module-loader.js +29 -0
  301. package/src/extractCode.js +41 -0
  302. package/src/hydration/evaluate.js +54 -0
  303. package/src/hydration/extractStrategies.js +91 -0
  304. package/src/hydration/hydrationLoader.js +330 -0
  305. package/src/icons.js +898 -0
  306. package/src/layouts/atlas/atlasDoc.css +877 -0
  307. package/src/layouts/atlas/atlasDocLayout.js +275 -0
  308. package/src/layouts/atlas/atlasHero.css +774 -0
  309. package/src/layouts/atlas/atlasHeroLayout.js +337 -0
  310. package/src/layouts/atlas/atlasNotFound.css +365 -0
  311. package/src/layouts/atlas/atlasNotFoundLayout.js +69 -0
  312. package/src/layouts/layout-helper.js +92 -0
  313. package/src/layouts/layout.js +52 -0
  314. package/src/loaded-page-module.js +97 -0
  315. package/src/main.js +72 -0
  316. package/src/markdownCompiler.js +303 -0
  317. package/src/markdownHook.js +148 -0
  318. package/src/menu.js +210 -0
  319. package/src/menus/MainMenu.js +58 -0
  320. package/src/menus/RocketMenu.js +191 -0
  321. package/src/menus/RocketNextPage.js +25 -0
  322. package/src/menus/RocketPreviousPage.js +29 -0
  323. package/src/menus/RocketToc.js +309 -0
  324. package/src/menus/pageNavigation.js +285 -0
  325. package/src/page-pagination.js +241 -0
  326. package/src/page-runtime.js +481 -0
  327. package/src/pages.js +537 -0
  328. package/src/publicAssets.js +336 -0
  329. package/src/requestDemoMetadata.js +97 -0
  330. package/src/resolve.js +15 -0
  331. package/src/siteDiscoverability.js +184 -0
  332. package/src/siteHeadMetadata.js +69 -0
  333. package/src/socialPreviewImages.js +482 -0
  334. package/src/socialPreviewTemplatePreview.js +352 -0
  335. package/src/ssr.js +14 -0
  336. package/src/standalone-demo-url.js +147 -0
  337. package/src/static-page-module-loader.js +29 -0
  338. package/src/transform.js +720 -0
  339. package/src/urlLifecycle.js +57 -0
  340. package/src/wds-plugin.js +307 -0
@@ -0,0 +1,720 @@
1
+ /** Runs on: import-hook */
2
+ import markdown from 'remark-parse';
3
+ import { unified } from 'unified';
4
+ import gfm from 'remark-gfm';
5
+ import remark2rehype from 'remark-rehype';
6
+ import rehypePrism from 'rehype-prism-plus';
7
+ import rawHtml from 'rehype-raw';
8
+ import htmlStringify from 'rehype-stringify';
9
+ import rehypeSlug from 'rehype-slug';
10
+ import rehypeLinkHeadings from 'rehype-autolink-headings';
11
+ import { extractMdCode } from './extractCode.js';
12
+ import { visit } from 'unist-util-visit';
13
+ import { init, parse as parseExports } from 'es-module-lexer';
14
+ import { headLinesToTree } from './menu.js';
15
+ import { parseRequestDemoMetadata } from './requestDemoMetadata.js';
16
+ import ts from 'typescript';
17
+
18
+ /** @type {import('rehype-autolink-headings').Options} */
19
+ const headingAnchorOptions = {
20
+ behavior: 'append',
21
+ properties: {
22
+ className: ['heading-anchor'],
23
+ ariaLabel: 'Link to this heading',
24
+ },
25
+ content: {
26
+ type: 'text',
27
+ value: '#',
28
+ },
29
+ };
30
+
31
+ /**
32
+ * @param {string} md
33
+ */
34
+ export async function mdToJs(md) {
35
+ const result = await unified()
36
+ .use(markdown)
37
+ .use(gfm)
38
+ .use(extractMdCode('server'))
39
+ .use(extractMdCode('client'))
40
+ .use(parseDemos)
41
+ .use(parseRequestDemos)
42
+ .use(captureCodeBlockData)
43
+ .use(escapeRocketMd)
44
+ .use(remark2rehype, { allowDangerousHtml: true })
45
+ // now html
46
+ .use(rawHtml)
47
+ .use(fixImageTags)
48
+ .use(rehypePrism)
49
+ .use(wrapCodeBlocks)
50
+ .use(escapeCodeBlocks)
51
+ .use(rehypeSlug)
52
+ .use(rehypeLinkHeadings, headingAnchorOptions)
53
+ .use(extractHeadings)
54
+
55
+ .use(htmlStringify)
56
+ .process(md);
57
+
58
+ const code = /** @type {{client: string; server: string}} */ (result.data.code);
59
+ const headlines = /** @type {import('@rocket/js/types.js').Headline[]} */ (result.data.headings);
60
+
61
+ const moduleCode = await makeJsFile(
62
+ code.server,
63
+ code.client || '',
64
+ result.value.toString(),
65
+ headlines,
66
+ );
67
+ return moduleCode;
68
+ }
69
+
70
+ /**
71
+ * @param {string} md
72
+ * @param {string} demo
73
+ */
74
+ export async function mdToJsSingleDemo(md, demo) {
75
+ const result = await unified()
76
+ .use(markdown)
77
+ .use(extractMdCode('server'))
78
+ .use(extractMdCode('client'))
79
+ .use(extractSingleDemo, demo)
80
+ .use(captureCodeBlockData)
81
+ .use(remark2rehype, { allowDangerousHtml: true })
82
+ // now html
83
+ .use(rawHtml)
84
+ .use(rehypePrism)
85
+ .use(wrapCodeBlocks)
86
+ .use(escapeCodeBlocks)
87
+
88
+ .use(htmlStringify)
89
+ .process(md);
90
+
91
+ const code = /** @type {{client: string; server: string}} */ (result.data.code);
92
+
93
+ let litImport = "import { html } from 'lit'";
94
+ if (/import\s*?{(?:\n|.)*?html(\n|.)*}.*/m.test(code.server)) {
95
+ litImport = '';
96
+ }
97
+ const moduleCode = `
98
+ import {render} from '@lit-labs/ssr';
99
+ ${litImport}
100
+ ${code.server}
101
+ export function contentFn(data, layout) {
102
+ data._clientCode = \`${code.client
103
+ .replace(/\\/g, '\\\\')
104
+ .replace(/\$/g, '\\$')
105
+ .replace(/`/g, '\\`')}\`;
106
+ data.content = html\`${result.value.toString()}\`;
107
+
108
+ const layoutResult = layout(data);
109
+ return render(layoutResult);
110
+ }`;
111
+ return moduleCode;
112
+ }
113
+
114
+ /**
115
+ * @param {string} serverCode
116
+ * @param {string} clientCode
117
+ * @param {string} markdown
118
+ * @param {import('@rocket/js/types.js').Headline[]} headlines
119
+ * @returns {Promise<string>}
120
+ */
121
+ async function makeJsFile(serverCode, clientCode, markdown, headlines) {
122
+ let litImport = "import { html } from 'lit'";
123
+ const normalizedServerCode = normalizeLayoutExportBindings(serverCode);
124
+ if (/import\s*?{(?:\n|.)*?html(\n|.)*}.*/m.test(normalizedServerCode)) {
125
+ litImport = '';
126
+ }
127
+ return `
128
+ import {render} from '@lit-labs/ssr';
129
+ ${litImport}
130
+ ${normalizedServerCode}
131
+ export function contentFn(data, defaultLayout) {
132
+ let renderLayout = defaultLayout;
133
+ if (typeof layout !== 'undefined') {
134
+ renderLayout = layout;
135
+ }
136
+ data._clientCode = \`${clientCode
137
+ .replace(/\\/g, '\\\\')
138
+ .replace(/\$/g, '\\$')
139
+ .replace(/`/g, '\\`')}\`;
140
+ data.content = html\`${markdown}\`;
141
+ data.toc = ${JSON.stringify(headLinesToTree(headlines))};
142
+
143
+ const layoutResult = renderLayout(data);
144
+ return render(layoutResult);
145
+ }`;
146
+ }
147
+
148
+ /**
149
+ * Direct ESM re-exports do not create local bindings, but the generated Markdown module calls the
150
+ * selected layout from inside contentFn. Rewriting only direct `layout` re-exports keeps the public
151
+ * Page syntax working while preserving the generated function's local binding lookup.
152
+ *
153
+ * @param {string} serverCode
154
+ * @returns {string}
155
+ */
156
+ function normalizeLayoutExportBindings(serverCode) {
157
+ if (typeof serverCode !== 'string') {
158
+ return '';
159
+ }
160
+ const sourceFile = ts.createSourceFile(
161
+ 'page-server.js',
162
+ serverCode,
163
+ ts.ScriptTarget.Latest,
164
+ true,
165
+ ts.ScriptKind.JS,
166
+ );
167
+ /** @type {{start: number; end: number; text: string}[]} */
168
+ const replacements = [];
169
+
170
+ for (const statement of sourceFile.statements) {
171
+ if (
172
+ !ts.isExportDeclaration(statement) ||
173
+ !statement.moduleSpecifier ||
174
+ !statement.exportClause ||
175
+ !ts.isNamedExports(statement.exportClause)
176
+ ) {
177
+ continue;
178
+ }
179
+
180
+ const layoutExport = statement.exportClause.elements.find(
181
+ element => element.name.text === 'layout',
182
+ );
183
+ if (!layoutExport) {
184
+ continue;
185
+ }
186
+
187
+ const moduleSpecifier = statement.moduleSpecifier.getText(sourceFile);
188
+ const attributes = statement.attributes ? ` ${statement.attributes.getText(sourceFile)}` : '';
189
+ const importedName = (layoutExport.propertyName || layoutExport.name).getText(sourceFile);
190
+ const layoutImportSpecifier =
191
+ importedName === 'layout' ? 'layout' : `${importedName} as layout`;
192
+ const replacementLines = [
193
+ `import { ${layoutImportSpecifier} } from ${moduleSpecifier}${attributes};`,
194
+ 'export { layout };',
195
+ ];
196
+
197
+ const remainingExports = statement.exportClause.elements.filter(
198
+ element => element !== layoutExport,
199
+ );
200
+ if (remainingExports.length) {
201
+ const remainingSpecifiers = remainingExports.map(element => {
202
+ if (element.propertyName) {
203
+ return `${element.propertyName.getText(sourceFile)} as ${element.name.getText(sourceFile)}`;
204
+ }
205
+ return element.name.getText(sourceFile);
206
+ });
207
+ replacementLines.push(
208
+ `export { ${remainingSpecifiers.join(', ')} } from ${moduleSpecifier}${attributes};`,
209
+ );
210
+ }
211
+
212
+ replacements.push({
213
+ start: statement.getStart(sourceFile),
214
+ end: statement.end,
215
+ text: replacementLines.join('\n'),
216
+ });
217
+ }
218
+
219
+ if (!replacements.length) {
220
+ return serverCode;
221
+ }
222
+
223
+ let normalizedCode = serverCode;
224
+ for (const replacement of replacements.toReversed()) {
225
+ normalizedCode =
226
+ normalizedCode.slice(0, replacement.start) +
227
+ replacement.text +
228
+ normalizedCode.slice(replacement.end);
229
+ }
230
+ return normalizedCode;
231
+ }
232
+
233
+ function parseDemos() {
234
+ /** @type {{name: string, code: string}[]} */
235
+ const demos = [];
236
+
237
+ /** @type {import('unist-util-visit').Visitor} */
238
+ const visitor = _node => {
239
+ const node = /** @type {import('mdast').Code & {visited: boolean}} */ (_node);
240
+ if (isDemoCodeNode(node) && typeof node.value === 'string' && !node.visited) {
241
+ const codePreview = structuredClone(node);
242
+ codePreview.visited = true;
243
+ codePreview.meta = demoCodeBlockMeta(node.meta);
244
+ const code = node.value;
245
+ const parsed = parseExports(code);
246
+ const name = parsed[1][0].ln || parsed[1][0].n;
247
+ // we transform a code node into a root node, so cast
248
+ const rootNode = /** @type {import('mdast').Root} */ (/** @type {unknown} */ (node));
249
+ rootNode.type = 'root';
250
+ rootNode.children = [
251
+ { type: 'html', value: `<rocket-js-demo demo-name="${name}">` },
252
+ { type: 'text', value: '\n\n' },
253
+ codePreview,
254
+ { type: 'text', value: '\n\n' },
255
+ { type: 'html', value: '</rocket-js-demo>' },
256
+ ];
257
+ // root nodes don't have values
258
+ // @ts-ignore
259
+ delete node.value;
260
+ delete node.lang;
261
+ delete node.meta;
262
+ demos.push({ name, code });
263
+ }
264
+ };
265
+
266
+ /**
267
+ * @param {import('unist').Node} tree
268
+ * @param {import('vfile').VFile} file
269
+ */
270
+ return async function (tree, file) {
271
+ await init;
272
+ visit(tree, 'code', visitor);
273
+ if (!file.data) {
274
+ file.data = {};
275
+ }
276
+
277
+ const code = /** @type {{client: string}} */ (file.data?.code);
278
+
279
+ if (demos.length) {
280
+ const demoCode = demos.map(demo => demo.code).join('\n');
281
+ const invokeDemosCode = demos
282
+ .map(demo => `{key: '${demo.name}', demo: ${demo.name}}`)
283
+ .join(', ');
284
+
285
+ // @ts-ignore
286
+ file.data.code.client = [
287
+ '// client code',
288
+ code.client + ';',
289
+ '// demo code',
290
+ demoCode,
291
+ '// demo setup code',
292
+ 'let needsElements = false;',
293
+ `for (const demo of [${invokeDemosCode}]) {`,
294
+ ' const element = document.querySelector(`rocket-js-demo[demo-name="${demo.key}"]`);',
295
+ ' if (element) {',
296
+ ' needsElements = true;',
297
+ ' element.demo = demo.demo;',
298
+ ' }',
299
+ '}',
300
+ 'if (needsElements) {',
301
+ ' import("@rocket/js/define/RocketJsDemo.js");',
302
+ '}',
303
+ ].join('\n');
304
+ }
305
+
306
+ return tree;
307
+ };
308
+ }
309
+
310
+ function parseRequestDemos() {
311
+ /** @type {import('unist-util-visit').Visitor} */
312
+ const visitor = _node => {
313
+ const node = /** @type {import('mdast').Code & {visited: boolean}} */ (_node);
314
+ if (!isRequestDemoCodeNode(node) || typeof node.value !== 'string' || node.visited) {
315
+ return;
316
+ }
317
+
318
+ const metadata = parseRequestDemoMetadata(node.meta);
319
+ const codePreview = structuredClone(node);
320
+ codePreview.visited = true;
321
+ codePreview.meta = metadata.label
322
+ ? `label="${escapeFenceAttribute(metadata.label)}"`
323
+ : undefined;
324
+
325
+ const rootNode = /** @type {import('mdast').Root} */ (/** @type {unknown} */ (node));
326
+ rootNode.type = 'root';
327
+ rootNode.children = [
328
+ { type: 'html', value: requestDemoFallbackStart(metadata) },
329
+ { type: 'text', value: '\n\n' },
330
+ codePreview,
331
+ { type: 'text', value: '\n\n' },
332
+ { type: 'html', value: requestDemoFallbackEnd() },
333
+ ];
334
+ // root nodes don't have values
335
+ // @ts-ignore
336
+ delete node.value;
337
+ delete node.lang;
338
+ delete node.meta;
339
+ };
340
+
341
+ /**
342
+ * @param {import('unist').Node} tree
343
+ */
344
+ return function (tree) {
345
+ visit(tree, 'code', visitor);
346
+ return tree;
347
+ };
348
+ }
349
+
350
+ /**
351
+ * @param {import('mdast').Code} node
352
+ */
353
+ function isRequestDemoCodeNode(node) {
354
+ return node.lang === 'js' && /^request-demo(?:\s|$)/.test(node.meta || '');
355
+ }
356
+
357
+ /**
358
+ * @param {import('mdast').Code} node
359
+ */
360
+ function isDemoCodeNode(node) {
361
+ return node.lang === 'js' && /(?:^|\s)demo(?:\s|$)/.test(node.meta || '');
362
+ }
363
+
364
+ /**
365
+ * @param {string | null | undefined} meta
366
+ */
367
+ function demoCodeBlockMeta(meta) {
368
+ const codeBlockMeta = (meta || '').replace(/(?:^|\s)demo(?=\s|$)/, ' ').trim();
369
+
370
+ return codeBlockMeta || undefined;
371
+ }
372
+
373
+ /**
374
+ * @param {import('./requestDemoMetadata.js').RequestDemoMetadata} metadata
375
+ */
376
+ function requestDemoFallbackStart(metadata) {
377
+ const urlAttribute = escapeHtmlAttribute(metadata.url);
378
+ const labelAttribute = metadata.label ? ` label="${escapeHtmlAttribute(metadata.label)}"` : '';
379
+ const heightAttribute = metadata.height !== undefined ? ` height="${metadata.height}"` : '';
380
+
381
+ return `<rocket-request-demo url="${urlAttribute}"${labelAttribute}${heightAttribute}>`;
382
+ }
383
+
384
+ function requestDemoFallbackEnd() {
385
+ return '</rocket-request-demo>';
386
+ }
387
+
388
+ /**
389
+ * @param {string} demoName
390
+ */
391
+ function extractSingleDemo(demoName) {
392
+ /** @type {{name: string, code: string, node: import('mdast').Root} | null} */
393
+ let demo = null;
394
+
395
+ /** @type {import('unist-util-visit').Visitor} */
396
+ const visitor = _node => {
397
+ const node = /** @type {import('mdast').Code & {visited: boolean}} */ (_node);
398
+ if (isDemoCodeNode(node) && typeof node.value === 'string' && !node.visited) {
399
+ const codePreview = structuredClone(node);
400
+ codePreview.visited = true;
401
+ codePreview.meta = demoCodeBlockMeta(node.meta);
402
+ const code = node.value;
403
+ const parsed = parseExports(code);
404
+ const name = parsed[1][0].ln || parsed[1][0].n;
405
+ if (name !== demoName) {
406
+ return;
407
+ }
408
+ // we transform a code node into a root node, so cast
409
+ const rootNode = /** @type {import('mdast').Root} */ (/** @type {unknown} */ (node));
410
+ rootNode.type = 'root';
411
+ rootNode.children = [
412
+ {
413
+ type: 'html',
414
+ value: `<rocket-js-demo demo-name="${name}" single-demo>`,
415
+ },
416
+ { type: 'text', value: '\n\n' },
417
+ codePreview,
418
+ { type: 'text', value: '\n\n' },
419
+ { type: 'html', value: '</rocket-js-demo>' },
420
+ ];
421
+ // root nodes don't have values
422
+ // @ts-ignore
423
+ delete node.value;
424
+ delete node.lang;
425
+ delete node.meta;
426
+ demo = { name, code, node: rootNode };
427
+ }
428
+ };
429
+
430
+ /**
431
+ * @param {import('unist').Node} tree
432
+ * @param {import('vfile').VFile} file
433
+ */
434
+ return async function (tree, file) {
435
+ await init;
436
+ visit(tree, 'code', visitor);
437
+ if (!file.data) {
438
+ file.data = {};
439
+ }
440
+
441
+ if (demo) {
442
+ Object.assign(tree, demo?.node);
443
+ const code = /** @type {{client: string}} */ (file.data?.code);
444
+ // @ts-ignore
445
+ file.data.code.client = [
446
+ '// client code',
447
+ code.client + ';',
448
+ '// demo code',
449
+ demo.code + ';',
450
+ '// demo setup code',
451
+ `const element = document.querySelector(\`rocket-js-demo[demo-name="${demo.name}"]\`);`,
452
+ `element.demo = ${demo.name};`,
453
+ 'import("@rocket/js/define/RocketJsDemo.js");',
454
+ ].join('\n');
455
+ }
456
+
457
+ return tree;
458
+ };
459
+ }
460
+
461
+ function captureCodeBlockData() {
462
+ /** @type {import('unist-util-visit').Visitor} */
463
+ const visitor = _node => {
464
+ const node = /** @type {import('mdast').Code} */ (_node);
465
+ const label = parseCodeBlockLabel(node.meta);
466
+ node.data = node.data || {};
467
+ node.data.hProperties = {
468
+ ...node.data.hProperties,
469
+ ...(node.meta ? { metastring: node.meta } : {}),
470
+ 'data-rocket-code-label': label || '',
471
+ 'data-rocket-code-language': node.lang || '',
472
+ 'data-rocket-code-encoded': Buffer.from(node.value, 'utf8').toString('base64'),
473
+ };
474
+ };
475
+
476
+ /**
477
+ * @param {import('unist').Node} tree
478
+ */
479
+ return function (tree) {
480
+ visit(tree, 'code', visitor);
481
+ return tree;
482
+ };
483
+ }
484
+
485
+ /**
486
+ * @param {string | null | undefined} meta
487
+ */
488
+ function parseCodeBlockLabel(meta) {
489
+ if (!meta) {
490
+ return undefined;
491
+ }
492
+ return /(?:^|\s)label="([^"]+)"/.exec(meta)?.[1];
493
+ }
494
+
495
+ /**
496
+ * @param {string} value
497
+ */
498
+ function escapeFenceAttribute(value) {
499
+ return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
500
+ }
501
+
502
+ /**
503
+ * @param {string} value
504
+ */
505
+ function escapeHtml(value) {
506
+ return value.replace(/[&<>"'`$\\]/g, char => htmlEscapes[char]);
507
+ }
508
+
509
+ /**
510
+ * @param {string} value
511
+ */
512
+ function escapeHtmlAttribute(value) {
513
+ return escapeHtml(value);
514
+ }
515
+
516
+ /** @type {Record<string, string>} */
517
+ const htmlEscapes = {
518
+ '&': '&amp;',
519
+ '<': '&lt;',
520
+ '>': '&gt;',
521
+ '"': '&quot;',
522
+ "'": '&#39;',
523
+ '`': '&#96;',
524
+ $: '&#36;',
525
+ '\\': '&#92;',
526
+ };
527
+
528
+ function wrapCodeBlocks() {
529
+ /** @type {import('unist-util-visit').Visitor} */
530
+ const visitor = (_node, index, _parent) => {
531
+ const pre = /** @type {import('hast').Element} */ (_node);
532
+ const parent = /** @type {import('hast').Element} */ (_parent);
533
+ const code = pre.children.find(child => child.type === 'element' && child.tagName === 'code');
534
+ if (!code || code.type !== 'element') {
535
+ return;
536
+ }
537
+
538
+ delete code.properties.metastring;
539
+ const label = readStringProperty(
540
+ code.properties['data-rocket-code-label'] ?? code.properties.dataRocketCodeLabel,
541
+ );
542
+ const encodedCode = readStringProperty(
543
+ code.properties['data-rocket-code-encoded'] ?? code.properties.dataRocketCodeEncoded,
544
+ );
545
+ if (encodedCode === undefined || index === undefined) {
546
+ return;
547
+ }
548
+
549
+ const language = readStringProperty(
550
+ code.properties['data-rocket-code-language'] ?? code.properties.dataRocketCodeLanguage,
551
+ );
552
+ delete code.properties['data-rocket-code-label'];
553
+ delete code.properties.dataRocketCodeLabel;
554
+ delete code.properties['data-rocket-code-language'];
555
+ delete code.properties.dataRocketCodeLanguage;
556
+ delete code.properties['data-rocket-code-encoded'];
557
+ delete code.properties.dataRocketCodeEncoded;
558
+
559
+ const properties = {
560
+ ...(label ? { label } : {}),
561
+ ...(language ? { language } : {}),
562
+ 'encoded-code': encodedCode,
563
+ };
564
+
565
+ parent.children[index] = {
566
+ type: 'element',
567
+ tagName: 'rocket-code-block',
568
+ properties,
569
+ children: [pre],
570
+ };
571
+ };
572
+
573
+ /**
574
+ * @param {import('unist').Node} tree
575
+ * @returns {import('unist').Node}
576
+ */
577
+ return function (tree) {
578
+ visit(tree, { type: 'element', tagName: 'pre' }, visitor);
579
+ return tree;
580
+ };
581
+ }
582
+
583
+ /**
584
+ * @param {unknown} value
585
+ */
586
+ function readStringProperty(value) {
587
+ if (Array.isArray(value)) {
588
+ return value.join(' ');
589
+ }
590
+ return typeof value === 'string' ? value : undefined;
591
+ }
592
+
593
+ /**
594
+ * @param {string} string
595
+ * @returns {string}
596
+ */
597
+ function escapeOutsideTemplates(string) {
598
+ let result = '';
599
+ let templateLevels = 0;
600
+ for (let i = 0; i < string.length; i++) {
601
+ if (string[i] === '$' && string[i + 1] === '{' && string[i - 1] !== '\\') {
602
+ templateLevels++;
603
+ } else if (templateLevels && string[i] === '}') {
604
+ templateLevels--;
605
+ }
606
+ if (templateLevels) {
607
+ result += string[i];
608
+ } else {
609
+ result += string[i].replace('\\', '\\\\').replace('`', '\\`');
610
+ }
611
+ }
612
+
613
+ return result;
614
+ }
615
+
616
+ function escapeRocketMd() {
617
+ /** @type {import('unist-util-visit').Visitor} */
618
+ const visitor = _node => {
619
+ const node = /** @type {import('mdast').Text} */ (_node);
620
+ if (node.type === 'text' && typeof node.value === 'string') {
621
+ node.value = escapeOutsideTemplates(node.value);
622
+ }
623
+ };
624
+
625
+ /**
626
+ * @param {import('unist').Node} tree
627
+ */
628
+ return function (tree) {
629
+ visit(tree, 'text', visitor);
630
+ return tree;
631
+ };
632
+ }
633
+
634
+ function fixImageTags() {
635
+ /** @type {import('unist-util-visit').Visitor} */
636
+ const visitor = _node => {
637
+ const node = /** @type {import('hast').Element} */ (_node);
638
+ if (node.type === 'element' && node.tagName === 'img') {
639
+ const props = node.properties || {};
640
+ const src = typeof props.src === 'string' ? decodeURIComponent(props.src) : props.src;
641
+
642
+ node.properties = { ...props, src };
643
+ }
644
+ };
645
+
646
+ /**
647
+ * @param {import('unist').Node} tree
648
+ */
649
+ return function (tree) {
650
+ visit(tree, 'element', visitor);
651
+ return tree;
652
+ };
653
+ }
654
+
655
+ /**
656
+ * visits all 'pre > code' elements and escapes any text inside
657
+ */
658
+ function escapeCodeBlocks() {
659
+ /** @type {import('unist-util-visit').Visitor} */
660
+ const visitor = (_node, _, _parent) => {
661
+ const node = /** @type {import('hast').Element} */ (_node);
662
+ const parent = /** @type {import('hast').Element} */ (_parent);
663
+ if (parent?.type === 'element' && parent.tagName === 'pre') {
664
+ visit(node, 'text', replacer);
665
+ }
666
+ };
667
+
668
+ /** @type {import('unist-util-visit').Visitor} */
669
+ const replacer = _node => {
670
+ const node = /** @type {import('hast').Text} */ (_node);
671
+ if (typeof node.value !== 'string') {
672
+ return;
673
+ }
674
+ node.value = node.value.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$/g, '\\$');
675
+ };
676
+
677
+ /**
678
+ * @param {import('unist').Node} tree
679
+ * @returns {import('unist').Node}
680
+ */
681
+ return function (tree) {
682
+ visit(tree, { type: 'element', tagName: 'code' }, visitor);
683
+ return tree;
684
+ };
685
+ }
686
+
687
+ function extractHeadings() {
688
+ /** @type {import('@rocket/js/types.js').Headline[]} */
689
+ const headings = [];
690
+
691
+ /** @type {import('unist-util-visit').Visitor} */
692
+ const visitor = _node => {
693
+ const node = /** @type {import('hast').Element} */ (_node);
694
+ if ('menu-exclude' in node.properties) {
695
+ return;
696
+ }
697
+ const match = node.tagName.match(/h([1-6])/);
698
+ const text = /** @type {string} */ (
699
+ node.properties['link-text'] ||
700
+ node.children.find(child => child.type === 'text')?.value ||
701
+ ''
702
+ );
703
+ if (match) {
704
+ const id = node.properties?.id;
705
+ if (typeof id === 'string') {
706
+ headings.push({ id, level: parseInt(match[1]), text });
707
+ }
708
+ }
709
+ };
710
+
711
+ /**
712
+ * @param {import('unist').Node} tree
713
+ * @param {import('vfile').VFile} file
714
+ */
715
+ return function (tree, file) {
716
+ visit(tree, { type: 'element' }, visitor);
717
+ file.data.headings = headings;
718
+ return tree;
719
+ };
720
+ }