repl-sdk 0.0.0 → 1.0.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 (305) hide show
  1. package/dist/apl-fqmucPXA.js +141 -0
  2. package/dist/apl-fqmucPXA.js.map +1 -0
  3. package/dist/asciiarmor-DucZyvP0.js +57 -0
  4. package/dist/asciiarmor-DucZyvP0.js.map +1 -0
  5. package/dist/asn1-BnOEsgAm.js +145 -0
  6. package/dist/asn1-BnOEsgAm.js.map +1 -0
  7. package/dist/assets/tar-worker-CxTcoQcr.js +593 -0
  8. package/dist/assets/tar-worker-CxTcoQcr.js.map +1 -0
  9. package/dist/asterisk-QAlztEwS.js +346 -0
  10. package/dist/asterisk-QAlztEwS.js.map +1 -0
  11. package/dist/brainfuck-DZVCuF_t.js +54 -0
  12. package/dist/brainfuck-DZVCuF_t.js.map +1 -0
  13. package/dist/clike-CTYGlS6x.js +800 -0
  14. package/dist/clike-CTYGlS6x.js.map +1 -0
  15. package/dist/clojure-BhXMqnxz.js +850 -0
  16. package/dist/clojure-BhXMqnxz.js.map +1 -0
  17. package/dist/cmake-BGaNd9E7.js +72 -0
  18. package/dist/cmake-BGaNd9E7.js.map +1 -0
  19. package/dist/cobol-4yqQntpt.js +121 -0
  20. package/dist/cobol-4yqQntpt.js.map +1 -0
  21. package/dist/codemirror-De3S70Np.js +2912 -0
  22. package/dist/codemirror-De3S70Np.js.map +1 -0
  23. package/dist/coffeescript-D2dXvhEc.js +309 -0
  24. package/dist/coffeescript-D2dXvhEc.js.map +1 -0
  25. package/dist/commonlisp-CF_VNHQR.js +131 -0
  26. package/dist/commonlisp-CF_VNHQR.js.map +1 -0
  27. package/dist/crystal-DyuLTqLs.js +399 -0
  28. package/dist/crystal-DyuLTqLs.js.map +1 -0
  29. package/dist/css-DkSyTW67.js +1773 -0
  30. package/dist/css-DkSyTW67.js.map +1 -0
  31. package/dist/cypher-Dlu_3r4V.js +122 -0
  32. package/dist/cypher-Dlu_3r4V.js.map +1 -0
  33. package/dist/d-UURgV0Ux.js +180 -0
  34. package/dist/d-UURgV0Ux.js.map +1 -0
  35. package/dist/diff-B_Bi2Crb.js +26 -0
  36. package/dist/diff-B_Bi2Crb.js.map +1 -0
  37. package/dist/dockerfile-Bvk733Ga.js +202 -0
  38. package/dist/dockerfile-Bvk733Ga.js.map +1 -0
  39. package/dist/dtd-Dy74G54E.js +115 -0
  40. package/dist/dtd-Dy74G54E.js.map +1 -0
  41. package/dist/dylan-TSb-Nfix.js +315 -0
  42. package/dist/dylan-TSb-Nfix.js.map +1 -0
  43. package/dist/ebnf-4fKAGW3a.js +141 -0
  44. package/dist/ebnf-4fKAGW3a.js.map +1 -0
  45. package/dist/ecl-B59qGGVg.js +179 -0
  46. package/dist/ecl-B59qGGVg.js.map +1 -0
  47. package/dist/eiffel-Dze7nlu3.js +135 -0
  48. package/dist/eiffel-Dze7nlu3.js.map +1 -0
  49. package/dist/elm-DG7jkhNZ.js +177 -0
  50. package/dist/elm-DG7jkhNZ.js.map +1 -0
  51. package/dist/erlang-BO6gOnGA.js +675 -0
  52. package/dist/erlang-BO6gOnGA.js.map +1 -0
  53. package/dist/factor-CMxFHDqz.js +66 -0
  54. package/dist/factor-CMxFHDqz.js.map +1 -0
  55. package/dist/fcl-CDDUNjTj.js +142 -0
  56. package/dist/fcl-CDDUNjTj.js.map +1 -0
  57. package/dist/forth-B9D2JCeE.js +117 -0
  58. package/dist/forth-B9D2JCeE.js.map +1 -0
  59. package/dist/fortran-CAG2BFbe.js +468 -0
  60. package/dist/fortran-CAG2BFbe.js.map +1 -0
  61. package/dist/gas-0Aw8zDr5.js +294 -0
  62. package/dist/gas-0Aw8zDr5.js.map +1 -0
  63. package/dist/gherkin-DhZlEZiy.js +116 -0
  64. package/dist/gherkin-DhZlEZiy.js.map +1 -0
  65. package/dist/gjs-DfguZDLq.js +173 -0
  66. package/dist/gjs-DfguZDLq.js.map +1 -0
  67. package/dist/gmd-Yas-Oo8k.js +163 -0
  68. package/dist/gmd-Yas-Oo8k.js.map +1 -0
  69. package/dist/groovy-CpwJiBl7.js +224 -0
  70. package/dist/groovy-CpwJiBl7.js.map +1 -0
  71. package/dist/haskell-ySd-OUo8.js +460 -0
  72. package/dist/haskell-ySd-OUo8.js.map +1 -0
  73. package/dist/haxe-7MlzfeYV.js +515 -0
  74. package/dist/haxe-7MlzfeYV.js.map +1 -0
  75. package/dist/hbs-CxcmWxSJ.js +62 -0
  76. package/dist/hbs-CxcmWxSJ.js.map +1 -0
  77. package/dist/http-BqypyemW.js +80 -0
  78. package/dist/http-BqypyemW.js.map +1 -0
  79. package/dist/idl-4HIGJlDI.js +986 -0
  80. package/dist/idl-4HIGJlDI.js.map +1 -0
  81. package/dist/index-B3Meoznj.js +118 -0
  82. package/dist/index-B3Meoznj.js.map +1 -0
  83. package/dist/index-BQyfDUUx.js +692 -0
  84. package/dist/index-BQyfDUUx.js.map +1 -0
  85. package/dist/index-BRDroAD8.js +305 -0
  86. package/dist/index-BRDroAD8.js.map +1 -0
  87. package/dist/index-BRMAzRyM.js +179 -0
  88. package/dist/index-BRMAzRyM.js.map +1 -0
  89. package/dist/index-Bb8uYQgv.js +927 -0
  90. package/dist/index-Bb8uYQgv.js.map +1 -0
  91. package/dist/index-BlOjO66K.js +17618 -0
  92. package/dist/index-BlOjO66K.js.map +1 -0
  93. package/dist/index-BoGWnSNL.js +706 -0
  94. package/dist/index-BoGWnSNL.js.map +1 -0
  95. package/dist/index-BsRrEiOu.js +98 -0
  96. package/dist/index-BsRrEiOu.js.map +1 -0
  97. package/dist/index-C2sFZMth.js +391 -0
  98. package/dist/index-C2sFZMth.js.map +1 -0
  99. package/dist/index-C7xwOjmS.js +291 -0
  100. package/dist/index-C7xwOjmS.js.map +1 -0
  101. package/dist/index-CA3lFUx6.js +315 -0
  102. package/dist/index-CA3lFUx6.js.map +1 -0
  103. package/dist/index-CB-pPTIf.js +98 -0
  104. package/dist/index-CB-pPTIf.js.map +1 -0
  105. package/dist/index-CCa6x1FE.js +386 -0
  106. package/dist/index-CCa6x1FE.js.map +1 -0
  107. package/dist/index-CD4DINI1.js +158 -0
  108. package/dist/index-CD4DINI1.js.map +1 -0
  109. package/dist/index-CE0B_fcG.js +328 -0
  110. package/dist/index-CE0B_fcG.js.map +1 -0
  111. package/dist/index-CVGAEPMV.js +2139 -0
  112. package/dist/index-CVGAEPMV.js.map +1 -0
  113. package/dist/index-CmaT2afn.js +332 -0
  114. package/dist/index-CmaT2afn.js.map +1 -0
  115. package/dist/index-D8sUxXp5.js +83 -0
  116. package/dist/index-D8sUxXp5.js.map +1 -0
  117. package/dist/index-DIz8Vpn-.js +737 -0
  118. package/dist/index-DIz8Vpn-.js.map +1 -0
  119. package/dist/index-DNP1xT-S.js +408 -0
  120. package/dist/index-DNP1xT-S.js.map +1 -0
  121. package/dist/index-DOAqdvnQ.js +862 -0
  122. package/dist/index-DOAqdvnQ.js.map +1 -0
  123. package/dist/index-DVUMFbgi.js +152 -0
  124. package/dist/index-DVUMFbgi.js.map +1 -0
  125. package/dist/index-VeTBKRVd.js +83 -0
  126. package/dist/index-VeTBKRVd.js.map +1 -0
  127. package/dist/index-dXZeR7Bx.js +1767 -0
  128. package/dist/index-dXZeR7Bx.js.map +1 -0
  129. package/dist/index-gtqbIb6T.js +62 -0
  130. package/dist/index-gtqbIb6T.js.map +1 -0
  131. package/dist/index-pN_pUAQ7.js +2426 -0
  132. package/dist/index-pN_pUAQ7.js.map +1 -0
  133. package/dist/index-wasu5VX0.js +1150 -0
  134. package/dist/index-wasu5VX0.js.map +1 -0
  135. package/dist/javascript-Bt8B7yTi.js +993 -0
  136. package/dist/javascript-Bt8B7yTi.js.map +1 -0
  137. package/dist/julia-Bs6JJhYG.js +408 -0
  138. package/dist/julia-Bs6JJhYG.js.map +1 -0
  139. package/dist/livescript-DmzgM3Yt.js +297 -0
  140. package/dist/livescript-DmzgM3Yt.js.map +1 -0
  141. package/dist/lua-8cJgIlqe.js +257 -0
  142. package/dist/lua-8cJgIlqe.js.map +1 -0
  143. package/dist/mathematica-DNLOL9PQ.js +111 -0
  144. package/dist/mathematica-DNLOL9PQ.js.map +1 -0
  145. package/dist/mbox-Ga7d4MMN.js +118 -0
  146. package/dist/mbox-Ga7d4MMN.js.map +1 -0
  147. package/dist/mirc-Dma3B8rS.js +108 -0
  148. package/dist/mirc-Dma3B8rS.js.map +1 -0
  149. package/dist/mllike-DHn7xckP.js +335 -0
  150. package/dist/mllike-DHn7xckP.js.map +1 -0
  151. package/dist/modelica-0d55jYY0.js +148 -0
  152. package/dist/modelica-0d55jYY0.js.map +1 -0
  153. package/dist/mscgen-DdqZYINH.js +136 -0
  154. package/dist/mscgen-DdqZYINH.js.map +1 -0
  155. package/dist/mumps-Btr8VblO.js +94 -0
  156. package/dist/mumps-Btr8VblO.js.map +1 -0
  157. package/dist/nginx-DTDtBDVN.js +142 -0
  158. package/dist/nginx-DTDtBDVN.js.map +1 -0
  159. package/dist/nsis-3zG7tgur.js +63 -0
  160. package/dist/nsis-3zG7tgur.js.map +1 -0
  161. package/dist/ntriples-CvgOYMpL.js +154 -0
  162. package/dist/ntriples-CvgOYMpL.js.map +1 -0
  163. package/dist/octave-DYBj3-tl.js +201 -0
  164. package/dist/octave-DYBj3-tl.js.map +1 -0
  165. package/dist/oz-R_e8WMIi.js +232 -0
  166. package/dist/oz-R_e8WMIi.js.map +1 -0
  167. package/dist/parse-CAqQaKsh.js +21685 -0
  168. package/dist/parse-CAqQaKsh.js.map +1 -0
  169. package/dist/pascal-GD8iposT.js +106 -0
  170. package/dist/pascal-GD8iposT.js.map +1 -0
  171. package/dist/perl-DL9mHpoi.js +1106 -0
  172. package/dist/perl-DL9mHpoi.js.map +1 -0
  173. package/dist/pig-C_4T4YIV.js +102 -0
  174. package/dist/pig-C_4T4YIV.js.map +1 -0
  175. package/dist/powershell-B0suO7Vd.js +329 -0
  176. package/dist/powershell-B0suO7Vd.js.map +1 -0
  177. package/dist/properties-BR-vP1aU.js +59 -0
  178. package/dist/properties-BR-vP1aU.js.map +1 -0
  179. package/dist/protobuf-BxgpyhoW.js +78 -0
  180. package/dist/protobuf-BxgpyhoW.js.map +1 -0
  181. package/dist/pug-vHnWR0UE.js +406 -0
  182. package/dist/pug-vHnWR0UE.js.map +1 -0
  183. package/dist/puppet-Bdao66PW.js +138 -0
  184. package/dist/puppet-Bdao66PW.js.map +1 -0
  185. package/dist/python-BFGRmuZ9.js +427 -0
  186. package/dist/python-BFGRmuZ9.js.map +1 -0
  187. package/dist/q-CrbCVq4a.js +132 -0
  188. package/dist/q-CrbCVq4a.js.map +1 -0
  189. package/dist/r-V7nswm59.js +171 -0
  190. package/dist/r-V7nswm59.js.map +1 -0
  191. package/dist/render-app-island-B-i8rvGi.js +61 -0
  192. package/dist/render-app-island-B-i8rvGi.js.map +1 -0
  193. package/dist/repl-sdk.js +7 -0
  194. package/dist/repl-sdk.js.map +1 -0
  195. package/dist/rpm-C-DLY-If.js +110 -0
  196. package/dist/rpm-C-DLY-If.js.map +1 -0
  197. package/dist/ruby-JDKLJNK0.js +331 -0
  198. package/dist/ruby-JDKLJNK0.js.map +1 -0
  199. package/dist/sas-D2UG-yhZ.js +208 -0
  200. package/dist/sas-D2UG-yhZ.js.map +1 -0
  201. package/dist/scheme-BKzrkGJD.js +223 -0
  202. package/dist/scheme-BKzrkGJD.js.map +1 -0
  203. package/dist/shell-BlsXDxCn.js +223 -0
  204. package/dist/shell-BlsXDxCn.js.map +1 -0
  205. package/dist/sieve-CjwBwOY5.js +136 -0
  206. package/dist/sieve-CjwBwOY5.js.map +1 -0
  207. package/dist/simple-mode-DMneyfDu.js +131 -0
  208. package/dist/simple-mode-DMneyfDu.js.map +1 -0
  209. package/dist/smalltalk-BOIGQuhN.js +122 -0
  210. package/dist/smalltalk-BOIGQuhN.js.map +1 -0
  211. package/dist/solr-CwD7U71z.js +70 -0
  212. package/dist/solr-CwD7U71z.js.map +1 -0
  213. package/dist/sparql-DYskk2vE.js +250 -0
  214. package/dist/sparql-DYskk2vE.js.map +1 -0
  215. package/dist/spreadsheet-Bgtt3oLP.js +88 -0
  216. package/dist/spreadsheet-Bgtt3oLP.js.map +1 -0
  217. package/dist/sql-Cei9CMfk.js +343 -0
  218. package/dist/sql-Cei9CMfk.js.map +1 -0
  219. package/dist/stex-C1nZSzAw.js +231 -0
  220. package/dist/stex-C1nZSzAw.js.map +1 -0
  221. package/dist/stylus-BkS-boTH.js +566 -0
  222. package/dist/stylus-BkS-boTH.js.map +1 -0
  223. package/dist/swift-FRZi1uvB.js +292 -0
  224. package/dist/swift-FRZi1uvB.js.map +1 -0
  225. package/dist/tcl-CUcaCdmq.js +115 -0
  226. package/dist/tcl-CUcaCdmq.js.map +1 -0
  227. package/dist/textile-BnFpjsrl.js +415 -0
  228. package/dist/textile-BnFpjsrl.js.map +1 -0
  229. package/dist/tiddlywiki-CjprD-Qp.js +219 -0
  230. package/dist/tiddlywiki-CjprD-Qp.js.map +1 -0
  231. package/dist/tiki-DK9DOeWn.js +269 -0
  232. package/dist/tiki-DK9DOeWn.js.map +1 -0
  233. package/dist/toml-BOuWGMcf.js +77 -0
  234. package/dist/toml-BOuWGMcf.js.map +1 -0
  235. package/dist/troff-E1bJ0PPL.js +62 -0
  236. package/dist/troff-E1bJ0PPL.js.map +1 -0
  237. package/dist/ttcn-cfg-Dc39-fIP.js +134 -0
  238. package/dist/ttcn-cfg-Dc39-fIP.js.map +1 -0
  239. package/dist/ttcn-tKd4HLu4.js +193 -0
  240. package/dist/ttcn-tKd4HLu4.js.map +1 -0
  241. package/dist/turtle-Dq7-1WAf.js +125 -0
  242. package/dist/turtle-Dq7-1WAf.js.map +1 -0
  243. package/dist/vb-Dp90gtsv.js +197 -0
  244. package/dist/vb-Dp90gtsv.js.map +1 -0
  245. package/dist/vbscript-Bfn8O8I7.js +479 -0
  246. package/dist/vbscript-Bfn8O8I7.js.map +1 -0
  247. package/dist/velocity-BwIZK1TH.js +150 -0
  248. package/dist/velocity-BwIZK1TH.js.map +1 -0
  249. package/dist/verilog-CnT9bMk0.js +430 -0
  250. package/dist/verilog-CnT9bMk0.js.map +1 -0
  251. package/dist/vhdl-DCkMIyT9.js +159 -0
  252. package/dist/vhdl-DCkMIyT9.js.map +1 -0
  253. package/dist/webidl-BTLTThCm.js +205 -0
  254. package/dist/webidl-BTLTThCm.js.map +1 -0
  255. package/dist/xquery-BrBUuxMR.js +526 -0
  256. package/dist/xquery-BrBUuxMR.js.map +1 -0
  257. package/dist/yacas-b5lAVEIl.js +131 -0
  258. package/dist/yacas-b5lAVEIl.js.map +1 -0
  259. package/dist/z80-ClgwfNdB.js +93 -0
  260. package/dist/z80-ClgwfNdB.js.map +1 -0
  261. package/package.json +81 -9
  262. package/src/cache.js +138 -0
  263. package/src/cdn.js +93 -0
  264. package/src/codemirror.js +161 -0
  265. package/src/compilers/ember/gjs.js +212 -0
  266. package/src/compilers/ember/gmd.js +190 -0
  267. package/src/compilers/ember/hbs.js +98 -0
  268. package/src/compilers/ember/render-app-island.js +83 -0
  269. package/src/compilers/ember.js +166 -0
  270. package/src/compilers/js.js +32 -0
  271. package/src/compilers/markdown/build-compiler.js +151 -0
  272. package/src/compilers/markdown/const.js +2 -0
  273. package/src/compilers/markdown/heading-id.js +75 -0
  274. package/src/compilers/markdown/live-code-extraction.js +198 -0
  275. package/src/compilers/markdown/parse.js +22 -0
  276. package/src/compilers/markdown/parse.test.ts +363 -0
  277. package/src/compilers/markdown/sanitize-for-glimmer.js +26 -0
  278. package/src/compilers/markdown/types.ts +21 -0
  279. package/src/compilers/markdown/utils.js +78 -0
  280. package/src/compilers/markdown.js +125 -0
  281. package/src/compilers/mermaid.js +35 -0
  282. package/src/compilers/react.js +59 -0
  283. package/src/compilers/svelte.js +116 -0
  284. package/src/compilers/vue.js +58 -0
  285. package/src/compilers.js +108 -0
  286. package/src/es-module-shim.js +53 -0
  287. package/src/index.d.ts +53 -4
  288. package/src/index.js +744 -89
  289. package/src/npm.js +58 -0
  290. package/src/request.Request.test.ts +59 -0
  291. package/src/request.js +140 -0
  292. package/src/resolve.fromImports.test.ts +35 -0
  293. package/src/resolve.fromInternalImport.test.ts +69 -0
  294. package/src/resolve.js +352 -0
  295. package/src/resolve.resolvePath.test.ts +24 -0
  296. package/src/resolve.test.ts +23 -0
  297. package/src/specifier.js +71 -0
  298. package/src/specifier.test.ts +90 -0
  299. package/src/tar-worker.js +61 -0
  300. package/src/tar.js +76 -0
  301. package/src/types.ts +335 -58
  302. package/src/utils.js +28 -1
  303. package/declarations/index.d.ts +0 -73
  304. package/dist/index.js +0 -107
  305. package/dist/index.js.map +0 -1
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @typedef {import('unified').Plugin} UPlugin
3
+ */
4
+ import { buildCompiler } from './build-compiler.js';
5
+
6
+ /**
7
+ * @param {string} input
8
+ * @param {import('./types').InternalOptions} options
9
+ *
10
+ * @returns {Promise<{ text: string; codeBlocks: { lang: string; format: string; code: string; name: string }[] }>}
11
+ */
12
+ export async function parseMarkdown(input, options) {
13
+ const markdownCompiler = buildCompiler(options);
14
+ const processed = await markdownCompiler.process(input);
15
+ const liveCode = /** @type {{ lang: string; format: string; code: string; name: string }[]} */ (
16
+ processed.data.liveCode || []
17
+ );
18
+ // @ts-ignore - processed is typed as unknown due to unified processor complexity
19
+ const templateOnly = processed.toString();
20
+
21
+ return { text: templateOnly, codeBlocks: liveCode };
22
+ }
@@ -0,0 +1,363 @@
1
+ import rehypeShiki from '@shikijs/rehype';
2
+ import { stripIndent } from 'common-tags';
3
+ import { visit } from 'unist-util-visit';
4
+ import { describe, expect as errorExpect, it } from 'vitest';
5
+
6
+ import { parseMarkdown } from './parse.js';
7
+ import { buildCodeFenceMetaUtils } from './utils.js';
8
+
9
+ import type { Element, Root as HastRoot } from 'hast';
10
+ import type { Heading, Root as MdastRoot } from 'mdast';
11
+
12
+ const expect = errorExpect.soft;
13
+
14
+ function assertOutput(actual: string, expected: string) {
15
+ const _actual = actual?.split('\n')?.filter(Boolean)?.join('\n')?.trim();
16
+ const _expected = expected.split('\n').filter(Boolean).join('\n').trim();
17
+
18
+ expect(_actual).toBe(_expected);
19
+ }
20
+
21
+ function assertCodeBlocks(
22
+ actual: unknown,
23
+ expected: { code: string; format: string; meta: string }[]
24
+ ) {
25
+ expect(actual).toMatchObject(expected);
26
+ }
27
+
28
+ const ALLOWED_FORMATS = ['gjs', 'jsx', 'vue', 'svelte', 'hbs'];
29
+ const defaults = {
30
+ ...buildCodeFenceMetaUtils({
31
+ getAllowedFormats: () => ALLOWED_FORMATS,
32
+ getFlavorsFor: (lang) => {
33
+ if (lang === 'jsx') {
34
+ return ['react'];
35
+ }
36
+
37
+ return [];
38
+ },
39
+ optionsFor: () => ({}),
40
+ }),
41
+ ALLOWED_FORMATS,
42
+ };
43
+
44
+ describe('options', () => {
45
+ describe('remarkPlugins', () => {
46
+ it('works', async () => {
47
+ const result = await parseMarkdown(`# Title`, {
48
+ ...defaults,
49
+ remarkPlugins: [
50
+ function noH1() {
51
+ return (tree: MdastRoot) => {
52
+ visit(tree, 'heading', function (node: Heading) {
53
+ if (node.depth === 1) {
54
+ node.depth = 2;
55
+ }
56
+ });
57
+ };
58
+ },
59
+ ],
60
+ });
61
+
62
+ expect(result.text).toBe('<h2 id="title">Title</h2>');
63
+ expect(result.codeBlocks).to.deep.equal([]);
64
+ });
65
+
66
+ it('w/ options', async () => {
67
+ const result = await parseMarkdown(`# Title`, {
68
+ ...defaults,
69
+ remarkPlugins: [
70
+ [
71
+ function noH1(options: { depth: 1 | 2 | 3 | 4 | 5 | 6 }) {
72
+ return (tree: MdastRoot) => {
73
+ visit(tree, 'heading', function (node: Heading) {
74
+ if (node.depth === 1) {
75
+ node.depth = options.depth;
76
+ }
77
+ });
78
+ };
79
+ },
80
+ { depth: 3 },
81
+ ],
82
+ ],
83
+ });
84
+
85
+ expect(result.text).toBe('<h3 id="title">Title</h3>');
86
+ expect(result.codeBlocks).to.deep.equal([]);
87
+ });
88
+ });
89
+
90
+ describe('rehypePlugins', () => {
91
+ it('works', async () => {
92
+ const result = await parseMarkdown(`# Title`, {
93
+ ...defaults,
94
+ rehypePlugins: [
95
+ function noH1() {
96
+ return (tree: HastRoot) => {
97
+ visit(tree, 'element', function (node: Element) {
98
+ if (node.tagName === 'h1') {
99
+ node.tagName = 'h2';
100
+ }
101
+ });
102
+ };
103
+ },
104
+ ],
105
+ });
106
+
107
+ expect(result.text).toBe('<h2 id="title">Title</h2>');
108
+ expect(result.codeBlocks).to.deep.equal([]);
109
+ });
110
+
111
+ it('w/ options', async () => {
112
+ const result = await parseMarkdown(`# Title`, {
113
+ ...defaults,
114
+ rehypePlugins: [
115
+ [
116
+ function noH1(options: { depth: 1 | 2 | 3 | 4 | 5 | 6 }) {
117
+ return (tree: HastRoot) => {
118
+ visit(tree, 'element', function (node: Element) {
119
+ if (node.tagName === 'h1') {
120
+ node.tagName = `h${options.depth ?? 2}`;
121
+ }
122
+ });
123
+ };
124
+ },
125
+ { depth: 3 },
126
+ ],
127
+ ],
128
+ });
129
+
130
+ expect(result.text).toBe('<h3 id="title">Title</h3>');
131
+ expect(result.codeBlocks).to.deep.equal([]);
132
+ });
133
+
134
+ it('retains {{ }} escaping', async () => {
135
+ const result = await parseMarkdown(
136
+ stripIndent`
137
+ # Title
138
+
139
+ \`\`\`gjs
140
+ const two = 2
141
+
142
+ <template>
143
+ {{two}}
144
+ </template>
145
+ \`\`\`
146
+ `,
147
+ {
148
+ ...defaults,
149
+ rehypePlugins: [[rehypeShiki, { theme: 'github-dark' }]],
150
+ }
151
+ );
152
+
153
+ assertOutput(
154
+ result.text,
155
+ `<h1 id="title">Title</h1>
156
+ <div class="repl-sdk__snippet" data-repl-output><pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#F97583">const</span><span style="color:#79B8FF"> two</span><span style="color:#F97583"> =</span><span style="color:#79B8FF"> 2</span></span>
157
+ <span class="line"></span>
158
+ <span class="line"><span style="color:#E1E4E8">&#x3C;</span><span style="color:#85E89D">template</span><span style="color:#E1E4E8">></span></span>
159
+ <span class="line"><span style="color:#F97583"> \\{{</span><span style="color:#79B8FF">two</span><span style="color:#F97583">}}</span></span>
160
+ <span class="line"><span style="color:#E1E4E8">&#x3C;/</span><span style="color:#85E89D">template</span><span style="color:#E1E4E8">></span></span></code></pre></div>`
161
+ );
162
+ });
163
+ });
164
+
165
+ describe('codefences', () => {
166
+ describe('hbs', () => {
167
+ it('Code fence is live', async () => {
168
+ const snippet = `{{concat "hello" " " "there"}}`;
169
+ const result = await parseMarkdown(
170
+ stripIndent`
171
+ # Title
172
+
173
+ \`\`\`hbs live
174
+ ${snippet}
175
+ \`\`\`
176
+ `.trim(),
177
+ { ...defaults }
178
+ );
179
+
180
+ expect(result.text).toMatchInlineSnapshot(`
181
+ "<h1 id="title">Title</h1>
182
+ <div id="repl_1" class="repl-sdk__demo"></div>"
183
+ `);
184
+
185
+ assertCodeBlocks(result.codeBlocks, [
186
+ {
187
+ code: snippet,
188
+ format: 'hbs',
189
+ meta: 'live',
190
+ },
191
+ ]);
192
+ });
193
+ });
194
+
195
+ describe('gjs', () => {
196
+ it('Code fence does not have the "live" keyword', async function () {
197
+ const result = await parseMarkdown(
198
+ stripIndent`
199
+ # Title
200
+
201
+ \`\`\`gjs
202
+ const two = 2;
203
+ \`\`\`
204
+ `,
205
+ { ...defaults }
206
+ );
207
+
208
+ assertOutput(
209
+ result.text,
210
+ stripIndent`
211
+ <h1 id="title">Title</h1>
212
+
213
+ <div class=\"repl-sdk__snippet\" data-repl-output><pre><code class=\"language-gjs\"> const two = 2;
214
+ </code></pre></div>
215
+ `
216
+ );
217
+
218
+ expect(result.codeBlocks).to.deep.equal([]);
219
+ });
220
+
221
+ it('Code fence is live', async function () {
222
+ const snippet = `const two = 2`;
223
+ const result = await parseMarkdown(
224
+ stripIndent`
225
+ # Title
226
+
227
+ \`\`\`gjs live
228
+ ${snippet}
229
+ \`\`\`
230
+ `,
231
+ { ...defaults }
232
+ );
233
+
234
+ expect(result.text).toMatchInlineSnapshot(`
235
+ "<h1 id="title">Title</h1>
236
+ <div id="repl_2" class="repl-sdk__demo"></div>"
237
+ `);
238
+
239
+ assertCodeBlocks(result.codeBlocks, [
240
+ {
241
+ code: snippet,
242
+ format: 'gjs',
243
+ meta: 'live',
244
+ },
245
+ ]);
246
+ });
247
+
248
+ it('Code with preview fence has {{ }} tokens escaped', async function () {
249
+ const result = await parseMarkdown(
250
+ stripIndent`
251
+ # Title
252
+
253
+ \`\`\`gjs
254
+ const two = 2
255
+
256
+ <template>
257
+ {{two}}
258
+ </template>
259
+ \`\`\`
260
+ `,
261
+ { ...defaults }
262
+ );
263
+
264
+ assertOutput(
265
+ result.text,
266
+ stripIndent`
267
+ <h1 id="title">Title</h1>
268
+
269
+ <div class=\"repl-sdk__snippet\" data-repl-output><pre><code class=\"language-gjs\">const two = 2
270
+
271
+ &#x3C;template>
272
+ \\{{two}}
273
+ &#x3C;/template>
274
+ </code></pre></div>
275
+ `
276
+ );
277
+ });
278
+
279
+ it('Inline Code with {{ }} tokens is escaped', async function () {
280
+ const result = await parseMarkdown(
281
+ stripIndent`
282
+ # Title
283
+
284
+ \`{{ foo }}\`
285
+ `,
286
+ { ...defaults }
287
+ );
288
+
289
+ assertOutput(
290
+ result.text,
291
+ stripIndent`
292
+ <h1 id="title">Title</h1>
293
+ <p><code>\\{{ foo }}</code></p>
294
+ `
295
+ );
296
+ });
297
+
298
+ it('Can invoke a component again when defined in a live fence', async function () {
299
+ const snippet = `const two = 2`;
300
+ const result = await parseMarkdown(
301
+ stripIndent`
302
+ # Title
303
+
304
+ \`\`\`gjs live
305
+ ${snippet}
306
+ \`\`\`
307
+ <Demo />
308
+ `,
309
+ { ...defaults }
310
+ );
311
+
312
+ expect(result.text).toMatchInlineSnapshot(`
313
+ "<h1 id="title">Title</h1>
314
+ <div id="repl_3" class="repl-sdk__demo"></div>
315
+ <Demo />"
316
+ `);
317
+
318
+ assertCodeBlocks(result.codeBlocks, [
319
+ {
320
+ code: snippet,
321
+ format: 'gjs',
322
+ meta: 'live',
323
+ },
324
+ ]);
325
+ });
326
+
327
+ it('Code fence imports things', async function () {
328
+ const snippet = stripIndent`
329
+ import Component from '@glimmer/component';
330
+ import { on } from '@ember/modifier';
331
+
332
+ <template>
333
+ <button {{on "click" console.log}}>Click</button>
334
+ </template>
335
+ `;
336
+ const result = await parseMarkdown(
337
+ `hi\n` + `\n` + '```gjs live preview\n' + snippet + '\n```',
338
+ { ...defaults }
339
+ );
340
+
341
+ expect(result.text).toMatchInlineSnapshot(`
342
+ "<p>hi</p>
343
+ <div id="repl_4" class="repl-sdk__demo"></div>
344
+ <div class="repl-sdk__snippet" data-repl-output><pre><code class="language-gjs">import Component from '@glimmer/component';
345
+ import { on } from '@ember/modifier';
346
+
347
+ &#x3C;template>
348
+ &#x3C;button \\{{on "click" console.log}}>Click&#x3C;/button>
349
+ &#x3C;/template>
350
+ </code></pre></div>"
351
+ `);
352
+
353
+ assertCodeBlocks(result.codeBlocks, [
354
+ {
355
+ code: snippet,
356
+ format: 'gjs',
357
+ meta: 'live preview',
358
+ },
359
+ ]);
360
+ });
361
+ });
362
+ });
363
+ });
@@ -0,0 +1,26 @@
1
+ import { visit } from 'unist-util-visit';
2
+
3
+ /**
4
+ * @type {import('unified').Plugin<[], import('hast').Root>}
5
+ */
6
+ export function sanitizeForGlimmer(/* options */) {
7
+ return function transformer(tree) {
8
+ visit(tree, 'element', function visitor(node) {
9
+ if (node.type === 'element' && 'tagName' in node) {
10
+ const element = /** @type {import('hast').Element} */ (node);
11
+
12
+ if (!['pre', 'code'].includes(element.tagName)) return;
13
+
14
+ visit(node, 'text', function textVisitor(textNode) {
15
+ if (textNode.type === 'text') {
16
+ const text = /** @type {import('hast').Text} */ (textNode);
17
+
18
+ text.value = text.value.replace(/{{/g, '\\{{');
19
+ }
20
+ });
21
+
22
+ return 'skip';
23
+ }
24
+ });
25
+ };
26
+ }
@@ -0,0 +1,21 @@
1
+ export interface LiveCodeExtractionOptions {
2
+ isLive?: (meta: string, lang: string) => boolean;
3
+ ALLOWED_FORMATS?: string[];
4
+ isPreview?: (meta: string) => boolean;
5
+ isBelow?: (meta: string) => boolean;
6
+ needsLive?: (lang: string) => boolean;
7
+ getFlavorFromMeta?: (meta: string, lang: string) => string | undefined;
8
+ }
9
+
10
+ export interface PublicOptions {
11
+ code?: {
12
+ classList?: string[];
13
+ };
14
+ demo?: {
15
+ classList?: string[];
16
+ };
17
+ remarkPlugins?: unknown[];
18
+ rehypePlugins?: unknown[];
19
+ }
20
+
21
+ export type InternalOptions = PublicOptions & LiveCodeExtractionOptions;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * @param {string} lang
3
+ */
4
+ export function isNotMarkdownLike(lang) {
5
+ return lang !== 'md' && lang !== 'gmd' && lang !== 'mdx';
6
+ }
7
+
8
+ /**
9
+ * @param {string} meta
10
+ */
11
+ export function isPreview(meta) {
12
+ if (!meta) return false;
13
+
14
+ return meta.includes('preview');
15
+ }
16
+
17
+ /**
18
+ * @param {string} meta
19
+ */
20
+ export function isBelow(meta) {
21
+ if (!meta) return false;
22
+
23
+ return meta.includes('below');
24
+ }
25
+
26
+ /**
27
+ * @param {Pick<import('../../types').PublicMethods, 'getAllowedFormats' | 'getFlavorsFor' | 'optionsFor'>} api
28
+ */
29
+ export function buildCodeFenceMetaUtils(api) {
30
+ const allowedFormats = api.getAllowedFormats().filter(isNotMarkdownLike);
31
+
32
+ /**
33
+ * @param {string} lang
34
+ * @param {string | undefined} [ flavor ]
35
+ */
36
+ function needsLive(lang, flavor) {
37
+ if (!allowedFormats.includes(lang)) return false;
38
+
39
+ return api.optionsFor(lang, flavor).needsLiveMeta ?? true;
40
+ }
41
+
42
+ /**
43
+ * @param {string} meta
44
+ * @param {string} lang
45
+ */
46
+ function getFlavorFromMeta(meta, lang) {
47
+ const flavors = api.getFlavorsFor(lang);
48
+
49
+ const flavor = meta
50
+ ?.trim()
51
+ .split(' ')
52
+ .find((metum) => flavors.includes(metum));
53
+
54
+ return flavor;
55
+ }
56
+
57
+ /**
58
+ * @param {string} meta
59
+ * @param {string} lang
60
+ */
61
+ function isLive(meta, lang) {
62
+ const flavor = getFlavorFromMeta(meta, lang);
63
+
64
+ if (!needsLive(lang, flavor)) return true;
65
+ if (!meta) return false;
66
+
67
+ return meta.includes('live');
68
+ }
69
+
70
+ return {
71
+ isPreview,
72
+ isBelow,
73
+ isLive,
74
+ needsLive,
75
+ allowedFormats,
76
+ getFlavorFromMeta,
77
+ };
78
+ }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * @typedef {import('unified').Plugin} Plugin
3
+ */
4
+ import { assert, isRecord } from '../utils.js';
5
+ import { buildCodeFenceMetaUtils } from './markdown/utils.js';
6
+
7
+ /**
8
+ * @param {unknown} [ options ]
9
+ * @returns {{ remarkPlugins: Plugin[], rehypePlugins: Plugin[] }}
10
+ */
11
+ export function filterOptions(options) {
12
+ if (!isRecord(options)) {
13
+ return { remarkPlugins: [], rehypePlugins: [] };
14
+ }
15
+
16
+ return {
17
+ remarkPlugins: /** @type {Plugin[]}*/ (options?.remarkPlugins || []),
18
+ rehypePlugins: /** @type {Plugin[]}*/ (options?.rehypePlugins || []),
19
+ };
20
+ }
21
+
22
+ /**
23
+ * @type {import('../types.ts').CompilerConfig}
24
+ */
25
+ export const md = {
26
+ codemirror: {
27
+ lang: async () => {
28
+ const { glimdown } = await import('codemirror-lang-glimdown');
29
+
30
+ /**
31
+ * pre-configured markdown with GFM, and a few other extensions
32
+ */
33
+ return glimdown();
34
+ },
35
+ },
36
+ compiler: async (config, api) => {
37
+ const { isLive, isPreview, needsLive, allowedFormats, isBelow, getFlavorFromMeta } =
38
+ buildCodeFenceMetaUtils(api);
39
+
40
+ // Try both possible structures
41
+ const userOptions = filterOptions(
42
+ /** @type {Record<string, unknown>} */ (config.userOptions)?.md || config
43
+ );
44
+
45
+ // No recursing for now.
46
+
47
+ const { parseMarkdown } = await import('./markdown/parse.js');
48
+
49
+ /**
50
+ * @type {import('../types.ts').Compiler}
51
+ */
52
+ return {
53
+ compile: async (text, options) => {
54
+ const compileOptions = filterOptions(options);
55
+ const result = await parseMarkdown(text, {
56
+ remarkPlugins: [...userOptions.remarkPlugins, ...compileOptions.remarkPlugins],
57
+ rehypePlugins: [...userOptions.rehypePlugins, ...compileOptions.rehypePlugins],
58
+ isLive,
59
+ isPreview,
60
+ isBelow,
61
+ needsLive,
62
+ ALLOWED_FORMATS: allowedFormats,
63
+ getFlavorFromMeta,
64
+ });
65
+ const escaped = result.text.replace(/`/g, '\\`');
66
+
67
+ return { compiled: `export default \`${escaped}\``, ...result };
68
+ },
69
+ render: async (element, compiled, extra, compiler) => {
70
+ element.innerHTML = /** @type {string} */ (compiled);
71
+
72
+ /**
73
+ * @type {(() => void)[]}
74
+ */
75
+ const destroyables = [];
76
+
77
+ await Promise.all(
78
+ /** @type {unknown[]} */ (extra.codeBlocks).map(async (/** @type {unknown} */ info) => {
79
+ /** @type {Record<string, unknown>} */
80
+ const infoObj = /** @type {Record<string, unknown>} */ (info);
81
+
82
+ if (
83
+ !api.canCompile(
84
+ /** @type {string} */ (infoObj.format),
85
+ /** @type {string} */ (infoObj.flavor)
86
+ )
87
+ ) {
88
+ return;
89
+ }
90
+
91
+ const flavor = /** @type {string} */ (infoObj.flavor);
92
+ const subRender = await compiler.compile(
93
+ /** @type {string} */ (infoObj.format),
94
+ /** @type {string} */ (infoObj.code),
95
+ {
96
+ ...compiler.optionsFor(/** @type {string} */ (infoObj.format), flavor),
97
+ flavor: flavor,
98
+ }
99
+ );
100
+
101
+ const selector = `#${/** @type {string} */ (infoObj.placeholderId)}`;
102
+ const target = element.querySelector(selector);
103
+
104
+ assert(
105
+ `Could not find placeholder / target element (using selector: \`${selector}\`). ` +
106
+ `Could not render ${/** @type {string} */ (infoObj.format)} block.`,
107
+ target
108
+ );
109
+
110
+ destroyables.push(subRender.destroy);
111
+ target.appendChild(subRender.element);
112
+ })
113
+ );
114
+
115
+ compiler.announce('info', 'Done');
116
+
117
+ return () => {
118
+ for (const subDestroy of destroyables) {
119
+ subDestroy();
120
+ }
121
+ };
122
+ },
123
+ };
124
+ },
125
+ };
@@ -0,0 +1,35 @@
1
+ import { esmsh } from '../cdn.js';
2
+
3
+ /**
4
+ * @type {import('../types.ts').CompilerConfig}
5
+ */
6
+ export const mermaid = {
7
+ needsLiveMeta: false,
8
+ codemirror: {
9
+ lang: async () => {
10
+ const { mermaid } = await import('codemirror-lang-mermaid');
11
+
12
+ return mermaid();
13
+ },
14
+ },
15
+ compiler: async (config, api) => {
16
+ const versions = config.versions;
17
+ const { default: mermaid } = await api.tryResolve('mermaid', () => {
18
+ return esmsh.import(versions, 'mermaid');
19
+ });
20
+
21
+ let id = 0;
22
+
23
+ return {
24
+ compile: async (text) => {
25
+ return `export default \`${text}\`;`;
26
+ },
27
+ render: async (element, text, _, compiler) => {
28
+ const { svg } = await mermaid.render('graphDiv' + id++, text);
29
+
30
+ element.innerHTML = svg;
31
+ compiler.announce('info', 'Done');
32
+ },
33
+ };
34
+ },
35
+ };