nebula-cms 0.1.3 → 0.1.4

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 (380) hide show
  1. package/README.md +2 -0
  2. package/dist/astro/index.d.ts +43 -0
  3. package/dist/astro/index.d.ts.map +1 -0
  4. package/dist/astro/index.js +223 -0
  5. package/dist/client/Admin.svelte.d.ts +11 -0
  6. package/dist/client/Admin.svelte.d.ts.map +1 -0
  7. package/dist/client/components/BackendPicker.svelte.d.ts +4 -0
  8. package/dist/client/components/BackendPicker.svelte.d.ts.map +1 -0
  9. package/dist/client/components/DraftChip.svelte.d.ts +10 -0
  10. package/dist/client/components/DraftChip.svelte.d.ts.map +1 -0
  11. package/dist/client/components/MetadataForm.svelte.d.ts +12 -0
  12. package/dist/client/components/MetadataForm.svelte.d.ts.map +1 -0
  13. package/dist/client/components/ThemeToggle.svelte.d.ts +19 -0
  14. package/dist/client/components/ThemeToggle.svelte.d.ts.map +1 -0
  15. package/dist/client/components/dialogs/DeleteDraftDialog.svelte.d.ts +11 -0
  16. package/dist/client/components/dialogs/DeleteDraftDialog.svelte.d.ts.map +1 -0
  17. package/dist/client/components/dialogs/FilenameDialog.svelte.d.ts +13 -0
  18. package/dist/client/components/dialogs/FilenameDialog.svelte.d.ts.map +1 -0
  19. package/dist/client/components/editor/EditorPane.svelte.d.ts +4 -0
  20. package/dist/client/components/editor/EditorPane.svelte.d.ts.map +1 -0
  21. package/dist/client/components/editor/EditorTabs.svelte.d.ts +8 -0
  22. package/dist/client/components/editor/EditorTabs.svelte.d.ts.map +1 -0
  23. package/dist/client/components/editor/EditorToolbar.svelte.d.ts +4 -0
  24. package/dist/client/components/editor/EditorToolbar.svelte.d.ts.map +1 -0
  25. package/dist/client/components/editor/FormatSelector.svelte.d.ts +4 -0
  26. package/dist/client/components/editor/FormatSelector.svelte.d.ts.map +1 -0
  27. package/dist/client/components/editor/Toolbar.svelte.d.ts +19 -0
  28. package/dist/client/components/editor/Toolbar.svelte.d.ts.map +1 -0
  29. package/dist/client/components/fields/ArrayField.svelte.d.ts +15 -0
  30. package/dist/client/components/fields/ArrayField.svelte.d.ts.map +1 -0
  31. package/dist/client/components/fields/ArrayItem.svelte.d.ts +28 -0
  32. package/dist/client/components/fields/ArrayItem.svelte.d.ts.map +1 -0
  33. package/dist/client/components/fields/BooleanField.svelte.d.ts +16 -0
  34. package/dist/client/components/fields/BooleanField.svelte.d.ts.map +1 -0
  35. package/dist/client/components/fields/DateField.svelte.d.ts +16 -0
  36. package/dist/client/components/fields/DateField.svelte.d.ts.map +1 -0
  37. package/dist/client/components/fields/EnumField.svelte.d.ts +17 -0
  38. package/dist/client/components/fields/EnumField.svelte.d.ts.map +1 -0
  39. package/dist/client/components/fields/FieldWrapper.svelte.d.ts +18 -0
  40. package/dist/client/components/fields/FieldWrapper.svelte.d.ts.map +1 -0
  41. package/dist/client/components/fields/NumberField.svelte.d.ts +16 -0
  42. package/dist/client/components/fields/NumberField.svelte.d.ts.map +1 -0
  43. package/dist/client/components/fields/ObjectField.svelte.d.ts +16 -0
  44. package/dist/client/components/fields/ObjectField.svelte.d.ts.map +1 -0
  45. package/dist/client/components/fields/SchemaField.svelte.d.ts +16 -0
  46. package/dist/client/components/fields/SchemaField.svelte.d.ts.map +1 -0
  47. package/dist/client/components/fields/StringField.svelte.d.ts +16 -0
  48. package/dist/client/components/fields/StringField.svelte.d.ts.map +1 -0
  49. package/dist/client/components/sidebar/AdminSidebar.svelte.d.ts +19 -0
  50. package/dist/client/components/sidebar/AdminSidebar.svelte.d.ts.map +1 -0
  51. package/dist/client/components/sidebar/AdminSidebarSort.svelte.d.ts +12 -0
  52. package/dist/client/components/sidebar/AdminSidebarSort.svelte.d.ts.map +1 -0
  53. package/dist/client/css/icons.css +29 -0
  54. package/dist/client/index.d.ts +2 -0
  55. package/dist/client/index.d.ts.map +1 -0
  56. package/dist/client/js/drafts/merge.svelte.d.ts +24 -0
  57. package/dist/client/js/drafts/merge.svelte.d.ts.map +1 -0
  58. package/dist/client/js/drafts/merge.svelte.js +106 -0
  59. package/dist/client/js/drafts/ops.svelte.d.ts +31 -0
  60. package/dist/client/js/drafts/ops.svelte.d.ts.map +1 -0
  61. package/dist/client/js/drafts/ops.svelte.js +182 -0
  62. package/dist/client/js/drafts/storage.d.ts +45 -0
  63. package/dist/client/js/drafts/storage.d.ts.map +1 -0
  64. package/dist/client/js/drafts/storage.js +76 -0
  65. package/dist/client/js/drafts/workers/diff.d.ts +2 -0
  66. package/dist/client/js/drafts/workers/diff.d.ts.map +1 -0
  67. package/dist/client/js/drafts/workers/diff.js +20 -0
  68. package/dist/client/js/editor/editor.svelte.d.ts +124 -0
  69. package/dist/client/js/editor/editor.svelte.d.ts.map +1 -0
  70. package/dist/client/js/editor/editor.svelte.js +294 -0
  71. package/dist/client/js/editor/languages.d.ts +11 -0
  72. package/dist/client/js/editor/languages.d.ts.map +1 -0
  73. package/dist/client/js/editor/languages.js +93 -0
  74. package/dist/client/js/editor/link-wrap.d.ts +6 -0
  75. package/dist/client/js/editor/link-wrap.d.ts.map +1 -0
  76. package/{src/client/js/editor/link-wrap.ts → dist/client/js/editor/link-wrap.js} +17 -24
  77. package/dist/client/js/editor/markdown-shortcuts.d.ts +4 -0
  78. package/dist/client/js/editor/markdown-shortcuts.d.ts.map +1 -0
  79. package/dist/client/js/editor/markdown-shortcuts.js +219 -0
  80. package/dist/client/js/handlers/admin.d.ts +64 -0
  81. package/dist/client/js/handlers/admin.d.ts.map +1 -0
  82. package/dist/client/js/handlers/admin.js +186 -0
  83. package/dist/client/js/state/dialogs.svelte.d.ts +16 -0
  84. package/dist/client/js/state/dialogs.svelte.d.ts.map +1 -0
  85. package/dist/client/js/state/dialogs.svelte.js +28 -0
  86. package/dist/client/js/state/router.svelte.d.ts +44 -0
  87. package/dist/client/js/state/router.svelte.d.ts.map +1 -0
  88. package/dist/client/js/state/router.svelte.js +135 -0
  89. package/dist/client/js/state/schema.svelte.d.ts +51 -0
  90. package/dist/client/js/state/schema.svelte.d.ts.map +1 -0
  91. package/{src/client/js/state/schema.svelte.ts → dist/client/js/state/schema.svelte.js} +55 -70
  92. package/dist/client/js/state/state.svelte.d.ts +68 -0
  93. package/dist/client/js/state/state.svelte.d.ts.map +1 -0
  94. package/dist/client/js/state/state.svelte.js +291 -0
  95. package/dist/client/js/state/theme.svelte.d.ts +24 -0
  96. package/dist/client/js/state/theme.svelte.d.ts.map +1 -0
  97. package/{src/client/js/state/theme.svelte.ts → dist/client/js/state/theme.svelte.js} +54 -91
  98. package/dist/client/js/storage/adapter.d.ts +130 -0
  99. package/dist/client/js/storage/adapter.d.ts.map +1 -0
  100. package/dist/client/js/storage/adapter.js +5 -0
  101. package/dist/client/js/storage/client.d.ts +72 -0
  102. package/dist/client/js/storage/client.d.ts.map +1 -0
  103. package/dist/client/js/storage/client.js +121 -0
  104. package/dist/client/js/storage/db.d.ts +8 -0
  105. package/dist/client/js/storage/db.d.ts.map +1 -0
  106. package/dist/client/js/storage/db.js +35 -0
  107. package/dist/client/js/storage/fsa.d.ts +51 -0
  108. package/dist/client/js/storage/fsa.d.ts.map +1 -0
  109. package/dist/client/js/storage/fsa.js +91 -0
  110. package/dist/client/js/storage/github.d.ts +62 -0
  111. package/dist/client/js/storage/github.d.ts.map +1 -0
  112. package/dist/client/js/storage/github.js +216 -0
  113. package/dist/client/js/storage/storage.d.ts +32 -0
  114. package/dist/client/js/storage/storage.d.ts.map +1 -0
  115. package/dist/client/js/storage/storage.js +68 -0
  116. package/dist/client/js/storage/workers/frontmatter.d.ts +2 -0
  117. package/dist/client/js/storage/workers/frontmatter.d.ts.map +1 -0
  118. package/dist/client/js/storage/workers/frontmatter.js +253 -0
  119. package/dist/client/js/storage/workers/storage.d.ts +2 -0
  120. package/dist/client/js/storage/workers/storage.d.ts.map +1 -0
  121. package/dist/client/js/storage/workers/storage.js +167 -0
  122. package/dist/client/js/storage/workers/toml-parser.d.ts +2 -0
  123. package/dist/client/js/storage/workers/toml-parser.d.ts.map +1 -0
  124. package/dist/client/js/storage/workers/toml-parser.js +75 -0
  125. package/dist/client/js/storage/workers/yaml-parser.d.ts +2 -0
  126. package/dist/client/js/storage/workers/yaml-parser.d.ts.map +1 -0
  127. package/dist/client/js/storage/workers/yaml-parser.js +100 -0
  128. package/dist/client/js/utils/file-types.d.ts +58 -0
  129. package/dist/client/js/utils/file-types.d.ts.map +1 -0
  130. package/{src/client/js/utils/file-types.ts → dist/client/js/utils/file-types.js} +75 -107
  131. package/dist/client/js/utils/format.d.ts +8 -0
  132. package/dist/client/js/utils/format.d.ts.map +1 -0
  133. package/{src/client/js/utils/format.ts → dist/client/js/utils/format.js} +5 -6
  134. package/dist/client/js/utils/frontmatter.d.ts +12 -0
  135. package/dist/client/js/utils/frontmatter.d.ts.map +1 -0
  136. package/dist/client/js/utils/frontmatter.js +29 -0
  137. package/dist/client/js/utils/schema-utils.d.ts +110 -0
  138. package/dist/client/js/utils/schema-utils.d.ts.map +1 -0
  139. package/dist/client/js/utils/schema-utils.js +242 -0
  140. package/dist/client/js/utils/slug.d.ts +8 -0
  141. package/dist/client/js/utils/slug.d.ts.map +1 -0
  142. package/{src/client/js/utils/slug.ts → dist/client/js/utils/slug.js} +6 -7
  143. package/dist/client/js/utils/sort.d.ts +41 -0
  144. package/dist/client/js/utils/sort.d.ts.map +1 -0
  145. package/dist/client/js/utils/sort.js +65 -0
  146. package/dist/client/js/utils/stable-stringify.d.ts +8 -0
  147. package/dist/client/js/utils/stable-stringify.d.ts.map +1 -0
  148. package/dist/client/js/utils/stable-stringify.js +23 -0
  149. package/dist/client/js/utils/url-utils.d.ts +11 -0
  150. package/dist/client/js/utils/url-utils.d.ts.map +1 -0
  151. package/{src/client/js/utils/url-utils.ts → dist/client/js/utils/url-utils.js} +22 -23
  152. package/dist/types.d.ts +22 -0
  153. package/dist/types.d.ts.map +1 -0
  154. package/dist/types.js +1 -0
  155. package/package.json +4 -1
  156. package/.github/workflows/ci.yml +0 -27
  157. package/.github/workflows/publish.yml +0 -34
  158. package/.mcp.json +0 -12
  159. package/.prettierignore +0 -5
  160. package/.prettierrc.cjs +0 -22
  161. package/AGENTS.md +0 -183
  162. package/playground/astro.config.mjs +0 -7
  163. package/playground/node_modules/.bin/astro +0 -21
  164. package/playground/node_modules/.vite/deps/@astrojs_svelte_client__js.js +0 -85
  165. package/playground/node_modules/.vite/deps/@astrojs_svelte_client__js.js.map +0 -7
  166. package/playground/node_modules/.vite/deps/_metadata.json +0 -184
  167. package/playground/node_modules/.vite/deps/astro___aria-query.js +0 -6776
  168. package/playground/node_modules/.vite/deps/astro___aria-query.js.map +0 -7
  169. package/playground/node_modules/.vite/deps/astro___axobject-query.js +0 -3754
  170. package/playground/node_modules/.vite/deps/astro___axobject-query.js.map +0 -7
  171. package/playground/node_modules/.vite/deps/astro___html-escaper.js +0 -34
  172. package/playground/node_modules/.vite/deps/astro___html-escaper.js.map +0 -7
  173. package/playground/node_modules/.vite/deps/chunk-AJXJMYAF.js +0 -0
  174. package/playground/node_modules/.vite/deps/chunk-AJXJMYAF.js.map +0 -7
  175. package/playground/node_modules/.vite/deps/chunk-BUSYA2B4.js +0 -8
  176. package/playground/node_modules/.vite/deps/chunk-BUSYA2B4.js.map +0 -7
  177. package/playground/node_modules/.vite/deps/chunk-CNYJBM5F.js +0 -21
  178. package/playground/node_modules/.vite/deps/chunk-CNYJBM5F.js.map +0 -7
  179. package/playground/node_modules/.vite/deps/chunk-DBPNBGEI.js +0 -223
  180. package/playground/node_modules/.vite/deps/chunk-DBPNBGEI.js.map +0 -7
  181. package/playground/node_modules/.vite/deps/chunk-FPEUJ7DG.js +0 -27
  182. package/playground/node_modules/.vite/deps/chunk-FPEUJ7DG.js.map +0 -7
  183. package/playground/node_modules/.vite/deps/chunk-MHDZ3SK7.js +0 -1005
  184. package/playground/node_modules/.vite/deps/chunk-MHDZ3SK7.js.map +0 -7
  185. package/playground/node_modules/.vite/deps/chunk-RBDTDTPY.js +0 -204
  186. package/playground/node_modules/.vite/deps/chunk-RBDTDTPY.js.map +0 -7
  187. package/playground/node_modules/.vite/deps/chunk-RJGEXL5C.js +0 -688
  188. package/playground/node_modules/.vite/deps/chunk-RJGEXL5C.js.map +0 -7
  189. package/playground/node_modules/.vite/deps/chunk-YL4MIWGJ.js +0 -5099
  190. package/playground/node_modules/.vite/deps/chunk-YL4MIWGJ.js.map +0 -7
  191. package/playground/node_modules/.vite/deps/chunk-ZOV3DWEJ.js +0 -4376
  192. package/playground/node_modules/.vite/deps/chunk-ZOV3DWEJ.js.map +0 -7
  193. package/playground/node_modules/.vite/deps/chunk-ZP4UNCSN.js +0 -23
  194. package/playground/node_modules/.vite/deps/chunk-ZP4UNCSN.js.map +0 -7
  195. package/playground/node_modules/.vite/deps/chunk-ZREFNRZZ.js +0 -148
  196. package/playground/node_modules/.vite/deps/chunk-ZREFNRZZ.js.map +0 -7
  197. package/playground/node_modules/.vite/deps/package.json +0 -3
  198. package/playground/node_modules/.vite/deps/smol-toml.js +0 -843
  199. package/playground/node_modules/.vite/deps/smol-toml.js.map +0 -7
  200. package/playground/node_modules/.vite/deps/svelte.js +0 -55
  201. package/playground/node_modules/.vite/deps/svelte.js.map +0 -7
  202. package/playground/node_modules/.vite/deps/svelte___clsx.js +0 -9
  203. package/playground/node_modules/.vite/deps/svelte___clsx.js.map +0 -7
  204. package/playground/node_modules/.vite/deps/svelte_animate.js +0 -57
  205. package/playground/node_modules/.vite/deps/svelte_animate.js.map +0 -7
  206. package/playground/node_modules/.vite/deps/svelte_attachments.js +0 -15
  207. package/playground/node_modules/.vite/deps/svelte_attachments.js.map +0 -7
  208. package/playground/node_modules/.vite/deps/svelte_easing.js +0 -67
  209. package/playground/node_modules/.vite/deps/svelte_easing.js.map +0 -7
  210. package/playground/node_modules/.vite/deps/svelte_events.js +0 -11
  211. package/playground/node_modules/.vite/deps/svelte_events.js.map +0 -7
  212. package/playground/node_modules/.vite/deps/svelte_internal.js +0 -5
  213. package/playground/node_modules/.vite/deps/svelte_internal.js.map +0 -7
  214. package/playground/node_modules/.vite/deps/svelte_internal_client.js +0 -402
  215. package/playground/node_modules/.vite/deps/svelte_internal_client.js.map +0 -7
  216. package/playground/node_modules/.vite/deps/svelte_internal_disclose-version.js +0 -10
  217. package/playground/node_modules/.vite/deps/svelte_internal_disclose-version.js.map +0 -7
  218. package/playground/node_modules/.vite/deps/svelte_internal_flags_async.js +0 -8
  219. package/playground/node_modules/.vite/deps/svelte_internal_flags_async.js.map +0 -7
  220. package/playground/node_modules/.vite/deps/svelte_internal_flags_legacy.js +0 -8
  221. package/playground/node_modules/.vite/deps/svelte_internal_flags_legacy.js.map +0 -7
  222. package/playground/node_modules/.vite/deps/svelte_internal_flags_tracing.js +0 -8
  223. package/playground/node_modules/.vite/deps/svelte_internal_flags_tracing.js.map +0 -7
  224. package/playground/node_modules/.vite/deps/svelte_legacy.js +0 -35
  225. package/playground/node_modules/.vite/deps/svelte_legacy.js.map +0 -7
  226. package/playground/node_modules/.vite/deps/svelte_motion.js +0 -545
  227. package/playground/node_modules/.vite/deps/svelte_motion.js.map +0 -7
  228. package/playground/node_modules/.vite/deps/svelte_reactivity.js +0 -29
  229. package/playground/node_modules/.vite/deps/svelte_reactivity.js.map +0 -7
  230. package/playground/node_modules/.vite/deps/svelte_reactivity_window.js +0 -127
  231. package/playground/node_modules/.vite/deps/svelte_reactivity_window.js.map +0 -7
  232. package/playground/node_modules/.vite/deps/svelte_store.js +0 -103
  233. package/playground/node_modules/.vite/deps/svelte_store.js.map +0 -7
  234. package/playground/node_modules/.vite/deps/svelte_transition.js +0 -208
  235. package/playground/node_modules/.vite/deps/svelte_transition.js.map +0 -7
  236. package/playground/package.json +0 -16
  237. package/playground/pnpm-lock.yaml +0 -3167
  238. package/playground/src/content/authors/jane-doe.json +0 -8
  239. package/playground/src/content/config/build.toml +0 -2
  240. package/playground/src/content/courses/web-fundamentals.json +0 -29
  241. package/playground/src/content/docs/advanced.mdx +0 -6
  242. package/playground/src/content/docs/intro.md +0 -6
  243. package/playground/src/content/guides/getting-started.mdx +0 -6
  244. package/playground/src/content/posts/hello-world.md +0 -7
  245. package/playground/src/content/products/t-shirt.json +0 -16
  246. package/playground/src/content/recipes/pancakes.mdoc +0 -8
  247. package/playground/src/content/settings/site.yml +0 -2
  248. package/playground/src/content.config.ts +0 -198
  249. package/playground/src/env.d.ts +0 -1
  250. package/playground/src/pages/index.astro +0 -11
  251. package/playground/src/pages/nebula.astro +0 -14
  252. package/pnpm-workspace.yaml +0 -2
  253. package/scripts/subset-icons.mjs +0 -178
  254. package/src/astro/index.ts +0 -295
  255. package/src/client/js/drafts/merge.svelte.ts +0 -121
  256. package/src/client/js/drafts/ops.svelte.ts +0 -227
  257. package/src/client/js/drafts/storage.ts +0 -108
  258. package/src/client/js/drafts/workers/diff.ts +0 -40
  259. package/src/client/js/editor/editor.svelte.ts +0 -343
  260. package/src/client/js/editor/languages.ts +0 -98
  261. package/src/client/js/editor/markdown-shortcuts.ts +0 -261
  262. package/src/client/js/handlers/admin.ts +0 -246
  263. package/src/client/js/state/dialogs.svelte.ts +0 -35
  264. package/src/client/js/state/router.svelte.ts +0 -156
  265. package/src/client/js/state/state.svelte.ts +0 -334
  266. package/src/client/js/storage/adapter.ts +0 -102
  267. package/src/client/js/storage/client.ts +0 -150
  268. package/src/client/js/storage/db.ts +0 -36
  269. package/src/client/js/storage/fsa.ts +0 -110
  270. package/src/client/js/storage/github.ts +0 -297
  271. package/src/client/js/storage/storage.ts +0 -83
  272. package/src/client/js/storage/workers/frontmatter.ts +0 -320
  273. package/src/client/js/storage/workers/storage.ts +0 -177
  274. package/src/client/js/storage/workers/toml-parser.ts +0 -106
  275. package/src/client/js/storage/workers/yaml-parser.ts +0 -132
  276. package/src/client/js/utils/frontmatter.ts +0 -38
  277. package/src/client/js/utils/schema-utils.ts +0 -295
  278. package/src/client/js/utils/sort.ts +0 -84
  279. package/src/client/js/utils/stable-stringify.ts +0 -27
  280. package/src/types.ts +0 -25
  281. package/svelte.config.js +0 -4
  282. package/tests/astro/build.test.ts +0 -63
  283. package/tests/astro/index.test.ts +0 -689
  284. package/tests/client/components/Admin.test.ts +0 -446
  285. package/tests/client/components/BackendPicker.test.ts +0 -239
  286. package/tests/client/components/DraftChip.test.ts +0 -53
  287. package/tests/client/components/MetadataForm.test.ts +0 -164
  288. package/tests/client/components/dialogs/DeleteDraftDialog.test.ts +0 -91
  289. package/tests/client/components/dialogs/FilenameDialog.test.ts +0 -209
  290. package/tests/client/components/dialogs/dialog-stubs.ts +0 -19
  291. package/tests/client/components/editor/EditorPane.test.ts +0 -100
  292. package/tests/client/components/editor/EditorTabs.test.ts +0 -253
  293. package/tests/client/components/editor/EditorToolbar.test.ts +0 -252
  294. package/tests/client/components/editor/fixtures.ts +0 -31
  295. package/tests/client/components/fields/ArrayField.test.ts +0 -197
  296. package/tests/client/components/fields/BooleanField.test.ts +0 -206
  297. package/tests/client/components/fields/DateField.test.ts +0 -210
  298. package/tests/client/components/fields/EnumField.test.ts +0 -246
  299. package/tests/client/components/fields/NumberField.test.ts +0 -240
  300. package/tests/client/components/fields/ObjectField.test.ts +0 -157
  301. package/tests/client/components/fields/SchemaField.test.ts +0 -190
  302. package/tests/client/components/fields/StringField.test.ts +0 -223
  303. package/tests/client/components/sidebar/AdminSidebar.test.ts +0 -285
  304. package/tests/client/components/sidebar/AdminSidebarSort.test.ts +0 -135
  305. package/tests/client/components/sidebar/sort-mock.ts +0 -23
  306. package/tests/client/js/drafts/fixtures.ts +0 -22
  307. package/tests/client/js/drafts/merge.test.ts +0 -282
  308. package/tests/client/js/drafts/ops.test.ts +0 -658
  309. package/tests/client/js/drafts/storage.test.ts +0 -200
  310. package/tests/client/js/drafts/workers/diff.test.ts +0 -165
  311. package/tests/client/js/editor/editor.test.ts +0 -616
  312. package/tests/client/js/editor/link-wrap.test.ts +0 -225
  313. package/tests/client/js/editor/markdown-shortcuts.test.ts +0 -370
  314. package/tests/client/js/handlers/admin.test.ts +0 -467
  315. package/tests/client/js/state/router.test.ts +0 -619
  316. package/tests/client/js/state/schema.test.ts +0 -266
  317. package/tests/client/js/state/state.test.ts +0 -328
  318. package/tests/client/js/storage/adapter.test.ts +0 -115
  319. package/tests/client/js/storage/client.test.ts +0 -250
  320. package/tests/client/js/storage/db.test.ts +0 -59
  321. package/tests/client/js/storage/fsa.test.ts +0 -284
  322. package/tests/client/js/storage/github.test.ts +0 -349
  323. package/tests/client/js/storage/mock-port.ts +0 -95
  324. package/tests/client/js/storage/storage.test.ts +0 -77
  325. package/tests/client/js/storage/workers/frontmatter.test.ts +0 -479
  326. package/tests/client/js/storage/workers/storage.test.ts +0 -299
  327. package/tests/client/js/storage/workers/toml-parser.test.ts +0 -169
  328. package/tests/client/js/storage/workers/yaml-parser.test.ts +0 -168
  329. package/tests/client/js/utils/file-types.test.ts +0 -268
  330. package/tests/client/js/utils/frontmatter.test.ts +0 -87
  331. package/tests/client/js/utils/schema-utils.test.ts +0 -318
  332. package/tests/client/js/utils/slug.test.ts +0 -58
  333. package/tests/client/js/utils/sort.test.ts +0 -276
  334. package/tests/client/js/utils/stable-stringify.test.ts +0 -68
  335. package/tests/client/js/utils/url-utils.test.ts +0 -70
  336. package/tests/e2e/backend-connection.test.ts +0 -301
  337. package/tests/e2e/draft-lifecycle.test.ts +0 -388
  338. package/tests/e2e/editing.test.ts +0 -355
  339. package/tests/e2e/github-adapter.test.ts +0 -330
  340. package/tests/e2e/helpers/mock-adapter.ts +0 -166
  341. package/tests/e2e/helpers/test-app.ts +0 -155
  342. package/tests/e2e/navigation.test.ts +0 -358
  343. package/tests/e2e/publishing.test.ts +0 -345
  344. package/tests/e2e/unsaved-changes.test.ts +0 -317
  345. package/tests/setup.ts +0 -2
  346. package/tests/stubs/codemirror.ts +0 -197
  347. package/tsconfig.json +0 -19
  348. package/vitest.config.ts +0 -178
  349. /package/{src → dist}/client/Admin.svelte +0 -0
  350. /package/{src → dist}/client/components/BackendPicker.svelte +0 -0
  351. /package/{src → dist}/client/components/DraftChip.svelte +0 -0
  352. /package/{src → dist}/client/components/MetadataForm.svelte +0 -0
  353. /package/{src → dist}/client/components/ThemeToggle.svelte +0 -0
  354. /package/{src → dist}/client/components/dialogs/DeleteDraftDialog.svelte +0 -0
  355. /package/{src → dist}/client/components/dialogs/FilenameDialog.svelte +0 -0
  356. /package/{src → dist}/client/components/editor/EditorPane.svelte +0 -0
  357. /package/{src → dist}/client/components/editor/EditorTabs.svelte +0 -0
  358. /package/{src → dist}/client/components/editor/EditorToolbar.svelte +0 -0
  359. /package/{src → dist}/client/components/editor/FormatSelector.svelte +0 -0
  360. /package/{src → dist}/client/components/editor/Toolbar.svelte +0 -0
  361. /package/{src → dist}/client/components/fields/ArrayField.svelte +0 -0
  362. /package/{src → dist}/client/components/fields/ArrayItem.svelte +0 -0
  363. /package/{src → dist}/client/components/fields/BooleanField.svelte +0 -0
  364. /package/{src → dist}/client/components/fields/DateField.svelte +0 -0
  365. /package/{src → dist}/client/components/fields/EnumField.svelte +0 -0
  366. /package/{src → dist}/client/components/fields/FieldWrapper.svelte +0 -0
  367. /package/{src → dist}/client/components/fields/NumberField.svelte +0 -0
  368. /package/{src → dist}/client/components/fields/ObjectField.svelte +0 -0
  369. /package/{src → dist}/client/components/fields/SchemaField.svelte +0 -0
  370. /package/{src → dist}/client/components/fields/StringField.svelte +0 -0
  371. /package/{src → dist}/client/components/sidebar/AdminSidebar.svelte +0 -0
  372. /package/{src → dist}/client/components/sidebar/AdminSidebarSort.svelte +0 -0
  373. /package/{src → dist}/client/css/a11y.css +0 -0
  374. /package/{src → dist}/client/css/btn.css +0 -0
  375. /package/{src → dist}/client/css/dialog.css +0 -0
  376. /package/{src → dist}/client/css/field-input.css +0 -0
  377. /package/{src → dist}/client/css/reset.css +0 -0
  378. /package/{src → dist}/client/css/theme.css +0 -0
  379. /package/{src/client/index.ts → dist/client/index.js} +0 -0
  380. /package/{src → dist}/virtual.d.ts +0 -0
