livemark 0.2.0 → 0.7.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 (348) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +5 -1
  3. package/build/actions/changelog/build.d.ts +14 -0
  4. package/build/actions/changelog/build.js +158 -0
  5. package/build/actions/changelog/build.unit.js +66 -0
  6. package/build/actions/config/define.d.ts +6 -0
  7. package/build/actions/config/define.js +8 -0
  8. package/build/actions/config/define.unit.js +29 -0
  9. package/build/actions/config/load.d.ts +5 -0
  10. package/build/actions/config/load.js +25 -0
  11. package/build/actions/config/load.unit.js +23 -0
  12. package/build/commands/build.d.ts +5 -0
  13. package/build/commands/build.js +14 -0
  14. package/build/commands/escape.d.ts +9 -0
  15. package/build/commands/escape.js +56 -0
  16. package/build/commands/preview.d.ts +5 -0
  17. package/build/commands/preview.js +18 -0
  18. package/build/commands/start.d.ts +5 -0
  19. package/build/commands/start.js +19 -0
  20. package/build/docs/markdown/includes/example.d.ts +58 -0
  21. package/build/docs/markdown/includes/example.js +5 -0
  22. package/build/entrypoints/main.d.ts +2 -0
  23. package/build/entrypoints/main.js +12 -0
  24. package/build/helpers/program.d.ts +2 -0
  25. package/build/helpers/program.js +5 -0
  26. package/build/index.d.ts +1 -4
  27. package/build/index.js +2 -5
  28. package/build/livemark.config.d.ts +58 -0
  29. package/build/livemark.config.js +25 -0
  30. package/build/models/config.d.ts +340 -0
  31. package/build/models/config.js +34 -0
  32. package/build/models/link.d.ts +13 -0
  33. package/build/models/link.js +9 -0
  34. package/build/models/patch.d.ts +21 -0
  35. package/build/models/patch.js +7 -0
  36. package/build/models/section.d.ts +75 -0
  37. package/build/models/section.js +26 -0
  38. package/build/models/theme.d.ts +72 -0
  39. package/build/models/theme.js +73 -0
  40. package/build/program.d.ts +2 -0
  41. package/build/program.js +16 -0
  42. package/build/vite.config.d.ts +2 -0
  43. package/build/vite.config.js +48 -0
  44. package/build/website/assets/logo.svg +117 -0
  45. package/build/website/client.tsx +10 -0
  46. package/build/website/components/Abbr.tsx +17 -0
  47. package/build/website/components/AnsiCode.tsx +15 -0
  48. package/build/website/components/Article.tsx +172 -0
  49. package/build/website/components/BackToTop.tsx +32 -0
  50. package/build/website/components/Banner.tsx +32 -0
  51. package/build/website/components/BlogIndex.tsx +121 -0
  52. package/build/website/components/BlogSidebar.tsx +162 -0
  53. package/build/website/components/Breadcrumbs.tsx +22 -0
  54. package/build/website/components/Callout.tsx +72 -0
  55. package/build/website/components/Card.tsx +48 -0
  56. package/build/website/components/Cards.tsx +8 -0
  57. package/build/website/components/ChangelogIndex.tsx +111 -0
  58. package/build/website/components/ChangelogSidebar.tsx +120 -0
  59. package/build/website/components/CodeBlock.tsx +135 -0
  60. package/build/website/components/CodeTabs.tsx +83 -0
  61. package/build/website/components/Column.tsx +4 -0
  62. package/build/website/components/Columns.tsx +12 -0
  63. package/build/website/components/Content.tsx +7 -0
  64. package/build/website/components/ContentTab.tsx +7 -0
  65. package/build/website/components/ContentTabs.tsx +82 -0
  66. package/build/website/components/DefaultCatchBoundary.tsx +54 -0
  67. package/build/website/components/DefinitionList.tsx +21 -0
  68. package/build/website/components/Details.tsx +30 -0
  69. package/build/website/components/FileTree.tsx +52 -0
  70. package/build/website/components/Footer.tsx +16 -0
  71. package/build/website/components/FootnoteRef.tsx +52 -0
  72. package/build/website/components/Heading.tsx +20 -0
  73. package/build/website/components/InlineBadge.tsx +9 -0
  74. package/build/website/components/InlineIcon.tsx +10 -0
  75. package/build/website/components/InlineToc.tsx +31 -0
  76. package/build/website/components/Layout.tsx +190 -0
  77. package/build/website/components/LinkButton.tsx +31 -0
  78. package/build/website/components/Mermaid.tsx +18 -0
  79. package/build/website/components/MermaidRenderer.tsx +37 -0
  80. package/build/website/components/MiniSidebar.tsx +49 -0
  81. package/build/website/components/NotFound.tsx +27 -0
  82. package/build/website/components/PackageTabs.tsx +74 -0
  83. package/build/website/components/PageToolbar.tsx +75 -0
  84. package/build/website/components/PrevNext.tsx +60 -0
  85. package/build/website/components/Search.tsx +28 -0
  86. package/build/website/components/SearchDialog.tsx +245 -0
  87. package/build/website/components/Section.tsx +24 -0
  88. package/build/website/components/SectionHeader.tsx +35 -0
  89. package/build/website/components/Sidebar.tsx +160 -0
  90. package/build/website/components/SidebarLinks.tsx +70 -0
  91. package/build/website/components/SidebarSections.tsx +71 -0
  92. package/build/website/components/SiteTitle.tsx +21 -0
  93. package/build/website/components/SortableTable.tsx +81 -0
  94. package/build/website/components/SoundCloud.tsx +16 -0
  95. package/build/website/components/TagIndex.tsx +120 -0
  96. package/build/website/components/Theme.tsx +39 -0
  97. package/build/website/components/Toc.tsx +226 -0
  98. package/build/website/components/YouTube.tsx +16 -0
  99. package/build/website/components/ZoomImage.tsx +25 -0
  100. package/build/website/content/article.ts +78 -0
  101. package/build/website/content/tag.ts +29 -0
  102. package/build/website/content-collections.ts +208 -0
  103. package/build/website/elements/accordion.tsx +78 -0
  104. package/build/website/elements/alert-dialog.tsx +185 -0
  105. package/build/website/elements/alert.tsx +74 -0
  106. package/build/website/elements/aspect-ratio.tsx +22 -0
  107. package/build/website/elements/avatar.tsx +107 -0
  108. package/build/website/elements/badge.tsx +51 -0
  109. package/build/website/elements/breadcrumb.tsx +120 -0
  110. package/build/website/elements/button-group.tsx +87 -0
  111. package/build/website/elements/button.tsx +57 -0
  112. package/build/website/elements/calendar.tsx +229 -0
  113. package/build/website/elements/card.tsx +102 -0
  114. package/build/website/elements/carousel.tsx +240 -0
  115. package/build/website/elements/chart.tsx +372 -0
  116. package/build/website/elements/checkbox.tsx +26 -0
  117. package/build/website/elements/collapsible.tsx +19 -0
  118. package/build/website/elements/command.tsx +210 -0
  119. package/build/website/elements/context-menu.tsx +270 -0
  120. package/build/website/elements/dialog.tsx +152 -0
  121. package/build/website/elements/direction.tsx +4 -0
  122. package/build/website/elements/drawer.tsx +127 -0
  123. package/build/website/elements/dropdown-menu.tsx +260 -0
  124. package/build/website/elements/empty.tsx +104 -0
  125. package/build/website/elements/field.tsx +235 -0
  126. package/build/website/elements/hover-card.tsx +49 -0
  127. package/build/website/elements/input-group.tsx +171 -0
  128. package/build/website/elements/input-otp.tsx +84 -0
  129. package/build/website/elements/input.tsx +18 -0
  130. package/build/website/elements/item.tsx +199 -0
  131. package/build/website/elements/kbd.tsx +26 -0
  132. package/build/website/elements/label.tsx +17 -0
  133. package/build/website/elements/menubar.tsx +282 -0
  134. package/build/website/elements/native-select.tsx +56 -0
  135. package/build/website/elements/navigation-menu.tsx +171 -0
  136. package/build/website/elements/pagination.tsx +133 -0
  137. package/build/website/elements/popover.tsx +88 -0
  138. package/build/website/elements/progress.tsx +81 -0
  139. package/build/website/elements/radio-group.tsx +36 -0
  140. package/build/website/elements/resizable.tsx +48 -0
  141. package/build/website/elements/scroll-area.tsx +51 -0
  142. package/build/website/elements/select.tsx +200 -0
  143. package/build/website/elements/separator.tsx +22 -0
  144. package/build/website/elements/sheet.tsx +130 -0
  145. package/build/website/elements/sidebar.tsx +717 -0
  146. package/build/website/elements/skeleton.tsx +13 -0
  147. package/build/website/elements/slider.tsx +57 -0
  148. package/build/website/elements/sonner.tsx +40 -0
  149. package/build/website/elements/spinner.tsx +16 -0
  150. package/build/website/elements/switch.tsx +30 -0
  151. package/build/website/elements/table.tsx +112 -0
  152. package/build/website/elements/tabs.tsx +79 -0
  153. package/build/website/elements/textarea.tsx +16 -0
  154. package/build/website/elements/toggle-group.tsx +87 -0
  155. package/build/website/elements/toggle.tsx +43 -0
  156. package/build/website/elements/tooltip.tsx +67 -0
  157. package/build/website/env.d.ts +14 -0
  158. package/build/website/helpers/article-icon.ts +61 -0
  159. package/build/website/helpers/article.ts +90 -0
  160. package/build/website/helpers/changelog-source.ts +16 -0
  161. package/build/website/helpers/changelog-source.unit.ts +38 -0
  162. package/build/website/helpers/dynamic-icon-resolver.tsx +19 -0
  163. package/build/website/helpers/dynamic-icon.tsx +12 -0
  164. package/build/website/helpers/favicon.ts +7 -0
  165. package/build/website/helpers/model.ts +4 -0
  166. package/build/website/helpers/resolve-asset-path.ts +9 -0
  167. package/build/website/helpers/resolve-includes.ts +131 -0
  168. package/build/website/helpers/resolve-includes.unit.ts +126 -0
  169. package/build/website/helpers/search-text.ts +15 -0
  170. package/build/website/helpers/section.ts +50 -0
  171. package/build/website/helpers/section.unit.ts +71 -0
  172. package/build/website/helpers/style.ts +6 -0
  173. package/build/website/helpers/theme.ts +27 -0
  174. package/build/website/helpers/toc-context.ts +10 -0
  175. package/build/website/helpers/toc.ts +46 -0
  176. package/build/website/helpers/toc.unit.ts +74 -0
  177. package/build/website/hooks/in-view.ts +30 -0
  178. package/build/website/hooks/media.ts +19 -0
  179. package/build/website/models/article.ts +55 -0
  180. package/build/website/models/toc.ts +5 -0
  181. package/build/website/plugins/rehype-inline-code.ts +107 -0
  182. package/build/website/plugins/rehype-task-list-a11y.ts +33 -0
  183. package/build/website/plugins/remark-abbr.ts +46 -0
  184. package/build/website/plugins/remark-abbr.unit.ts +99 -0
  185. package/build/website/plugins/remark-ansi.ts +248 -0
  186. package/build/website/plugins/remark-ansi.unit.ts +197 -0
  187. package/build/website/plugins/remark-badge.ts +50 -0
  188. package/build/website/plugins/remark-badge.unit.ts +96 -0
  189. package/build/website/plugins/remark-button.ts +60 -0
  190. package/build/website/plugins/remark-button.unit.ts +147 -0
  191. package/build/website/plugins/remark-callout.ts +57 -0
  192. package/build/website/plugins/remark-card.ts +80 -0
  193. package/build/website/plugins/remark-code-tabs.ts +87 -0
  194. package/build/website/plugins/remark-columns.ts +66 -0
  195. package/build/website/plugins/remark-custom-heading-id.ts +70 -0
  196. package/build/website/plugins/remark-custom-heading-id.unit.ts +131 -0
  197. package/build/website/plugins/remark-deflist.ts +36 -0
  198. package/build/website/plugins/remark-details.ts +49 -0
  199. package/build/website/plugins/remark-filetree.ts +89 -0
  200. package/build/website/plugins/remark-filetree.unit.ts +137 -0
  201. package/build/website/plugins/remark-github-callout.ts +71 -0
  202. package/build/website/plugins/remark-icon.ts +42 -0
  203. package/build/website/plugins/remark-image.ts +34 -0
  204. package/build/website/plugins/remark-media.ts +62 -0
  205. package/build/website/plugins/remark-media.unit.ts +74 -0
  206. package/build/website/plugins/remark-mermaid.ts +23 -0
  207. package/build/website/plugins/remark-npm.ts +52 -0
  208. package/build/website/plugins/remark-steps.ts +36 -0
  209. package/build/website/plugins/remark-steps.unit.ts +97 -0
  210. package/build/website/plugins/remark-tab.ts +100 -0
  211. package/build/website/plugins/remark-tab.unit.ts +181 -0
  212. package/build/website/plugins/remark-toc.ts +39 -0
  213. package/build/website/plugins/remark-toc.unit.ts +82 -0
  214. package/build/website/plugins/shiki-icon.ts +82 -0
  215. package/build/website/plugins/shiki-line-highlight.ts +174 -0
  216. package/build/website/plugins/vite-livemark.ts +91 -0
  217. package/build/website/routeTree.gen.ts +86 -0
  218. package/build/website/router.tsx +34 -0
  219. package/build/website/routes/$.tsx +92 -0
  220. package/build/website/routes/__root.tsx +97 -0
  221. package/build/website/server.ts +7 -0
  222. package/build/website/styles/general.css +163 -0
  223. package/build/website/styles/markdown.css +214 -0
  224. package/build/website/vite.config.ts +71 -0
  225. package/package.json +120 -12
  226. package/skills/authoring/SKILL.md +97 -0
  227. package/skills/configuration/SKILL.md +120 -0
  228. package/skills/customization/SKILL.md +118 -0
  229. package/build/descriptor/index.d.ts +0 -3
  230. package/build/descriptor/index.js +0 -4
  231. package/build/descriptor/load.d.ts +0 -8
  232. package/build/descriptor/load.js +0 -40
  233. package/build/descriptor/node.d.ts +0 -125
  234. package/build/descriptor/node.js +0 -9
  235. package/build/descriptor/save.d.ts +0 -8
  236. package/build/descriptor/save.js +0 -17
  237. package/build/descriptor/save.spec.js +0 -80
  238. package/build/descriptor/validate.d.ts +0 -9
  239. package/build/descriptor/validate.js +0 -14
  240. package/build/descriptor/validate.spec.js +0 -124
  241. package/build/dialect/Dialect.d.ts +0 -88
  242. package/build/dialect/Dialect.js +0 -2
  243. package/build/dialect/index.d.ts +0 -3
  244. package/build/dialect/index.js +0 -3
  245. package/build/dialect/load.d.ts +0 -4
  246. package/build/dialect/load.js +0 -7
  247. package/build/dialect/save.d.ts +0 -9
  248. package/build/dialect/save.js +0 -13
  249. package/build/dialect/validate.d.ts +0 -1
  250. package/build/dialect/validate.js +0 -4
  251. package/build/metadata/index.d.ts +0 -3
  252. package/build/metadata/index.js +0 -4
  253. package/build/metadata/load.d.ts +0 -10
  254. package/build/metadata/load.js +0 -55
  255. package/build/metadata/node.d.ts +0 -125
  256. package/build/metadata/node.js +0 -9
  257. package/build/metadata/save.d.ts +0 -8
  258. package/build/metadata/save.js +0 -17
  259. package/build/metadata/save.spec.js +0 -80
  260. package/build/metadata/validate.d.ts +0 -9
  261. package/build/metadata/validate.js +0 -14
  262. package/build/metadata/validate.spec.d.ts +0 -1
  263. package/build/metadata/validate.spec.js +0 -124
  264. package/build/package/Contributor.d.ts +0 -21
  265. package/build/package/Contributor.js +0 -2
  266. package/build/package/Package.d.ts +0 -65
  267. package/build/package/Package.js +0 -2
  268. package/build/package/index.d.ts +0 -4
  269. package/build/package/index.js +0 -3
  270. package/build/package/load.d.ts +0 -4
  271. package/build/package/load.js +0 -7
  272. package/build/package/save.d.ts +0 -9
  273. package/build/package/save.js +0 -13
  274. package/build/package/validate.d.ts +0 -1
  275. package/build/package/validate.js +0 -4
  276. package/build/resource/License.d.ts +0 -18
  277. package/build/resource/License.js +0 -2
  278. package/build/resource/Resource.d.ts +0 -67
  279. package/build/resource/Resource.js +0 -2
  280. package/build/resource/Source.d.ts +0 -17
  281. package/build/resource/Source.js +0 -2
  282. package/build/resource/index.d.ts +0 -5
  283. package/build/resource/index.js +0 -2
  284. package/build/resource/load.d.ts +0 -1
  285. package/build/resource/load.js +0 -2
  286. package/build/resource/save.d.ts +0 -9
  287. package/build/resource/save.js +0 -13
  288. package/build/resource/types/index.d.ts +0 -1
  289. package/build/resource/types/index.js +0 -2
  290. package/build/resource/types/table.d.ts +0 -29
  291. package/build/resource/types/table.js +0 -2
  292. package/build/resource/validate.d.ts +0 -1
  293. package/build/resource/validate.js +0 -4
  294. package/build/schema/Field.d.ts +0 -5
  295. package/build/schema/Field.js +0 -2
  296. package/build/schema/Schema.d.ts +0 -55
  297. package/build/schema/Schema.js +0 -2
  298. package/build/schema/fields/any.d.ts +0 -20
  299. package/build/schema/fields/any.js +0 -2
  300. package/build/schema/fields/array.d.ts +0 -32
  301. package/build/schema/fields/array.js +0 -2
  302. package/build/schema/fields/base.d.ts +0 -42
  303. package/build/schema/fields/base.js +0 -2
  304. package/build/schema/fields/boolean.d.ts +0 -28
  305. package/build/schema/fields/boolean.js +0 -2
  306. package/build/schema/fields/date.d.ts +0 -35
  307. package/build/schema/fields/date.js +0 -2
  308. package/build/schema/fields/datetime.d.ts +0 -35
  309. package/build/schema/fields/datetime.js +0 -2
  310. package/build/schema/fields/duration.d.ts +0 -28
  311. package/build/schema/fields/duration.js +0 -2
  312. package/build/schema/fields/geojson.d.ts +0 -26
  313. package/build/schema/fields/geojson.js +0 -2
  314. package/build/schema/fields/geopoint.d.ts +0 -27
  315. package/build/schema/fields/geopoint.js +0 -2
  316. package/build/schema/fields/index.d.ts +0 -16
  317. package/build/schema/fields/index.js +0 -17
  318. package/build/schema/fields/integer.d.ts +0 -37
  319. package/build/schema/fields/integer.js +0 -2
  320. package/build/schema/fields/list.d.ts +0 -36
  321. package/build/schema/fields/list.js +0 -2
  322. package/build/schema/fields/number.d.ts +0 -40
  323. package/build/schema/fields/number.js +0 -2
  324. package/build/schema/fields/object.d.ts +0 -32
  325. package/build/schema/fields/object.js +0 -2
  326. package/build/schema/fields/string.d.ts +0 -40
  327. package/build/schema/fields/string.js +0 -2
  328. package/build/schema/fields/time.d.ts +0 -35
  329. package/build/schema/fields/time.js +0 -2
  330. package/build/schema/fields/year.d.ts +0 -28
  331. package/build/schema/fields/year.js +0 -2
  332. package/build/schema/fields/yearmonth.d.ts +0 -28
  333. package/build/schema/fields/yearmonth.js +0 -2
  334. package/build/schema/index.d.ts +0 -4
  335. package/build/schema/index.js +0 -2
  336. package/build/schema/load.d.ts +0 -1
  337. package/build/schema/load.js +0 -2
  338. package/build/schema/save.d.ts +0 -9
  339. package/build/schema/save.js +0 -13
  340. package/build/schema/validate.d.ts +0 -1
  341. package/build/schema/validate.js +0 -4
  342. package/build/tsconfig.tsbuildinfo +0 -1
  343. package/index.ts +0 -0
  344. package/tsconfig.json +0 -10
  345. package/typedoc.json +0 -4
  346. /package/build/{descriptor/save.spec.d.ts → actions/changelog/build.unit.d.ts} +0 -0
  347. /package/build/{descriptor/validate.spec.d.ts → actions/config/define.unit.d.ts} +0 -0
  348. /package/build/{metadata/save.spec.d.ts → actions/config/load.unit.d.ts} +0 -0
