@temelj/mdx 0.13.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (369) hide show
  1. package/README.md +468 -82
  2. package/dist/character-entities.d.mts +4 -0
  3. package/dist/character-entities.d.mts.map +1 -0
  4. package/dist/character-entities.mjs +2132 -0
  5. package/dist/character-entities.mjs.map +1 -0
  6. package/dist/character-reference.d.mts +6 -0
  7. package/dist/character-reference.d.mts.map +1 -0
  8. package/dist/character-reference.mjs +18 -0
  9. package/dist/character-reference.mjs.map +1 -0
  10. package/dist/compile-analysis.d.mts +28 -0
  11. package/dist/compile-analysis.d.mts.map +1 -0
  12. package/dist/compile-analysis.mjs +74 -0
  13. package/dist/compile-analysis.mjs.map +1 -0
  14. package/dist/compile-emit.d.mts +9 -0
  15. package/dist/compile-emit.d.mts.map +1 -0
  16. package/dist/compile-emit.mjs +187 -0
  17. package/dist/compile-emit.mjs.map +1 -0
  18. package/dist/compile-esm.d.mts +34 -0
  19. package/dist/compile-esm.d.mts.map +1 -0
  20. package/dist/compile-esm.mjs +187 -0
  21. package/dist/compile-esm.mjs.map +1 -0
  22. package/dist/compile-names.d.mts +13 -0
  23. package/dist/compile-names.d.mts.map +1 -0
  24. package/dist/compile-names.mjs +32 -0
  25. package/dist/compile-names.mjs.map +1 -0
  26. package/dist/compiler.d.mts +69 -85
  27. package/dist/compiler.d.mts.map +1 -1
  28. package/dist/compiler.mjs +185 -418
  29. package/dist/compiler.mjs.map +1 -1
  30. package/dist/diagnostics.d.mts +37 -0
  31. package/dist/diagnostics.d.mts.map +1 -0
  32. package/dist/diagnostics.mjs +57 -0
  33. package/dist/diagnostics.mjs.map +1 -0
  34. package/dist/errors.d.mts +157 -0
  35. package/dist/errors.d.mts.map +1 -0
  36. package/dist/errors.mjs +263 -0
  37. package/dist/errors.mjs.map +1 -0
  38. package/dist/footnote-numbering.d.mts +27 -0
  39. package/dist/footnote-numbering.d.mts.map +1 -0
  40. package/dist/footnote-numbering.mjs +49 -0
  41. package/dist/footnote-numbering.mjs.map +1 -0
  42. package/dist/format-context.d.mts +46 -0
  43. package/dist/format-context.d.mts.map +1 -0
  44. package/dist/format-context.mjs +26 -0
  45. package/dist/format-context.mjs.map +1 -0
  46. package/dist/format-directive.d.mts +9 -0
  47. package/dist/format-directive.d.mts.map +1 -0
  48. package/dist/format-directive.mjs +99 -0
  49. package/dist/format-directive.mjs.map +1 -0
  50. package/dist/format-jsx.d.mts +8 -0
  51. package/dist/format-jsx.d.mts.map +1 -0
  52. package/dist/format-jsx.mjs +47 -0
  53. package/dist/format-jsx.mjs.map +1 -0
  54. package/dist/format-math.d.mts +9 -0
  55. package/dist/format-math.d.mts.map +1 -0
  56. package/dist/format-math.mjs +79 -0
  57. package/dist/format-math.mjs.map +1 -0
  58. package/dist/format-safe.d.mts +25 -0
  59. package/dist/format-safe.d.mts.map +1 -0
  60. package/dist/format-safe.mjs +366 -0
  61. package/dist/format-safe.mjs.map +1 -0
  62. package/dist/format-table.d.mts +8 -0
  63. package/dist/format-table.d.mts.map +1 -0
  64. package/dist/format-table.mjs +55 -0
  65. package/dist/format-table.mjs.map +1 -0
  66. package/dist/format-track.d.mts +18 -0
  67. package/dist/format-track.d.mts.map +1 -0
  68. package/dist/format-track.mjs +34 -0
  69. package/dist/format-track.mjs.map +1 -0
  70. package/dist/format.d.mts +7 -0
  71. package/dist/format.d.mts.map +1 -0
  72. package/dist/format.mjs +549 -0
  73. package/dist/format.mjs.map +1 -0
  74. package/dist/frontmatter.d.mts +15 -0
  75. package/dist/frontmatter.d.mts.map +1 -0
  76. package/dist/frontmatter.mjs +187 -0
  77. package/dist/frontmatter.mjs.map +1 -0
  78. package/dist/heading.d.mts +6 -0
  79. package/dist/heading.d.mts.map +1 -0
  80. package/dist/heading.mjs +19 -0
  81. package/dist/heading.mjs.map +1 -0
  82. package/dist/html-format.d.mts +32 -0
  83. package/dist/html-format.d.mts.map +1 -0
  84. package/dist/html-format.mjs +127 -0
  85. package/dist/html-format.mjs.map +1 -0
  86. package/dist/html-lower.d.mts +78 -0
  87. package/dist/html-lower.d.mts.map +1 -0
  88. package/dist/html-lower.mjs +583 -0
  89. package/dist/html-lower.mjs.map +1 -0
  90. package/dist/html-stream.d.mts +13 -0
  91. package/dist/html-stream.d.mts.map +1 -0
  92. package/dist/html-stream.mjs +32 -0
  93. package/dist/html-stream.mjs.map +1 -0
  94. package/dist/html.d.mts +120 -0
  95. package/dist/html.d.mts.map +1 -0
  96. package/dist/html.mjs +77 -0
  97. package/dist/html.mjs.map +1 -0
  98. package/dist/identifier.d.mts +4 -0
  99. package/dist/identifier.d.mts.map +1 -0
  100. package/dist/identifier.mjs +8 -0
  101. package/dist/identifier.mjs.map +1 -0
  102. package/dist/javascript-ast.d.mts +16 -0
  103. package/dist/javascript-ast.d.mts.map +1 -0
  104. package/dist/javascript-ast.mjs +39 -0
  105. package/dist/javascript-ast.mjs.map +1 -0
  106. package/dist/javascript-jsx.d.mts +24 -0
  107. package/dist/javascript-jsx.d.mts.map +1 -0
  108. package/dist/javascript-jsx.mjs +189 -0
  109. package/dist/javascript-jsx.mjs.map +1 -0
  110. package/dist/javascript.d.mts +9 -0
  111. package/dist/javascript.d.mts.map +1 -0
  112. package/dist/javascript.mjs +31 -0
  113. package/dist/javascript.mjs.map +1 -0
  114. package/dist/jsx-reference.d.mts +15 -0
  115. package/dist/jsx-reference.d.mts.map +1 -0
  116. package/dist/jsx-reference.mjs +31 -0
  117. package/dist/jsx-reference.mjs.map +1 -0
  118. package/dist/mod.d.mts +25 -8
  119. package/dist/mod.mjs +19 -7
  120. package/dist/model.d.mts +196 -0
  121. package/dist/model.d.mts.map +1 -0
  122. package/dist/model.mjs +113 -0
  123. package/dist/model.mjs.map +1 -0
  124. package/dist/parser/block-container-recognizers.d.mts +40 -0
  125. package/dist/parser/block-container-recognizers.d.mts.map +1 -0
  126. package/dist/parser/block-container-recognizers.mjs +90 -0
  127. package/dist/parser/block-container-recognizers.mjs.map +1 -0
  128. package/dist/parser/block-directive-recognizers.d.mts +22 -0
  129. package/dist/parser/block-directive-recognizers.d.mts.map +1 -0
  130. package/dist/parser/block-directive-recognizers.mjs +77 -0
  131. package/dist/parser/block-directive-recognizers.mjs.map +1 -0
  132. package/dist/parser/block-leaf-recognizers.d.mts +53 -0
  133. package/dist/parser/block-leaf-recognizers.d.mts.map +1 -0
  134. package/dist/parser/block-leaf-recognizers.mjs +386 -0
  135. package/dist/parser/block-leaf-recognizers.mjs.map +1 -0
  136. package/dist/parser/block-parser.d.mts +38 -0
  137. package/dist/parser/block-parser.d.mts.map +1 -0
  138. package/dist/parser/block-parser.mjs +895 -0
  139. package/dist/parser/block-parser.mjs.map +1 -0
  140. package/dist/parser/block-syntax.d.mts +240 -0
  141. package/dist/parser/block-syntax.d.mts.map +1 -0
  142. package/dist/parser/characters.d.mts +19 -0
  143. package/dist/parser/characters.d.mts.map +1 -0
  144. package/dist/parser/characters.mjs +52 -0
  145. package/dist/parser/characters.mjs.map +1 -0
  146. package/dist/parser/config.d.mts +16 -0
  147. package/dist/parser/config.d.mts.map +1 -0
  148. package/dist/parser/config.mjs +25 -0
  149. package/dist/parser/config.mjs.map +1 -0
  150. package/dist/parser/directive-attributes.d.mts +9 -0
  151. package/dist/parser/directive-attributes.d.mts.map +1 -0
  152. package/dist/parser/directive-attributes.mjs +24 -0
  153. package/dist/parser/directive-attributes.mjs.map +1 -0
  154. package/dist/parser/embedded-scanner.d.mts +18 -0
  155. package/dist/parser/embedded-scanner.d.mts.map +1 -0
  156. package/dist/parser/embedded-scanner.mjs +199 -0
  157. package/dist/parser/embedded-scanner.mjs.map +1 -0
  158. package/dist/parser/inline-autolink.d.mts +7 -0
  159. package/dist/parser/inline-autolink.d.mts.map +1 -0
  160. package/dist/parser/inline-autolink.mjs +42 -0
  161. package/dist/parser/inline-autolink.mjs.map +1 -0
  162. package/dist/parser/inline-character-reference.d.mts +7 -0
  163. package/dist/parser/inline-character-reference.d.mts.map +1 -0
  164. package/dist/parser/inline-character-reference.mjs +22 -0
  165. package/dist/parser/inline-character-reference.mjs.map +1 -0
  166. package/dist/parser/inline-code.d.mts +7 -0
  167. package/dist/parser/inline-code.d.mts.map +1 -0
  168. package/dist/parser/inline-code.mjs +29 -0
  169. package/dist/parser/inline-code.mjs.map +1 -0
  170. package/dist/parser/inline-directive.d.mts +9 -0
  171. package/dist/parser/inline-directive.d.mts.map +1 -0
  172. package/dist/parser/inline-directive.mjs +45 -0
  173. package/dist/parser/inline-directive.mjs.map +1 -0
  174. package/dist/parser/inline-embedded.d.mts +19 -0
  175. package/dist/parser/inline-embedded.d.mts.map +1 -0
  176. package/dist/parser/inline-embedded.mjs +92 -0
  177. package/dist/parser/inline-embedded.mjs.map +1 -0
  178. package/dist/parser/inline-emphasis.d.mts +11 -0
  179. package/dist/parser/inline-emphasis.d.mts.map +1 -0
  180. package/dist/parser/inline-emphasis.mjs +79 -0
  181. package/dist/parser/inline-emphasis.mjs.map +1 -0
  182. package/dist/parser/inline-input.d.mts +46 -0
  183. package/dist/parser/inline-input.d.mts.map +1 -0
  184. package/dist/parser/inline-input.mjs +137 -0
  185. package/dist/parser/inline-input.mjs.map +1 -0
  186. package/dist/parser/inline-link.d.mts +12 -0
  187. package/dist/parser/inline-link.d.mts.map +1 -0
  188. package/dist/parser/inline-link.mjs +187 -0
  189. package/dist/parser/inline-link.mjs.map +1 -0
  190. package/dist/parser/inline-math.d.mts +10 -0
  191. package/dist/parser/inline-math.d.mts.map +1 -0
  192. package/dist/parser/inline-math.mjs +46 -0
  193. package/dist/parser/inline-math.mjs.map +1 -0
  194. package/dist/parser/inline-output.d.mts +34 -0
  195. package/dist/parser/inline-output.d.mts.map +1 -0
  196. package/dist/parser/inline-output.mjs +62 -0
  197. package/dist/parser/inline-output.mjs.map +1 -0
  198. package/dist/parser/inline-parser.d.mts +14 -0
  199. package/dist/parser/inline-parser.d.mts.map +1 -0
  200. package/dist/parser/inline-parser.mjs +328 -0
  201. package/dist/parser/inline-parser.mjs.map +1 -0
  202. package/dist/parser/inline-pending.d.mts +23 -0
  203. package/dist/parser/inline-pending.d.mts.map +1 -0
  204. package/dist/parser/inline-pending.mjs +100 -0
  205. package/dist/parser/inline-pending.mjs.map +1 -0
  206. package/dist/parser/inline-syntax.d.mts +118 -0
  207. package/dist/parser/inline-syntax.d.mts.map +1 -0
  208. package/dist/parser/inline-syntax.mjs +1 -0
  209. package/dist/parser/javascript-boundary.d.mts +16 -0
  210. package/dist/parser/javascript-boundary.d.mts.map +1 -0
  211. package/dist/parser/javascript-boundary.mjs +42 -0
  212. package/dist/parser/javascript-boundary.mjs.map +1 -0
  213. package/dist/parser/javascript-scanner.d.mts +22 -0
  214. package/dist/parser/javascript-scanner.d.mts.map +1 -0
  215. package/dist/parser/javascript-scanner.mjs +122 -0
  216. package/dist/parser/javascript-scanner.mjs.map +1 -0
  217. package/dist/parser/materialize-cache.d.mts +34 -0
  218. package/dist/parser/materialize-cache.d.mts.map +1 -0
  219. package/dist/parser/materialize-cache.mjs +12 -0
  220. package/dist/parser/materialize-cache.mjs.map +1 -0
  221. package/dist/parser/materialize-jsx.d.mts +14 -0
  222. package/dist/parser/materialize-jsx.d.mts.map +1 -0
  223. package/dist/parser/materialize-jsx.mjs +76 -0
  224. package/dist/parser/materialize-jsx.mjs.map +1 -0
  225. package/dist/parser/materialize.d.mts +61 -0
  226. package/dist/parser/materialize.d.mts.map +1 -0
  227. package/dist/parser/materialize.mjs +736 -0
  228. package/dist/parser/materialize.mjs.map +1 -0
  229. package/dist/parser/recognizer.d.mts +20 -0
  230. package/dist/parser/recognizer.d.mts.map +1 -0
  231. package/dist/parser/recognizer.mjs +24 -0
  232. package/dist/parser/recognizer.mjs.map +1 -0
  233. package/dist/parser/session.d.mts +42 -0
  234. package/dist/parser/session.d.mts.map +1 -0
  235. package/dist/parser/session.mjs +89 -0
  236. package/dist/parser/session.mjs.map +1 -0
  237. package/dist/parser.d.mts +25 -0
  238. package/dist/parser.d.mts.map +1 -0
  239. package/dist/parser.mjs +37 -0
  240. package/dist/parser.mjs.map +1 -0
  241. package/dist/plugin-internal.d.mts +25 -0
  242. package/dist/plugin-internal.d.mts.map +1 -0
  243. package/dist/plugin-internal.mjs +99 -0
  244. package/dist/plugin-internal.mjs.map +1 -0
  245. package/dist/plugin.d.mts +37 -0
  246. package/dist/plugin.d.mts.map +1 -0
  247. package/dist/plugin.mjs +1 -0
  248. package/dist/plugins/code-block-metadata.d.mts +42 -0
  249. package/dist/plugins/code-block-metadata.d.mts.map +1 -0
  250. package/dist/plugins/code-block-metadata.mjs +133 -0
  251. package/dist/plugins/code-block-metadata.mjs.map +1 -0
  252. package/dist/plugins/heading-id.d.mts +15 -0
  253. package/dist/plugins/heading-id.d.mts.map +1 -0
  254. package/dist/plugins/heading-id.mjs +45 -0
  255. package/dist/plugins/heading-id.mjs.map +1 -0
  256. package/dist/plugins/lower-heading.d.mts +16 -0
  257. package/dist/plugins/lower-heading.d.mts.map +1 -0
  258. package/dist/plugins/lower-heading.mjs +28 -0
  259. package/dist/plugins/lower-heading.mjs.map +1 -0
  260. package/dist/plugins/math-render.d.mts +26 -0
  261. package/dist/plugins/math-render.d.mts.map +1 -0
  262. package/dist/plugins/math-render.mjs +51 -0
  263. package/dist/plugins/math-render.mjs.map +1 -0
  264. package/dist/plugins/mod.d.mts +9 -5
  265. package/dist/plugins/mod.mjs +8 -5
  266. package/dist/plugins/remove-esm.d.mts +10 -0
  267. package/dist/plugins/remove-esm.d.mts.map +1 -0
  268. package/dist/plugins/remove-esm.mjs +12 -0
  269. package/dist/plugins/remove-esm.mjs.map +1 -0
  270. package/dist/plugins/shiki.d.mts +21 -0
  271. package/dist/plugins/shiki.d.mts.map +1 -0
  272. package/dist/plugins/shiki.mjs +144 -0
  273. package/dist/plugins/shiki.mjs.map +1 -0
  274. package/dist/plugins/syntax-highlight.d.mts +38 -0
  275. package/dist/plugins/syntax-highlight.d.mts.map +1 -0
  276. package/dist/plugins/syntax-highlight.mjs +106 -0
  277. package/dist/plugins/syntax-highlight.mjs.map +1 -0
  278. package/dist/processor.d.mts +60 -0
  279. package/dist/processor.d.mts.map +1 -0
  280. package/dist/processor.mjs +106 -0
  281. package/dist/processor.mjs.map +1 -0
  282. package/dist/ranges.d.mts +10 -0
  283. package/dist/ranges.d.mts.map +1 -0
  284. package/dist/ranges.mjs +22 -0
  285. package/dist/ranges.mjs.map +1 -0
  286. package/dist/source-map.d.mts +28 -0
  287. package/dist/source-map.d.mts.map +1 -0
  288. package/dist/source-map.mjs +90 -0
  289. package/dist/source-map.mjs.map +1 -0
  290. package/dist/source-text.d.mts +35 -0
  291. package/dist/source-text.d.mts.map +1 -0
  292. package/dist/source-text.mjs +132 -0
  293. package/dist/source-text.mjs.map +1 -0
  294. package/dist/source.d.mts +86 -0
  295. package/dist/source.d.mts.map +1 -0
  296. package/dist/source.mjs +264 -0
  297. package/dist/source.mjs.map +1 -0
  298. package/dist/stream-events.d.mts +59 -0
  299. package/dist/stream-events.d.mts.map +1 -0
  300. package/dist/stream-events.mjs +115 -0
  301. package/dist/stream-events.mjs.map +1 -0
  302. package/dist/stream-session.d.mts +79 -0
  303. package/dist/stream-session.d.mts.map +1 -0
  304. package/dist/stream-session.mjs +904 -0
  305. package/dist/stream-session.mjs.map +1 -0
  306. package/dist/stream-tail.d.mts +84 -0
  307. package/dist/stream-tail.d.mts.map +1 -0
  308. package/dist/stream-tail.mjs +359 -0
  309. package/dist/stream-tail.mjs.map +1 -0
  310. package/dist/stream-types.d.mts +89 -0
  311. package/dist/stream-types.d.mts.map +1 -0
  312. package/dist/stream-types.mjs +1 -0
  313. package/dist/stream.d.mts +28 -0
  314. package/dist/stream.d.mts.map +1 -0
  315. package/dist/stream.mjs +68 -0
  316. package/dist/stream.mjs.map +1 -0
  317. package/dist/syntax-options.d.mts +21 -0
  318. package/dist/syntax-options.d.mts.map +1 -0
  319. package/dist/syntax-options.mjs +26 -0
  320. package/dist/syntax-options.mjs.map +1 -0
  321. package/dist/traversal.d.mts +25 -0
  322. package/dist/traversal.d.mts.map +1 -0
  323. package/dist/traversal.mjs +136 -0
  324. package/dist/traversal.mjs.map +1 -0
  325. package/dist/tree.d.mts +18 -0
  326. package/dist/tree.d.mts.map +1 -0
  327. package/dist/tree.mjs +43 -0
  328. package/dist/tree.mjs.map +1 -0
  329. package/dist/unified/adapter.d.mts +24 -0
  330. package/dist/unified/adapter.d.mts.map +1 -0
  331. package/dist/unified/adapter.mjs +44 -0
  332. package/dist/unified/adapter.mjs.map +1 -0
  333. package/dist/unified/mod.d.mts +2 -0
  334. package/dist/unified/mod.mjs +1 -0
  335. package/dist/unified/runtime.d.mts +10 -0
  336. package/dist/unified/runtime.d.mts.map +1 -0
  337. package/dist/unified/runtime.mjs +115 -0
  338. package/dist/unified/runtime.mjs.map +1 -0
  339. package/dist/unified/tree-bridge.d.mts +63 -0
  340. package/dist/unified/tree-bridge.d.mts.map +1 -0
  341. package/dist/unified/tree-bridge.mjs +876 -0
  342. package/dist/unified/tree-bridge.mjs.map +1 -0
  343. package/dist/uri.d.mts +5 -0
  344. package/dist/uri.d.mts.map +1 -0
  345. package/dist/uri.mjs +32 -0
  346. package/dist/uri.mjs.map +1 -0
  347. package/package.json +56 -27
  348. package/dist/plugins/heading-id/plugin.d.mts +0 -17
  349. package/dist/plugins/heading-id/plugin.d.mts.map +0 -1
  350. package/dist/plugins/heading-id/plugin.mjs +0 -23
  351. package/dist/plugins/heading-id/plugin.mjs.map +0 -1
  352. package/dist/plugins/remove-imports-exports.d.mts +0 -10
  353. package/dist/plugins/remove-imports-exports.d.mts.map +0 -1
  354. package/dist/plugins/remove-imports-exports.mjs +0 -15
  355. package/dist/plugins/remove-imports-exports.mjs.map +0 -1
  356. package/dist/plugins/syntax-highlight/code-meta.d.mts +0 -22
  357. package/dist/plugins/syntax-highlight/code-meta.d.mts.map +0 -1
  358. package/dist/plugins/syntax-highlight/code-meta.mjs +0 -38
  359. package/dist/plugins/syntax-highlight/code-meta.mjs.map +0 -1
  360. package/dist/plugins/syntax-highlight/plugin.d.mts +0 -57
  361. package/dist/plugins/syntax-highlight/plugin.d.mts.map +0 -1
  362. package/dist/plugins/syntax-highlight/plugin.mjs +0 -93
  363. package/dist/plugins/syntax-highlight/plugin.mjs.map +0 -1
  364. package/dist/plugins/tree-processor/plugin.d.mts +0 -19
  365. package/dist/plugins/tree-processor/plugin.d.mts.map +0 -1
  366. package/dist/plugins/tree-processor/plugin.mjs +0 -21
  367. package/dist/plugins/tree-processor/plugin.mjs.map +0 -1
  368. package/dist/types.d.mts +0 -2
  369. /package/dist/{types.mjs → parser/block-syntax.mjs} +0 -0