@@ -1,108 +0,0 @@
1
- /*
2
- * Draft persistence layer backed by IndexedDB.
3
- * CRUD operations for draft content entries, used by the editor and merge logic.
4
- */
5
-
6
- import { openDB } from '../storage/db';
7
-
8
- /**
9
- * A draft content entry persisted in IndexedDB.
10
- */
11
- export type Draft = {
12
- // UUID primary key
13
- id: string;
14
- // Collection this draft belongs to
15
- collection: string;
16
- // Filename (null if not yet named)
17
- filename: string | null;
18
- // true = brand new content, false = draft of existing live file
19
- isNew: boolean;
20
- // Parsed frontmatter data
21
- formData: Record<string, unknown>;
22
- // Markdown body content
23
- body: string;
24
- // Stable-stringified snapshot of original live {formData, body} at draft creation — null for new content
25
- snapshot: string | null;
26
- // ISO date string of when the draft was first created
27
- createdAt: string;
28
- };
29
-
30
- // Object store name for drafts
31
- const STORE = 'drafts';
32
-
33
- /**
34
- * Saves or updates a draft in IndexedDB.
35
- * @param {Draft} draft - The draft record to persist
36
- * @return {Promise<void>}
37
- */
38
- export async function saveDraft(draft: Draft): Promise<void> {
39
- const db = await openDB();
40
- return new Promise((resolve, reject) => {
41
- const tx = db.transaction(STORE, 'readwrite');
42
- tx.objectStore(STORE).put(draft);
43
- tx.oncomplete = () => resolve();
44
- tx.onerror = () => reject(tx.error);
45
- });
46
- }
47
-
48
- /**
49
- * Loads all drafts for a given collection.
50
- * @param {string} collection - The collection name to filter by
51
- * @return {Promise<Draft[]>} All drafts belonging to the collection
52
- */
53
- export async function loadDrafts(collection: string): Promise<Draft[]> {
54
- const db = await openDB();
55
- return new Promise((resolve, reject) => {
56
- const tx = db.transaction(STORE, 'readonly');
57
- const request = tx.objectStore(STORE).getAll();
58
- request.onsuccess = () => {
59
- const all = request.result as Draft[];
60
- resolve(all.filter((d) => d.collection === collection));
61
- };
62
- request.onerror = () => reject(request.error);
63
- });
64
- }
65
-
66
- /**
67
- * Loads a single draft by ID.
68
- * @param {string} id - The draft UUID
69
- * @return {Promise<Draft | null>} The draft, or null if not found
70
- */
71
- export async function loadDraft(id: string): Promise<Draft | null> {
72
- const db = await openDB();
73
- return new Promise((resolve, reject) => {
74
- const tx = db.transaction(STORE, 'readonly');
75
- const request = tx.objectStore(STORE).get(id);
76
- request.onsuccess = () => resolve(request.result ?? null);
77
- request.onerror = () => reject(request.error);
78
- });
79
- }
80
-
81
- /**
82
- * Deletes a draft from IndexedDB by ID.
83
- * @param {string} id - The draft UUID to delete
84
- * @return {Promise<void>}
85
- */
86
- export async function deleteDraft(id: string): Promise<void> {
87
- const db = await openDB();
88
- return new Promise((resolve, reject) => {
89
- const tx = db.transaction(STORE, 'readwrite');
90
- tx.objectStore(STORE).delete(id);
91
- tx.oncomplete = () => resolve();
92
- tx.onerror = () => reject(tx.error);
93
- });
94
- }
95
-
96
- /**
97
- * Finds a draft linked to a specific live file.
98
- * @param {string} collection - The collection name
99
- * @param {string} filename - The live file's filename
100
- * @return {Promise<Draft | null>} The matching draft, or null if none exists
101
- */
102
- export async function getDraftByFile(
103
- collection: string,
104
- filename: string,
105
- ): Promise<Draft | null> {
106
- const drafts = await loadDrafts(collection);
107
- return drafts.find((d) => !d.isNew && d.filename === filename) ?? null;
108
- }
@@ -1,40 +0,0 @@
1
- import { stableStringify } from '../../utils/stable-stringify';
2
-
3
- /**
4
- * Input entry for comparing a draft snapshot against live content.
5
- */
6
- type DiffEntry = {
7
- // Draft UUID
8
- draftId: string;
9
- // The draft's stored snapshot string (from stableStringify at draft creation)
10
- snapshot: string;
11
- // Current live frontmatter data
12
- liveFormData: Record<string, unknown>;
13
- // Current live body content
14
- liveBody: string;
15
- };
16
-
17
- /*
18
- * Listens for diff requests, compares each draft's snapshot against current
19
- * live content, and returns a map of draftId to isOutdated.
20
- */
21
- self.addEventListener('message', (event: MessageEvent) => {
22
- const { type, entries } = event.data as {
23
- type: string;
24
- entries: DiffEntry[];
25
- };
26
- if (type !== 'diff') return;
27
-
28
- const results: Record<string, boolean> = {};
29
-
30
- for (const entry of entries) {
31
- // Reconstruct the comparable string using the same format as snapshot creation
32
- const liveString = stableStringify({
33
- formData: entry.liveFormData,
34
- body: entry.liveBody,
35
- });
36
- results[entry.draftId] = liveString !== entry.snapshot;
37
- }
38
-
39
- self.postMessage({ type: 'diff-result', results });
40
- });
@@ -1,343 +0,0 @@
1
- /*
2
- * Reactive editor state for the file editing view.
3
- * Manages loading, saving, and dirty-checking of content files and drafts.
4
- */
5
-
6
- import { registerDirtyChecker } from '../state/router.svelte';
7
- import { splitFrontmatter } from '../utils/frontmatter';
8
- import { setByPath, type PathSegment } from '../utils/schema-utils';
9
- import { getDraftByFile } from '../drafts/storage';
10
- import { storageClient } from '../state/state.svelte';
11
- import {
12
- getFileCategory,
13
- stripExtension,
14
- getDefaultExtension,
15
- FILE_TYPES,
16
- } from '../utils/file-types';
17
-
18
- // Editor file state exposed via getEditorFile().
19
- export type EditorFile = {
20
- body: string;
21
- formData: Record<string, unknown>;
22
- dirty: boolean;
23
- saving: boolean;
24
- filename: string;
25
- bodyLoaded: boolean;
26
- draftId: string | null;
27
- isNewDraft: boolean;
28
- };
29
-
30
- // Shape for bulk-setting all editor state via applyEditorState.
31
- export type EditorStateConfig = {
32
- body: string;
33
- formData: Record<string, unknown>;
34
- filename: string;
35
- bodyLoaded: boolean;
36
- draftId: string | null;
37
- isNewDraft: boolean;
38
- snapshot: string | null;
39
- collection: string;
40
- draftCreatedAt: string | null;
41
- };
42
-
43
- let body = $state('');
44
- let formData = $state<Record<string, unknown>>({});
45
- let dirty = $state(false);
46
- let saving = $state(false);
47
- let lastSavedBody = '';
48
- let lastSavedFormData = '{}';
49
- let filename = $state('');
50
- let fileOpen = $state(false);
51
- let activeTab = $state('metadata');
52
- let bodyLoaded = $state(false);
53
- let originalFilename = $state(''); // filename at load time — publish uses this to detect renames
54
- // Draft-specific state
55
- let draftId = $state<string | null>(null);
56
- let isNewDraft = $state(false);
57
- let snapshot = $state<string | null>(null);
58
- let currentCollection = $state('');
59
- let draftCreatedAt = $state<string | null>(null);
60
- registerDirtyChecker(() => dirty);
61
-
62
- export const editor = {
63
- // Current structured form data for the open file.
64
- get data(): Record<string, unknown> {
65
- return formData;
66
- },
67
- // Currently active editor tab identifier.
68
- get tab(): string {
69
- return activeTab;
70
- },
71
- // Filename at load time — publish uses this to detect renames.
72
- get originalFilename(): string {
73
- return originalFilename;
74
- },
75
- };
76
-
77
- /**
78
- * Applies a full set of editor state values, resetting dirty/saving flags and updating save baselines.
79
- * @param {EditorStateConfig} c - All editor state fields to apply
80
- * @param {boolean} open - Whether to mark the file as open
81
- * @return {void}
82
- */
83
- export function applyEditorState(c: EditorStateConfig, open: boolean): void {
84
- formData = c.formData;
85
- lastSavedFormData = JSON.stringify(c.formData);
86
- body = c.body;
87
- lastSavedBody = c.body;
88
- dirty = false;
89
- formDataDirty = false;
90
- saving = false;
91
- filename = c.filename;
92
- originalFilename = c.filename;
93
- bodyLoaded = c.bodyLoaded;
94
- activeTab = 'metadata';
95
- fileOpen = open;
96
- draftId = c.draftId;
97
- isNewDraft = c.isNewDraft;
98
- snapshot = c.snapshot;
99
- currentCollection = c.collection;
100
- draftCreatedAt = c.draftCreatedAt;
101
- }
102
-
103
- /*
104
- * Tracks whether formData has diverged from its saved snapshot.
105
- * Updated only by updateFormField to avoid re-serializing on every body keystroke.
106
- */
107
- let formDataDirty = false;
108
- /**
109
- * Recomputes dirty state from body comparison and the cached formData flag.
110
- * @return {void}
111
- */
112
- function recomputeDirty(): void {
113
- dirty = body !== lastSavedBody || formDataDirty;
114
- }
115
-
116
- /**
117
- * Returns a snapshot of draft-related internal state for use by editor-draft-ops. Exposes private module state without leaking $state reactivity.
118
- * @return {object} Snapshot of all draft-related editor state
119
- */
120
- export function _getDraftState() {
121
- return {
122
- saving,
123
- draftId,
124
- isNewDraft,
125
- snapshot,
126
- currentCollection,
127
- draftCreatedAt,
128
- lastSavedFormData,
129
- lastSavedBody,
130
- formData,
131
- body,
132
- filename,
133
- originalFilename,
134
- dirty,
135
- };
136
- }
137
-
138
- /**
139
- * Applies draft-related state mutations from editor-draft-ops back into the reactive module state.
140
- * @param {Partial<ReturnType<typeof _getDraftState>>} updates - Fields to update
141
- * @return {void}
142
- */
143
- export function _setDraftState(
144
- updates: Partial<ReturnType<typeof _getDraftState>>,
145
- ): void {
146
- if ('saving' in updates) saving = updates.saving!;
147
- if ('draftId' in updates) draftId = updates.draftId!;
148
- if ('isNewDraft' in updates) isNewDraft = updates.isNewDraft!;
149
- if ('snapshot' in updates) snapshot = updates.snapshot!;
150
- if ('draftCreatedAt' in updates) draftCreatedAt = updates.draftCreatedAt!;
151
- if ('lastSavedFormData' in updates)
152
- lastSavedFormData = updates.lastSavedFormData!;
153
- if ('lastSavedBody' in updates) lastSavedBody = updates.lastSavedBody!;
154
- if ('dirty' in updates) dirty = updates.dirty!;
155
- if ('originalFilename' in updates)
156
- originalFilename = updates.originalFilename!;
157
- }
158
- /**
159
- * Returns the current editor file state, or null if no file is open.
160
- * @return {EditorFile | null} The current editor file state, or null
161
- */
162
- export function getEditorFile(): EditorFile | null {
163
- if (!fileOpen) return null;
164
- return {
165
- body,
166
- formData,
167
- dirty,
168
- saving,
169
- filename,
170
- bodyLoaded,
171
- draftId,
172
- isNewDraft,
173
- };
174
- }
175
- /**
176
- * Sets the active editor tab.
177
- * @param {string} tab - The tab identifier to activate
178
- * @return {void}
179
- */
180
- export function setActiveTab(tab: string): void {
181
- activeTab = tab;
182
- }
183
- /**
184
- * Updates a single field within formData by path and recomputes dirty state.
185
- * @param {PathSegment[]} path - Ordered path segments addressing the field
186
- * @param {unknown} value - The new value to assign at the given path
187
- * @return {void}
188
- */
189
- export function updateFormField(path: PathSegment[], value: unknown): void {
190
- setByPath(formData, path, value);
191
- formDataDirty = JSON.stringify(formData) !== lastSavedFormData;
192
- recomputeDirty();
193
- }
194
-
195
- /**
196
- * Populates the editor with metadata so the UI renders without waiting for the async file read. Checks IndexedDB for an existing draft first — if found, loads draft data instead.
197
- * @param {string} collection - The collection this file belongs to
198
- * @param {string} itemFilename - The content file's name
199
- * @param {Record<string, unknown>} data - Pre-parsed frontmatter data
200
- * @return {Promise<void>}
201
- */
202
- export async function preloadFile(
203
- collection: string,
204
- itemFilename: string,
205
- data: Record<string, unknown>,
206
- ): Promise<void> {
207
- // Compare slugs so a format change (e.g. .md → .mdx) doesn't trigger a full reload
208
- if (stripExtension(filename) === stripExtension(itemFilename) && fileOpen)
209
- return;
210
-
211
- // Check IndexedDB for an existing draft of this live file
212
- const d = await getDraftByFile(collection, itemFilename);
213
- if (d) {
214
- // Draft already contains body content, no disk read needed
215
- applyEditorState(
216
- {
217
- body: d.body,
218
- formData: d.formData,
219
- filename: itemFilename,
220
- bodyLoaded: true,
221
- draftId: d.id,
222
- isNewDraft: d.isNew,
223
- snapshot: d.snapshot,
224
- collection,
225
- draftCreatedAt: d.createdAt,
226
- },
227
- true,
228
- );
229
- return;
230
- }
231
- // No draft — load live data; $state.snapshot strips Svelte reactive proxies
232
- applyEditorState(
233
- {
234
- body: '',
235
- formData: $state.snapshot(data) as Record<string, unknown>,
236
- filename: itemFilename,
237
- bodyLoaded: false,
238
- draftId: null,
239
- isNewDraft: false,
240
- snapshot: null,
241
- collection,
242
- draftCreatedAt: null,
243
- },
244
- true,
245
- );
246
- }
247
-
248
- /**
249
- * Sets the filename for the current editor file. Used by the filename dialog.
250
- * @param {string} newFilename - The new filename to set
251
- * @return {void}
252
- */
253
- export function setFilename(newFilename: string): void {
254
- filename = newFilename;
255
- }
256
-
257
- /**
258
- * Changes the file format by swapping the filename extension to the new type's default. Preserves the slug (base filename without extension) and leaves originalFilename untouched so publishFile can detect the rename and delete the old file on disk.
259
- * @param {string} newType - The type identifier to switch to (e.g. 'md', 'json')
260
- * @return {void}
261
- */
262
- export function changeFileFormat(newType: string): void {
263
- const ext = getDefaultExtension(newType);
264
- if (!ext) return;
265
- const slug = filename ? stripExtension(filename) : '';
266
- filename = slug ? slug + ext : '';
267
- // Switch to metadata tab if the new format has no body editor
268
- const config = FILE_TYPES[newType];
269
- if (config && !config.hasBody && activeTab === 'body') activeTab = 'metadata';
270
- }
271
-
272
- /**
273
- * Sets a default file format for a new draft based on the collection's supported file types. Only applies when the editor has no filename yet (new draft). Sets the activeTab to 'body' if the format supports body editing.
274
- * @param {string[]} fileTypes - Type identifiers from the schema's files array
275
- * @return {void}
276
- */
277
- export function setDefaultFormat(fileTypes: string[]): void {
278
- if (filename || fileTypes.length === 0) return;
279
- const defaultType = fileTypes[0];
280
- const ext = getDefaultExtension(defaultType);
281
- if (!ext) return;
282
- // Set just the extension so EditorTabs and FormatSelector derive the correct type
283
- filename = ext;
284
- // Activate body tab for content types that support it
285
- if (FILE_TYPES[defaultType]?.hasBody) activeTab = 'body';
286
- }
287
-
288
- /**
289
- * Loads body content via StorageClient for an already-preloaded file, completing the two-phase load.
290
- * @param {string} collection - The collection the file belongs to
291
- * @param {string} filename - The filename to read within the collection
292
- * @return {Promise<void>}
293
- */
294
- export async function loadFileBody(
295
- collection: string,
296
- filename: string,
297
- ): Promise<void> {
298
- const category = getFileCategory(filename);
299
- if (category === 'data') {
300
- // Data files have no body — all content was parsed as formData during preload
301
- bodyLoaded = true;
302
- return;
303
- }
304
- if (!storageClient) return;
305
- const text = await storageClient.readFile(collection, filename);
306
- const split = splitFrontmatter(text);
307
- // Strip leading/trailing newlines from body; added back on save when reconstituting the file
308
- body = lastSavedBody = split.body.replace(/^\n+/, '').replace(/\n+$/, '');
309
- bodyLoaded = true;
310
- }
311
-
312
- /**
313
- * Updates the editor body content and recomputes dirty state.
314
- * Only compares body against its saved snapshot — avoids serializing
315
- * formData to JSON on every keystroke from CodeMirror's update listener.
316
- * @param {string} content - The new body content
317
- * @return {void}
318
- */
319
- export function updateBody(content: string): void {
320
- body = content;
321
- recomputeDirty();
322
- }
323
-
324
- /**
325
- * Resets all editor state including draft-specific fields.
326
- * @return {void}
327
- */
328
- export function clearEditor(): void {
329
- applyEditorState(
330
- {
331
- body: '',
332
- formData: {},
333
- filename: '',
334
- bodyLoaded: false,
335
- draftId: null,
336
- isNewDraft: false,
337
- snapshot: null,
338
- collection: '',
339
- draftCreatedAt: null,
340
- },
341
- false,
342
- );
343
- }
@@ -1,98 +0,0 @@
1
- /*
2
- * Language extension registry for the CodeMirror editor.
3
- * Provides lazy-loaded language extensions keyed by file type identifier.
4
- * Today all body formats use the same markdown parser — the registry
5
- * exists so MDX/Markdoc-specific parsers can drop in later without
6
- * changing EditorPane.
7
- */
8
-
9
- import { markdown, markdownLanguage } from '@codemirror/lang-markdown';
10
- import { languages } from '@codemirror/language-data';
11
- import { syntaxHighlighting, HighlightStyle } from '@codemirror/language';
12
- import { tags as t } from '@lezer/highlight';
13
- import type { Extension } from '@codemirror/state';
14
-
15
- // Highlight style for the editor — headings are sized, syntax markers are dimmed.
16
- const editorHighlight = HighlightStyle.define([
17
- // Headings — larger, bold
18
- {
19
- tag: t.heading1,
20
- fontSize: '1.5rem',
21
- fontWeight: 'bold',
22
- color: 'var(--cms-fg)',
23
- },
24
- {
25
- tag: t.heading2,
26
- fontSize: '1.25rem',
27
- fontWeight: 'bold',
28
- color: 'var(--cms-fg)',
29
- },
30
- {
31
- tag: t.heading3,
32
- fontSize: '1rem',
33
- fontWeight: 'bold',
34
- color: 'var(--cms-fg)',
35
- },
36
- // Emphasis
37
- { tag: t.strong, fontWeight: 'bold', color: 'var(--cms-fg)' },
38
- { tag: t.emphasis, fontStyle: 'italic', color: 'var(--cms-fg)' },
39
- // Inline code
40
- { tag: t.monospace, color: 'var(--light-orange)' },
41
- // Links
42
- { tag: t.link, color: 'var(--light-teal)', textDecoration: 'underline' },
43
- { tag: t.url, color: 'var(--light-green)' },
44
- // Syntax markers — dimmed
45
- { tag: t.processingInstruction, color: 'var(--cms-muted)' },
46
- { tag: t.labelName, color: 'var(--light-teal)' },
47
- // Code block language tag
48
- { tag: t.tagName, color: 'var(--light-purple)' },
49
- // Lists
50
- { tag: t.list, color: 'var(--light-teal)' },
51
- // Blockquotes
52
- { tag: t.quote, color: 'var(--cms-muted)', fontStyle: 'italic' },
53
- // Code block contents — language-specific highlighting
54
- { tag: t.keyword, color: 'var(--light-plum)' },
55
- { tag: t.string, color: 'var(--light-orange)' },
56
- { tag: t.variableName, color: 'var(--light-teal)' },
57
- { tag: t.function(t.variableName), color: 'var(--gold)' },
58
- { tag: t.typeName, color: 'var(--light-green)' },
59
- { tag: t.number, color: 'var(--light-purple)' },
60
- { tag: t.bool, color: 'var(--light-purple)' },
61
- { tag: t.comment, color: 'var(--cms-muted)', fontStyle: 'italic' },
62
- { tag: t.operator, color: 'var(--light-red)' },
63
- { tag: t.punctuation, color: 'var(--cms-muted)' },
64
- { tag: t.meta, color: 'var(--cms-muted)' },
65
- ]);
66
-
67
- /*
68
- * Cached extensions per file type — avoids re-creating parser instances and
69
- * lets CodeMirror short-circuit its extension diff via reference equality.
70
- */
71
- const cache = new Map<string, Extension>();
72
-
73
- /**
74
- * Returns the composed language extension (parser + syntax highlighting)
75
- * for a given file type. Results are cached per type so repeated calls
76
- * return the same reference. Today all body formats use the same markdown
77
- * extension — individual entries can diverge when custom parsers are added.
78
- * @param {string} fileType - Type identifier from the file type registry (e.g. 'md', 'mdx', 'markdoc')
79
- * @return {Extension} The composed CodeMirror language extension
80
- */
81
- export function getLanguageExtension(fileType: string): Extension {
82
- let ext = cache.get(fileType);
83
- if (ext) return ext;
84
-
85
- /*
86
- * All body formats currently use the same markdown parser.
87
- * When MDX/Markdoc-specific parsers are built, add branches here.
88
- */
89
- ext = [
90
- markdown({
91
- base: markdownLanguage,
92
- codeLanguages: languages,
93
- }),
94
- syntaxHighlighting(editorHighlight),
95
- ];
96
- cache.set(fileType, ext);
97
- return ext;
98
- }