buninu 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 (435) hide show
  1. package/.bashrc +11 -0
  2. package/ARCHITECTURE.md +452 -0
  3. package/LICENSE +21 -0
  4. package/README.md +121 -0
  5. package/apps/bun/make-bunBin.sh +84 -0
  6. package/apps/jsgotty/LICENSE +23 -0
  7. package/apps/jsgotty/LICENSES/Apache-2.0-zmodem.js.txt +201 -0
  8. package/apps/jsgotty/NOTICE +21 -0
  9. package/apps/jsgotty/README.en.md +290 -0
  10. package/apps/jsgotty/README.md +292 -0
  11. package/apps/jsgotty/client.mjs +700 -0
  12. package/apps/jsgotty/env.sh +2 -0
  13. package/apps/jsgotty/gotty.js +3325 -0
  14. package/apps/jsgotty/node_modules/.package-lock.json +35 -0
  15. package/apps/jsgotty/node_modules/node-addon-api/LICENSE.md +9 -0
  16. package/apps/jsgotty/node_modules/node-addon-api/README.md +319 -0
  17. package/apps/jsgotty/node_modules/node-addon-api/common.gypi +20 -0
  18. package/apps/jsgotty/node_modules/node-addon-api/except.gypi +25 -0
  19. package/apps/jsgotty/node_modules/node-addon-api/index.js +12 -0
  20. package/apps/jsgotty/node_modules/node-addon-api/napi-inl.deprecated.h +186 -0
  21. package/apps/jsgotty/node_modules/node-addon-api/napi-inl.h +6607 -0
  22. package/apps/jsgotty/node_modules/node-addon-api/napi.h +3201 -0
  23. package/apps/jsgotty/node_modules/node-addon-api/node_addon_api.gyp +32 -0
  24. package/apps/jsgotty/node_modules/node-addon-api/node_api.gyp +9 -0
  25. package/apps/jsgotty/node_modules/node-addon-api/noexcept.gypi +26 -0
  26. package/apps/jsgotty/node_modules/node-addon-api/nothing.c +0 -0
  27. package/apps/jsgotty/node_modules/node-addon-api/package-support.json +21 -0
  28. package/apps/jsgotty/node_modules/node-addon-api/package.json +480 -0
  29. package/apps/jsgotty/node_modules/node-addon-api/tools/README.md +73 -0
  30. package/apps/jsgotty/node_modules/node-addon-api/tools/check-napi.js +99 -0
  31. package/apps/jsgotty/node_modules/node-addon-api/tools/clang-format.js +71 -0
  32. package/apps/jsgotty/node_modules/node-addon-api/tools/conversion.js +301 -0
  33. package/apps/jsgotty/node_modules/node-addon-api/tools/eslint-format.js +79 -0
  34. package/apps/jsgotty/node_modules/ws/LICENSE +20 -0
  35. package/apps/jsgotty/node_modules/ws/README.md +548 -0
  36. package/apps/jsgotty/node_modules/ws/browser.js +8 -0
  37. package/apps/jsgotty/node_modules/ws/index.js +22 -0
  38. package/apps/jsgotty/node_modules/ws/lib/buffer-util.js +131 -0
  39. package/apps/jsgotty/node_modules/ws/lib/constants.js +19 -0
  40. package/apps/jsgotty/node_modules/ws/lib/event-target.js +292 -0
  41. package/apps/jsgotty/node_modules/ws/lib/extension.js +203 -0
  42. package/apps/jsgotty/node_modules/ws/lib/limiter.js +55 -0
  43. package/apps/jsgotty/node_modules/ws/lib/permessage-deflate.js +528 -0
  44. package/apps/jsgotty/node_modules/ws/lib/receiver.js +760 -0
  45. package/apps/jsgotty/node_modules/ws/lib/sender.js +607 -0
  46. package/apps/jsgotty/node_modules/ws/lib/stream.js +161 -0
  47. package/apps/jsgotty/node_modules/ws/lib/subprotocol.js +62 -0
  48. package/apps/jsgotty/node_modules/ws/lib/validation.js +152 -0
  49. package/apps/jsgotty/node_modules/ws/lib/websocket-server.js +562 -0
  50. package/apps/jsgotty/node_modules/ws/lib/websocket.js +1407 -0
  51. package/apps/jsgotty/node_modules/ws/package.json +70 -0
  52. package/apps/jsgotty/node_modules/ws/wrapper.mjs +21 -0
  53. package/apps/jsgotty/package-lock.json +46 -0
  54. package/apps/jsgotty/package.json +13 -0
  55. package/apps/jsgotty/patches/windowsPtyAgent.js +326 -0
  56. package/apps/jsgotty/patches/windowsTerminal.js +204 -0
  57. package/apps/jsgotty/rz.js +199 -0
  58. package/apps/jsgotty/single-exe/README.md +80 -0
  59. package/apps/jsgotty/single-exe/assetsHelper.js +90 -0
  60. package/apps/jsgotty/single-exe/assetsLoader.mjs +85 -0
  61. package/apps/jsgotty/single-exe/compiled.js +138 -0
  62. package/apps/jsgotty/single-exe/entry.mjs +9 -0
  63. package/apps/jsgotty/single-exe/packAssets.sh +7 -0
  64. package/apps/jsgotty/static/css/index.css +13 -0
  65. package/apps/jsgotty/static/css/kitty.css +61 -0
  66. package/apps/jsgotty/static/css/xterm.css +218 -0
  67. package/apps/jsgotty/static/css/xterm_customize.css +32 -0
  68. package/apps/jsgotty/static/favicon.ico +0 -0
  69. package/apps/jsgotty/static/help.md +125 -0
  70. package/apps/jsgotty/static/icon.svg +66 -0
  71. package/apps/jsgotty/static/icon_192.png +0 -0
  72. package/apps/jsgotty/static/index.html +164 -0
  73. package/apps/jsgotty/static/js/gotty.js +31537 -0
  74. package/apps/jsgotty/static/js/gotty.js.LICENSE.txt +7 -0
  75. package/apps/jsgotty/static/js/gotty.js.map +1 -0
  76. package/apps/jsgotty/static/js/gotty.licenses.txt +650 -0
  77. package/apps/jsgotty/static/js/kitty.js +1045 -0
  78. package/apps/jsgotty/static/js/windows_bridge.js +194 -0
  79. package/apps/jsgotty/static/js/xterm-addon-unicode11.js +2 -0
  80. package/apps/jsgotty/static/js/zmodem.js +1 -0
  81. package/apps/jsgotty/static/manifest.json +15 -0
  82. package/apps/jsgotty/sz.js +273 -0
  83. package/apps/jsgotty/tests/kitty-order.test.js +58 -0
  84. package/apps/jsgotty/viu.mjs +393 -0
  85. package/apps/jsgotty/wgotty +62 -0
  86. package/apps/jsgotty/windows-bridge-node.js +60 -0
  87. package/apps/jsgotty/zmodem-node.js +260 -0
  88. package/apps/jsmdcui/CHANGELOG.md +1048 -0
  89. package/apps/jsmdcui/LICENSE +22 -0
  90. package/apps/jsmdcui/README.md +1269 -0
  91. package/apps/jsmdcui/cdp-maze.js +141 -0
  92. package/apps/jsmdcui/clean.sh +9 -0
  93. package/apps/jsmdcui/demos/basic.jpg +0 -0
  94. package/apps/jsmdcui/demos/chinese.md +32 -0
  95. package/apps/jsmdcui/demos/event.md +170 -0
  96. package/apps/jsmdcui/demos/good.jpg +0 -0
  97. package/apps/jsmdcui/demos/image-processor.md +366 -0
  98. package/apps/jsmdcui/demos/image-processor.zh-TW.md +366 -0
  99. package/apps/jsmdcui/demos/img-change.md +73 -0
  100. package/apps/jsmdcui/demos/imgtool-zh.md +298 -0
  101. package/apps/jsmdcui/demos/imgtool.md +298 -0
  102. package/apps/jsmdcui/demos/maze.md +149 -0
  103. package/apps/jsmdcui/demos/reactive.md +40 -0
  104. package/apps/jsmdcui/demos/reader.md +513 -0
  105. package/apps/jsmdcui/demos/select.md +63 -0
  106. package/apps/jsmdcui/demos/todo-zh.md +190 -0
  107. package/apps/jsmdcui/demos/todo.md +191 -0
  108. package/apps/jsmdcui/edit +9 -0
  109. package/apps/jsmdcui/jsmdcui.sh +5 -0
  110. package/apps/jsmdcui/llm-maze.txt +94 -0
  111. package/apps/jsmdcui/package.json +19 -0
  112. package/apps/jsmdcui/project_structure.txt +35 -0
  113. package/apps/jsmdcui/runmd.mjs +1140 -0
  114. package/apps/jsmdcui/runtime/colorschemes/atom-dark.micro +33 -0
  115. package/apps/jsmdcui/runtime/colorschemes/bubblegum.micro +31 -0
  116. package/apps/jsmdcui/runtime/colorschemes/cmc-16.micro +47 -0
  117. package/apps/jsmdcui/runtime/colorschemes/cmc-tc.micro +43 -0
  118. package/apps/jsmdcui/runtime/colorschemes/darcula.micro +34 -0
  119. package/apps/jsmdcui/runtime/colorschemes/default.micro +1 -0
  120. package/apps/jsmdcui/runtime/colorschemes/dracula-tc.micro +49 -0
  121. package/apps/jsmdcui/runtime/colorschemes/dukedark-tc.micro +38 -0
  122. package/apps/jsmdcui/runtime/colorschemes/dukelight-tc.micro +38 -0
  123. package/apps/jsmdcui/runtime/colorschemes/dukeubuntu-tc.micro +38 -0
  124. package/apps/jsmdcui/runtime/colorschemes/geany.micro +29 -0
  125. package/apps/jsmdcui/runtime/colorschemes/gotham.micro +29 -0
  126. package/apps/jsmdcui/runtime/colorschemes/gruvbox-tc.micro +29 -0
  127. package/apps/jsmdcui/runtime/colorschemes/gruvbox.micro +26 -0
  128. package/apps/jsmdcui/runtime/colorschemes/material-tc.micro +36 -0
  129. package/apps/jsmdcui/runtime/colorschemes/monokai-dark.micro +28 -0
  130. package/apps/jsmdcui/runtime/colorschemes/monokai.micro +34 -0
  131. package/apps/jsmdcui/runtime/colorschemes/one-dark.micro +39 -0
  132. package/apps/jsmdcui/runtime/colorschemes/railscast.micro +37 -0
  133. package/apps/jsmdcui/runtime/colorschemes/simple.micro +33 -0
  134. package/apps/jsmdcui/runtime/colorschemes/solarized-tc.micro +31 -0
  135. package/apps/jsmdcui/runtime/colorschemes/solarized.micro +30 -0
  136. package/apps/jsmdcui/runtime/colorschemes/sunny-day.micro +29 -0
  137. package/apps/jsmdcui/runtime/colorschemes/twilight.micro +40 -0
  138. package/apps/jsmdcui/runtime/colorschemes/zenburn.micro +30 -0
  139. package/apps/jsmdcui/runtime/help/actions.md +161 -0
  140. package/apps/jsmdcui/runtime/help/cdp.md +124 -0
  141. package/apps/jsmdcui/runtime/help/colors.md +421 -0
  142. package/apps/jsmdcui/runtime/help/commands.md +161 -0
  143. package/apps/jsmdcui/runtime/help/copypaste.md +149 -0
  144. package/apps/jsmdcui/runtime/help/defaultkeys.md +148 -0
  145. package/apps/jsmdcui/runtime/help/help.md +1269 -0
  146. package/apps/jsmdcui/runtime/help/keybindings.md +355 -0
  147. package/apps/jsmdcui/runtime/help/linter.md +90 -0
  148. package/apps/jsmdcui/runtime/help/options.md +709 -0
  149. package/apps/jsmdcui/runtime/help/plugins.md +544 -0
  150. package/apps/jsmdcui/runtime/help/tutorial.md +112 -0
  151. package/apps/jsmdcui/runtime/jsplugins/cdp/cdp-server.js +1185 -0
  152. package/apps/jsmdcui/runtime/jsplugins/cdp/cdp.js +201 -0
  153. package/apps/jsmdcui/runtime/jsplugins/chapter/chapter.js +111 -0
  154. package/apps/jsmdcui/runtime/jsplugins/diff/diff.js +46 -0
  155. package/apps/jsmdcui/runtime/jsplugins/example/example.js +117 -0
  156. package/apps/jsmdcui/runtime/jsplugins/linter/linter.js +281 -0
  157. package/apps/jsmdcui/runtime/plugins/autoclose/autoclose.lua +75 -0
  158. package/apps/jsmdcui/runtime/plugins/ftoptions/ftoptions.lua +17 -0
  159. package/apps/jsmdcui/runtime/plugins/literate/README.md +5 -0
  160. package/apps/jsmdcui/runtime/plugins/literate/literate.lua +55 -0
  161. package/apps/jsmdcui/runtime/plugins/status/help/status.md +21 -0
  162. package/apps/jsmdcui/runtime/plugins/status/status.lua +62 -0
  163. package/apps/jsmdcui/runtime/syntax/LICENSE +22 -0
  164. package/apps/jsmdcui/runtime/syntax/PowerShell.yaml +128 -0
  165. package/apps/jsmdcui/runtime/syntax/README.md +63 -0
  166. package/apps/jsmdcui/runtime/syntax/ada.yaml +43 -0
  167. package/apps/jsmdcui/runtime/syntax/apacheconf.yaml +59 -0
  168. package/apps/jsmdcui/runtime/syntax/arduino.yaml +101 -0
  169. package/apps/jsmdcui/runtime/syntax/asciidoc.yaml +51 -0
  170. package/apps/jsmdcui/runtime/syntax/asm.yaml +123 -0
  171. package/apps/jsmdcui/runtime/syntax/ats.yaml +99 -0
  172. package/apps/jsmdcui/runtime/syntax/awk.yaml +44 -0
  173. package/apps/jsmdcui/runtime/syntax/b.yaml +87 -0
  174. package/apps/jsmdcui/runtime/syntax/bat.yaml +57 -0
  175. package/apps/jsmdcui/runtime/syntax/c.yaml +60 -0
  176. package/apps/jsmdcui/runtime/syntax/caddyfile.yaml +23 -0
  177. package/apps/jsmdcui/runtime/syntax/cake.yaml +7 -0
  178. package/apps/jsmdcui/runtime/syntax/clojure.yaml +38 -0
  179. package/apps/jsmdcui/runtime/syntax/cmake.yaml +42 -0
  180. package/apps/jsmdcui/runtime/syntax/coffeescript.yaml +56 -0
  181. package/apps/jsmdcui/runtime/syntax/colortest.yaml +19 -0
  182. package/apps/jsmdcui/runtime/syntax/conky.yaml +17 -0
  183. package/apps/jsmdcui/runtime/syntax/cpp.yaml +91 -0
  184. package/apps/jsmdcui/runtime/syntax/crontab.yaml +36 -0
  185. package/apps/jsmdcui/runtime/syntax/crystal.yaml +72 -0
  186. package/apps/jsmdcui/runtime/syntax/csharp.yaml +52 -0
  187. package/apps/jsmdcui/runtime/syntax/css.yaml +44 -0
  188. package/apps/jsmdcui/runtime/syntax/csx.yaml +8 -0
  189. package/apps/jsmdcui/runtime/syntax/cuda.yaml +68 -0
  190. package/apps/jsmdcui/runtime/syntax/cython.yaml +52 -0
  191. package/apps/jsmdcui/runtime/syntax/d.yaml +121 -0
  192. package/apps/jsmdcui/runtime/syntax/dart.yaml +46 -0
  193. package/apps/jsmdcui/runtime/syntax/default.yaml +10 -0
  194. package/apps/jsmdcui/runtime/syntax/dockerfile.yaml +36 -0
  195. package/apps/jsmdcui/runtime/syntax/dot.yaml +29 -0
  196. package/apps/jsmdcui/runtime/syntax/elixir.yaml +30 -0
  197. package/apps/jsmdcui/runtime/syntax/elm.yaml +38 -0
  198. package/apps/jsmdcui/runtime/syntax/erb.yaml +42 -0
  199. package/apps/jsmdcui/runtime/syntax/erlang.yaml +45 -0
  200. package/apps/jsmdcui/runtime/syntax/fish.yaml +48 -0
  201. package/apps/jsmdcui/runtime/syntax/forth.yaml +34 -0
  202. package/apps/jsmdcui/runtime/syntax/fortran.yaml +64 -0
  203. package/apps/jsmdcui/runtime/syntax/freebsd-kernel.yaml +14 -0
  204. package/apps/jsmdcui/runtime/syntax/fsharp.yaml +48 -0
  205. package/apps/jsmdcui/runtime/syntax/gdscript.yaml +61 -0
  206. package/apps/jsmdcui/runtime/syntax/gemini.yaml +19 -0
  207. package/apps/jsmdcui/runtime/syntax/gentoo-ebuild.yaml +48 -0
  208. package/apps/jsmdcui/runtime/syntax/gentoo-etc-portage.yaml +23 -0
  209. package/apps/jsmdcui/runtime/syntax/git-commit.yaml +35 -0
  210. package/apps/jsmdcui/runtime/syntax/git-config.yaml +14 -0
  211. package/apps/jsmdcui/runtime/syntax/git-rebase-todo.yaml +19 -0
  212. package/apps/jsmdcui/runtime/syntax/gleam.yaml +69 -0
  213. package/apps/jsmdcui/runtime/syntax/glsl.yaml +26 -0
  214. package/apps/jsmdcui/runtime/syntax/gnuplot.yaml +15 -0
  215. package/apps/jsmdcui/runtime/syntax/go.yaml +62 -0
  216. package/apps/jsmdcui/runtime/syntax/godoc.yaml +17 -0
  217. package/apps/jsmdcui/runtime/syntax/golo.yaml +73 -0
  218. package/apps/jsmdcui/runtime/syntax/gomod.yaml +31 -0
  219. package/apps/jsmdcui/runtime/syntax/graphql.yaml +47 -0
  220. package/apps/jsmdcui/runtime/syntax/groff.yaml +30 -0
  221. package/apps/jsmdcui/runtime/syntax/groovy.yaml +111 -0
  222. package/apps/jsmdcui/runtime/syntax/haml.yaml +16 -0
  223. package/apps/jsmdcui/runtime/syntax/hare.yaml +52 -0
  224. package/apps/jsmdcui/runtime/syntax/haskell.yaml +52 -0
  225. package/apps/jsmdcui/runtime/syntax/hc.yaml +52 -0
  226. package/apps/jsmdcui/runtime/syntax/html.yaml +70 -0
  227. package/apps/jsmdcui/runtime/syntax/html4.yaml +25 -0
  228. package/apps/jsmdcui/runtime/syntax/html5.yaml +25 -0
  229. package/apps/jsmdcui/runtime/syntax/ini.yaml +23 -0
  230. package/apps/jsmdcui/runtime/syntax/inputrc.yaml +14 -0
  231. package/apps/jsmdcui/runtime/syntax/java.yaml +37 -0
  232. package/apps/jsmdcui/runtime/syntax/javascript.yaml +124 -0
  233. package/apps/jsmdcui/runtime/syntax/jinja2.yaml +19 -0
  234. package/apps/jsmdcui/runtime/syntax/json.yaml +39 -0
  235. package/apps/jsmdcui/runtime/syntax/jsonnet.yaml +92 -0
  236. package/apps/jsmdcui/runtime/syntax/julia.yaml +57 -0
  237. package/apps/jsmdcui/runtime/syntax/justfile.yaml +40 -0
  238. package/apps/jsmdcui/runtime/syntax/keymap.yaml +27 -0
  239. package/apps/jsmdcui/runtime/syntax/kickstart.yaml +16 -0
  240. package/apps/jsmdcui/runtime/syntax/kotlin.yaml +66 -0
  241. package/apps/jsmdcui/runtime/syntax/kvlang.yaml +67 -0
  242. package/apps/jsmdcui/runtime/syntax/ledger.yaml +14 -0
  243. package/apps/jsmdcui/runtime/syntax/lfe.yaml +17 -0
  244. package/apps/jsmdcui/runtime/syntax/lilypond.yaml +26 -0
  245. package/apps/jsmdcui/runtime/syntax/lisp.yaml +17 -0
  246. package/apps/jsmdcui/runtime/syntax/log.yaml +92 -0
  247. package/apps/jsmdcui/runtime/syntax/lua.yaml +111 -0
  248. package/apps/jsmdcui/runtime/syntax/mail.yaml +25 -0
  249. package/apps/jsmdcui/runtime/syntax/makefile.yaml +38 -0
  250. package/apps/jsmdcui/runtime/syntax/man.yaml +12 -0
  251. package/apps/jsmdcui/runtime/syntax/markdown.yaml +64 -0
  252. package/apps/jsmdcui/runtime/syntax/mc.yaml +23 -0
  253. package/apps/jsmdcui/runtime/syntax/meson.yaml +51 -0
  254. package/apps/jsmdcui/runtime/syntax/micro.yaml +34 -0
  255. package/apps/jsmdcui/runtime/syntax/mpdconf.yaml +13 -0
  256. package/apps/jsmdcui/runtime/syntax/msbuild.yaml +6 -0
  257. package/apps/jsmdcui/runtime/syntax/nanorc.yaml +16 -0
  258. package/apps/jsmdcui/runtime/syntax/nftables.yaml +30 -0
  259. package/apps/jsmdcui/runtime/syntax/nginx.yaml +22 -0
  260. package/apps/jsmdcui/runtime/syntax/nim.yaml +27 -0
  261. package/apps/jsmdcui/runtime/syntax/nix.yaml +32 -0
  262. package/apps/jsmdcui/runtime/syntax/nu.yaml +114 -0
  263. package/apps/jsmdcui/runtime/syntax/objc.yaml +60 -0
  264. package/apps/jsmdcui/runtime/syntax/ocaml.yaml +43 -0
  265. package/apps/jsmdcui/runtime/syntax/octave.yaml +83 -0
  266. package/apps/jsmdcui/runtime/syntax/odin.yaml +64 -0
  267. package/apps/jsmdcui/runtime/syntax/pascal.yaml +45 -0
  268. package/apps/jsmdcui/runtime/syntax/patch.yaml +14 -0
  269. package/apps/jsmdcui/runtime/syntax/peg.yaml +16 -0
  270. package/apps/jsmdcui/runtime/syntax/perl.yaml +58 -0
  271. package/apps/jsmdcui/runtime/syntax/php.yaml +60 -0
  272. package/apps/jsmdcui/runtime/syntax/pkg-config.yaml +12 -0
  273. package/apps/jsmdcui/runtime/syntax/po.yaml +12 -0
  274. package/apps/jsmdcui/runtime/syntax/pony.yaml +37 -0
  275. package/apps/jsmdcui/runtime/syntax/pov.yaml +21 -0
  276. package/apps/jsmdcui/runtime/syntax/privoxy-action.yaml +14 -0
  277. package/apps/jsmdcui/runtime/syntax/privoxy-config.yaml +10 -0
  278. package/apps/jsmdcui/runtime/syntax/privoxy-filter.yaml +12 -0
  279. package/apps/jsmdcui/runtime/syntax/proto.yaml +40 -0
  280. package/apps/jsmdcui/runtime/syntax/prql.yaml +84 -0
  281. package/apps/jsmdcui/runtime/syntax/puppet.yaml +22 -0
  282. package/apps/jsmdcui/runtime/syntax/python2.yaml +60 -0
  283. package/apps/jsmdcui/runtime/syntax/python3.yaml +80 -0
  284. package/apps/jsmdcui/runtime/syntax/r.yaml +32 -0
  285. package/apps/jsmdcui/runtime/syntax/raku.yaml +42 -0
  286. package/apps/jsmdcui/runtime/syntax/reST.yaml +18 -0
  287. package/apps/jsmdcui/runtime/syntax/renpy.yaml +15 -0
  288. package/apps/jsmdcui/runtime/syntax/rpmspec.yaml +43 -0
  289. package/apps/jsmdcui/runtime/syntax/ruby.yaml +73 -0
  290. package/apps/jsmdcui/runtime/syntax/rust.yaml +78 -0
  291. package/apps/jsmdcui/runtime/syntax/sage.yaml +60 -0
  292. package/apps/jsmdcui/runtime/syntax/scad.yaml +53 -0
  293. package/apps/jsmdcui/runtime/syntax/scala.yaml +33 -0
  294. package/apps/jsmdcui/runtime/syntax/sed.yaml +13 -0
  295. package/apps/jsmdcui/runtime/syntax/sh.yaml +69 -0
  296. package/apps/jsmdcui/runtime/syntax/sls.yaml +15 -0
  297. package/apps/jsmdcui/runtime/syntax/smalltalk.yaml +55 -0
  298. package/apps/jsmdcui/runtime/syntax/solidity.yaml +41 -0
  299. package/apps/jsmdcui/runtime/syntax/sql.yaml +35 -0
  300. package/apps/jsmdcui/runtime/syntax/stata.yaml +67 -0
  301. package/apps/jsmdcui/runtime/syntax/svelte.yaml +27 -0
  302. package/apps/jsmdcui/runtime/syntax/swift.yaml +103 -0
  303. package/apps/jsmdcui/runtime/syntax/systemd.yaml +16 -0
  304. package/apps/jsmdcui/runtime/syntax/tcl.yaml +18 -0
  305. package/apps/jsmdcui/runtime/syntax/terraform.yaml +87 -0
  306. package/apps/jsmdcui/runtime/syntax/tex.yaml +32 -0
  307. package/apps/jsmdcui/runtime/syntax/toml.yaml +56 -0
  308. package/apps/jsmdcui/runtime/syntax/twig.yaml +55 -0
  309. package/apps/jsmdcui/runtime/syntax/typescript.yaml +49 -0
  310. package/apps/jsmdcui/runtime/syntax/v.yaml +80 -0
  311. package/apps/jsmdcui/runtime/syntax/vala.yaml +26 -0
  312. package/apps/jsmdcui/runtime/syntax/verilog.yaml +60 -0
  313. package/apps/jsmdcui/runtime/syntax/vhdl.yaml +37 -0
  314. package/apps/jsmdcui/runtime/syntax/vi.yaml +31 -0
  315. package/apps/jsmdcui/runtime/syntax/vue.yaml +64 -0
  316. package/apps/jsmdcui/runtime/syntax/xml.yaml +37 -0
  317. package/apps/jsmdcui/runtime/syntax/xresources.yaml +14 -0
  318. package/apps/jsmdcui/runtime/syntax/yaml.yaml +34 -0
  319. package/apps/jsmdcui/runtime/syntax/yum.yaml +12 -0
  320. package/apps/jsmdcui/runtime/syntax/zig.yaml +52 -0
  321. package/apps/jsmdcui/runtime/syntax/zscript.yaml +72 -0
  322. package/apps/jsmdcui/runtime/syntax/zsh.yaml +52 -0
  323. package/apps/jsmdcui/single-exe/README.md +473 -0
  324. package/apps/jsmdcui/single-exe/assetsHelper.js +191 -0
  325. package/apps/jsmdcui/single-exe/assetsLoader.mjs +85 -0
  326. package/apps/jsmdcui/single-exe/compiled.js +212 -0
  327. package/apps/jsmdcui/single-exe/entry.mjs +10 -0
  328. package/apps/jsmdcui/single-exe/packAssets.sh +7 -0
  329. package/apps/jsmdcui/src/MDCUI_DEFAULT_EDIT +0 -0
  330. package/apps/jsmdcui/src/buffer/backup.js +165 -0
  331. package/apps/jsmdcui/src/buffer/buffer.js +126 -0
  332. package/apps/jsmdcui/src/buffer/fixed3-codec.js +140 -0
  333. package/apps/jsmdcui/src/buffer/loc.js +38 -0
  334. package/apps/jsmdcui/src/buffer/message.js +29 -0
  335. package/apps/jsmdcui/src/build-args.js +40 -0
  336. package/apps/jsmdcui/src/config/clean.js +172 -0
  337. package/apps/jsmdcui/src/config/colorscheme.js +99 -0
  338. package/apps/jsmdcui/src/config/config.js +125 -0
  339. package/apps/jsmdcui/src/config/defaults.js +109 -0
  340. package/apps/jsmdcui/src/cui/fence-events.mjs +144 -0
  341. package/apps/jsmdcui/src/cui/heading-ids.mjs +1568 -0
  342. package/apps/jsmdcui/src/cui/id-collision.mjs +111 -0
  343. package/apps/jsmdcui/src/cui/identity.mjs +26 -0
  344. package/apps/jsmdcui/src/cui/kitty-debug.mjs +25 -0
  345. package/apps/jsmdcui/src/cui/kitty-images.mjs +280 -0
  346. package/apps/jsmdcui/src/cui/kitty-mode.mjs +6 -0
  347. package/apps/jsmdcui/src/cui/rerender-queue.mjs +66 -0
  348. package/apps/jsmdcui/src/cui/rpc.mjs +1525 -0
  349. package/apps/jsmdcui/src/cui/server.mjs +128 -0
  350. package/apps/jsmdcui/src/cui/table-render.mjs +286 -0
  351. package/apps/jsmdcui/src/cui/table-row-edit.mjs +226 -0
  352. package/apps/jsmdcui/src/cui/task-checkbox.mjs +60 -0
  353. package/apps/jsmdcui/src/cui/template-components.mjs +253 -0
  354. package/apps/jsmdcui/src/cui/text-block-resize.mjs +177 -0
  355. package/apps/jsmdcui/src/cui/tui-links.mjs +560 -0
  356. package/apps/jsmdcui/src/display/ansi-style.js +60 -0
  357. package/apps/jsmdcui/src/highlight/highlighter.js +243 -0
  358. package/apps/jsmdcui/src/highlight/parser.js +225 -0
  359. package/apps/jsmdcui/src/index.js +9573 -0
  360. package/apps/jsmdcui/src/lua/engine.js +68 -0
  361. package/apps/jsmdcui/src/platform/archive.js +50 -0
  362. package/apps/jsmdcui/src/platform/clipboard.js +278 -0
  363. package/apps/jsmdcui/src/platform/commands.js +221 -0
  364. package/apps/jsmdcui/src/platform/terminal.js +5 -0
  365. package/apps/jsmdcui/src/plugins/js-bridge.js +3377 -0
  366. package/apps/jsmdcui/src/plugins/manager.js +674 -0
  367. package/apps/jsmdcui/src/runtime/encodings.js +10 -0
  368. package/apps/jsmdcui/src/runtime/registry.js +134 -0
  369. package/apps/jsmdcui/src/screen/cell-buffer.js +81 -0
  370. package/apps/jsmdcui/src/screen/events.js +263 -0
  371. package/apps/jsmdcui/src/screen/screen.js +249 -0
  372. package/apps/jsmdcui/src/screen/vt100.js +571 -0
  373. package/apps/jsmdcui/src/shell/shell.js +70 -0
  374. package/apps/jsmdcui/testapp.md +78 -0
  375. package/apps/jsmdcui/tests/assets-helper.test.js +150 -0
  376. package/apps/jsmdcui/tests/backup.test.js +158 -0
  377. package/apps/jsmdcui/tests/cat-markdown.test.js +139 -0
  378. package/apps/jsmdcui/tests/cmphex3b64.js +95 -0
  379. package/apps/jsmdcui/tests/compiled-runtime.test.js +139 -0
  380. package/apps/jsmdcui/tests/config-settings.test.js +52 -0
  381. package/apps/jsmdcui/tests/demo.test.js +447 -0
  382. package/apps/jsmdcui/tests/docs-sync.test.js +14 -0
  383. package/apps/jsmdcui/tests/fence-events.test.js +1293 -0
  384. package/apps/jsmdcui/tests/heading-ids.test.js +559 -0
  385. package/apps/jsmdcui/tests/heading-list-selector.test.js +2393 -0
  386. package/apps/jsmdcui/tests/id-collision.test.js +514 -0
  387. package/apps/jsmdcui/tests/js-plugin-prompts.test.js +110 -0
  388. package/apps/jsmdcui/tests/key-event.md +10 -0
  389. package/apps/jsmdcui/tests/kitty-demo.md +184 -0
  390. package/apps/jsmdcui/tests/kitty-images.test.js +288 -0
  391. package/apps/jsmdcui/tests/kitty-mode.test.js +14 -0
  392. package/apps/jsmdcui/tests/platform-commands.test.js +18 -0
  393. package/apps/jsmdcui/tests/platform-terminal.test.js +8 -0
  394. package/apps/jsmdcui/tests/pty-demo.js +492 -0
  395. package/apps/jsmdcui/tests/rerender-queue.test.js +130 -0
  396. package/apps/jsmdcui/tests/table-render.test.js +150 -0
  397. package/apps/jsmdcui/tests/table-row-edit.test.js +138 -0
  398. package/apps/jsmdcui/tests/task-checkbox.test.js +33 -0
  399. package/apps/jsmdcui/tests/template-components.test.js +422 -0
  400. package/apps/jsmdcui/tests/text-block-resize.test.js +222 -0
  401. package/apps/jsmdcui/tests/textarea.md +8 -0
  402. package/apps/jsmdcui/tests/tui-links.test.js +298 -0
  403. package/apps/jsmdcui/tests/wui-responsive-images.test.js +60 -0
  404. package/apps/jsmdcui/tests/wui.test.js +108 -0
  405. package/apps/jsmdcui/tests/wv-client.js +96 -0
  406. package/apps/jsmdcui/tui +7 -0
  407. package/apps/jsmdcui/wui +9 -0
  408. package/apps/musl-la/LICENSES/Apache-2.0_LLVM_Exceptions_license.txt +311 -0
  409. package/apps/musl-la/LICENSES/Apache-2.0_license.txt +177 -0
  410. package/apps/musl-la/LICENSES/BSD-3-Clause_license.txt +43 -0
  411. package/apps/musl-la/LICENSES/GPL-3.0.txt +674 -0
  412. package/apps/musl-la/LICENSES/LGPL-3.0.txt +165 -0
  413. package/apps/musl-la/LICENSES/MIT.txt +21 -0
  414. package/apps/musl-la/LICENSES/curl_license.txt +22 -0
  415. package/apps/musl-la/LICENSES/gcc_runtime_exception.txt +73 -0
  416. package/apps/musl-la/LICENSES/zlib_license.txt +22 -0
  417. package/apps/musl-la/LICENSE_musl.txt +193 -0
  418. package/apps/musl-la/NOTICE +56 -0
  419. package/apps/musl-la/ldmusl +0 -0
  420. package/apps/musl-la/libgcc_s.so.1 +0 -0
  421. package/apps/musl-la/libstdc++.so.6 +0 -0
  422. package/apps/musl-la/musl-la.sh +5 -0
  423. package/bin/bun.sh +57 -0
  424. package/bin/glow.sh +5 -0
  425. package/bin/init.js +395 -0
  426. package/bin/jmi.sh +5 -0
  427. package/bin/jsgotty.sh +5 -0
  428. package/bin/libsh-loader.c +135 -0
  429. package/bin/libsh-loader.so +0 -0
  430. package/bin/multicall.sh +90 -0
  431. package/bin/shc.js +5 -0
  432. package/bin/switch_to_android.sh +9 -0
  433. package/bin/switch_to_linux.sh +7 -0
  434. package/icon.png +0 -0
  435. package/package.json +31 -0