@@ -0,0 +1,144 @@
1
+ import { codeLineSelected } from "./code-block-metadata.mjs";
2
+ import { isBoolean, isNumber, isString } from "@temelj/value";
3
+ //#region src/plugins/shiki.ts
4
+ const specialLanguages = /* @__PURE__ */ new Set([
5
+ "ansi",
6
+ "plain",
7
+ "plaintext",
8
+ "text",
9
+ "txt"
10
+ ]);
11
+ /** Adapts a caller-owned, preloaded Shiki highlighter to Temelj's code highlighter. */
12
+ function createShikiHighlighter(highlighter, options) {
13
+ const { commandLineClassName = "line-command", fallbackLanguage, highlightedLineClassName = "highlighted", includeDataAttributes = [], languageAliases = {}, lineNumberClassName = "line-number", lineNumberWidthProperty = "--line-number-width", ...codeOptions } = options;
14
+ const loadedLanguages = new Set(highlighter.getLoadedLanguages().map((language) => language.toLowerCase()));
15
+ const aliases = /* @__PURE__ */ new Map();
16
+ for (const [from, to] of Object.entries(languageAliases)) aliases.set(from.toLowerCase(), to.toLowerCase());
17
+ return {
18
+ kind: "synchronous",
19
+ highlight(request) {
20
+ request.signal?.throwIfAborted();
21
+ const language = resolveLanguage(request.language, aliases, fallbackLanguage, loadedLanguages);
22
+ if (language === void 0) return;
23
+ const root = highlighter.codeToHast(request.code, {
24
+ ...codeOptions,
25
+ lang: language,
26
+ meta: request.metadata.raw === void 0 ? void 0 : { __raw: request.metadata.raw },
27
+ structure: "classic"
28
+ });
29
+ request.signal?.throwIfAborted();
30
+ const pre = onlyPreElement(root.children);
31
+ decorateCodeBlock(pre, request, {
32
+ commandLineClassName,
33
+ highlightedLineClassName,
34
+ includeDataAttributes,
35
+ lineNumberClassName,
36
+ lineNumberWidthProperty
37
+ });
38
+ return convertElement(pre);
39
+ }
40
+ };
41
+ }
42
+ function resolveLanguage(authored, aliases, fallback, loaded) {
43
+ const normalized = authored.toLowerCase();
44
+ const requested = aliases.get(normalized) ?? normalized;
45
+ if (isAvailableLanguage(requested, loaded)) return requested;
46
+ const normalizedFallback = fallback?.toLowerCase();
47
+ return normalizedFallback !== void 0 && isAvailableLanguage(normalizedFallback, loaded) ? normalizedFallback : void 0;
48
+ }
49
+ function isAvailableLanguage(language, loaded) {
50
+ return language.length > 0 && (loaded.has(language) || specialLanguages.has(language));
51
+ }
52
+ function onlyPreElement(children) {
53
+ const first = children[0];
54
+ if (children.length !== 1 || first?.type !== "element" || first.tagName !== "pre") throw new TypeError("Shiki must return one classic pre element");
55
+ return first;
56
+ }
57
+ function decorateCodeBlock(pre, request, options) {
58
+ const code = pre.children.find((node) => node.type === "element" && node.tagName === "code");
59
+ if (code === void 0) throw new TypeError("Shiki pre element does not contain code");
60
+ addClass(code, `language-${request.language}`);
61
+ const lines = code.children.filter((node) => node.type === "element" && hasClass(node, "line"));
62
+ let largestLineNumber = 1;
63
+ for (const [index, line] of lines.entries()) {
64
+ const physicalLine = index + 1;
65
+ const displayedLine = (request.metadata.lineNumbers?.start ?? 1) + index;
66
+ line.properties["data-line"] = displayedLine;
67
+ if (request.metadata.highlightedLines !== void 0 && codeLineSelected(request.metadata.highlightedLines, physicalLine)) addClass(line, options.highlightedLineClassName);
68
+ if (request.metadata.lineNumbers !== void 0 && codeLineSelected(request.metadata.lineNumbers.lines, physicalLine)) {
69
+ addClass(line, options.lineNumberClassName);
70
+ largestLineNumber = Math.max(largestLineNumber, displayedLine);
71
+ }
72
+ if (request.metadata.commandLines !== void 0 && codeLineSelected(request.metadata.commandLines, physicalLine)) addClass(line, options.commandLineClassName);
73
+ }
74
+ if (request.metadata.fileName !== void 0) pre.properties["data-file-name"] = request.metadata.fileName;
75
+ if (request.metadata.lineNumbers !== void 0) {
76
+ const declaration = `${options.lineNumberWidthProperty}:${String(largestLineNumber).length}ch`;
77
+ const current = pre.properties.style;
78
+ pre.properties.style = isString(current) && current.length > 0 ? `${current.replace(/;?$/u, ";")}${declaration}` : declaration;
79
+ }
80
+ for (const attribute of options.includeDataAttributes) switch (attribute) {
81
+ case "language":
82
+ pre.properties["data-language"] = request.language;
83
+ break;
84
+ case "line-count":
85
+ pre.properties["data-line-count"] = lines.length;
86
+ break;
87
+ case "meta":
88
+ if (request.metadata.raw !== void 0) pre.properties["data-meta"] = request.metadata.raw;
89
+ break;
90
+ case "source-code":
91
+ pre.properties["data-source-code"] = request.code;
92
+ break;
93
+ default: return attribute;
94
+ }
95
+ }
96
+ function hasClass(element, name) {
97
+ const value = element.properties.class;
98
+ return isString(value) ? value.split(/\s+/u).includes(name) : Array.isArray(value) && value.includes(name);
99
+ }
100
+ function addClass(element, name) {
101
+ const value = element.properties.class;
102
+ const classes = isString(value) ? value.split(/\s+/u).filter((item) => item.length > 0) : Array.isArray(value) ? value.filter((item) => isString(item)) : [];
103
+ if (!classes.includes(name)) classes.push(name);
104
+ element.properties.class = classes;
105
+ }
106
+ function convertNode(node) {
107
+ switch (node.type) {
108
+ case "element": return convertElement(node);
109
+ case "text": return {
110
+ kind: "text",
111
+ value: node.value
112
+ };
113
+ default: throw new TypeError(`Shiki returned unsupported ${node.type} content`);
114
+ }
115
+ }
116
+ function convertElement(node) {
117
+ return {
118
+ kind: "element",
119
+ tagName: node.tagName,
120
+ attributes: convertProperties(node.properties),
121
+ children: node.children.map(convertNode)
122
+ };
123
+ }
124
+ function convertProperties(properties) {
125
+ const attributes = {};
126
+ for (const [name, value] of Object.entries(properties)) {
127
+ if (value === null || value === void 0) continue;
128
+ const attributeName = name === "className" ? "class" : name;
129
+ if (isBoolean(value) || isNumber(value) || isString(value)) {
130
+ attributes[attributeName] = value;
131
+ continue;
132
+ }
133
+ if (Array.isArray(value) && value.every((item) => isNumber(item) || isString(item))) {
134
+ attributes[attributeName] = value;
135
+ continue;
136
+ }
137
+ throw new TypeError(`Shiki returned an unsupported ${JSON.stringify(name)} property`);
138
+ }
139
+ return attributes;
140
+ }
141
+ //#endregion
142
+ export { createShikiHighlighter };
143
+
144
+ //# sourceMappingURL=shiki.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shiki.mjs","names":["_exhaustive"],"sources":["../../src/plugins/shiki.ts"],"sourcesContent":["import type { CodeToHastOptions, HighlighterGeneric } from \"shiki/types\";\n\nimport { isString, isBoolean, isNumber } from \"@temelj/value\";\n\nimport type { HtmlAttributeValue, HtmlAttributes, HtmlElementNode, HtmlNode } from \"../html.ts\";\nimport type { SyntaxHighlighter, SyntaxHighlightRequest } from \"./syntax-highlight.ts\";\n\nimport { codeLineSelected } from \"./code-block-metadata.ts\";\n\ntype ShikiHighlighter = Pick<\n HighlighterGeneric<string, string>,\n \"codeToHast\" | \"getLoadedLanguages\"\n>;\n\ntype ShikiCodeToHastOptions<T> = T extends unknown ? Omit<T, \"lang\" | \"meta\" | \"structure\"> : never;\n\nexport type ShikiCodeOptions = ShikiCodeToHastOptions<CodeToHastOptions<string, string>>;\n\nexport type ShikiDataAttribute = \"language\" | \"line-count\" | \"meta\" | \"source-code\";\n\nexport type ShikiHighlighterOptions = ShikiCodeOptions &\n Readonly<{\n commandLineClassName?: string;\n fallbackLanguage?: string;\n highlightedLineClassName?: string;\n includeDataAttributes?: readonly ShikiDataAttribute[];\n languageAliases?: Readonly<Record<string, string>>;\n lineNumberClassName?: string;\n lineNumberWidthProperty?: string;\n }>;\n\nconst specialLanguages = new Set([\"ansi\", \"plain\", \"plaintext\", \"text\", \"txt\"]);\n\n/** Adapts a caller-owned, preloaded Shiki highlighter to Temelj's code highlighter. */\nexport function createShikiHighlighter(\n highlighter: ShikiHighlighter,\n options: ShikiHighlighterOptions,\n): SyntaxHighlighter {\n const {\n commandLineClassName = \"line-command\",\n fallbackLanguage,\n highlightedLineClassName = \"highlighted\",\n includeDataAttributes = [],\n languageAliases = {},\n lineNumberClassName = \"line-number\",\n lineNumberWidthProperty = \"--line-number-width\",\n ...codeOptions\n } = options;\n\n const loadedLanguages = new Set(\n highlighter.getLoadedLanguages().map((language) => language.toLowerCase()),\n );\n\n const aliases = new Map<string, string>();\n\n for (const [from, to] of Object.entries(languageAliases)) {\n aliases.set(from.toLowerCase(), to.toLowerCase());\n }\n\n return {\n kind: \"synchronous\",\n highlight(request: SyntaxHighlightRequest) {\n request.signal?.throwIfAborted();\n\n const language = resolveLanguage(\n request.language,\n aliases,\n fallbackLanguage,\n loadedLanguages,\n );\n\n if (language === undefined) {\n return;\n }\n\n const root = highlighter.codeToHast(request.code, {\n ...codeOptions,\n lang: language,\n meta: request.metadata.raw === undefined ? undefined : { __raw: request.metadata.raw },\n structure: \"classic\",\n });\n\n request.signal?.throwIfAborted();\n const pre = onlyPreElement(root.children);\n decorateCodeBlock(pre, request, {\n commandLineClassName,\n highlightedLineClassName,\n includeDataAttributes,\n lineNumberClassName,\n lineNumberWidthProperty,\n });\n\n return convertElement(pre);\n },\n };\n}\n\ninterface DecorationOptions {\n readonly commandLineClassName: string;\n readonly highlightedLineClassName: string;\n readonly includeDataAttributes: readonly ShikiDataAttribute[];\n readonly lineNumberClassName: string;\n readonly lineNumberWidthProperty: string;\n}\n\ntype ShikiRoot = ReturnType<ShikiHighlighter[\"codeToHast\"]>;\n\ntype ShikiNode = ShikiRoot[\"children\"][number];\n\ntype ShikiElement = Extract<ShikiNode, { type: \"element\" }>;\n\nfunction resolveLanguage(\n authored: string,\n aliases: ReadonlyMap<string, string>,\n fallback: string | undefined,\n loaded: ReadonlySet<string>,\n): string | undefined {\n const normalized = authored.toLowerCase();\n const requested = aliases.get(normalized) ?? normalized;\n\n if (isAvailableLanguage(requested, loaded)) {\n return requested;\n }\n\n const normalizedFallback = fallback?.toLowerCase();\n\n return normalizedFallback !== undefined && isAvailableLanguage(normalizedFallback, loaded)\n ? normalizedFallback\n : undefined;\n}\n\nfunction isAvailableLanguage(language: string, loaded: ReadonlySet<string>): boolean {\n return language.length > 0 && (loaded.has(language) || specialLanguages.has(language));\n}\n\nfunction onlyPreElement(children: ShikiRoot[\"children\"]): ShikiElement {\n const first = children[0];\n\n if (children.length !== 1 || first?.type !== \"element\" || first.tagName !== \"pre\") {\n throw new TypeError(\"Shiki must return one classic pre element\");\n }\n\n return first;\n}\n\nfunction decorateCodeBlock(\n pre: ShikiElement,\n request: SyntaxHighlightRequest,\n options: DecorationOptions,\n): void {\n const code = pre.children.find(\n (node): node is ShikiElement => node.type === \"element\" && node.tagName === \"code\",\n );\n\n if (code === undefined) {\n throw new TypeError(\"Shiki pre element does not contain code\");\n }\n\n addClass(code, `language-${request.language}`);\n\n const lines = code.children.filter(\n (node): node is ShikiElement => node.type === \"element\" && hasClass(node, \"line\"),\n );\n\n let largestLineNumber = 1;\n\n for (const [index, line] of lines.entries()) {\n const physicalLine = index + 1;\n const displayedLine = (request.metadata.lineNumbers?.start ?? 1) + index;\n line.properties[\"data-line\"] = displayedLine;\n\n if (\n request.metadata.highlightedLines !== undefined &&\n codeLineSelected(request.metadata.highlightedLines, physicalLine)\n ) {\n addClass(line, options.highlightedLineClassName);\n }\n\n if (\n request.metadata.lineNumbers !== undefined &&\n codeLineSelected(request.metadata.lineNumbers.lines, physicalLine)\n ) {\n addClass(line, options.lineNumberClassName);\n largestLineNumber = Math.max(largestLineNumber, displayedLine);\n }\n\n if (\n request.metadata.commandLines !== undefined &&\n codeLineSelected(request.metadata.commandLines, physicalLine)\n ) {\n addClass(line, options.commandLineClassName);\n }\n }\n\n if (request.metadata.fileName !== undefined) {\n pre.properties[\"data-file-name\"] = request.metadata.fileName;\n }\n\n if (request.metadata.lineNumbers !== undefined) {\n const declaration = `${options.lineNumberWidthProperty}:${String(largestLineNumber).length}ch`;\n const current = pre.properties.style;\n pre.properties.style =\n isString(current) && current.length > 0\n ? `${current.replace(/;?$/u, \";\")}${declaration}`\n : declaration;\n }\n\n for (const attribute of options.includeDataAttributes) {\n switch (attribute) {\n case \"language\":\n pre.properties[\"data-language\"] = request.language;\n break;\n case \"line-count\":\n pre.properties[\"data-line-count\"] = lines.length;\n break;\n case \"meta\":\n if (request.metadata.raw !== undefined) {\n pre.properties[\"data-meta\"] = request.metadata.raw;\n }\n\n break;\n case \"source-code\":\n pre.properties[\"data-source-code\"] = request.code;\n break;\n default: {\n const _exhaustive: never = attribute;\n\n return _exhaustive;\n }\n }\n }\n}\n\nfunction hasClass(element: ShikiElement, name: string): boolean {\n const value = element.properties.class;\n\n return isString(value)\n ? value.split(/\\s+/u).includes(name)\n : Array.isArray(value) && value.includes(name);\n}\n\nfunction addClass(element: ShikiElement, name: string): void {\n const value = element.properties.class;\n\n const classes = isString(value)\n ? value.split(/\\s+/u).filter((item) => item.length > 0)\n : Array.isArray(value)\n ? value.filter((item): item is string => isString(item))\n : [];\n\n if (!classes.includes(name)) {\n classes.push(name);\n }\n\n element.properties.class = classes;\n}\n\nfunction convertNode(node: ShikiNode): HtmlNode {\n switch (node.type) {\n case \"element\":\n return convertElement(node);\n case \"text\":\n return { kind: \"text\", value: node.value };\n default:\n throw new TypeError(`Shiki returned unsupported ${node.type} content`);\n }\n}\n\nfunction convertElement(node: ShikiElement): HtmlElementNode {\n return {\n kind: \"element\",\n tagName: node.tagName,\n attributes: convertProperties(node.properties),\n children: node.children.map(convertNode),\n };\n}\n\nfunction convertProperties(properties: ShikiElement[\"properties\"]): HtmlAttributes {\n const attributes: Record<string, HtmlAttributeValue> = {};\n\n for (const [name, value] of Object.entries(properties)) {\n if (value === null || value === undefined) {\n continue;\n }\n\n const attributeName = name === \"className\" ? \"class\" : name;\n\n if (isBoolean(value) || isNumber(value) || isString(value)) {\n attributes[attributeName] = value;\n continue;\n }\n\n if (Array.isArray(value) && value.every((item) => isNumber(item) || isString(item))) {\n attributes[attributeName] = value;\n continue;\n }\n\n throw new TypeError(`Shiki returned an unsupported ${JSON.stringify(name)} property`);\n }\n\n return attributes;\n}\n"],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import { HtmlElementNode, HtmlRootNode } from "../html.mjs";
2
+ import { HtmlPlugin, HtmlPluginContext, PluginFailureMode } from "../plugin.mjs";
3
+ import { CodeBlockMetadata } from "./code-block-metadata.mjs";
4
+ //#region src/plugins/syntax-highlight.d.ts
5
+ export interface SyntaxHighlightRequest {
6
+ readonly code: string;
7
+ readonly language: string;
8
+ readonly metadata: CodeBlockMetadata;
9
+ readonly signal?: AbortSignal;
10
+ }
11
+ export interface SynchronousSyntaxHighlighter {
12
+ readonly kind: "synchronous";
13
+ highlight(request: SyntaxHighlightRequest): HtmlElementNode | undefined;
14
+ }
15
+ export interface AsynchronousSyntaxHighlighter {
16
+ readonly kind: "asynchronous";
17
+ highlight(request: SyntaxHighlightRequest): Promise<HtmlElementNode | undefined>;
18
+ }
19
+ export type SyntaxHighlighter = SynchronousSyntaxHighlighter | AsynchronousSyntaxHighlighter;
20
+ export interface SyntaxHighlightPluginOptions {
21
+ readonly highlighter: SyntaxHighlighter;
22
+ readonly maximumCacheEntries?: number;
23
+ readonly mode?: PluginFailureMode;
24
+ }
25
+ /** Highlights fenced code through a caller-supplied service and bounded cache. */
26
+ export declare class SyntaxHighlightPlugin implements HtmlPlugin {
27
+ readonly name = "syntax-highlight";
28
+ private readonly cache;
29
+ private readonly highlighter;
30
+ private readonly maximumCacheEntries;
31
+ private readonly mode;
32
+ constructor(options: SyntaxHighlightPluginOptions);
33
+ transform(context: HtmlPluginContext): HtmlRootNode | Promise<HtmlRootNode>;
34
+ private highlight;
35
+ private highlightFailure;
36
+ }
37
+ //#endregion
38
+ //# sourceMappingURL=syntax-highlight.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syntax-highlight.d.mts","names":[],"sources":["../../src/plugins/syntax-highlight.ts"],"mappings":";;;;iBAUiB;WACN;WACA;WACA,UAAU;WACV,SAAS;;iBAGH;WACN;EACT,UAAU,SAAS,yBAAyB;;iBAG7B;WACN;EACT,UAAU,SAAS,yBAAyB,QAAQ;;YAG1C,oBAAoB,+BAA+B;iBAE9C;WACN,aAAa;WACb;WACA,OAAO;;;qBAML,iCAAiC;WAC5B;mBACC;mBACA;mBACA;mBACA;EAEjB,YAAmB,SAAS;EAYrB,UAAU,SAAS,oBAAoB,eAAe,QAAQ;UAiD7D;UAoDA"}
@@ -0,0 +1,106 @@
1
+ import { ConfigurationError } from "../errors.mjs";
2
+ import { replaceHtmlNodes } from "../plugin-internal.mjs";
3
+ import { CodeBlockMetadataError, parseCodeBlockMetadata } from "./code-block-metadata.mjs";
4
+ import { isPromise } from "@temelj/value";
5
+ //#region src/plugins/syntax-highlight.ts
6
+ /** Highlights fenced code through a caller-supplied service and bounded cache. */
7
+ var SyntaxHighlightPlugin = class {
8
+ name = "syntax-highlight";
9
+ cache = /* @__PURE__ */ new Map();
10
+ highlighter;
11
+ maximumCacheEntries;
12
+ mode;
13
+ constructor(options) {
14
+ const maximum = options.maximumCacheEntries ?? 128;
15
+ if (!Number.isSafeInteger(maximum) || maximum < 0) throw ConfigurationError.invalidCacheCapacity("syntax-highlight", maximum);
16
+ this.highlighter = options.highlighter;
17
+ this.maximumCacheEntries = maximum;
18
+ this.mode = options.mode ?? "tolerant";
19
+ }
20
+ transform(context) {
21
+ return replaceHtmlNodes(context.root, (node) => {
22
+ if (node.kind !== "codeBlock") return;
23
+ let metadata;
24
+ try {
25
+ metadata = parseCodeBlockMetadata(node.meta);
26
+ } catch (error) {
27
+ if (!(error instanceof CodeBlockMetadataError) || this.mode === "strict") throw error;
28
+ metadata = error.metadata;
29
+ for (const issue of error.issues) context.diagnostics.add({
30
+ severity: "warning",
31
+ code: "mdx.plugin.syntax-highlight.meta",
32
+ message: issue.message,
33
+ span: span(node, context)
34
+ });
35
+ }
36
+ const request = {
37
+ code: node.code,
38
+ language: node.language,
39
+ metadata,
40
+ signal: context.signal
41
+ };
42
+ try {
43
+ const result = this.highlight(request);
44
+ return isPromise(result) ? result.then((element) => anchor(element, node), (cause) => this.highlightFailure(cause, node, context)) : anchor(result, node);
45
+ } catch (cause) {
46
+ return this.highlightFailure(cause, node, context);
47
+ }
48
+ });
49
+ }
50
+ highlight(request) {
51
+ if (this.maximumCacheEntries === 0 || request.signal !== void 0) return this.highlighter.highlight(request);
52
+ const key = JSON.stringify([
53
+ request.language,
54
+ request.metadata.raw,
55
+ request.code
56
+ ]);
57
+ const cached = this.cache.get(key);
58
+ if (cached !== void 0) {
59
+ this.cache.delete(key);
60
+ this.cache.set(key, cached);
61
+ return cached;
62
+ }
63
+ const result = this.highlighter.highlight(request);
64
+ if (result === void 0) return;
65
+ const cachedResult = isPromise(result) ? result.then((element) => {
66
+ if (element === void 0) this.cache.delete(key);
67
+ return element;
68
+ }, (cause) => {
69
+ this.cache.delete(key);
70
+ throw cause;
71
+ }) : result;
72
+ this.cache.set(key, cachedResult);
73
+ if (this.cache.size > this.maximumCacheEntries) {
74
+ const oldest = this.cache.keys().next().value;
75
+ if (oldest !== void 0) this.cache.delete(oldest);
76
+ }
77
+ return cachedResult;
78
+ }
79
+ highlightFailure(cause, node, context) {
80
+ context.signal?.throwIfAborted();
81
+ if (this.mode === "strict") throw cause;
82
+ context.diagnostics.add({
83
+ severity: "warning",
84
+ code: "mdx.plugin.syntax-highlight",
85
+ message: `Could not highlight ${node.language} code: ${cause instanceof Error ? cause.message : String(cause)}`,
86
+ span: span(node, context)
87
+ });
88
+ }
89
+ };
90
+ function anchor(highlighted, source) {
91
+ return highlighted === void 0 ? void 0 : {
92
+ ...highlighted,
93
+ origin: source.origin
94
+ };
95
+ }
96
+ function span(node, context) {
97
+ return node.origin === void 0 ? void 0 : {
98
+ file: context.file,
99
+ start: node.origin.start,
100
+ end: node.origin.end
101
+ };
102
+ }
103
+ //#endregion
104
+ export { SyntaxHighlightPlugin };
105
+
106
+ //# sourceMappingURL=syntax-highlight.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syntax-highlight.mjs","names":[],"sources":["../../src/plugins/syntax-highlight.ts"],"sourcesContent":["import { isPromise } from \"@temelj/value\";\n\nimport type { HtmlCodeBlockNode, HtmlElementNode, HtmlRootNode } from \"../html.ts\";\nimport type { HtmlPlugin, HtmlPluginContext, PluginFailureMode } from \"../plugin.ts\";\nimport type { CodeBlockMetadata } from \"./code-block-metadata.ts\";\n\nimport { ConfigurationError } from \"../errors.ts\";\nimport { replaceHtmlNodes } from \"../plugin-internal.ts\";\nimport { CodeBlockMetadataError, parseCodeBlockMetadata } from \"./code-block-metadata.ts\";\n\nexport interface SyntaxHighlightRequest {\n readonly code: string;\n readonly language: string;\n readonly metadata: CodeBlockMetadata;\n readonly signal?: AbortSignal;\n}\n\nexport interface SynchronousSyntaxHighlighter {\n readonly kind: \"synchronous\";\n highlight(request: SyntaxHighlightRequest): HtmlElementNode | undefined;\n}\n\nexport interface AsynchronousSyntaxHighlighter {\n readonly kind: \"asynchronous\";\n highlight(request: SyntaxHighlightRequest): Promise<HtmlElementNode | undefined>;\n}\n\nexport type SyntaxHighlighter = SynchronousSyntaxHighlighter | AsynchronousSyntaxHighlighter;\n\nexport interface SyntaxHighlightPluginOptions {\n readonly highlighter: SyntaxHighlighter;\n readonly maximumCacheEntries?: number;\n readonly mode?: PluginFailureMode;\n}\n\ntype CachedHighlight = HtmlElementNode | Promise<HtmlElementNode | undefined>;\n\n/** Highlights fenced code through a caller-supplied service and bounded cache. */\nexport class SyntaxHighlightPlugin implements HtmlPlugin {\n public readonly name = \"syntax-highlight\";\n private readonly cache = new Map<string, CachedHighlight>();\n private readonly highlighter: SyntaxHighlighter;\n private readonly maximumCacheEntries: number;\n private readonly mode: PluginFailureMode;\n\n public constructor(options: SyntaxHighlightPluginOptions) {\n const maximum = options.maximumCacheEntries ?? 128;\n\n if (!Number.isSafeInteger(maximum) || maximum < 0) {\n throw ConfigurationError.invalidCacheCapacity(\"syntax-highlight\", maximum);\n }\n\n this.highlighter = options.highlighter;\n this.maximumCacheEntries = maximum;\n this.mode = options.mode ?? \"tolerant\";\n }\n\n public transform(context: HtmlPluginContext): HtmlRootNode | Promise<HtmlRootNode> {\n return replaceHtmlNodes(context.root, (node) => {\n if (node.kind !== \"codeBlock\") {\n return;\n }\n\n let metadata: CodeBlockMetadata;\n\n try {\n metadata = parseCodeBlockMetadata(node.meta);\n } catch (error) {\n if (!(error instanceof CodeBlockMetadataError) || this.mode === \"strict\") {\n throw error;\n }\n\n metadata = error.metadata;\n\n for (const issue of error.issues) {\n context.diagnostics.add({\n severity: \"warning\",\n code: \"mdx.plugin.syntax-highlight.meta\",\n message: issue.message,\n span: span(node, context),\n });\n }\n }\n\n const request: SyntaxHighlightRequest = {\n code: node.code,\n language: node.language,\n metadata,\n signal: context.signal,\n };\n\n try {\n const result = this.highlight(request);\n\n return isPromise(result)\n ? result.then(\n (element) => anchor(element, node),\n (cause: unknown) => this.highlightFailure(cause, node, context),\n )\n : anchor(result, node);\n } catch (cause) {\n return this.highlightFailure(cause, node, context);\n }\n });\n }\n\n private highlight(\n request: SyntaxHighlightRequest,\n ): HtmlElementNode | undefined | Promise<HtmlElementNode | undefined> {\n if (this.maximumCacheEntries === 0 || request.signal !== undefined) {\n return this.highlighter.highlight(request);\n }\n\n const key = JSON.stringify([request.language, request.metadata.raw, request.code]);\n const cached = this.cache.get(key);\n\n if (cached !== undefined) {\n this.cache.delete(key);\n this.cache.set(key, cached);\n\n return cached;\n }\n\n const result = this.highlighter.highlight(request);\n\n if (result === undefined) {\n return;\n }\n\n const cachedResult = isPromise(result)\n ? result.then(\n (element) => {\n if (element === undefined) {\n this.cache.delete(key);\n }\n\n return element;\n },\n (cause: unknown) => {\n this.cache.delete(key);\n throw cause;\n },\n )\n : result;\n\n this.cache.set(key, cachedResult);\n\n if (this.cache.size > this.maximumCacheEntries) {\n const oldest = this.cache.keys().next().value;\n\n if (oldest !== undefined) {\n this.cache.delete(oldest);\n }\n }\n\n return cachedResult;\n }\n\n private highlightFailure(\n cause: unknown,\n node: HtmlCodeBlockNode,\n context: HtmlPluginContext,\n ): undefined {\n context.signal?.throwIfAborted();\n\n if (this.mode === \"strict\") {\n throw cause;\n }\n\n context.diagnostics.add({\n severity: \"warning\",\n code: \"mdx.plugin.syntax-highlight\",\n message: `Could not highlight ${node.language} code: ${cause instanceof Error ? cause.message : String(cause)}`,\n span: span(node, context),\n });\n }\n}\n\nfunction anchor(\n highlighted: HtmlElementNode | undefined,\n source: HtmlCodeBlockNode,\n): HtmlElementNode | undefined {\n return highlighted === undefined ? undefined : { ...highlighted, origin: source.origin };\n}\n\nfunction span(\n node: HtmlCodeBlockNode,\n context: HtmlPluginContext,\n): Readonly<{ file: HtmlPluginContext[\"file\"]; start: number; end: number }> | undefined {\n return node.origin === undefined\n ? undefined\n : { file: context.file, start: node.origin.start, end: node.origin.end };\n}\n"],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import { HtmlRootNode } from "./html.mjs";
2
+ import { SourceFile } from "./source.mjs";
3
+ import { HtmlRenderOptions } from "./html-lower.mjs";
4
+ import { ParseOptions, ParseResult } from "./parser.mjs";
5
+ import { DocumentPlugin, HtmlPlugin } from "./plugin.mjs";
6
+ //#region src/processor.d.ts
7
+ export interface ProcessorOptions extends ParseOptions {
8
+ /** Run on the semantic document before lowering and before compilation. */
9
+ readonly documentPlugins?: readonly DocumentPlugin[];
10
+ /** Run on lowered HTML. They do not affect compiled output. */
11
+ readonly htmlPlugins?: readonly HtmlPlugin[];
12
+ readonly html?: Omit<HtmlRenderOptions, "source">;
13
+ }
14
+ export interface ProcessResult extends ParseResult {
15
+ readonly html: HtmlRootNode;
16
+ }
17
+ export interface ProcessOptions {
18
+ readonly signal?: AbortSignal;
19
+ }
20
+ /** Strict input: a source string, a `SourceFile`, or an existing parse result. */
21
+ export type ProcessInput = string | SourceFile | ParseResult;
22
+ /**
23
+ * Parses, transforms, and lowers MDX with one configuration.
24
+ * Operations throw ParseError, LimitError, or TransformError on failure.
25
+ */
26
+ export declare class Processor {
27
+ readonly options: ProcessorOptions;
28
+ constructor(options?: ProcessorOptions);
29
+ /** @throws {ParseError | LimitError | ConfigurationError} Parsing fails. */
30
+ parse(source: string | SourceFile): ParseResult;
31
+ /** @throws {MdxError} Parsing, transformation, or configuration fails. */
32
+ process(input: ProcessInput, options?: ProcessOptions): Promise<ProcessResult>;
33
+ /**
34
+ * Processes synchronously.
35
+ * @throws {MdxError} Parsing, transformation, or configuration fails.
36
+ * @throws {ConfigurationError} A plugin returns a promise.
37
+ */
38
+ processSync(input: ProcessInput): ProcessResult;
39
+ /**
40
+ * Parses and runs document plugins without lowering. Pass the result to
41
+ * `compile` to emit JavaScript from the transformed document.
42
+ * @throws {MdxError} Parsing, transformation, or configuration fails.
43
+ */
44
+ transform(input: ProcessInput, options?: ProcessOptions): Promise<ParseResult>;
45
+ /**
46
+ * Transforms synchronously.
47
+ * @throws {MdxError} Parsing, transformation, or configuration fails.
48
+ * @throws {ConfigurationError} A plugin returns a promise.
49
+ */
50
+ transformSync(input: ProcessInput): ParseResult;
51
+ /** Lowers transformed documents and runs HTML plugins with the same diagnostics. */
52
+ private processStages;
53
+ private transformStage;
54
+ /** Parses and runs document plugins: the stage shared by transforming and processing. */
55
+ private documentStage;
56
+ private get documentPlugins();
57
+ private get htmlPlugins();
58
+ }
59
+ //#endregion
60
+ //# sourceMappingURL=processor.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"processor.d.mts","names":[],"sources":["../src/processor.ts"],"mappings":";;;;;;iBAeiB,yBAAyB;;WAE/B,2BAA2B;;WAE3B,uBAAuB;WACvB,OAAO,KAAK;;iBAGN,sBAAsB;WAC5B,MAAM;;iBAGA;WACN,SAAS;;;YAIR,wBAAwB,aAAa;;;;;qBAMpC;WACK,SAAS;EAEzB,YAAmB,UAAS;;EAUrB,MAAM,iBAAiB,aAAa;;EAK9B,QAAQ,OAAO,cAAc,UAAS,iBAAsB,QAAQ;;;;;;EAS1E,YAAY,OAAO,eAAe;;;;;;EAS5B,UAAU,OAAO,cAAc,UAAS,iBAAsB,QAAQ;;;;;;EAS5E,cAAc,OAAO,eAAe;;UAKnC;UAuBA;;UAeA;cAsBI;cAIA"}
@@ -0,0 +1,106 @@
1
+ import { DiagnosticBag } from "./diagnostics.mjs";
2
+ import { SourceFile } from "./source.mjs";
3
+ import { lowerHtml } from "./html-lower.mjs";
4
+ import { parse } from "./parser.mjs";
5
+ import { runDocumentPlugins, runHtmlPlugins } from "./plugin-internal.mjs";
6
+ import { isPromise, isString } from "@temelj/value";
7
+ //#region src/processor.ts
8
+ /**
9
+ * Parses, transforms, and lowers MDX with one configuration.
10
+ * Operations throw ParseError, LimitError, or TransformError on failure.
11
+ */
12
+ var Processor = class {
13
+ options;
14
+ constructor(options = {}) {
15
+ this.options = {
16
+ ...options,
17
+ documentPlugins: [...options.documentPlugins ?? []],
18
+ htmlPlugins: [...options.htmlPlugins ?? []]
19
+ };
20
+ }
21
+ /** @throws {ParseError | LimitError | ConfigurationError} Parsing fails. */
22
+ parse(source) {
23
+ return parse(source, this.options);
24
+ }
25
+ /** @throws {MdxError} Parsing, transformation, or configuration fails. */
26
+ async process(input, options = {}) {
27
+ return this.processStages(input, false, options.signal);
28
+ }
29
+ /**
30
+ * Processes synchronously.
31
+ * @throws {MdxError} Parsing, transformation, or configuration fails.
32
+ * @throws {ConfigurationError} A plugin returns a promise.
33
+ */
34
+ processSync(input) {
35
+ return settled(this.processStages(input, true));
36
+ }
37
+ /**
38
+ * Parses and runs document plugins without lowering. Pass the result to
39
+ * `compile` to emit JavaScript from the transformed document.
40
+ * @throws {MdxError} Parsing, transformation, or configuration fails.
41
+ */
42
+ async transform(input, options = {}) {
43
+ return this.transformStage(input, false, options.signal);
44
+ }
45
+ /**
46
+ * Transforms synchronously.
47
+ * @throws {MdxError} Parsing, transformation, or configuration fails.
48
+ * @throws {ConfigurationError} A plugin returns a promise.
49
+ */
50
+ transformSync(input) {
51
+ return settled(this.transformStage(input, true));
52
+ }
53
+ /** Lowers transformed documents and runs HTML plugins with the same diagnostics. */
54
+ processStages(input, synchronous, signal) {
55
+ return chain(this.documentStage(input, synchronous, signal), (stage) => chain(runHtmlPlugins(lowerHtml(stage.document, {
56
+ ...this.options.html,
57
+ source: stage.file
58
+ }), this.htmlPlugins, stage.run), (html) => Object.freeze({
59
+ file: stage.file,
60
+ document: stage.document,
61
+ html,
62
+ diagnostics: stage.run.diagnostics.snapshot()
63
+ })));
64
+ }
65
+ transformStage(input, synchronous, signal) {
66
+ return chain(this.documentStage(input, synchronous, signal), (stage) => Object.freeze({
67
+ file: stage.file,
68
+ document: stage.document,
69
+ diagnostics: stage.run.diagnostics.snapshot()
70
+ }));
71
+ }
72
+ /** Parses and runs document plugins: the stage shared by transforming and processing. */
73
+ documentStage(input, synchronous, signal) {
74
+ signal?.throwIfAborted();
75
+ const parsed = input instanceof SourceFile || isString(input) ? this.parse(input) : input;
76
+ const run = {
77
+ diagnostics: new DiagnosticBag(parsed.diagnostics),
78
+ file: parsed.file,
79
+ signal,
80
+ syntax: this.options.syntax ?? {},
81
+ synchronous
82
+ };
83
+ return chain(runDocumentPlugins(parsed.document, this.documentPlugins, run), (document) => ({
84
+ file: parsed.file,
85
+ document,
86
+ run
87
+ }));
88
+ }
89
+ get documentPlugins() {
90
+ return this.options.documentPlugins ?? [];
91
+ }
92
+ get htmlPlugins() {
93
+ return this.options.htmlPlugins ?? [];
94
+ }
95
+ };
96
+ function chain(value, step) {
97
+ return isPromise(value) ? value.then(step) : step(value);
98
+ }
99
+ function settled(value) {
100
+ if (isPromise(value)) throw new TypeError("Synchronous plugin run returned a promise");
101
+ return value;
102
+ }
103
+ //#endregion
104
+ export { Processor };
105
+
106
+ //# sourceMappingURL=processor.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"processor.mjs","names":[],"sources":["../src/processor.ts"],"sourcesContent":["import { isPromise, isString } from \"@temelj/value\";\n\nimport type { HtmlRenderOptions } from \"./html-lower.ts\";\nimport type { HtmlRootNode } from \"./html.ts\";\nimport type { DocumentNode } from \"./model.ts\";\nimport type { ParseOptions, ParseResult } from \"./parser.ts\";\nimport type { PluginRun } from \"./plugin-internal.ts\";\nimport type { DocumentPlugin, HtmlPlugin } from \"./plugin.ts\";\n\nimport { DiagnosticBag } from \"./diagnostics.ts\";\nimport { lowerHtml } from \"./html-lower.ts\";\nimport { parse } from \"./parser.ts\";\nimport { runDocumentPlugins, runHtmlPlugins } from \"./plugin-internal.ts\";\nimport { SourceFile } from \"./source.ts\";\n\nexport interface ProcessorOptions extends ParseOptions {\n /** Run on the semantic document before lowering and before compilation. */\n readonly documentPlugins?: readonly DocumentPlugin[];\n /** Run on lowered HTML. They do not affect compiled output. */\n readonly htmlPlugins?: readonly HtmlPlugin[];\n readonly html?: Omit<HtmlRenderOptions, \"source\">;\n}\n\nexport interface ProcessResult extends ParseResult {\n readonly html: HtmlRootNode;\n}\n\nexport interface ProcessOptions {\n readonly signal?: AbortSignal;\n}\n\n/** Strict input: a source string, a `SourceFile`, or an existing parse result. */\nexport type ProcessInput = string | SourceFile | ParseResult;\n\n/**\n * Parses, transforms, and lowers MDX with one configuration.\n * Operations throw ParseError, LimitError, or TransformError on failure.\n */\nexport class Processor {\n public readonly options: ProcessorOptions;\n\n public constructor(options: ProcessorOptions = {}) {\n // Later changes to the caller's plugin arrays do not reconfigure the processor.\n this.options = {\n ...options,\n documentPlugins: [...(options.documentPlugins ?? [])],\n htmlPlugins: [...(options.htmlPlugins ?? [])],\n };\n }\n\n /** @throws {ParseError | LimitError | ConfigurationError} Parsing fails. */\n public parse(source: string | SourceFile): ParseResult {\n return parse(source, this.options);\n }\n\n /** @throws {MdxError} Parsing, transformation, or configuration fails. */\n public async process(input: ProcessInput, options: ProcessOptions = {}): Promise<ProcessResult> {\n return this.processStages(input, false, options.signal);\n }\n\n /**\n * Processes synchronously.\n * @throws {MdxError} Parsing, transformation, or configuration fails.\n * @throws {ConfigurationError} A plugin returns a promise.\n */\n public processSync(input: ProcessInput): ProcessResult {\n return settled(this.processStages(input, true));\n }\n\n /**\n * Parses and runs document plugins without lowering. Pass the result to\n * `compile` to emit JavaScript from the transformed document.\n * @throws {MdxError} Parsing, transformation, or configuration fails.\n */\n public async transform(input: ProcessInput, options: ProcessOptions = {}): Promise<ParseResult> {\n return this.transformStage(input, false, options.signal);\n }\n\n /**\n * Transforms synchronously.\n * @throws {MdxError} Parsing, transformation, or configuration fails.\n * @throws {ConfigurationError} A plugin returns a promise.\n */\n public transformSync(input: ProcessInput): ParseResult {\n return settled(this.transformStage(input, true));\n }\n\n /** Lowers transformed documents and runs HTML plugins with the same diagnostics. */\n private processStages(\n input: ProcessInput,\n synchronous: boolean,\n signal?: AbortSignal,\n ): Settling<ProcessResult> {\n return chain(this.documentStage(input, synchronous, signal), (stage) =>\n chain(\n runHtmlPlugins(\n lowerHtml(stage.document, { ...this.options.html, source: stage.file }),\n this.htmlPlugins,\n stage.run,\n ),\n (html): ProcessResult =>\n Object.freeze({\n file: stage.file,\n document: stage.document,\n html,\n diagnostics: stage.run.diagnostics.snapshot(),\n }),\n ),\n );\n }\n\n private transformStage(\n input: ProcessInput,\n synchronous: boolean,\n signal?: AbortSignal,\n ): Settling<ParseResult> {\n return chain(this.documentStage(input, synchronous, signal), (stage): ParseResult =>\n Object.freeze({\n file: stage.file,\n document: stage.document,\n diagnostics: stage.run.diagnostics.snapshot(),\n }),\n );\n }\n\n /** Parses and runs document plugins: the stage shared by transforming and processing. */\n private documentStage(\n input: ProcessInput,\n synchronous: boolean,\n signal?: AbortSignal,\n ): Settling<DocumentStage> {\n signal?.throwIfAborted();\n const parsed = input instanceof SourceFile || isString(input) ? this.parse(input) : input;\n\n const run: PluginRun = {\n diagnostics: new DiagnosticBag(parsed.diagnostics),\n file: parsed.file,\n signal,\n syntax: this.options.syntax ?? {},\n synchronous,\n };\n\n return chain(\n runDocumentPlugins(parsed.document, this.documentPlugins, run),\n (document): DocumentStage => ({ file: parsed.file, document, run }),\n );\n }\n\n private get documentPlugins(): readonly DocumentPlugin[] {\n return this.options.documentPlugins ?? [];\n }\n\n private get htmlPlugins(): readonly HtmlPlugin[] {\n return this.options.htmlPlugins ?? [];\n }\n}\n\ninterface DocumentStage {\n readonly file: SourceFile;\n readonly document: DocumentNode;\n readonly run: PluginRun;\n}\n\n/** A value now, or later when an asynchronous plugin is involved. */\ntype Settling<TValue> = TValue | Promise<TValue>;\n\nfunction chain<TValue, TResult>(\n value: Settling<TValue>,\n step: (value: TValue) => Settling<TResult>,\n): Settling<TResult> {\n return isPromise(value) ? value.then(step) : step(value);\n}\n\nfunction settled<T>(value: Settling<T>): T {\n // A synchronous run rejects asynchronous plugins before returning a promise.\n if (isPromise(value)) {\n throw new TypeError(\"Synchronous plugin run returned a promise\");\n }\n\n return value;\n}\n"],"mappings":";;;;;;;;;;;AAsCA,IAAa,YAAb,MAAuB;CACrB;CAEA,YAAmB,UAA4B,CAAC,GAAG;EAEjD,KAAK,UAAU;GACb,GAAG;GACH,iBAAiB,CAAC,GAAI,QAAQ,mBAAmB,CAAC,CAAE;GACpD,aAAa,CAAC,GAAI,QAAQ,eAAe,CAAC,CAAE;EAC9C;CACF;;CAGA,MAAa,QAA0C;EACrD,OAAO,MAAM,QAAQ,KAAK,OAAO;CACnC;;CAGA,MAAa,QAAQ,OAAqB,UAA0B,CAAC,GAA2B;EAC9F,OAAO,KAAK,cAAc,OAAO,OAAO,QAAQ,MAAM;CACxD;;;;;;CAOA,YAAmB,OAAoC;EACrD,OAAO,QAAQ,KAAK,cAAc,OAAO,IAAI,CAAC;CAChD;;;;;;CAOA,MAAa,UAAU,OAAqB,UAA0B,CAAC,GAAyB;EAC9F,OAAO,KAAK,eAAe,OAAO,OAAO,QAAQ,MAAM;CACzD;;;;;;CAOA,cAAqB,OAAkC;EACrD,OAAO,QAAQ,KAAK,eAAe,OAAO,IAAI,CAAC;CACjD;;CAGA,cACE,OACA,aACA,QACyB;EACzB,OAAO,MAAM,KAAK,cAAc,OAAO,aAAa,MAAM,IAAI,UAC5D,MACE,eACE,UAAU,MAAM,UAAU;GAAE,GAAG,KAAK,QAAQ;GAAM,QAAQ,MAAM;EAAK,CAAC,GACtE,KAAK,aACL,MAAM,GACR,IACC,SACC,OAAO,OAAO;GACZ,MAAM,MAAM;GACZ,UAAU,MAAM;GAChB;GACA,aAAa,MAAM,IAAI,YAAY,SAAS;EAC9C,CAAC,CACL,CACF;CACF;CAEA,eACE,OACA,aACA,QACuB;EACvB,OAAO,MAAM,KAAK,cAAc,OAAO,aAAa,MAAM,IAAI,UAC5D,OAAO,OAAO;GACZ,MAAM,MAAM;GACZ,UAAU,MAAM;GAChB,aAAa,MAAM,IAAI,YAAY,SAAS;EAC9C,CAAC,CACH;CACF;;CAGA,cACE,OACA,aACA,QACyB;EACzB,QAAQ,eAAe;EACvB,MAAM,SAAS,iBAAiB,cAAc,SAAS,KAAK,IAAI,KAAK,MAAM,KAAK,IAAI;EAEpF,MAAM,MAAiB;GACrB,aAAa,IAAI,cAAc,OAAO,WAAW;GACjD,MAAM,OAAO;GACb;GACA,QAAQ,KAAK,QAAQ,UAAU,CAAC;GAChC;EACF;EAEA,OAAO,MACL,mBAAmB,OAAO,UAAU,KAAK,iBAAiB,GAAG,IAC5D,cAA6B;GAAE,MAAM,OAAO;GAAM;GAAU;EAAI,EACnE;CACF;CAEA,IAAY,kBAA6C;EACvD,OAAO,KAAK,QAAQ,mBAAmB,CAAC;CAC1C;CAEA,IAAY,cAAqC;EAC/C,OAAO,KAAK,QAAQ,eAAe,CAAC;CACtC;AACF;AAWA,SAAS,MACP,OACA,MACmB;CACnB,OAAO,UAAU,KAAK,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,KAAK;AACzD;AAEA,SAAS,QAAW,OAAuB;CAEzC,IAAI,UAAU,KAAK,GACjB,MAAM,IAAI,UAAU,2CAA2C;CAGjE,OAAO;AACT"}
@@ -0,0 +1,10 @@
1
+ //#region src/ranges.d.ts
2
+ export interface SourceRange {
3
+ readonly start: number;
4
+ readonly end: number;
5
+ }
6
+ export declare function sourceRange(start: number, end: number): SourceRange;
7
+ export declare function rangesIntersect(left: SourceRange, right: SourceRange): boolean;
8
+ export declare function shiftRange(range: SourceRange, offset: number): SourceRange;
9
+ //#endregion
10
+ //# sourceMappingURL=ranges.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ranges.d.mts","names":[],"sources":["../src/ranges.ts"],"mappings":";iBAAiB;WACN;WACA;;wBAGK,YAAY,eAAe,cAAc;wBAQzC,gBAAgB,MAAM,aAAa,OAAO;wBAQ1C,WAAW,OAAO,aAAa,iBAAiB"}
@@ -0,0 +1,22 @@
1
+ //#region src/ranges.ts
2
+ function sourceRange(start, end) {
3
+ if (!Number.isSafeInteger(start) || !Number.isSafeInteger(end) || start < 0 || end < start) throw new RangeError(`Invalid source range ${start}..${end}`);
4
+ return Object.freeze({
5
+ start,
6
+ end
7
+ });
8
+ }
9
+ function rangesIntersect(left, right) {
10
+ if (right.start === right.end) return left.start < right.start && right.start < left.end;
11
+ return left.start < right.end && right.start < left.end;
12
+ }
13
+ function shiftRange(range, offset) {
14
+ return {
15
+ start: range.start + offset,
16
+ end: range.end + offset
17
+ };
18
+ }
19
+ //#endregion
20
+ export { rangesIntersect, shiftRange, sourceRange };
21
+
22
+ //# sourceMappingURL=ranges.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ranges.mjs","names":[],"sources":["../src/ranges.ts"],"sourcesContent":["export interface SourceRange {\n readonly start: number;\n readonly end: number;\n}\n\nexport function sourceRange(start: number, end: number): SourceRange {\n if (!Number.isSafeInteger(start) || !Number.isSafeInteger(end) || start < 0 || end < start) {\n throw new RangeError(`Invalid source range ${start}..${end}`);\n }\n\n return Object.freeze({ start, end });\n}\n\nexport function rangesIntersect(left: SourceRange, right: SourceRange): boolean {\n if (right.start === right.end) {\n return left.start < right.start && right.start < left.end;\n }\n\n return left.start < right.end && right.start < left.end;\n}\n\nexport function shiftRange(range: SourceRange, offset: number): SourceRange {\n return { start: range.start + offset, end: range.end + offset };\n}\n"],"mappings":";AAKA,SAAgB,YAAY,OAAe,KAA0B;CACnE,IAAI,CAAC,OAAO,cAAc,KAAK,KAAK,CAAC,OAAO,cAAc,GAAG,KAAK,QAAQ,KAAK,MAAM,OACnF,MAAM,IAAI,WAAW,wBAAwB,MAAM,IAAI,KAAK;CAG9D,OAAO,OAAO,OAAO;EAAE;EAAO;CAAI,CAAC;AACrC;AAEA,SAAgB,gBAAgB,MAAmB,OAA6B;CAC9E,IAAI,MAAM,UAAU,MAAM,KACxB,OAAO,KAAK,QAAQ,MAAM,SAAS,MAAM,QAAQ,KAAK;CAGxD,OAAO,KAAK,QAAQ,MAAM,OAAO,MAAM,QAAQ,KAAK;AACtD;AAEA,SAAgB,WAAW,OAAoB,QAA6B;CAC1E,OAAO;EAAE,OAAO,MAAM,QAAQ;EAAQ,KAAK,MAAM,MAAM;CAAO;AAChE"}
@@ -0,0 +1,28 @@
1
+ import { SourceRange } from "./ranges.mjs";
2
+ import { SourceFile } from "./source.mjs";
3
+ //#region src/source-map.d.ts
4
+ export interface SourceMap {
5
+ readonly file?: string;
6
+ readonly mappings: string;
7
+ readonly names: readonly string[];
8
+ readonly sources: readonly string[];
9
+ readonly sourcesContent: readonly string[];
10
+ readonly version: 3;
11
+ }
12
+ /** Private generated-text builder that records original MDX locations. */
13
+ export declare class CodeWriter {
14
+ private readonly chunks;
15
+ private readonly points;
16
+ private column;
17
+ private line;
18
+ private size;
19
+ private readonly sourceFile;
20
+ constructor(sourceFile: SourceFile | undefined);
21
+ get length(): number;
22
+ /** Writes generated code. `origin` maps it to a range in the source file. */
23
+ write(value: string, origin?: SourceRange): void;
24
+ toString(): string;
25
+ sourceMap(sourceName: string, outputName?: string): SourceMap;
26
+ }
27
+ //#endregion
28
+ //# sourceMappingURL=source-map.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-map.d.mts","names":[],"sources":["../src/source-map.ts"],"mappings":";;;iBAKiB;WACN;WACA;WACA;WACA;WACA;WACA;;;qBAWE;mBACM;mBACA;UACT;UACA;UACA;mBACS;EAEjB,YAAmB,YAAY;MAIpB;;EAKJ,MAAM,eAAe,SAAS;EA8B9B;EAIA,UAAU,oBAAoB,sBAAsB"}