@@ -0,0 +1,97 @@
1
+ import type { Heading, Root, Text } from "mdast"
2
+ import { describe, expect, it } from "vite-plus/test"
3
+ import { transformStepHeadings } from "./remark-steps.ts"
4
+
5
+ function makeHeading(depth: 1 | 2 | 3 | 4 | 5 | 6, text: string): Heading {
6
+ return { type: "heading", depth, children: [{ type: "text", value: text }] }
7
+ }
8
+
9
+ function makeTree(...children: Root["children"]): Root {
10
+ return { type: "root", children }
11
+ }
12
+
13
+ function findHeading(tree: Root, index: number): Heading {
14
+ const node = tree.children[index]
15
+ if (!node || node.type !== "heading") throw new Error("No heading at index")
16
+ return node
17
+ }
18
+
19
+ function headingText(heading: Heading): string {
20
+ return heading.children
21
+ .filter((c): c is Text => c.type === "text")
22
+ .map(c => c.value)
23
+ .join("")
24
+ }
25
+
26
+ describe("transformStepHeadings", () => {
27
+ function process(tree: Root) {
28
+ transformStepHeadings(tree)
29
+ return tree
30
+ }
31
+
32
+ it("should strip [step] and set data-step attribute", () => {
33
+ const tree = process(
34
+ makeTree(makeHeading(3, "Install Dependencies [step]")),
35
+ )
36
+ const heading = findHeading(tree, 0)
37
+ expect(heading.data?.hProperties).toEqual({ "data-step": 1 })
38
+ expect(headingText(heading)).toBe("Install Dependencies")
39
+ })
40
+
41
+ it("should auto-increment step numbers", () => {
42
+ const tree = process(
43
+ makeTree(
44
+ makeHeading(3, "Step One [step]"),
45
+ makeHeading(3, "Step Two [step]"),
46
+ makeHeading(3, "Step Three [step]"),
47
+ ),
48
+ )
49
+
50
+ expect(findHeading(tree, 0).data?.hProperties).toEqual({ "data-step": 1 })
51
+ expect(findHeading(tree, 1).data?.hProperties).toEqual({ "data-step": 2 })
52
+ expect(findHeading(tree, 2).data?.hProperties).toEqual({ "data-step": 3 })
53
+ })
54
+
55
+ it("should leave headings without [step] unchanged", () => {
56
+ const tree = process(makeTree(makeHeading(2, "Normal Heading")))
57
+ const heading = findHeading(tree, 0)
58
+ expect(heading.data).toBeUndefined()
59
+ expect(headingText(heading)).toBe("Normal Heading")
60
+ })
61
+
62
+ it("should only count [step] headings for numbering", () => {
63
+ const tree = process(
64
+ makeTree(
65
+ makeHeading(3, "First [step]"),
66
+ makeHeading(3, "Not a step"),
67
+ makeHeading(3, "Second [step]"),
68
+ ),
69
+ )
70
+
71
+ expect(findHeading(tree, 0).data?.hProperties).toEqual({ "data-step": 1 })
72
+ expect(findHeading(tree, 1).data).toBeUndefined()
73
+ expect(findHeading(tree, 2).data?.hProperties).toEqual({ "data-step": 2 })
74
+ })
75
+
76
+ it("should handle different heading depths", () => {
77
+ const tree = process(
78
+ makeTree(
79
+ makeHeading(2, "Big Step [step]"),
80
+ makeHeading(4, "Small Step [step]"),
81
+ ),
82
+ )
83
+
84
+ expect(findHeading(tree, 0).data?.hProperties).toEqual({ "data-step": 1 })
85
+ expect(findHeading(tree, 1).data?.hProperties).toEqual({ "data-step": 2 })
86
+ })
87
+
88
+ it("should preserve existing hProperties", () => {
89
+ const heading = makeHeading(3, "Custom [step]")
90
+ heading.data = { hProperties: { id: "custom-id" } }
91
+ const tree = process(makeTree(heading))
92
+ expect(findHeading(tree, 0).data?.hProperties).toEqual({
93
+ id: "custom-id",
94
+ "data-step": 1,
95
+ })
96
+ })
97
+ })
@@ -0,0 +1,100 @@
1
+ import type { Root } from "mdast"
2
+ import type { ContainerDirective } from "mdast-util-directive"
3
+ import type { Plugin } from "unified"
4
+ import { visit, SKIP } from "unist-util-visit"
5
+
6
+ /** Walk a mdast tree and convert :::tab directives into ContentTab/ContentTabs JSX elements */
7
+ export function transformTabDirectives(tree: Root) {
8
+ visit(
9
+ tree,
10
+ "containerDirective",
11
+ (node: ContainerDirective, index, parent) => {
12
+ if (node.name !== "tab" || index === undefined || !parent) return
13
+
14
+ const title = node.attributes?.title ?? ""
15
+ const sync = node.attributes?.sync
16
+
17
+ const attrs: { type: "mdxJsxAttribute"; name: string; value: string }[] =
18
+ [{ type: "mdxJsxAttribute" as const, name: "title", value: title }]
19
+ if (sync) {
20
+ attrs.push({
21
+ type: "mdxJsxAttribute" as const,
22
+ name: "sync",
23
+ value: sync,
24
+ })
25
+ }
26
+
27
+ const jsxNode = {
28
+ type: "mdxJsxFlowElement" as const,
29
+ name: "ContentTab",
30
+ attributes: attrs,
31
+ children: node.children,
32
+ data: { _mdxExplicitJsx: true },
33
+ }
34
+
35
+ // @ts-expect-error mdxJsxFlowElement is not in mdast types
36
+ parent.children[index] = jsxNode
37
+ return SKIP
38
+ },
39
+ )
40
+
41
+ const children = tree.children
42
+ let i = 0
43
+ while (i < children.length) {
44
+ const node = children[i]
45
+ // @ts-expect-error mdxJsxFlowElement is not in mdast types
46
+ if (node?.type !== "mdxJsxFlowElement" || node.name !== "ContentTab") {
47
+ i++
48
+ continue
49
+ }
50
+
51
+ let j = i + 1
52
+ while (j < children.length) {
53
+ const next = children[j]
54
+ // @ts-expect-error mdxJsxFlowElement is not in mdast types
55
+ if (next?.type !== "mdxJsxFlowElement" || next.name !== "ContentTab")
56
+ break
57
+ j++
58
+ }
59
+
60
+ const group = children.slice(i, j)
61
+
62
+ const firstChild = group[0]
63
+ // @ts-expect-error accessing mdxJsx attributes on untyped node
64
+ const syncAttr = firstChild?.attributes?.find(
65
+ (a: { name: string }) => a.name === "sync",
66
+ )
67
+ const wrapperAttrs: {
68
+ type: "mdxJsxAttribute"
69
+ name: string
70
+ value: string
71
+ }[] = syncAttr
72
+ ? [
73
+ {
74
+ type: "mdxJsxAttribute" as const,
75
+ name: "sync",
76
+ value: syncAttr.value,
77
+ },
78
+ ]
79
+ : []
80
+
81
+ const wrapper = {
82
+ type: "mdxJsxFlowElement" as const,
83
+ name: "ContentTabs",
84
+ attributes: wrapperAttrs,
85
+ children: group,
86
+ data: { _mdxExplicitJsx: true },
87
+ }
88
+
89
+ // @ts-expect-error mdxJsxFlowElement is not in mdast types
90
+ children.splice(i, j - i, wrapper)
91
+ i++
92
+ }
93
+ }
94
+
95
+ /** Remark plugin that converts :::tab directives into ContentTab/ContentTabs JSX elements */
96
+ export const remarkTab: Plugin<[], Root> = () => {
97
+ return tree => {
98
+ transformTabDirectives(tree)
99
+ }
100
+ }
@@ -0,0 +1,181 @@
1
+ import type { Root } from "mdast"
2
+ import type { ContainerDirective } from "mdast-util-directive"
3
+ import { describe, expect, it } from "vite-plus/test"
4
+ import { transformTabDirectives } from "./remark-tab.ts"
5
+
6
+ function makeContainerDirective(
7
+ name: string,
8
+ attributes?: Record<string, string>,
9
+ ): ContainerDirective {
10
+ return {
11
+ type: "containerDirective",
12
+ name,
13
+ attributes: attributes ?? {},
14
+ children: [
15
+ { type: "paragraph", children: [{ type: "text", value: "content" }] },
16
+ ],
17
+ }
18
+ }
19
+
20
+ function makeTree(...children: Root["children"]): Root {
21
+ return { type: "root", children }
22
+ }
23
+
24
+ describe("transformTabDirectives", () => {
25
+ function process(tree: Root) {
26
+ transformTabDirectives(tree)
27
+ return tree
28
+ }
29
+
30
+ it("should convert :::tab directive to ContentTab JSX element", () => {
31
+ const directive = makeContainerDirective("tab", { title: "React" })
32
+ const tree = process(makeTree(directive))
33
+
34
+ const node = tree.children[0]
35
+ expect(node).toMatchObject({
36
+ type: "mdxJsxFlowElement",
37
+ name: "ContentTabs",
38
+ children: [
39
+ {
40
+ type: "mdxJsxFlowElement",
41
+ name: "ContentTab",
42
+ attributes: [
43
+ { type: "mdxJsxAttribute", name: "title", value: "React" },
44
+ ],
45
+ },
46
+ ],
47
+ })
48
+ })
49
+
50
+ it("should default title to empty string when not provided", () => {
51
+ const directive = makeContainerDirective("tab")
52
+ const tree = process(makeTree(directive))
53
+
54
+ const wrapper = tree.children[0]
55
+ expect(wrapper).toMatchObject({
56
+ type: "mdxJsxFlowElement",
57
+ name: "ContentTabs",
58
+ children: [
59
+ {
60
+ type: "mdxJsxFlowElement",
61
+ name: "ContentTab",
62
+ attributes: [{ type: "mdxJsxAttribute", name: "title", value: "" }],
63
+ },
64
+ ],
65
+ })
66
+ })
67
+
68
+ it("should ignore non-tab container directives", () => {
69
+ const directive = makeContainerDirective("note")
70
+ const tree = process(makeTree(directive))
71
+
72
+ expect(tree.children[0]).toMatchObject({
73
+ type: "containerDirective",
74
+ name: "note",
75
+ })
76
+ })
77
+
78
+ it("should wrap a single ContentTab in ContentTabs", () => {
79
+ const directive = makeContainerDirective("tab", { title: "Only" })
80
+ const tree = process(makeTree(directive))
81
+
82
+ expect(tree.children).toHaveLength(1)
83
+ expect(tree.children[0]).toMatchObject({
84
+ type: "mdxJsxFlowElement",
85
+ name: "ContentTabs",
86
+ children: [
87
+ {
88
+ type: "mdxJsxFlowElement",
89
+ name: "ContentTab",
90
+ },
91
+ ],
92
+ })
93
+ })
94
+
95
+ it("should group consecutive tabs into a single ContentTabs wrapper", () => {
96
+ const tab1 = makeContainerDirective("tab", { title: "React" })
97
+ const tab2 = makeContainerDirective("tab", { title: "Vue" })
98
+ const tab3 = makeContainerDirective("tab", { title: "Svelte" })
99
+ const tree = process(makeTree(tab1, tab2, tab3))
100
+
101
+ expect(tree.children).toHaveLength(1)
102
+ const wrapper = tree.children[0]
103
+ expect(wrapper).toMatchObject({
104
+ type: "mdxJsxFlowElement",
105
+ name: "ContentTabs",
106
+ })
107
+ // @ts-expect-error mdxJsxFlowElement is not in mdast types
108
+ expect(wrapper.children).toHaveLength(3)
109
+ })
110
+
111
+ it("should not group tabs separated by other elements", () => {
112
+ const tab1 = makeContainerDirective("tab", { title: "A" })
113
+ const separator = {
114
+ type: "paragraph" as const,
115
+ children: [{ type: "text" as const, value: "break" }],
116
+ }
117
+ const tab2 = makeContainerDirective("tab", { title: "B" })
118
+ const tree = process(makeTree(tab1, separator, tab2))
119
+
120
+ expect(tree.children).toHaveLength(3)
121
+ expect(tree.children[0]).toMatchObject({
122
+ type: "mdxJsxFlowElement",
123
+ name: "ContentTabs",
124
+ })
125
+ expect(tree.children[1]).toMatchObject({ type: "paragraph" })
126
+ expect(tree.children[2]).toMatchObject({
127
+ type: "mdxJsxFlowElement",
128
+ name: "ContentTabs",
129
+ })
130
+ })
131
+
132
+ it("should pass sync attribute to ContentTab when present", () => {
133
+ const directive = makeContainerDirective("tab", {
134
+ title: "npm",
135
+ sync: "pm",
136
+ })
137
+ const tree = process(makeTree(directive))
138
+
139
+ const wrapper = tree.children[0]
140
+ // @ts-expect-error mdxJsxFlowElement is not in mdast types
141
+ const tab = wrapper.children[0]
142
+ expect(tab).toMatchObject({
143
+ type: "mdxJsxFlowElement",
144
+ name: "ContentTab",
145
+ attributes: [
146
+ { type: "mdxJsxAttribute", name: "title", value: "npm" },
147
+ { type: "mdxJsxAttribute", name: "sync", value: "pm" },
148
+ ],
149
+ })
150
+ })
151
+
152
+ it("should propagate sync attribute to ContentTabs wrapper", () => {
153
+ const tab1 = makeContainerDirective("tab", {
154
+ title: "npm",
155
+ sync: "pm",
156
+ })
157
+ const tab2 = makeContainerDirective("tab", {
158
+ title: "pnpm",
159
+ sync: "pm",
160
+ })
161
+ const tree = process(makeTree(tab1, tab2))
162
+
163
+ expect(tree.children[0]).toMatchObject({
164
+ type: "mdxJsxFlowElement",
165
+ name: "ContentTabs",
166
+ attributes: [{ type: "mdxJsxAttribute", name: "sync", value: "pm" }],
167
+ })
168
+ })
169
+
170
+ it("should not add sync attribute when not present", () => {
171
+ const tab1 = makeContainerDirective("tab", { title: "A" })
172
+ const tab2 = makeContainerDirective("tab", { title: "B" })
173
+ const tree = process(makeTree(tab1, tab2))
174
+
175
+ expect(tree.children[0]).toMatchObject({
176
+ type: "mdxJsxFlowElement",
177
+ name: "ContentTabs",
178
+ attributes: [],
179
+ })
180
+ })
181
+ })
@@ -0,0 +1,39 @@
1
+ import type { Root } from "mdast"
2
+ import type { LeafDirective } from "mdast-util-directive"
3
+ import type { Plugin } from "unified"
4
+ import { visit } from "unist-util-visit"
5
+
6
+ /** Walk a mdast tree and convert toc leaf directives into InlineToc JSX elements */
7
+ export function transformTocDirectives(tree: Root) {
8
+ visit(tree, "leafDirective", (node: LeafDirective, index, parent) => {
9
+ if (node.name !== "toc" || index === undefined || !parent) return
10
+
11
+ const maxLevel = node.attributes?.maxLevel
12
+
13
+ const jsxNode = {
14
+ type: "mdxJsxFlowElement" as const,
15
+ name: "InlineToc",
16
+ attributes: maxLevel
17
+ ? [
18
+ {
19
+ type: "mdxJsxAttribute" as const,
20
+ name: "maxLevel",
21
+ value: maxLevel,
22
+ },
23
+ ]
24
+ : [],
25
+ children: [],
26
+ data: { _mdxExplicitJsx: true },
27
+ }
28
+
29
+ // @ts-expect-error mdxJsxFlowElement is not in mdast types
30
+ parent.children.splice(index, 1, jsxNode)
31
+ })
32
+ }
33
+
34
+ /** Remark plugin that converts ::toc leaf directives into InlineToc JSX elements */
35
+ export const remarkToc: Plugin<[], Root> = () => {
36
+ return tree => {
37
+ transformTocDirectives(tree)
38
+ }
39
+ }
@@ -0,0 +1,82 @@
1
+ import type { Root } from "mdast"
2
+ import type { LeafDirective } from "mdast-util-directive"
3
+ import { describe, expect, it } from "vite-plus/test"
4
+ import { transformTocDirectives } from "./remark-toc.ts"
5
+
6
+ function makeLeafDirective(
7
+ name: string,
8
+ attributes: Record<string, string> = {},
9
+ ): LeafDirective {
10
+ return {
11
+ type: "leafDirective" as LeafDirective["type"],
12
+ name,
13
+ attributes,
14
+ children: [],
15
+ }
16
+ }
17
+
18
+ function makeTree(...children: Root["children"]): Root {
19
+ return { type: "root", children }
20
+ }
21
+
22
+ function process(tree: Root) {
23
+ transformTocDirectives(tree)
24
+ return tree
25
+ }
26
+
27
+ describe("transformTocDirectives", () => {
28
+ it("should convert toc directive to InlineToc JSX element", () => {
29
+ const tree = process(makeTree(makeLeafDirective("toc")))
30
+ const node = tree.children[0]
31
+ expect(node).toMatchObject({
32
+ type: "mdxJsxFlowElement",
33
+ name: "InlineToc",
34
+ attributes: [],
35
+ children: [],
36
+ })
37
+ })
38
+
39
+ it("should ignore unrelated leaf directives", () => {
40
+ const tree = process(
41
+ makeTree(makeLeafDirective("video", { type: "youtube" })),
42
+ )
43
+ const node = tree.children[0]
44
+ expect(node).toMatchObject({ type: "leafDirective", name: "video" })
45
+ })
46
+
47
+ it("should handle multiple toc directives in the same tree", () => {
48
+ const tree = process(
49
+ makeTree(
50
+ makeLeafDirective("toc"),
51
+ { type: "paragraph", children: [{ type: "text", value: "hello" }] },
52
+ makeLeafDirective("toc"),
53
+ ),
54
+ )
55
+ expect(tree.children[0]).toMatchObject({
56
+ type: "mdxJsxFlowElement",
57
+ name: "InlineToc",
58
+ })
59
+ expect(tree.children[1]).toMatchObject({ type: "paragraph" })
60
+ expect(tree.children[2]).toMatchObject({
61
+ type: "mdxJsxFlowElement",
62
+ name: "InlineToc",
63
+ })
64
+ })
65
+
66
+ it("should preserve other children when converting toc directive", () => {
67
+ const tree = process(
68
+ makeTree(
69
+ { type: "paragraph", children: [{ type: "text", value: "before" }] },
70
+ makeLeafDirective("toc"),
71
+ { type: "paragraph", children: [{ type: "text", value: "after" }] },
72
+ ),
73
+ )
74
+ expect(tree.children).toHaveLength(3)
75
+ expect(tree.children[0]).toMatchObject({ type: "paragraph" })
76
+ expect(tree.children[1]).toMatchObject({
77
+ type: "mdxJsxFlowElement",
78
+ name: "InlineToc",
79
+ })
80
+ expect(tree.children[2]).toMatchObject({ type: "paragraph" })
81
+ })
82
+ })
@@ -0,0 +1,82 @@
1
+ interface HastElement {
2
+ properties: Record<string, unknown>
3
+ }
4
+
5
+ interface ShikiTransformer {
6
+ name: string
7
+ pre: (
8
+ this: { options: { lang?: string } },
9
+ pre: HastElement,
10
+ ) => HastElement | void
11
+ }
12
+
13
+ type Icon = { viewBox: string; fill: string; d: string }
14
+
15
+ const shortcuts: Record<string, string> = {
16
+ js: "javascript",
17
+ jsx: "react",
18
+ ts: "typescript",
19
+ tsx: "react",
20
+ py: "python",
21
+ bash: "shellscript",
22
+ sh: "shellscript",
23
+ shell: "shellscript",
24
+ zsh: "shellscript",
25
+ }
26
+
27
+ const icons: Record<string, Icon> = {
28
+ typescript: {
29
+ viewBox: "0 0 24 24",
30
+ fill: "currentColor",
31
+ d: "M1.125 0C.502 0 0 .502 0 1.125v21.75C0 23.498.502 24 1.125 24h21.75c.623 0 1.125-.502 1.125-1.125V1.125C24 .502 23.498 0 22.875 0zm17.363 9.75c.612 0 1.154.037 1.627.111a6.38 6.38 0 0 1 1.306.34v2.458a3.95 3.95 0 0 0-.643-.361 5.093 5.093 0 0 0-.717-.26 5.453 5.453 0 0 0-1.426-.2c-.3 0-.573.028-.819.086a2.1 2.1 0 0 0-.623.242c-.17.104-.3.229-.393.374a.888.888 0 0 0-.14.49c0 .196.053.373.156.529.104.156.252.304.443.444s.423.276.696.41c.273.135.582.274.926.416.47.197.892.407 1.266.628.374.222.695.473.963.753.268.279.472.598.614.957.142.359.214.776.214 1.253 0 .657-.125 1.21-.373 1.656a3.033 3.033 0 0 1-1.012 1.085 4.38 4.38 0 0 1-1.487.596c-.566.12-1.163.18-1.79.18a9.916 9.916 0 0 1-1.84-.164 5.544 5.544 0 0 1-1.512-.493v-2.63a5.033 5.033 0 0 0 3.237 1.2c.333 0 .624-.03.872-.09.249-.06.456-.144.623-.25.166-.108.29-.234.373-.38a1.023 1.023 0 0 0-.074-1.089 2.12 2.12 0 0 0-.537-.5 5.597 5.597 0 0 0-.807-.444 27.72 27.72 0 0 0-1.007-.436c-.918-.383-1.602-.852-2.053-1.405-.45-.553-.676-1.222-.676-2.005 0-.614.123-1.141.369-1.582.246-.441.58-.804 1.004-1.089a4.494 4.494 0 0 1 1.47-.629 7.536 7.536 0 0 1 1.77-.201zm-15.113.188h9.563v2.166H9.506v9.646H6.789v-9.646H3.375z",
32
+ },
33
+ javascript: {
34
+ viewBox: "0 0 24 24",
35
+ fill: "currentColor",
36
+ d: "M0 0h24v24H0V0zm22.034 18.276c-.175-1.095-.888-2.015-3.003-2.873-.736-.345-1.554-.585-1.797-1.14-.091-.33-.105-.51-.046-.705.15-.646.915-.84 1.515-.66.39.12.75.42.976.9 1.034-.676 1.034-.676 1.755-1.125-.27-.42-.405-.6-.586-.78-.63-.705-1.469-1.065-2.834-1.034l-.705.089c-.676.165-1.32.525-1.71 1.005-1.14 1.291-.811 3.541.569 4.471 1.365 1.02 3.361 1.244 3.616 2.205.24 1.17-.87 1.545-1.966 1.41-.811-.18-1.26-.586-1.755-1.336l-1.83 1.051c.21.48.45.689.81 1.109 1.74 1.756 6.09 1.666 6.871-1.004.029-.09.24-.705.074-1.65l.046.067zm-8.983-7.245h-2.248c0 1.938-.009 3.864-.009 5.805 0 1.232.063 2.363-.138 2.711-.33.689-1.18.601-1.566.48-.396-.196-.597-.466-.83-.855-.063-.105-.11-.196-.127-.196l-1.825 1.125c.305.63.75 1.172 1.324 1.517.855.51 2.004.675 3.207.405.783-.226 1.458-.691 1.811-1.411.51-.93.402-2.07.397-3.346.012-2.054 0-4.109 0-6.179l.004-.056z",
37
+ },
38
+ react: {
39
+ viewBox: "0 0 24 24",
40
+ fill: "currentColor",
41
+ d: "M14.23 12.004a2.236 2.236 0 0 1-2.235 2.236 2.236 2.236 0 0 1-2.236-2.236 2.236 2.236 0 0 1 2.235-2.236 2.236 2.236 0 0 1 2.236 2.236zm2.648-10.69c-1.346 0-3.107.96-4.888 2.622-1.78-1.653-3.542-2.602-4.887-2.602-.41 0-.783.093-1.106.278-1.375.793-1.683 3.264-.973 6.365C1.98 8.917 0 10.42 0 12.004c0 1.59 1.99 3.097 5.043 4.03-.704 3.113-.39 5.588.988 6.38.32.187.69.275 1.102.275 1.345 0 3.107-.96 4.888-2.624 1.78 1.654 3.542 2.603 4.887 2.603.41 0 .783-.09 1.106-.275 1.374-.792 1.683-3.263.973-6.365C22.02 15.096 24 13.59 24 12.004c0-1.59-1.99-3.097-5.043-4.032.704-3.11.39-5.587-.988-6.38-.318-.184-.688-.277-1.092-.278zm-.005 1.09v.006c.225 0 .406.044.558.127.666.382.955 1.835.73 3.704-.054.46-.142.945-.25 1.44-.96-.236-2.006-.417-3.107-.534-.66-.905-1.345-1.727-2.035-2.447 1.592-1.48 3.087-2.292 4.105-2.295zm-9.77.02c1.012 0 2.514.808 4.11 2.28-.686.72-1.37 1.537-2.02 2.442-1.107.117-2.154.298-3.113.538-.112-.49-.195-.964-.254-1.42-.23-1.868.054-3.32.714-3.707.19-.09.4-.127.563-.132zm4.882 3.05c.455.468.91.992 1.36 1.564-.44-.02-.89-.034-1.345-.034-.46 0-.915.01-1.36.034.44-.572.895-1.096 1.345-1.565zM12 8.1c.74 0 1.477.034 2.202.093.406.582.802 1.203 1.183 1.86.372.64.71 1.29 1.018 1.946-.308.655-.646 1.31-1.013 1.95-.38.66-.773 1.288-1.18 1.87-.728.063-1.466.098-2.21.098-.74 0-1.477-.035-2.202-.093-.406-.582-.802-1.204-1.183-1.86-.372-.64-.71-1.29-1.018-1.946.303-.657.646-1.313 1.013-1.954.38-.66.773-1.286 1.18-1.868.728-.064 1.466-.098 2.21-.098zm-3.635.254c-.24.377-.48.763-.704 1.16-.225.39-.435.782-.635 1.174-.265-.656-.49-1.31-.676-1.947.64-.15 1.315-.283 2.015-.386zm7.26 0c.695.103 1.365.23 2.006.387-.18.632-.405 1.282-.66 1.933-.2-.39-.41-.783-.64-1.174-.225-.392-.465-.774-.705-1.146zm3.063.675c.484.15.944.317 1.375.498 1.732.74 2.852 1.708 2.852 2.476-.005.768-1.125 1.74-2.857 2.475-.42.18-.88.342-1.355.493-.28-.958-.646-1.956-1.1-2.98.45-1.017.81-2.01 1.085-2.964zm-13.395.004c.278.96.645 1.957 1.1 2.98-.45 1.017-.812 2.01-1.086 2.964-.484-.15-.944-.318-1.37-.5-1.732-.737-2.852-1.706-2.852-2.474 0-.768 1.12-1.742 2.852-2.476.42-.18.88-.342 1.356-.494zm11.678 4.28c.265.657.49 1.312.676 1.948-.64.157-1.316.29-2.016.39.24-.375.48-.762.705-1.158.225-.39.435-.788.636-1.18zm-9.945.02c.2.392.41.783.64 1.175.23.39.465.772.705 1.143-.695-.102-1.365-.23-2.006-.386.18-.63.406-1.282.66-1.933zM17.92 16.32c.112.493.2.968.254 1.423.23 1.868-.054 3.32-.714 3.708-.147.09-.338.128-.563.128-1.012 0-2.514-.807-4.11-2.28.686-.72 1.37-1.536 2.02-2.44 1.107-.118 2.154-.3 3.113-.54zm-11.83.01c.96.234 2.006.415 3.107.532.66.905 1.345 1.727 2.035 2.446-1.595 1.483-3.092 2.295-4.11 2.295-.22-.005-.406-.05-.553-.132-.666-.38-.955-1.834-.73-3.703.054-.46.142-.944.25-1.438zm4.56.64c.44.02.89.034 1.345.034.46 0 .915-.01 1.36-.034-.44.572-.895 1.095-1.345 1.565-.455-.47-.91-.993-1.36-1.565z",
42
+ },
43
+ python: {
44
+ viewBox: "0 0 24 24",
45
+ fill: "currentColor",
46
+ d: "M14.25.18l.9.2.73.26.59.3.45.32.34.34.25.34.16.33.1.3.04.26.02.2-.01.13V8.5l-.05.63-.13.55-.21.46-.26.38-.3.31-.33.25-.35.19-.35.14-.33.1-.3.07-.26.04-.21.02H8.77l-.69.05-.59.14-.5.22-.41.27-.33.32-.27.35-.2.36-.15.37-.1.35-.07.32-.04.27-.02.21v3.06H3.17l-.21-.03-.28-.07-.32-.12-.35-.18-.36-.26-.36-.36-.35-.46-.32-.59-.28-.73-.21-.88-.14-1.05-.05-1.23.06-1.22.16-1.04.24-.87.32-.71.36-.57.4-.44.42-.33.42-.24.4-.16.36-.1.32-.05.24-.01h.16l.06.01H8.16v-.83H6.18l-.01-2.75-.02-.37.05-.34.11-.31.17-.28.25-.26.31-.23.38-.2.44-.18.51-.15.58-.12.64-.1.71-.06.77-.04.84-.02 1.27.05zm-6.3 1.98l-.23.33-.08.41.08.41.23.34.33.22.41.09.41-.09.33-.22.23-.34.08-.41-.08-.41-.23-.33-.33-.22-.41-.09-.41.09zm13.09 3.95l.28.06.32.12.35.18.36.27.36.35.35.47.32.59.28.73.21.88.14 1.04.05 1.23-.06 1.23-.16 1.04-.24.86-.32.71-.36.57-.4.45-.42.33-.42.24-.4.16-.36.09-.32.05-.24.02-.16-.01h-8.22v.82h5.84l.01 2.76.02.36-.05.34-.11.31-.17.29-.25.25-.31.24-.38.2-.44.17-.51.15-.58.13-.64.09-.71.07-.77.04-.84.01-1.27-.04-1.07-.14-.9-.2-.73-.25-.59-.3-.45-.33-.34-.34-.25-.34-.16-.33-.1-.3-.04-.25-.02-.2.01-.13v-5.34l.05-.64.13-.54.21-.46.26-.38.3-.32.33-.24.35-.2.35-.14.33-.1.3-.06.26-.04.21-.02.13-.01h5.84l.69-.05.59-.14.5-.21.41-.28.33-.32.27-.35.2-.36.15-.36.1-.35.07-.32.04-.28.02-.21V6.07h2.09l.14.01zm-6.47 14.25l-.23.33-.08.41.08.41.23.33.33.23.41.08.41-.08.33-.23.23-.33.08-.41-.08-.41-.23-.33-.33-.23-.41-.08-.41.08z",
47
+ },
48
+ rust: {
49
+ viewBox: "0 0 24 24",
50
+ fill: "currentColor",
51
+ d: "M23.8346 11.7033l-1.0073-.6236a13.7268 13.7268 0 00-.0283-.2936l.8656-.8069a.3483.3483 0 00-.1154-.578l-1.1066-.414a8.4958 8.4958 0 00-.087-.2856l.6904-.9587a.3462.3462 0 00-.2257-.5446l-1.1663-.1894a9.3574 9.3574 0 00-.1407-.2622l.4895-1.0761a.3438.3438 0 00-.3300-.4908l-1.1845.0416a6.7444 6.7444 0 00-.1873-.2268l.2723-1.153a.3472.3472 0 00-.4233-.4164l-1.1592.2683a14.1794 14.1794 0 00-.2231-.1817l.0467-1.1872a.3462.3462 0 00-.5765-.322l-1.0907.4878c-.0799-.0499-.1613-.0983-.2449-.1456l-.1787-1.1758a.3456.3456 0 00-.5766-.2329l-.9813.6919a13.596 13.596 0 00-.2571-.1049l-.3982-1.1175a.348.348 0 00-.5815-.1272l-.8352.8738a10.2102 10.2102 0 00-.2606-.0584l-.6082-1.0131a.3459.3459 0 00-.5659-.0197l-.6602 1.0257a6.3249 6.3249 0 00-.2574.0068L8.3862.8721a.3437.3437 0 00-.5368.0921l-.4676 1.1376a10.3014 10.3014 0 00-.2444.0856L6.2788 1.394a.3447.3447 0 00-.4916.2004l-.2615 1.2048a11.5632 11.5632 0 00-.2242.149l-.9215-.5549a.3445.3445 0 00-.4345.2945l-.0488 1.2261a11.0239 11.0239 0 00-.1989.2028l-1.0498-.2744a.3441.3441 0 00-.3684.3752l.1643 1.2026c-.0553.075-.1084.1515-.1598.2293l-1.1374.0132a.3427.3427 0 00-.2938.4422l.3698 1.1347a10.4633 10.4633 0 00-.1162.2474l-1.1817.2923a.3433.3433 0 00-.2134.4944l.5627 1.0262c-.0265.085-.0502.1713-.0713.258l-1.1812.5586a.343.343 0 00-.1299.5316l.7396.8793a13.0102 13.0102 0 00-.0236.264l-1.1355.8086a.3445.3445 0 00-.0429.5513l.8937.6986a9.0776 9.0776 0 00.0235.2643L.3108 14.515a.3455.3455 0 00.0432.5508l1.0185.4941a14.4526 14.4526 0 00.0694.2602l-.6564.9682a.3443.3443 0 00.1273.5483l1.1066.2713c.0437.0833.0891.1653.136.2462l-.4348 1.0848a.3445.3445 0 00.2069.5304l1.1564.0436c.0583.0749.1182.1485.1797.2205l-.2004 1.1603a.348.348 0 00.2824.4902l1.1669-.1838c.0694.064.1404.1265.2127.1874l.0387 1.1912a.3476.3476 0 00.3498.4306l1.1388-.4038a7.4207 7.4207 0 00.2381.1482l.2723 1.1772a.3459.3459 0 00.4074.3543l1.0738-.6104c.084.0393.169.077.2553.113l.4964 1.1178a.3476.3476 0 00.4529.2643l.9744-.7985c.0873.0285.1757.0553.2649.0803l.707 1.015a.3475.3475 0 00.4827.165l.8435-.9633a8.7717 8.7717 0 00.267.0418l.8978.8715a.347.347 0 00.4959.0582l.6863-1.1004c.0877-.0039.1754-.0094.2631-.0166l1.0645.6907a.3478.3478 0 00.4921-.0466l.5043-1.2024c.0829-.0168.1657-.0349.2476-.0546l1.2024.478a.3444.3444 0 00.4721-.1462l.305-1.2685a9.4986 9.4986 0 00.2264-.0963l1.3088.241a.3462.3462 0 00.4373-.2383l.0931-1.2948a12.775 12.775 0 00.1996-.1384l1.3811-.0133a.3442.3442 0 00.3879-.3209l-.1204-1.2792a12.0697 12.0697 0 00.1677-.1767l1.4174-.2612a.3462.3462 0 00.3266-.3935l-.3286-1.222a13.5765 13.5765 0 00.1307-.2093l1.4154-.4985a.3454.3454 0 00.2558-.4536l-.5275-1.1259a8.7256 8.7256 0 00.0899-.2341l1.3741-.7219a.3439.3439 0 00.1787-.4993l-.7113-.9937a9.1373 9.1373 0 00.0449-.2543l1.2944-.9275a.3446.3446 0 00.0963-.5323zM12.0522 4.5705a.703.703 0 01.5765-.098c.3473.0982.6615.2679.9263.4973a.3873.3873 0 01-.5765.098c-.3473-.0982-.6615-.2679-.9263-.4973zm-3.2 7.5508c.2.0 .4-.0 .6-.0l.2 .6h-1l.2-.6zm4.5 2.7l-.4-.3.3-.4c-.3-.2-.7-.3-1.1-.3l-.1.5-.1-.5c-.4.0-.8.1-1.1.3l.3.4-.4.3c-.3-.3-.5-.6-.6-1l.5-.1-.5-.2c0-.4.1-.8.3-1.2l.4.3-.3-.4c.3-.3.6-.5 1-.6l.1.5.1-.5c.4.0.8.2 1.1.4l-.3.4.4-.3c.2.3.3.7.4 1.1l-.5.1.5.2c-.0.4-.2.8-.4 1.1zm3.3-2.1l-.6.0-.2-.6h1l-.2.6z",
52
+ },
53
+ shellscript: {
54
+ viewBox: "0 0 24 24",
55
+ fill: "currentColor",
56
+ d: "M4.814 0h14.371a2.813 2.813 0 0 1 2.814 2.814v18.371A2.813 2.813 0 0 1 19.186 24H4.814A2.813 2.813 0 0 1 2 21.186V2.814A2.813 2.813 0 0 1 4.814 0zM5.8 21.2h12.39v-1.6H5.8zm6.636-4.762L7.394 12.17l1.07-1.258 5.043 4.268zm-1.111-5.889 1.07-1.258 5.043 4.268-5.043 4.268-1.07-1.258 3.972-3.01z",
57
+ },
58
+ default: {
59
+ viewBox: "0 0 24 24",
60
+ fill: "currentColor",
61
+ d: "M 6,1 C 4.354992,1 3,2.354992 3,4 v 16 c 0,1.645008 1.354992,3 3,3 h 12 c 1.645008,0 3,-1.354992 3,-3 V 8 7 A 1.0001,1.0001 0 0 0 20.707031,6.2929687 l -5,-5 A 1.0001,1.0001 0 0 0 15,1 h -1 z m 0,2 h 7 v 3 c 0,1.645008 1.354992,3 3,3 h 3 v 11 c 0,0.564129 -0.435871,1 -1,1 H 6 C 5.4358712,21 5,20.564129 5,20 V 4 C 5,3.4358712 5.4358712,3 6,3 Z M 15,3.4140625 18.585937,7 H 16 C 15.435871,7 15,6.5641288 15,6 Z",
62
+ },
63
+ }
64
+
65
+ /**
66
+ * Shiki transformer that injects a language icon SVG into the pre element.
67
+ */
68
+ export function transformerIcon(): ShikiTransformer {
69
+ return {
70
+ name: "livemark:icon",
71
+ pre(pre) {
72
+ const lang = this.options.lang
73
+ if (!lang) return
74
+
75
+ const iconName = lang in shortcuts ? shortcuts[lang]! : lang
76
+ const icon = iconName in icons ? icons[iconName]! : icons.default!
77
+
78
+ pre.properties.icon = `<svg viewBox="${icon.viewBox}"><path d="${icon.d}" fill="${icon.fill}" /></svg>`
79
+ return pre
80
+ },
81
+ }
82
+ }