@@ -0,0 +1,1568 @@
1
+ const EMPTY_BUN_HEADING_ID = /^-\d+$/;
2
+ const HTML_ENTITY =
3
+ /&(?:#(\d+);?|#x([\da-f]+);?|([a-z][\da-z]*)(;?))/gi;
4
+ const HTML_NUMERIC_REPLACEMENTS = new Map([
5
+ [0x80, 0x20ac],
6
+ [0x82, 0x201a],
7
+ [0x83, 0x0192],
8
+ [0x84, 0x201e],
9
+ [0x85, 0x2026],
10
+ [0x86, 0x2020],
11
+ [0x87, 0x2021],
12
+ [0x88, 0x02c6],
13
+ [0x89, 0x2030],
14
+ [0x8a, 0x0160],
15
+ [0x8b, 0x2039],
16
+ [0x8c, 0x0152],
17
+ [0x8e, 0x017d],
18
+ [0x91, 0x2018],
19
+ [0x92, 0x2019],
20
+ [0x93, 0x201c],
21
+ [0x94, 0x201d],
22
+ [0x95, 0x2022],
23
+ [0x96, 0x2013],
24
+ [0x97, 0x2014],
25
+ [0x98, 0x02dc],
26
+ [0x99, 0x2122],
27
+ [0x9a, 0x0161],
28
+ [0x9b, 0x203a],
29
+ [0x9c, 0x0153],
30
+ [0x9e, 0x017e],
31
+ [0x9f, 0x0178],
32
+ ]);
33
+ const NAMED_HTML_ENTITIES = new Map([
34
+ ["amp", "&"],
35
+ ["apos", "'"],
36
+ ["gt", ">"],
37
+ ["lt", "<"],
38
+ ["nbsp", "\u00a0"],
39
+ ["quot", '"'],
40
+ ]);
41
+ const LEGACY_HTML_ENTITIES = new Set([
42
+ "AElig", "AMP", "Aacute", "Acirc", "Agrave", "Aring", "Atilde",
43
+ "Auml", "COPY", "Ccedil", "ETH", "Eacute", "Ecirc", "Egrave",
44
+ "Euml", "GT", "Iacute", "Icirc", "Igrave", "Iuml", "LT",
45
+ "Ntilde", "Oacute", "Ocirc", "Ograve", "Oslash", "Otilde",
46
+ "Ouml", "QUOT", "REG", "THORN", "Uacute", "Ucirc", "Ugrave",
47
+ "Uuml", "Yacute", "aacute", "acirc", "acute", "aelig", "agrave",
48
+ "amp", "aring", "atilde", "auml", "brvbar", "ccedil", "cedil",
49
+ "cent", "copy", "curren", "deg", "divide", "eacute", "ecirc",
50
+ "egrave", "eth", "euml", "frac12", "frac14", "frac34", "gt",
51
+ "iacute", "icirc", "iexcl", "igrave", "iquest", "iuml", "laquo",
52
+ "lt", "macr", "micro", "middot", "nbsp", "not", "ntilde",
53
+ "oacute", "ocirc", "ograve", "ordf", "ordm", "oslash", "otilde",
54
+ "ouml", "para", "plusmn", "pound", "quot", "raquo", "reg", "sect",
55
+ "shy", "sup1", "sup2", "sup3", "szlig", "thorn", "times",
56
+ "uacute", "ucirc", "ugrave", "uml", "uuml", "yacute", "yen",
57
+ "yuml",
58
+ ]);
59
+ const DECODED_HTML_ENTITIES = new Map();
60
+
61
+ function decodeNamedHtmlEntity(whole, name) {
62
+ const known = NAMED_HTML_ENTITIES.get(String(name));
63
+ if (known != null) return known;
64
+ if (DECODED_HTML_ENTITIES.has(whole))
65
+ return DECODED_HTML_ENTITIES.get(whole);
66
+
67
+ let decoded = "";
68
+ try {
69
+ Bun.markdown.render(
70
+ whole,
71
+ {
72
+ text(value) {
73
+ decoded += String(value);
74
+ return "";
75
+ },
76
+ paragraph(children) {
77
+ return children;
78
+ },
79
+ },
80
+ );
81
+ } catch {
82
+ decoded = whole;
83
+ }
84
+ if (!decoded) decoded = whole;
85
+ DECODED_HTML_ENTITIES.set(whole, decoded);
86
+ return decoded;
87
+ }
88
+
89
+ function decodeHtmlEntities(value, { attribute = false } = {}) {
90
+ const input = String(value ?? "");
91
+ return input.replace(
92
+ HTML_ENTITY,
93
+ (whole, decimal, hexadecimal, name, semicolon, offset) => {
94
+ if (decimal != null || hexadecimal != null) {
95
+ const point = Number.parseInt(
96
+ decimal ?? hexadecimal,
97
+ hexadecimal == null ? 10 : 16,
98
+ );
99
+ if (
100
+ !Number.isInteger(point)
101
+ || point === 0
102
+ || point > 0x10ffff
103
+ || (point >= 0xd800 && point <= 0xdfff)
104
+ ) return "\ufffd";
105
+ return String.fromCodePoint(
106
+ HTML_NUMERIC_REPLACEMENTS.get(point) ?? point,
107
+ );
108
+ }
109
+ if (semicolon) return decodeNamedHtmlEntity(whole, name);
110
+
111
+ for (let end = name.length; end > 0; end--) {
112
+ const candidate = name.slice(0, end);
113
+ if (!LEGACY_HTML_ENTITIES.has(candidate)) continue;
114
+ const remainder = name.slice(end);
115
+ const following = remainder[0] ?? input[offset + whole.length] ?? "";
116
+ if (attribute && /[=A-Za-z0-9]/u.test(following)) return whole;
117
+ return decodeNamedHtmlEntity(`&${candidate};`, candidate) + remainder;
118
+ }
119
+ return whole;
120
+ },
121
+ );
122
+ }
123
+
124
+ export function readLeadingHtmlCharacterReference(value) {
125
+ const input = String(value ?? "");
126
+ if (!input.startsWith("&")) return null;
127
+
128
+ const numeric = input.match(/^&#(?:[xX][\da-fA-F]+|\d+);?/u);
129
+ if (numeric) {
130
+ return {
131
+ source: numeric[0],
132
+ decoded: decodeHtmlEntities(numeric[0]),
133
+ };
134
+ }
135
+
136
+ const terminated = input.match(/^&([A-Za-z][A-Za-z0-9]*);/u);
137
+ if (terminated) {
138
+ const decoded = decodeHtmlEntities(terminated[0]);
139
+ if (decoded !== terminated[0])
140
+ return { source: terminated[0], decoded };
141
+ }
142
+
143
+ const unterminated = input.match(/^&([A-Za-z][A-Za-z0-9]*)/u);
144
+ const name = unterminated?.[1] ?? "";
145
+ for (let end = name.length; end > 0; end--) {
146
+ const candidate = name.slice(0, end);
147
+ if (!LEGACY_HTML_ENTITIES.has(candidate)) continue;
148
+ const source = `&${candidate}`;
149
+ return {
150
+ source,
151
+ decoded: decodeNamedHtmlEntity(
152
+ `&${candidate};`,
153
+ candidate,
154
+ ),
155
+ };
156
+ }
157
+ return null;
158
+ }
159
+
160
+ function htmlTokenAt(input, start) {
161
+ if (input[start] !== "<") return null;
162
+ if (input.startsWith("<!--", start)) {
163
+ const close = input.indexOf("-->", start + 4);
164
+ return {
165
+ start,
166
+ end: close < 0 ? input.length : close + 3,
167
+ kind: "comment",
168
+ name: null,
169
+ closing: false,
170
+ selfClosing: false,
171
+ source: input.slice(start, close < 0 ? input.length : close + 3),
172
+ };
173
+ }
174
+ if (input.startsWith("<![CDATA[", start)) {
175
+ const close = input.indexOf("]]>", start + 9);
176
+ const end = close < 0 ? input.length : close + 3;
177
+ return {
178
+ start,
179
+ end,
180
+ kind: "comment",
181
+ name: null,
182
+ closing: false,
183
+ selfClosing: false,
184
+ source: input.slice(start, end),
185
+ };
186
+ }
187
+ if (input.startsWith("<?", start)) {
188
+ const close = input.indexOf("?>", start + 2);
189
+ const end = close < 0 ? input.length : close + 2;
190
+ return {
191
+ start,
192
+ end,
193
+ kind: "comment",
194
+ name: null,
195
+ closing: false,
196
+ selfClosing: false,
197
+ source: input.slice(start, end),
198
+ };
199
+ }
200
+
201
+ const match = input.slice(start).match(
202
+ /^<\s*(\/?)\s*([A-Za-z][\w:-]*)(?=[\t\n\f\r />])/,
203
+ );
204
+ if (!match) {
205
+ const close = input.indexOf(">", start + 1);
206
+ if (close < 0) return null;
207
+ return {
208
+ start,
209
+ end: close + 1,
210
+ kind: "other",
211
+ name: null,
212
+ closing: false,
213
+ selfClosing: false,
214
+ source: input.slice(start, close + 1),
215
+ };
216
+ }
217
+
218
+ const isWhitespace = character =>
219
+ character === "\t"
220
+ || character === "\n"
221
+ || character === "\f"
222
+ || character === "\r"
223
+ || character === " ";
224
+ let index = start + match[0].length;
225
+ let state = "before-attribute";
226
+ let quote = null;
227
+ for (; index < input.length; index++) {
228
+ const character = input[index];
229
+ if (state === "quoted-value") {
230
+ if (character === quote) {
231
+ quote = null;
232
+ state = "before-attribute";
233
+ }
234
+ continue;
235
+ }
236
+ if (character === "<") break;
237
+ if (character === ">") {
238
+ index++;
239
+ break;
240
+ }
241
+
242
+ if (state === "before-attribute") {
243
+ if (isWhitespace(character) || character === "/") continue;
244
+ state = "attribute-name";
245
+ continue;
246
+ }
247
+ if (state === "attribute-name") {
248
+ if (character === "=") state = "before-value";
249
+ else if (isWhitespace(character)) state = "after-attribute-name";
250
+ continue;
251
+ }
252
+ if (state === "after-attribute-name") {
253
+ if (isWhitespace(character)) continue;
254
+ if (character === "=") state = "before-value";
255
+ else if (character === "/") state = "before-attribute";
256
+ else state = "attribute-name";
257
+ continue;
258
+ }
259
+ if (state === "before-value") {
260
+ if (isWhitespace(character)) continue;
261
+ if (character === '"' || character === "'") {
262
+ quote = character;
263
+ state = "quoted-value";
264
+ } else {
265
+ state = "unquoted-value";
266
+ }
267
+ continue;
268
+ }
269
+ if (state === "unquoted-value" && isWhitespace(character))
270
+ state = "before-attribute";
271
+ }
272
+ if (index >= input.length && input.at(-1) !== ">") return null;
273
+
274
+ const source = input.slice(start, index);
275
+ return {
276
+ start,
277
+ end: index,
278
+ kind: "tag",
279
+ name: match[2].toLowerCase(),
280
+ closing: Boolean(match[1]),
281
+ selfClosing: !match[1] && /\/[\t\n\f\r ]*>$/.test(source),
282
+ source,
283
+ };
284
+ }
285
+
286
+ function nextHtmlToken(input, from) {
287
+ let start = input.indexOf("<", from);
288
+ while (start >= 0) {
289
+ const token = htmlTokenAt(input, start);
290
+ if (token) return token;
291
+ start = input.indexOf("<", start + 1);
292
+ }
293
+ return null;
294
+ }
295
+
296
+ const HEADING_OPAQUE_TAGS = new Set([
297
+ "iframe",
298
+ "noembed",
299
+ "noframes",
300
+ "noscript",
301
+ "plaintext",
302
+ "script",
303
+ "style",
304
+ "template",
305
+ "textarea",
306
+ "title",
307
+ "xmp",
308
+ ]);
309
+ const HEADING_RAW_TEXT_TAGS = new Set([
310
+ "iframe",
311
+ "noembed",
312
+ "noframes",
313
+ "noscript",
314
+ "script",
315
+ "style",
316
+ "textarea",
317
+ "title",
318
+ "xmp",
319
+ ]);
320
+
321
+ function matchingHtmlClose(input, opening) {
322
+ if (
323
+ opening?.kind !== "tag"
324
+ || opening.closing
325
+ || opening.selfClosing
326
+ ) return null;
327
+
328
+ let depth = 1;
329
+ let scan = opening.end;
330
+ let token;
331
+ while ((token = nextHtmlToken(input, scan))) {
332
+ scan = token.end;
333
+ if (
334
+ token.kind === "tag"
335
+ && !token.closing
336
+ && !token.selfClosing
337
+ && token.name !== opening.name
338
+ && HEADING_OPAQUE_TAGS.has(token.name)
339
+ ) {
340
+ const closing = closingOpaqueTag(input, token);
341
+ scan = closing?.end ?? input.length;
342
+ continue;
343
+ }
344
+ if (token.kind !== "tag" || token.name !== opening.name) continue;
345
+ if (token.closing) {
346
+ depth--;
347
+ if (depth === 0) return token;
348
+ } else if (!token.selfClosing) {
349
+ depth++;
350
+ }
351
+ }
352
+ return null;
353
+ }
354
+
355
+ function closingOpaqueTag(input, opening) {
356
+ if (opening?.name === "plaintext") return null;
357
+ if (!HEADING_RAW_TEXT_TAGS.has(opening?.name))
358
+ return matchingHtmlClose(input, opening);
359
+
360
+ const closingPattern = new RegExp(
361
+ `</${opening.name}(?=[\\s>])`,
362
+ "ig",
363
+ );
364
+ closingPattern.lastIndex = opening.end;
365
+ let match;
366
+ while ((match = closingPattern.exec(input)) !== null) {
367
+ const token = htmlTokenAt(input, match.index);
368
+ if (token?.kind === "tag" && token.closing)
369
+ return token;
370
+ closingPattern.lastIndex = match.index + 2;
371
+ }
372
+ return null;
373
+ }
374
+
375
+ function htmlAttribute(source, expectedName) {
376
+ const input = String(source ?? "");
377
+ const opening = input.match(/^<\s*\/?\s*[^\s/>]+/);
378
+ if (!opening) return undefined;
379
+ const wanted = String(expectedName).toLowerCase();
380
+ let index = opening[0].length;
381
+
382
+ while (index < input.length) {
383
+ while (/\s/u.test(input[index] ?? "")) index++;
384
+ if (input[index] === ">" || input[index] === "/" || index >= input.length)
385
+ return undefined;
386
+
387
+ const nameStart = index;
388
+ while (index < input.length && !/[\s=/>]/u.test(input[index])) index++;
389
+ const name = input.slice(nameStart, index).toLowerCase();
390
+ while (/\s/u.test(input[index] ?? "")) index++;
391
+ if (input[index] !== "=") {
392
+ if (name === wanted) return "";
393
+ continue;
394
+ }
395
+
396
+ index++;
397
+ while (/\s/u.test(input[index] ?? "")) index++;
398
+ const quote = input[index] === '"' || input[index] === "'"
399
+ ? input[index++]
400
+ : null;
401
+ const valueStart = index;
402
+ if (quote) {
403
+ while (index < input.length && input[index] !== quote) index++;
404
+ } else {
405
+ while (index < input.length && !/[\s>]/u.test(input[index])) index++;
406
+ }
407
+ const value = input.slice(valueStart, index);
408
+ if (quote && input[index] === quote) index++;
409
+ if (name === wanted)
410
+ return decodeHtmlEntities(value, { attribute: true });
411
+ }
412
+ return undefined;
413
+ }
414
+
415
+ function visibleHeadingText(value) {
416
+ const input = String(value ?? "");
417
+ let output = "";
418
+ let cursor = 0;
419
+ for (let index = 0; index < input.length;) {
420
+ const start = input.indexOf("<", index);
421
+ if (start < 0) break;
422
+ const token = htmlTokenAt(input, start);
423
+ if (!token) {
424
+ index = start + 1;
425
+ continue;
426
+ }
427
+ output += decodeHtmlEntities(input.slice(cursor, start));
428
+ if (!token.closing) {
429
+ if (token.name === "br") output += " ";
430
+ else if (token.name === "img")
431
+ output += htmlAttribute(token.source, "alt") ?? "";
432
+ else if (
433
+ !token.selfClosing
434
+ && HEADING_OPAQUE_TAGS.has(token.name)
435
+ ) {
436
+ const closing = closingOpaqueTag(input, token);
437
+ cursor = closing?.end ?? input.length;
438
+ index = cursor;
439
+ continue;
440
+ }
441
+ }
442
+ cursor = token.end;
443
+ index = token.end;
444
+ }
445
+ output += decodeHtmlEntities(input.slice(cursor));
446
+ return output;
447
+ }
448
+
449
+ function comparableHeadingText(value) {
450
+ return String(value ?? "")
451
+ .normalize("NFKC")
452
+ .replace(/\s+/gu, " ")
453
+ .trim();
454
+ }
455
+
456
+ function stableHeadingHash(value) {
457
+ const bytes = new TextEncoder().encode(
458
+ comparableHeadingText(value).toLowerCase(),
459
+ );
460
+ let hash = 0xcbf29ce484222325n;
461
+ for (const byte of bytes) {
462
+ hash ^= BigInt(byte);
463
+ hash = BigInt.asUintN(64, hash * 0x100000001b3n);
464
+ }
465
+ return hash.toString(16).padStart(16, "0");
466
+ }
467
+
468
+ export function normalizeUnicodeHeadingId(value) {
469
+ const normalized = comparableHeadingText(value).toLowerCase();
470
+ const tokens = normalized.match(
471
+ /[_\p{L}\p{N}][_\p{L}\p{M}\p{N}]*/gu,
472
+ );
473
+ return tokens?.join("-") || `mdcui-h-${stableHeadingHash(normalized)}`;
474
+ }
475
+
476
+ const TEXT_TOKEN_PATTERN = /\ue000([0-9a-z]+)\ue001/giu;
477
+ const HEADING_STRUCTURE_PATTERN = /\ue100h([0-9a-z]+)\ue101/giu;
478
+
479
+ function escapeHtmlText(value) {
480
+ return String(value)
481
+ .replaceAll("&", "&amp;")
482
+ .replaceAll("<", "&lt;")
483
+ .replaceAll(">", "&gt;");
484
+ }
485
+
486
+ function markdownHeadingEvents(markdown) {
487
+ const source = String(markdown ?? "");
488
+ const textValues = [];
489
+ const records = [];
490
+ const headings = [];
491
+ let containerOrdinal = 0;
492
+
493
+ const storedTextToken = (
494
+ value,
495
+ literal = false,
496
+ explicitSlugValue,
497
+ ) => {
498
+ const ordinal = textValues.length;
499
+ const text = String(value ?? "");
500
+ const token = literal ? null : htmlTokenAt(text, 0);
501
+ textValues.push({
502
+ value: text,
503
+ literal,
504
+ slugValue: explicitSlugValue ?? (
505
+ token && token.end === text.length ? "" : text
506
+ ),
507
+ });
508
+ return `\ue000${ordinal.toString(36)}\ue001`;
509
+ };
510
+ const textToken = value => storedTextToken(value);
511
+ const expandTextTokens = (children) =>
512
+ String(children ?? "").replace(
513
+ TEXT_TOKEN_PATTERN,
514
+ (whole, encoded) =>
515
+ textValues[Number.parseInt(encoded, 36)]?.value ?? whole,
516
+ );
517
+ const expandSlugTokens = (children) =>
518
+ String(children ?? "").replace(
519
+ TEXT_TOKEN_PATTERN,
520
+ (whole, encoded) =>
521
+ textValues[Number.parseInt(encoded, 36)]?.slugValue ?? whole,
522
+ ).replace(/\r\n?|\n/gu, " ");
523
+ const inlineHtmlFromTokens = (children) => {
524
+ const input = String(children ?? "");
525
+ let output = "";
526
+ let cursor = 0;
527
+ TEXT_TOKEN_PATTERN.lastIndex = 0;
528
+ let match;
529
+ while ((match = TEXT_TOKEN_PATTERN.exec(input)) !== null) {
530
+ output += escapeHtmlText(input.slice(cursor, match.index));
531
+ const stored = textValues[Number.parseInt(match[1], 36)];
532
+ const value = stored?.value ?? match[0];
533
+ const token = htmlTokenAt(value, 0);
534
+ output += !stored?.literal && token && token.end === value.length
535
+ ? value
536
+ : escapeHtmlText(value);
537
+ cursor = match.index + match[0].length;
538
+ }
539
+ return output + escapeHtmlText(input.slice(cursor));
540
+ };
541
+ const recordInlineHtml = (children) => {
542
+ const html = inlineHtmlFromTokens(children);
543
+ if (html.includes("<")) records.push({ type: "raw", html });
544
+ return "";
545
+ };
546
+ const headingStructure = (children) => {
547
+ const input = String(children ?? "");
548
+ HEADING_STRUCTURE_PATTERN.lastIndex = 0;
549
+ return Array.from(input.matchAll(HEADING_STRUCTURE_PATTERN), match =>
550
+ match[0]
551
+ ).join("");
552
+ };
553
+ const markHeadingContainer = (children, type) => {
554
+ const structure = headingStructure(children);
555
+ if (!structure) return "";
556
+ const container = `${type}:${containerOrdinal++}`;
557
+ HEADING_STRUCTURE_PATTERN.lastIndex = 0;
558
+ for (const match of structure.matchAll(HEADING_STRUCTURE_PATTERN)) {
559
+ const heading = headings[Number.parseInt(match[1], 36)];
560
+ if (heading) heading.containerPath.unshift(container);
561
+ }
562
+ return structure;
563
+ };
564
+ const passthrough = (children) => children;
565
+
566
+ Bun.markdown.render(
567
+ source,
568
+ {
569
+ text: textToken,
570
+ strong: passthrough,
571
+ emphasis: passthrough,
572
+ link: passthrough,
573
+ image(children) {
574
+ const slugValue = expandSlugTokens(children);
575
+ return storedTextToken(
576
+ visibleHeadingText(inlineHtmlFromTokens(children)),
577
+ true,
578
+ slugValue,
579
+ );
580
+ },
581
+ codespan(children) {
582
+ const value = expandTextTokens(children);
583
+ return storedTextToken(
584
+ value,
585
+ true,
586
+ value.replace(/\r\n?|\n/gu, ""),
587
+ );
588
+ },
589
+ strikethrough: passthrough,
590
+ heading(children, meta) {
591
+ const inlineHtml = inlineHtmlFromTokens(children);
592
+ const text = visibleHeadingText(inlineHtml);
593
+ const bunId = String(meta?.id ?? "");
594
+ const ordinal = headings.length;
595
+ const heading = {
596
+ bunId,
597
+ containerPath: [],
598
+ fallback: bunId === "" || EMPTY_BUN_HEADING_ID.test(bunId),
599
+ inlineHtml,
600
+ level: Number(meta?.level),
601
+ ordinal,
602
+ slugText: expandSlugTokens(children),
603
+ text,
604
+ };
605
+ headings.push(heading);
606
+ records.push({ type: "markdown", heading });
607
+ return `\ue100h${ordinal.toString(36)}\ue101`;
608
+ },
609
+ html(children) {
610
+ records.push({
611
+ type: "raw",
612
+ html: expandTextTokens(children),
613
+ });
614
+ return "";
615
+ },
616
+ paragraph: recordInlineHtml,
617
+ listItem(children) {
618
+ recordInlineHtml(children);
619
+ return markHeadingContainer(children, "list-item");
620
+ },
621
+ th: recordInlineHtml,
622
+ td: recordInlineHtml,
623
+ code() {
624
+ return "";
625
+ },
626
+ blockquote(children) {
627
+ return markHeadingContainer(children, "blockquote");
628
+ },
629
+ list(children) {
630
+ return markHeadingContainer(children, "list");
631
+ },
632
+ hr() {
633
+ return "";
634
+ },
635
+ table() {
636
+ return "";
637
+ },
638
+ thead() {
639
+ return "";
640
+ },
641
+ tbody() {
642
+ return "";
643
+ },
644
+ tr() {
645
+ return "";
646
+ },
647
+ },
648
+ { headings: { ids: true } },
649
+ );
650
+
651
+ const events = [];
652
+ const rawHeadings = [];
653
+ for (const record of records) {
654
+ if (record.type === "markdown") {
655
+ events.push(record);
656
+ continue;
657
+ }
658
+ for (const heading of htmlHeadings(record.html)) {
659
+ const rawHeading = { ...heading, blockSource: record.html };
660
+ rawHeadings.push(rawHeading);
661
+ events.push({ type: "raw", heading: rawHeading });
662
+ }
663
+ }
664
+ return { events, headings, rawHeadings };
665
+ }
666
+
667
+ function htmlHeadings(html) {
668
+ const input = String(html ?? "");
669
+ const headings = [];
670
+ let scan = 0;
671
+ let opening;
672
+ while ((opening = nextHtmlToken(input, scan))) {
673
+ scan = opening.end;
674
+ if (
675
+ opening.kind !== "tag"
676
+ || opening.closing
677
+ || opening.selfClosing
678
+ ) continue;
679
+ if (HEADING_OPAQUE_TAGS.has(opening.name)) {
680
+ const closing = closingOpaqueTag(input, opening);
681
+ scan = closing?.end ?? input.length;
682
+ continue;
683
+ }
684
+ const headingMatch = opening.name?.match(/^h([1-6])$/);
685
+ if (!headingMatch) continue;
686
+
687
+ const closing = matchingHtmlClose(input, opening);
688
+ if (!closing) continue;
689
+ const innerHTML = input.slice(opening.end, closing.start);
690
+ headings.push({
691
+ start: opening.start,
692
+ end: closing.end,
693
+ source: input.slice(opening.start, closing.end),
694
+ openingSource: opening.source,
695
+ level: Number(headingMatch[1]),
696
+ innerHTML,
697
+ id: htmlAttribute(opening.source, "id"),
698
+ text: visibleHeadingText(innerHTML),
699
+ });
700
+ scan = closing.end;
701
+ }
702
+ return headings;
703
+ }
704
+
705
+ function legacyHtmlHeadings(html) {
706
+ return htmlHeadings(html).map((heading, ordinal) => ({
707
+ id: heading.id ?? null,
708
+ html: heading.innerHTML,
709
+ text: heading.text,
710
+ level: heading.level,
711
+ ordinal,
712
+ }));
713
+ }
714
+
715
+ function matchedMarkdownHeadings(
716
+ markdownHeadings,
717
+ renderedHeadings,
718
+ events,
719
+ ) {
720
+ if (events.length !== renderedHeadings.length) return null;
721
+
722
+ const matched = Array(markdownHeadings.length);
723
+ let markdownOrdinal = 0;
724
+ for (let index = 0; index < events.length; index++) {
725
+ const event = events[index];
726
+ const rendered = renderedHeadings[index];
727
+ if (event.type === "raw") {
728
+ const raw = event.heading;
729
+ if (
730
+ !raw
731
+ || rendered.level !== raw.level
732
+ || rendered.id !== raw.id
733
+ || comparableHeadingText(rendered.text)
734
+ !== comparableHeadingText(raw.text)
735
+ ) return null;
736
+ continue;
737
+ }
738
+
739
+ const heading = event.heading;
740
+ const ordinal = markdownOrdinal++;
741
+ if (
742
+ !heading
743
+ || heading !== markdownHeadings[ordinal]
744
+ || rendered.level !== heading.level
745
+ || rendered.id !== heading.bunId
746
+ || comparableHeadingText(rendered.text)
747
+ !== comparableHeadingText(heading.text)
748
+ ) return null;
749
+ matched[ordinal] = { ...heading, rendered };
750
+ }
751
+ return matched.every(Boolean) ? matched : null;
752
+ }
753
+
754
+ function escapeHtmlAttribute(value, quote) {
755
+ let output = String(value)
756
+ .replaceAll("&", "&amp;")
757
+ .replaceAll("<", "&lt;")
758
+ .replaceAll(">", "&gt;");
759
+ output = quote === "'"
760
+ ? output.replaceAll("'", "&#x27;")
761
+ : output.replaceAll('"', "&quot;");
762
+ return output;
763
+ }
764
+
765
+ function replaceHeadingId(source, id) {
766
+ const input = String(source);
767
+ const opening = htmlTokenAt(input, 0);
768
+ if (opening?.kind !== "tag" || opening.closing) return input;
769
+ const replacement = opening.source.replace(
770
+ /(\bid\s*=\s*)(["'])(.*?)\2/i,
771
+ (whole, prefix, quote) =>
772
+ `${prefix}${quote}${escapeHtmlAttribute(id, quote)}${quote}`,
773
+ );
774
+ return replacement + input.slice(opening.end);
775
+ }
776
+
777
+ function sourceLineMarkerName(source) {
778
+ let marker = "mdcui-heading-source-line";
779
+ let suffix = 0;
780
+ while (source.toLowerCase().includes(`<${marker}`))
781
+ marker = `mdcui-heading-source-line-${++suffix}`;
782
+ return marker;
783
+ }
784
+
785
+ function sourceLineContentOffset(line) {
786
+ const input = String(line ?? "");
787
+ let index = 0;
788
+ const skipWhitespace = () => {
789
+ while (input[index] === " " || input[index] === "\t") index++;
790
+ };
791
+ skipWhitespace();
792
+
793
+ while (index < input.length) {
794
+ if (input[index] === ">") {
795
+ index++;
796
+ skipWhitespace();
797
+ continue;
798
+ }
799
+ const listMarker = input.slice(index).match(
800
+ /^(?:[-+*]|\d{1,9}[.)])(?=[ \t])/u,
801
+ );
802
+ if (!listMarker) break;
803
+ index += listMarker[0].length;
804
+ skipWhitespace();
805
+ }
806
+ return index;
807
+ }
808
+
809
+ function sourceLineHasAtxCandidate(line) {
810
+ const input = String(line ?? "");
811
+ return /^#{1,6}(?=[ \t]|$)/u.test(
812
+ input.slice(sourceLineContentOffset(input)),
813
+ );
814
+ }
815
+
816
+ function sourceLineHasSetextCandidate(line) {
817
+ const input = String(line ?? "");
818
+ const content = input.slice(sourceLineContentOffset(input)).trim();
819
+ return /^(?:=+|-+)$/u.test(content);
820
+ }
821
+
822
+ const REFERENCE_DEFINITION_START =
823
+ /^\[(?:\\[^\r\n]|[^\[\]\\]){1,999}\]:/u;
824
+
825
+ function setextHeadingStart(lines, contentIndex) {
826
+ let start = contentIndex;
827
+ while (start > 0) {
828
+ const previous = String(lines[start - 1] ?? "");
829
+ const content = previous.slice(
830
+ sourceLineContentOffset(previous),
831
+ ).trim();
832
+ if (!content) break;
833
+ if (sourceLineHasAtxCandidate(previous)) break;
834
+ if (/^(?:`{3,}|~{3,})/u.test(content)) break;
835
+ if (REFERENCE_DEFINITION_START.test(content)) break;
836
+ if (/^<\/?[A-Za-z][^>]*>$/u.test(content)) break;
837
+ if (sourceLineHasSetextCandidate(previous)) break;
838
+ start--;
839
+ }
840
+ return start;
841
+ }
842
+
843
+ const SETEXT_HTML_BLOCK_START = new RegExp(
844
+ "^(?:"
845
+ + "<!--|<\\?|<!\\[CDATA\\[|<![A-Z]"
846
+ + "|</?(?:script|pre|style|textarea)(?=[\\t\\n\\f\\r />])"
847
+ + "|</?(?:address|article|aside|base|basefont|blockquote|body|caption"
848
+ + "|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset"
849
+ + "|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header"
850
+ + "|hr|html|iframe|legend|li|link|main|menu|menuitem|nav|noframes"
851
+ + "|ol|optgroup|option|p|param|search|section|summary|table|tbody"
852
+ + "|td|tfoot|th|thead|title|tr|track|ul)(?=[\\t\\n\\f\\r />])"
853
+ + ")",
854
+ "iu",
855
+ );
856
+
857
+ function setextMarkerDelimiters(source) {
858
+ let open = "\ue200MDCUI_SETEXT";
859
+ let close = "\ue201";
860
+ while (source.includes(open)) open += "X";
861
+ while (source.includes(close)) close += "\ue201";
862
+ return { open, close };
863
+ }
864
+
865
+ function sourceLineBelongsToReferenceDefinition(
866
+ lines,
867
+ lineIndex,
868
+ possibleStart,
869
+ ) {
870
+ if (!Number.isInteger(possibleStart)) return false;
871
+ let hasContent = false;
872
+ Bun.markdown.render(
873
+ lines.slice(possibleStart, lineIndex + 1).join("\n"),
874
+ {
875
+ text() {
876
+ hasContent = true;
877
+ return "";
878
+ },
879
+ html() {
880
+ hasContent = true;
881
+ return "";
882
+ },
883
+ code() {
884
+ hasContent = true;
885
+ return "";
886
+ },
887
+ image() {
888
+ hasContent = true;
889
+ return "";
890
+ },
891
+ heading() {
892
+ hasContent = true;
893
+ return "";
894
+ },
895
+ hr() {
896
+ hasContent = true;
897
+ return "";
898
+ },
899
+ },
900
+ );
901
+ return !hasContent;
902
+ }
903
+
904
+ function sameMarkdownHeadingContent(left, right) {
905
+ return (
906
+ left?.level === right?.level
907
+ && left?.inlineHtml === right?.inlineHtml
908
+ && left?.slugText === right?.slugText
909
+ && left?.text === right?.text
910
+ );
911
+ }
912
+
913
+ function locateSetextHeadingStart(lines, underline, expected) {
914
+ const content = underline - 1;
915
+ if (content < 0) return 0;
916
+ const probes = new Map();
917
+ const matches = (start) => {
918
+ if (!probes.has(start)) {
919
+ const heading = markdownHeadingEvents(
920
+ lines.slice(start, underline + 1).join("\n"),
921
+ ).headings.at(-1);
922
+ probes.set(start, sameMarkdownHeadingContent(heading, expected));
923
+ }
924
+ return probes.get(start);
925
+ };
926
+
927
+ if (matches(content)) return content;
928
+
929
+ let higher = content;
930
+ let lower = null;
931
+ for (let distance = 1; lower == null;) {
932
+ const candidate = Math.max(0, content - distance);
933
+ if (matches(candidate)) lower = candidate;
934
+ else higher = candidate;
935
+ if (candidate === 0) break;
936
+ distance *= 2;
937
+ }
938
+ if (lower == null)
939
+ return setextHeadingStart(lines, content);
940
+
941
+ while (higher - lower > 1) {
942
+ const middle = Math.floor((lower + higher) / 2);
943
+ if (matches(middle)) lower = middle;
944
+ else higher = middle;
945
+ }
946
+ return lower;
947
+ }
948
+
949
+ function baseMarkdownHeadingId(heading) {
950
+ if (!heading) return "";
951
+ if (heading.fallback) return normalizeUnicodeHeadingId(heading.text);
952
+
953
+ const encoded = Array.from(heading.slugText ?? "", character =>
954
+ `&#x${character.codePointAt(0).toString(16)};`
955
+ ).join("");
956
+ let bunId = "";
957
+ Bun.markdown.render(
958
+ `# ${encoded}\n`,
959
+ {
960
+ heading(children, meta) {
961
+ bunId = String(meta?.id ?? "");
962
+ return "";
963
+ },
964
+ },
965
+ { headings: { ids: true } },
966
+ );
967
+ return bunId || heading.bunId;
968
+ }
969
+
970
+ export function collectMarkdownHeadingDeclarations(
971
+ markdown,
972
+ { includeLevel = false, includeEndLine = false } = {},
973
+ ) {
974
+ const source = String(markdown ?? "");
975
+ const lines = source.split(/\r\n?|\n/);
976
+ const marker = sourceLineMarkerName(source);
977
+ const setextMarker = setextMarkerDelimiters(source);
978
+ const atxCandidates = new Map();
979
+ const setextCandidates = [];
980
+ const possibleReferenceStarts = [];
981
+ let possibleReferenceStart = null;
982
+
983
+ for (let index = 0; index < lines.length; index++) {
984
+ const content = lines[index].slice(
985
+ sourceLineContentOffset(lines[index]),
986
+ );
987
+ if (!content.trim()) possibleReferenceStart = null;
988
+ if (REFERENCE_DEFINITION_START.test(content))
989
+ possibleReferenceStart = index;
990
+ possibleReferenceStarts[index] = possibleReferenceStart;
991
+
992
+ if (sourceLineHasAtxCandidate(lines[index])) {
993
+ atxCandidates.set(index, {
994
+ line: index + 1,
995
+ source: lines[index].trim(),
996
+ });
997
+ }
998
+ if (
999
+ index > 0
1000
+ && lines[index - 1].trim()
1001
+ && sourceLineHasSetextCandidate(lines[index])
1002
+ ) {
1003
+ const start = setextHeadingStart(lines, index - 1);
1004
+ setextCandidates.push({
1005
+ ordinal: setextCandidates.length,
1006
+ start,
1007
+ content: index - 1,
1008
+ underline: index,
1009
+ });
1010
+ }
1011
+ if (
1012
+ sourceLineHasAtxCandidate(lines[index])
1013
+ || sourceLineHasSetextCandidate(lines[index])
1014
+ || /^(?:`{3,}|~{3,})/u.test(content)
1015
+ || SETEXT_HTML_BLOCK_START.test(content)
1016
+ ) possibleReferenceStart = null;
1017
+ }
1018
+
1019
+ const markerPattern = new RegExp(
1020
+ `<${marker} data-mdcui-line="(\\d+)"></${marker}>`,
1021
+ "g",
1022
+ );
1023
+ const setextMarkerPattern = new RegExp(
1024
+ `${setextMarker.open}([0-9a-z]+)${setextMarker.close}[ ]?`,
1025
+ "giu",
1026
+ );
1027
+
1028
+ const markedLines = lines.slice();
1029
+ for (const [index] of atxCandidates) {
1030
+ const markerHtml =
1031
+ `<${marker} data-mdcui-line="${index}"></${marker}>`;
1032
+ const closingHashes =
1033
+ markedLines[index].match(/[ \t]+#+[ \t]*$/u);
1034
+ if (closingHashes?.index != null) {
1035
+ markedLines[index] =
1036
+ markedLines[index].slice(0, closingHashes.index)
1037
+ + ` ${markerHtml}`
1038
+ + markedLines[index].slice(closingHashes.index);
1039
+ } else {
1040
+ markedLines[index] += ` ${markerHtml}`;
1041
+ }
1042
+ }
1043
+
1044
+ const markedSetextLines = new Set();
1045
+ const setextByMarker = new Map();
1046
+ for (const candidate of setextCandidates) {
1047
+ const content = lines[candidate.content].slice(
1048
+ sourceLineContentOffset(lines[candidate.content]),
1049
+ );
1050
+ if (
1051
+ markedSetextLines.has(candidate.content)
1052
+ || sourceLineHasAtxCandidate(lines[candidate.content])
1053
+ || sourceLineHasSetextCandidate(lines[candidate.content])
1054
+ || /^(?:`{3,}|~{3,})/u.test(content)
1055
+ || sourceLineBelongsToReferenceDefinition(
1056
+ lines,
1057
+ candidate.content,
1058
+ possibleReferenceStarts[candidate.content],
1059
+ )
1060
+ || SETEXT_HTML_BLOCK_START.test(content)
1061
+ ) continue;
1062
+
1063
+ const markerOrdinal = setextByMarker.size;
1064
+ const token =
1065
+ `${setextMarker.open}${markerOrdinal.toString(36)}`
1066
+ + setextMarker.close;
1067
+ const offset = sourceLineContentOffset(markedLines[candidate.content]);
1068
+ markedLines[candidate.content] =
1069
+ markedLines[candidate.content].slice(0, offset)
1070
+ + `${token} `
1071
+ + markedLines[candidate.content].slice(offset);
1072
+ markedSetextLines.add(candidate.content);
1073
+ setextByMarker.set(markerOrdinal, {
1074
+ setextUnderline: candidate.underline,
1075
+ });
1076
+ }
1077
+
1078
+ const discovered = [];
1079
+ const markedHeadings = markdownHeadingEvents(
1080
+ markedLines.join("\n"),
1081
+ ).headings;
1082
+ for (const [headingOrdinal, heading] of markedHeadings.entries()) {
1083
+ markerPattern.lastIndex = 0;
1084
+ setextMarkerPattern.lastIndex = 0;
1085
+ const atxMatch = markerPattern.exec(heading.inlineHtml);
1086
+ const setextMatch = setextMarkerPattern.exec(heading.inlineHtml);
1087
+ const candidate = atxMatch
1088
+ ? atxCandidates.get(Number(atxMatch[1]))
1089
+ : setextByMarker.get(
1090
+ Number.parseInt(setextMatch?.[1] ?? "", 36),
1091
+ );
1092
+ if (!candidate) continue;
1093
+ markerPattern.lastIndex = 0;
1094
+ setextMarkerPattern.lastIndex = 0;
1095
+ discovered.push({
1096
+ ...candidate,
1097
+ headingOrdinal,
1098
+ level: heading.level,
1099
+ text: visibleHeadingText(
1100
+ heading.inlineHtml
1101
+ .replace(markerPattern, "")
1102
+ .replace(setextMarkerPattern, ""),
1103
+ ),
1104
+ });
1105
+ }
1106
+ discovered.sort((left, right) => left.line - right.line);
1107
+
1108
+ const actual = markdownHeadingEvents(source).headings;
1109
+ const discoveredByOrdinal = new Map(
1110
+ discovered.map(item => [item.headingOrdinal, item]),
1111
+ );
1112
+ const aligned = [];
1113
+ for (const heading of actual) {
1114
+ const found = discoveredByOrdinal.get(heading.ordinal);
1115
+ if (!found || found.level !== heading.level) {
1116
+ aligned.push({
1117
+ line: 1,
1118
+ source: heading.text || "(empty heading)",
1119
+ heading,
1120
+ });
1121
+ } else if (Number.isInteger(found.setextUnderline)) {
1122
+ const start = locateSetextHeadingStart(
1123
+ lines,
1124
+ found.setextUnderline,
1125
+ heading,
1126
+ );
1127
+ aligned.push({
1128
+ ...found,
1129
+ line: start + 1,
1130
+ source:
1131
+ `${lines.slice(start, found.setextUnderline)
1132
+ .map(line => line.trim()).join(" ")} / `
1133
+ + lines[found.setextUnderline].trim(),
1134
+ heading,
1135
+ });
1136
+ } else {
1137
+ aligned.push({ ...found, heading });
1138
+ }
1139
+ }
1140
+
1141
+ return aligned.map((heading) => ({
1142
+ id: baseMarkdownHeadingId(heading.heading),
1143
+ kind: "heading",
1144
+ ...(includeLevel ? { level: heading.heading.level } : {}),
1145
+ line: heading.line,
1146
+ ...(includeEndLine
1147
+ ? {
1148
+ endLine: Number.isInteger(heading.setextUnderline)
1149
+ ? heading.setextUnderline + 1
1150
+ : heading.line,
1151
+ }
1152
+ : {}),
1153
+ source: heading.source,
1154
+ })).filter(heading => heading.id);
1155
+ }
1156
+
1157
+ function markRawHeadingCandidates(markdown) {
1158
+ const source = String(markdown ?? "");
1159
+ let marker = "data-mdcui-raw-heading-source";
1160
+ let suffix = 0;
1161
+ while (source.toLowerCase().includes(marker))
1162
+ marker = `data-mdcui-raw-heading-source-${++suffix}`;
1163
+
1164
+ const lineStarts = [0];
1165
+ const lineEnds = [];
1166
+ const lineBreakPattern = /\r\n?|\n/g;
1167
+ let lineBreak;
1168
+ while ((lineBreak = lineBreakPattern.exec(source)) !== null) {
1169
+ lineEnds.push(lineBreak.index);
1170
+ lineStarts.push(lineBreak.index + lineBreak[0].length);
1171
+ }
1172
+ lineEnds.push(source.length);
1173
+
1174
+ const candidates = [];
1175
+ let lineIndex = 0;
1176
+ for (let index = 0; index < source.length;) {
1177
+ const openingName = source.slice(index).match(
1178
+ /^<([A-Za-z][\w:-]*)([\t\n\f\r />])/u,
1179
+ );
1180
+ if (
1181
+ !openingName
1182
+ || !/^h[1-6]$/iu.test(openingName[1])
1183
+ ) {
1184
+ index++;
1185
+ continue;
1186
+ }
1187
+
1188
+ const boundary = openingName[2];
1189
+ const afterBoundary = index + openingName[0].length;
1190
+ const selfClosing = boundary === "/"
1191
+ && /^[\t\n\f\r ]*>/u.test(source.slice(afterBoundary));
1192
+ const insertAt = afterBoundary
1193
+ - (boundary === ">" || selfClosing ? 1 : 0);
1194
+ while (
1195
+ lineIndex + 1 < lineStarts.length
1196
+ && lineStarts[lineIndex + 1] <= index
1197
+ ) lineIndex++;
1198
+ candidates.push({
1199
+ index,
1200
+ insertAt,
1201
+ line: lineIndex + 1,
1202
+ source: source.slice(
1203
+ lineStarts[lineIndex],
1204
+ lineEnds[lineIndex],
1205
+ ).trim(),
1206
+ });
1207
+ index = insertAt;
1208
+ }
1209
+
1210
+ const pieces = [];
1211
+ let cursor = 0;
1212
+ for (let ordinal = 0; ordinal < candidates.length; ordinal++) {
1213
+ const candidate = candidates[ordinal];
1214
+ pieces.push(
1215
+ source.slice(cursor, candidate.insertAt),
1216
+ ` ${marker}=${ordinal} `,
1217
+ );
1218
+ cursor = candidate.insertAt;
1219
+ }
1220
+ pieces.push(source.slice(cursor));
1221
+ return {
1222
+ candidates,
1223
+ marker,
1224
+ source: pieces.join(""),
1225
+ };
1226
+ }
1227
+
1228
+ function transformHtmlSynchronously(html, configure) {
1229
+ let rewriter = new HTMLRewriter();
1230
+ rewriter = configure(rewriter);
1231
+ const promise = rewriter.transform(new Response(String(html))).text();
1232
+ const result = Bun.peek(promise);
1233
+ if (typeof result !== "string")
1234
+ throw new Error("HTMLRewriter did not complete synchronously");
1235
+ return result;
1236
+ }
1237
+
1238
+ function browserHeadingRecords(html, rawMarker) {
1239
+ const records = [];
1240
+ let templateDepth = 0;
1241
+ const templateHandler = {
1242
+ element(element) {
1243
+ if (
1244
+ element.namespaceURI
1245
+ !== "http://www.w3.org/1999/xhtml"
1246
+ ) return;
1247
+ templateDepth++;
1248
+ element.onEndTag(() => {
1249
+ templateDepth = Math.max(0, templateDepth - 1);
1250
+ });
1251
+ },
1252
+ };
1253
+ const headingHandler = {
1254
+ element(element) {
1255
+ const rawOrdinal = element.getAttribute(rawMarker);
1256
+ const hasId = element.hasAttribute("id");
1257
+ records.push({
1258
+ id: hasId
1259
+ ? decodeHtmlEntities(
1260
+ element.getAttribute("id") ?? "",
1261
+ { attribute: true },
1262
+ )
1263
+ : undefined,
1264
+ level: Number(String(element.tagName).slice(1)),
1265
+ namespace: element.namespaceURI,
1266
+ rawOrdinal: /^\d+$/u.test(rawOrdinal ?? "")
1267
+ ? Number(rawOrdinal)
1268
+ : null,
1269
+ template: templateDepth > 0,
1270
+ });
1271
+ },
1272
+ };
1273
+ transformHtmlSynchronously(html, (rewriter) => {
1274
+ rewriter = rewriter.on("template", templateHandler);
1275
+ for (let level = 1; level <= 6; level++)
1276
+ rewriter = rewriter.on(`h${level}`, headingHandler);
1277
+ return rewriter;
1278
+ });
1279
+ return records;
1280
+ }
1281
+
1282
+ function equivalentHeadingRecords(original, marked) {
1283
+ return (
1284
+ original.length === marked.length
1285
+ && original.every((record, ordinal) => {
1286
+ const candidate = marked[ordinal];
1287
+ return (
1288
+ record.level === candidate.level
1289
+ && record.namespace === candidate.namespace
1290
+ && record.template === candidate.template
1291
+ && (
1292
+ candidate.rawOrdinal == null
1293
+ || String(record.id ?? "") === String(candidate.id ?? "")
1294
+ )
1295
+ );
1296
+ })
1297
+ );
1298
+ }
1299
+
1300
+ export function collectRawHtmlHeadingDeclarations(
1301
+ markdown,
1302
+ { strict = false, includeLevel = false } = {},
1303
+ ) {
1304
+ const marked = markRawHeadingCandidates(markdown);
1305
+ if (marked.candidates.length === 0) return [];
1306
+
1307
+ const original = Bun.markdown.html(
1308
+ String(markdown ?? ""),
1309
+ { headings: { ids: true } },
1310
+ );
1311
+ const rendered = Bun.markdown.html(
1312
+ marked.source,
1313
+ { headings: { ids: true } },
1314
+ );
1315
+ const originalRecords = browserHeadingRecords(original, marked.marker);
1316
+ const markedRecords = browserHeadingRecords(rendered, marked.marker);
1317
+ if (!equivalentHeadingRecords(originalRecords, markedRecords)) {
1318
+ if (strict)
1319
+ throw new Error("Raw HTML headings could not be classified safely");
1320
+ return [];
1321
+ }
1322
+
1323
+ const declarations = [];
1324
+ for (const heading of markedRecords) {
1325
+ if (
1326
+ heading.template
1327
+ || heading.rawOrdinal == null
1328
+ || !heading.id
1329
+ ) continue;
1330
+ const candidate = marked.candidates[heading.rawOrdinal];
1331
+ if (!candidate) continue;
1332
+ declarations.push({
1333
+ ordinal: heading.rawOrdinal,
1334
+ id: heading.id,
1335
+ kind: "raw HTML heading",
1336
+ ...(includeLevel ? { level: heading.level } : {}),
1337
+ line: candidate.line,
1338
+ source: candidate.source,
1339
+ });
1340
+ }
1341
+ declarations.sort((left, right) => left.ordinal - right.ordinal);
1342
+ return declarations.map(({ ordinal, ...declaration }) => declaration);
1343
+ }
1344
+
1345
+ function rewriteBrowserMarkdownHeadings(
1346
+ originalHtml,
1347
+ markedHtml,
1348
+ rawMarker,
1349
+ markdownHeadings,
1350
+ ) {
1351
+ const records = browserHeadingRecords(markedHtml, rawMarker);
1352
+ const originalRecords = browserHeadingRecords(originalHtml, rawMarker);
1353
+ if (!equivalentHeadingRecords(originalRecords, records))
1354
+ throw new Error("Raw heading markers changed the rendered structure");
1355
+
1356
+ const mainRecords = records
1357
+ .map((record, ordinal) => ({
1358
+ marked: record,
1359
+ original: originalRecords[ordinal],
1360
+ }))
1361
+ .filter(({ marked }) => !marked.template);
1362
+ const renderedMarkdown = mainRecords.filter(
1363
+ ({ marked }) => marked.rawOrdinal == null,
1364
+ );
1365
+ const normalized = (
1366
+ renderedMarkdown.length === markdownHeadings.length
1367
+ && renderedMarkdown.every(({ original }, ordinal) => {
1368
+ const heading = markdownHeadings[ordinal];
1369
+ return (
1370
+ original.level === heading.level
1371
+ && String(original.id ?? "") === heading.bunId
1372
+ );
1373
+ })
1374
+ );
1375
+ if (!normalized)
1376
+ throw new Error("Rendered Markdown headings could not be aligned");
1377
+
1378
+ const usedIds = new Set(
1379
+ mainRecords
1380
+ .filter(({ marked }) => marked.rawOrdinal != null)
1381
+ .map(({ original }) => original.id)
1382
+ .filter(Boolean),
1383
+ );
1384
+ for (const heading of markdownHeadings) {
1385
+ if (!heading.fallback && heading.bunId) usedIds.add(heading.bunId);
1386
+ }
1387
+ for (const heading of markdownHeadings) {
1388
+ if (!heading.fallback) {
1389
+ heading.id = heading.bunId;
1390
+ continue;
1391
+ }
1392
+ const base = normalizeUnicodeHeadingId(heading.text);
1393
+ let id = base;
1394
+ let suffix = 1;
1395
+ while (usedIds.has(id)) id = `${base}-${suffix++}`;
1396
+ heading.id = id;
1397
+ usedIds.add(id);
1398
+ }
1399
+
1400
+ let boundary = "MDCUI_HEADING_CONTENT";
1401
+ let boundarySuffix = 0;
1402
+ while (String(originalHtml).includes(boundary))
1403
+ boundary = `MDCUI_HEADING_CONTENT_${++boundarySuffix}`;
1404
+ let markdownOrdinal = 0;
1405
+ let recordOrdinal = 0;
1406
+ const headingHandler = {
1407
+ element(element) {
1408
+ const record = records[recordOrdinal++];
1409
+ if (record?.template || record?.rawOrdinal != null) return;
1410
+
1411
+ const ordinal = markdownOrdinal++;
1412
+ const heading = markdownHeadings[ordinal];
1413
+ if (!heading) return;
1414
+ element.setAttribute("id", heading.id);
1415
+ element.prepend(
1416
+ `<!--${boundary}:s:${ordinal.toString(36)}-->`,
1417
+ { html: true },
1418
+ );
1419
+ element.append(
1420
+ `<!--${boundary}:e:${ordinal.toString(36)}-->`,
1421
+ { html: true },
1422
+ );
1423
+ },
1424
+ };
1425
+ const rewritten = transformHtmlSynchronously(originalHtml, (rewriter) => {
1426
+ for (let level = 1; level <= 6; level++)
1427
+ rewriter = rewriter.on(`h${level}`, headingHandler);
1428
+ return rewriter;
1429
+ });
1430
+
1431
+ const innerHtml = new Map();
1432
+ const starts = new Map();
1433
+ const boundaryPattern = new RegExp(
1434
+ `<!--${boundary}:([se]):([0-9a-z]+)-->`,
1435
+ "g",
1436
+ );
1437
+ let match;
1438
+ while ((match = boundaryPattern.exec(rewritten)) !== null) {
1439
+ const ordinal = Number.parseInt(match[2], 36);
1440
+ if (match[1] === "s") {
1441
+ starts.set(ordinal, match.index + match[0].length);
1442
+ } else if (starts.has(ordinal)) {
1443
+ innerHtml.set(
1444
+ ordinal,
1445
+ rewritten.slice(starts.get(ordinal), match.index),
1446
+ );
1447
+ }
1448
+ }
1449
+ boundaryPattern.lastIndex = 0;
1450
+ const cleanHtml = rewritten.replace(boundaryPattern, "");
1451
+
1452
+ return {
1453
+ html: cleanHtml,
1454
+ normalized,
1455
+ headings: markdownHeadings.map((heading, ordinal) => ({
1456
+ id: heading.id,
1457
+ html: innerHtml.get(ordinal) ?? heading.inlineHtml,
1458
+ text: heading.text,
1459
+ level: heading.level,
1460
+ containerPath: heading.containerPath,
1461
+ ordinal,
1462
+ })),
1463
+ };
1464
+ }
1465
+
1466
+ export function renderMarkdownWithHeadingIds(markdown) {
1467
+ const source = String(markdown ?? "");
1468
+ const headingEvents = markdownHeadingEvents(source);
1469
+ const markdownHeadings = headingEvents.headings;
1470
+ const html = String(Bun.markdown.html(
1471
+ source,
1472
+ { headings: { ids: true } },
1473
+ ));
1474
+ if (markdownHeadings.length === 0)
1475
+ return { html, headings: [], normalized: true };
1476
+
1477
+ const marked = markRawHeadingCandidates(source);
1478
+ if (
1479
+ typeof HTMLRewriter === "function"
1480
+ && typeof Bun.peek === "function"
1481
+ ) {
1482
+ try {
1483
+ const markedHtml = String(Bun.markdown.html(
1484
+ marked.source,
1485
+ { headings: { ids: true } },
1486
+ ));
1487
+ return rewriteBrowserMarkdownHeadings(
1488
+ html,
1489
+ markedHtml,
1490
+ marked.marker,
1491
+ markdownHeadings,
1492
+ );
1493
+ } catch {
1494
+ return {
1495
+ html,
1496
+ headings: [],
1497
+ normalized: false,
1498
+ };
1499
+ }
1500
+ }
1501
+
1502
+ const renderedHeadings = htmlHeadings(html);
1503
+ const matched = matchedMarkdownHeadings(
1504
+ markdownHeadings,
1505
+ renderedHeadings,
1506
+ headingEvents.events,
1507
+ );
1508
+ if (!matched) {
1509
+ return {
1510
+ html,
1511
+ headings: legacyHtmlHeadings(html),
1512
+ normalized: false,
1513
+ };
1514
+ }
1515
+
1516
+ const matchedRendered = new Set(matched.map(item => item.rendered));
1517
+ const usedIds = new Set(
1518
+ renderedHeadings
1519
+ .filter(heading => !matchedRendered.has(heading))
1520
+ .map(heading => heading.id)
1521
+ .filter(Boolean),
1522
+ );
1523
+ for (const heading of matched) {
1524
+ if (!heading.fallback && heading.bunId) usedIds.add(heading.bunId);
1525
+ }
1526
+
1527
+ for (const heading of matched) {
1528
+ if (!heading.fallback) {
1529
+ heading.id = heading.bunId;
1530
+ continue;
1531
+ }
1532
+ const base = normalizeUnicodeHeadingId(heading.text);
1533
+ let id = base;
1534
+ let suffix = 1;
1535
+ while (usedIds.has(id)) id = `${base}-${suffix++}`;
1536
+ heading.id = id;
1537
+ usedIds.add(id);
1538
+ }
1539
+
1540
+ const replacementByStart = new Map(
1541
+ matched.map(heading => [
1542
+ heading.rendered.start,
1543
+ replaceHeadingId(heading.rendered.source, heading.id),
1544
+ ]),
1545
+ );
1546
+ let rewritten = "";
1547
+ let cursor = 0;
1548
+ for (const rendered of renderedHeadings) {
1549
+ const replacement = replacementByStart.get(rendered.start);
1550
+ if (replacement == null) continue;
1551
+ rewritten += html.slice(cursor, rendered.start) + replacement;
1552
+ cursor = rendered.end;
1553
+ }
1554
+ rewritten += html.slice(cursor);
1555
+
1556
+ return {
1557
+ html: rewritten,
1558
+ normalized: true,
1559
+ headings: matched.map((heading, ordinal) => ({
1560
+ id: heading.id,
1561
+ html: heading.rendered.innerHTML,
1562
+ text: heading.text,
1563
+ level: heading.level,
1564
+ containerPath: heading.containerPath,
1565
+ ordinal,
1566
+ })),
1567
+ };
1568
+ }