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,95 +0,0 @@
1
- /* Shared mock MessagePort factory for storage layer tests.
2
- *
3
- * Both the StorageClient tests (client-side) and the storage worker tests
4
- * (worker-side) need a fake MessagePort backed by EventTarget. This module
5
- * provides a base factory and two role-specific wrappers:
6
- *
7
- * - makeClientMockPort(): simulates a port from the client's perspective,
8
- * exposing a `respond` helper that fires incoming worker responses.
9
- * - makeWorkerMockPort(): simulates a port from the worker's perspective,
10
- * exposing a `send` helper that fires incoming client requests.
11
- */
12
-
13
- import { vi, type MockInstance } from 'vitest';
14
- import type {
15
- StorageRequest,
16
- StorageResponse,
17
- } from '../../../../src/client/js/storage/adapter';
18
-
19
- // The base port shape shared by both client and worker mocks.
20
- interface BaseMockPort {
21
- port: MessagePort;
22
- postSpy: ReturnType<typeof vi.fn>;
23
- }
24
-
25
- // Client-side mock adds a `respond` helper and includes `dispatchEvent`.
26
- export interface ClientMockPort extends BaseMockPort {
27
- respond: (data: StorageResponse & { _id?: string }) => void;
28
- }
29
-
30
- // Worker-side mock adds a `send` helper and omits `dispatchEvent`.
31
- export interface WorkerMockPort extends BaseMockPort {
32
- postSpy: MockInstance;
33
- send: (req: StorageRequest & { _id?: string }) => void;
34
- }
35
-
36
- /**
37
- * Creates a mock MessagePort for client-side tests. The port includes
38
- * dispatchEvent so StorageClient can fire events internally, and exposes
39
- * a `respond` helper to simulate incoming worker responses.
40
- * @return {ClientMockPort} The mock port, postMessage spy, and respond helper
41
- */
42
- export function makeClientMockPort(): ClientMockPort {
43
- const target = new EventTarget();
44
- const postSpy = vi.fn();
45
-
46
- const port = {
47
- addEventListener: target.addEventListener.bind(target),
48
- removeEventListener: target.removeEventListener.bind(target),
49
- dispatchEvent: target.dispatchEvent.bind(target),
50
- postMessage: postSpy,
51
- start: vi.fn(),
52
- } as unknown as MessagePort;
53
-
54
- /**
55
- * Fires a message event on the port, simulating a response from the worker.
56
- * @param {StorageResponse & { _id?: string }} data - The response payload
57
- * @return {void}
58
- */
59
- function respond(data: StorageResponse & { _id?: string }): void {
60
- const event = new MessageEvent('message', { data });
61
- target.dispatchEvent(event);
62
- }
63
-
64
- return { port, postSpy, respond };
65
- }
66
-
67
- /**
68
- * Creates a mock MessagePort for worker-side tests. The port captures
69
- * outgoing messages via postSpy and exposes a `send` helper to simulate
70
- * incoming client requests.
71
- * @return {WorkerMockPort} The mock port, postMessage spy, and send helper
72
- */
73
- export function makeWorkerMockPort(): WorkerMockPort {
74
- const target = new EventTarget();
75
- const postSpy = vi.fn();
76
-
77
- const port = {
78
- addEventListener: target.addEventListener.bind(target),
79
- removeEventListener: target.removeEventListener.bind(target),
80
- postMessage: postSpy,
81
- start: vi.fn(),
82
- } as unknown as MessagePort;
83
-
84
- /**
85
- * Fires a message event to simulate a client request arriving on the port.
86
- * @param {StorageRequest & { _id?: string }} req - The request payload
87
- * @return {void}
88
- */
89
- function send(req: StorageRequest & { _id?: string }): void {
90
- const event = new MessageEvent('message', { data: req });
91
- target.dispatchEvent(event);
92
- }
93
-
94
- return { port, postSpy, send };
95
- }
@@ -1,77 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
-
3
- //////////////////////////////
4
- // IDB backend persistence tests
5
- //
6
- // Uses fake-indexeddb (polyfilled via the setup file) to exercise the
7
- // actual IDB read/write logic without a browser. The FileSystemDirectoryHandle
8
- // type is unavailable in Node.js, so FSA tests use a plain object cast —
9
- // fake-indexeddb stores arbitrary values without type enforcement.
10
- //////////////////////////////
11
-
12
- import {
13
- saveBackend,
14
- loadBackend,
15
- clearBackend,
16
- } from '../../../../src/client/js/storage/storage';
17
-
18
- // ── Tests ─────────────────────────────────────────────────────────────────────
19
-
20
- describe('saveBackend / loadBackend', () => {
21
- it('persists a github backend config and retrieves it', async () => {
22
- const config = {
23
- type: 'github' as const,
24
- token: 'tok',
25
- repo: 'owner/repo',
26
- };
27
- await saveBackend(config);
28
- const result = await loadBackend();
29
- expect(result).toEqual(config);
30
- });
31
-
32
- it('persists an fsa backend config and retrieves it', async () => {
33
- // Use a plain object cast — fake-indexeddb doesn't enforce the actual type
34
- const fakeHandle = { kind: 'directory', name: 'root' };
35
- const config = {
36
- type: 'fsa' as const,
37
- handle: fakeHandle as unknown as FileSystemDirectoryHandle,
38
- };
39
- await saveBackend(config);
40
- const result = await loadBackend();
41
- expect(result?.type).toBe('fsa');
42
- });
43
-
44
- it('overwrites a previous config when called again', async () => {
45
- const first = { type: 'github' as const, token: 'first', repo: 'o/r' };
46
- const second = { type: 'github' as const, token: 'second', repo: 'o/r' };
47
- await saveBackend(first);
48
- await saveBackend(second);
49
- const result = await loadBackend();
50
- expect((result as typeof second).token).toBe('second');
51
- });
52
- });
53
-
54
- describe('loadBackend', () => {
55
- it('returns null when no backend has been saved', async () => {
56
- // Clear any state from previous tests
57
- await clearBackend();
58
- const result = await loadBackend();
59
- expect(result).toBeNull();
60
- });
61
- });
62
-
63
- describe('clearBackend', () => {
64
- it('removes the stored config so loadBackend returns null', async () => {
65
- const config = { type: 'github' as const, token: 'tok', repo: 'o/r' };
66
- await saveBackend(config);
67
- await clearBackend();
68
- const result = await loadBackend();
69
- expect(result).toBeNull();
70
- });
71
-
72
- it('is safe to call when no config is stored', async () => {
73
- await clearBackend();
74
- // Calling again should not throw
75
- await expect(clearBackend()).resolves.toBeUndefined();
76
- });
77
- });
@@ -1,479 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
-
3
- //////////////////////////////
4
- // Orchestrator worker tests
5
- //
6
- // The orchestrator worker registers a self.addEventListener('message', ...)
7
- // listener that handles 'port' and 'parse' message types. It categorises files
8
- // by extension — frontmatter files have their YAML block extracted and sent to
9
- // the YAML parser worker; JSON files are parsed inline; YAML/TOML data files
10
- // are routed to their respective parser workers.
11
- //
12
- // We mock Worker globally to intercept parser worker instantiation and
13
- // simulate parse-batch-result responses. StorageClient is mocked via vi.mock.
14
- //
15
- // IMPORTANT: The orchestrator lazily spawns parser workers and caches them at
16
- // module level. This means once a YAML worker is spawned in one test, all
17
- // subsequent tests reuse it. The spawnedWorkers array is therefore cumulative
18
- // across the entire suite — we do NOT clear it between tests.
19
- //////////////////////////////
20
-
21
- // ── Mock StorageClient ──────────────────────────────────────────────────────
22
-
23
- const mockListFiles = vi.fn();
24
-
25
- vi.mock('../../../../../src/client/js/storage/client', () => ({
26
- // Must use function keyword — arrow functions cannot be used with `new`
27
- StorageClient: function () {
28
- return { listFiles: mockListFiles };
29
- },
30
- }));
31
-
32
- // ── Mock Worker class ────────────────────────────────────────────────────────
33
-
34
- /**
35
- * Tracks all spawned mock workers by URL for assertions.
36
- * NOT cleared between tests — the orchestrator caches workers at module level.
37
- */
38
- const spawnedWorkers: MockWorkerInstance[] = [];
39
-
40
- /**
41
- * A minimal mock of Worker that captures postMessage calls and allows
42
- * simulating onmessage responses from parser workers.
43
- */
44
- class MockWorkerInstance {
45
- url: string;
46
- onmessage: ((event: MessageEvent) => void) | null = null;
47
- messages: Array<Record<string, unknown>> = [];
48
-
49
- /**
50
- * @param {string | URL} url - The URL passed to the Worker constructor
51
- */
52
- constructor(url: string | URL) {
53
- this.url = String(url);
54
- spawnedWorkers.push(this);
55
- }
56
-
57
- /**
58
- * Captures posted messages and auto-responds with parse-batch-result
59
- * by extracting a title from YAML/TOML-like "title: <value>" lines.
60
- * @param {Record<string, unknown>} msg - The message sent to the worker
61
- * @return {void}
62
- */
63
- postMessage(msg: Record<string, unknown>): void {
64
- this.messages.push(msg);
65
-
66
- // Auto-respond to parse-batch with mock results
67
- if (msg.type === 'parse-batch' && this.onmessage) {
68
- const items = msg.items as Array<{ key: string; content: string }>;
69
- const results: Record<string, Record<string, unknown>> = {};
70
- for (const item of items) {
71
- // Simulate parsing by creating a data object with the title extracted
72
- // from a "title: <value>" line in the YAML/TOML content
73
- const titleMatch = item.content.match(/title:\s*(.+)/);
74
- results[item.key] = titleMatch ? { title: titleMatch[1].trim() } : {};
75
- }
76
- // Respond asynchronously to match real worker behavior
77
- const id = msg.id as string;
78
- const handler = this.onmessage;
79
- queueMicrotask(() => {
80
- handler({
81
- data: { type: 'parse-batch-result', id, ok: true, results },
82
- } as MessageEvent);
83
- });
84
- }
85
- }
86
- }
87
-
88
- vi.stubGlobal('Worker', MockWorkerInstance);
89
-
90
- // ── Self mock ──────────────────────────────────────────────────────────────
91
-
92
- // The handler type uses a loose event shape: real MessageEvent validates
93
- // that ports[] entries are actual MessagePort instances, which we cannot
94
- // construct in Node.js. We type the captured handler loosely and call it
95
- // with plain objects that mirror the fields the worker actually reads.
96
- let messageHandler:
97
- | ((event: {
98
- data: Record<string, unknown>;
99
- ports: unknown[];
100
- }) => Promise<void>)
101
- | null = null;
102
- const selfPostMessage = vi.fn();
103
-
104
- vi.stubGlobal('self', {
105
- addEventListener: vi.fn((type: string, handler: unknown) => {
106
- if (type === 'message') {
107
- messageHandler = handler as (event: {
108
- data: Record<string, unknown>;
109
- ports: unknown[];
110
- }) => Promise<void>;
111
- }
112
- }),
113
- postMessage: selfPostMessage,
114
- });
115
-
116
- // ── Import module (after stubs) ────────────────────────────────────────────
117
-
118
- await import('../../../../../src/client/js/storage/workers/frontmatter');
119
-
120
- // ── Helpers ────────────────────────────────────────────────────────────────
121
-
122
- /**
123
- * Dispatches a fake event to the captured handler by calling it directly
124
- * with a plain object. We bypass MessageEvent construction because the
125
- * constructor validates that ports[] entries are real MessagePort instances.
126
- * @param {Record<string, unknown>} data - The message data payload
127
- * @param {unknown[]} ports - Optional port-like objects to include
128
- * @return {Promise<void>}
129
- */
130
- async function dispatch(
131
- data: Record<string, unknown>,
132
- ports: unknown[] = [],
133
- ): Promise<void> {
134
- await messageHandler!({ data, ports });
135
- }
136
-
137
- /**
138
- * Creates a minimal port-like object that satisfies the worker's StorageClient constructor.
139
- * @return {unknown} A fake port object
140
- */
141
- function makeFakePort(): unknown {
142
- return {
143
- addEventListener: vi.fn(),
144
- start: vi.fn(),
145
- postMessage: vi.fn(),
146
- };
147
- }
148
-
149
- /**
150
- * Waits for microtask queue to flush so async parser worker responses resolve.
151
- * @return {Promise<void>}
152
- */
153
- async function flushMicrotasks(): Promise<void> {
154
- await new Promise<void>((resolve) => queueMicrotask(resolve));
155
- }
156
-
157
- /**
158
- * Finds the latest result message from selfPostMessage calls.
159
- * @return {Record<string, unknown> | undefined} The result payload, or undefined
160
- */
161
- function findResult(): Record<string, unknown> | undefined {
162
- const call = selfPostMessage.mock.calls.find((c) => c[0].type === 'result');
163
- return call?.[0];
164
- }
165
-
166
- /**
167
- * Finds the latest error message from selfPostMessage calls.
168
- * @return {Record<string, unknown> | undefined} The error payload, or undefined
169
- */
170
- function findError(): Record<string, unknown> | undefined {
171
- const call = selfPostMessage.mock.calls.find((c) => c[0].type === 'error');
172
- return call?.[0];
173
- }
174
-
175
- // ── Tests ─────────────────────────────────────────────────────────────────────
176
-
177
- describe('orchestrator worker', () => {
178
- beforeEach(() => {
179
- vi.clearAllMocks();
180
- });
181
-
182
- afterEach(() => {
183
- vi.clearAllMocks();
184
- });
185
-
186
- it('registers a message listener on self', () => {
187
- expect(messageHandler).toBeTypeOf('function');
188
- });
189
-
190
- describe('port message', () => {
191
- it('does not post a response for a port initialization message', async () => {
192
- await dispatch({ type: 'port' }, [makeFakePort()]);
193
- expect(selfPostMessage).not.toHaveBeenCalled();
194
- });
195
- });
196
-
197
- describe('parse message', () => {
198
- it('posts an error when storageClient is not initialized', async () => {
199
- // The storageClient is module-level state — it may or may not be set
200
- // depending on test execution order. We trigger a guaranteed error by
201
- // leaving mockListFiles returning undefined, which causes a runtime
202
- // error inside the worker's parse handler.
203
- await dispatch({ type: 'parse', collection: 'posts' });
204
- const err = findError();
205
- expect(err).toBeDefined();
206
- expect(typeof err!.message).toBe('string');
207
- });
208
-
209
- it('spawns a YAML worker and extracts YAML block for frontmatter files', async () => {
210
- await dispatch({ type: 'port' }, [makeFakePort()]);
211
-
212
- mockListFiles.mockResolvedValueOnce([
213
- {
214
- filename: 'post.md',
215
- content: '---\ntitle: Hello World\n---\nBody content here',
216
- },
217
- ]);
218
-
219
- await dispatch({ type: 'parse', collection: 'posts' });
220
- await flushMicrotasks();
221
-
222
- // A YAML worker should have been spawned
223
- const yamlWorker = spawnedWorkers.find((w) =>
224
- w.url.includes('yaml-parser'),
225
- );
226
- expect(yamlWorker).toBeDefined();
227
-
228
- // It should have received a parse-batch with the extracted YAML block
229
- const batchMsg = yamlWorker!.messages.find(
230
- (m) => m.type === 'parse-batch',
231
- );
232
- expect(batchMsg).toBeDefined();
233
-
234
- const items = batchMsg!.items as Array<{ key: string; content: string }>;
235
- // The YAML block should NOT include the --- delimiters or body
236
- expect(items[0].content).toBe('title: Hello World');
237
- expect(items[0].key).toBe('post.md');
238
- });
239
-
240
- it('sorts frontmatter files alphabetically by title', async () => {
241
- await dispatch({ type: 'port' }, [makeFakePort()]);
242
-
243
- mockListFiles.mockResolvedValueOnce([
244
- { filename: 'b-post.md', content: '---\ntitle: B Post\n---\nBody B' },
245
- { filename: 'a-post.md', content: '---\ntitle: A Post\n---\nBody A' },
246
- ]);
247
-
248
- await dispatch({ type: 'parse', collection: 'posts' });
249
- await flushMicrotasks();
250
-
251
- const result = findResult();
252
- expect(result).toBeDefined();
253
- expect(result!.collection).toBe('posts');
254
-
255
- const items = result!.items as Array<{
256
- filename: string;
257
- data: Record<string, unknown>;
258
- }>;
259
- expect(items[0].filename).toBe('a-post.md');
260
- expect(items[1].filename).toBe('b-post.md');
261
- expect(items[0].data.title).toBe('A Post');
262
- });
263
-
264
- it('parses JSON data files inline without spawning a worker', async () => {
265
- await dispatch({ type: 'port' }, [makeFakePort()]);
266
-
267
- const workerCountBefore = spawnedWorkers.length;
268
-
269
- mockListFiles.mockResolvedValueOnce([
270
- {
271
- filename: 'config.json',
272
- content: '{"title": "JSON Config", "count": 42}',
273
- },
274
- ]);
275
-
276
- await dispatch({
277
- type: 'parse',
278
- collection: 'data',
279
- extensions: ['.json'],
280
- });
281
- await flushMicrotasks();
282
-
283
- const result = findResult();
284
- expect(result).toBeDefined();
285
-
286
- const items = result!.items as Array<{
287
- filename: string;
288
- data: Record<string, unknown>;
289
- }>;
290
- expect(items[0].filename).toBe('config.json');
291
- expect(items[0].data.title).toBe('JSON Config');
292
- expect(items[0].data.count).toBe(42);
293
-
294
- // No NEW parser workers should have been spawned for JSON-only parsing
295
- expect(spawnedWorkers.length).toBe(workerCountBefore);
296
- });
297
-
298
- it('routes YAML data files to the YAML worker', async () => {
299
- await dispatch({ type: 'port' }, [makeFakePort()]);
300
-
301
- mockListFiles.mockResolvedValueOnce([
302
- { filename: 'settings.yaml', content: 'title: YAML Settings' },
303
- ]);
304
-
305
- await dispatch({
306
- type: 'parse',
307
- collection: 'data',
308
- extensions: ['.yaml'],
309
- });
310
- await flushMicrotasks();
311
-
312
- // The YAML worker should exist (spawned in earlier test or this one)
313
- const yamlWorker = spawnedWorkers.find((w) =>
314
- w.url.includes('yaml-parser'),
315
- );
316
- expect(yamlWorker).toBeDefined();
317
-
318
- // Find the batch message containing YAML data file content
319
- const batchMsg = yamlWorker!.messages.find((m) => {
320
- if (m.type !== 'parse-batch') return false;
321
- const batchItems = m.items as Array<{
322
- key: string;
323
- content: string;
324
- }>;
325
- return batchItems.some((i) => i.key === 'settings.yaml');
326
- });
327
- expect(batchMsg).toBeDefined();
328
-
329
- const batchItems = batchMsg!.items as Array<{
330
- key: string;
331
- content: string;
332
- }>;
333
- const settingsItem = batchItems.find((i) => i.key === 'settings.yaml');
334
- // YAML data files send full content, not extracted block
335
- expect(settingsItem!.content).toBe('title: YAML Settings');
336
-
337
- const result = findResult();
338
- expect(result).toBeDefined();
339
- const items = result!.items as Array<{
340
- filename: string;
341
- data: Record<string, unknown>;
342
- }>;
343
- expect(items[0].data.title).toBe('YAML Settings');
344
- });
345
-
346
- it('routes TOML data files to the TOML worker', async () => {
347
- await dispatch({ type: 'port' }, [makeFakePort()]);
348
-
349
- mockListFiles.mockResolvedValueOnce([
350
- { filename: 'config.toml', content: 'title = "TOML Config"' },
351
- ]);
352
-
353
- await dispatch({
354
- type: 'parse',
355
- collection: 'data',
356
- extensions: ['.toml'],
357
- });
358
- await flushMicrotasks();
359
-
360
- // A TOML worker should have been spawned
361
- const tomlWorker = spawnedWorkers.find((w) =>
362
- w.url.includes('toml-parser'),
363
- );
364
- expect(tomlWorker).toBeDefined();
365
-
366
- const batchMsg = tomlWorker!.messages.find(
367
- (m) => m.type === 'parse-batch',
368
- );
369
- expect(batchMsg).toBeDefined();
370
-
371
- const result = findResult();
372
- expect(result).toBeDefined();
373
- });
374
-
375
- it('falls back to filename for sorting when title is absent', async () => {
376
- await dispatch({ type: 'port' }, [makeFakePort()]);
377
-
378
- mockListFiles.mockResolvedValueOnce([
379
- { filename: 'z-file.md', content: 'No frontmatter' },
380
- { filename: 'a-file.md', content: 'No frontmatter' },
381
- ]);
382
-
383
- await dispatch({ type: 'parse', collection: 'posts' });
384
- await flushMicrotasks();
385
-
386
- const result = findResult();
387
- const items = result!.items as Array<{
388
- filename: string;
389
- data: Record<string, unknown>;
390
- }>;
391
- expect(items[0].filename).toBe('a-file.md');
392
- });
393
-
394
- it('posts an error when listFiles throws', async () => {
395
- await dispatch({ type: 'port' }, [makeFakePort()]);
396
-
397
- mockListFiles.mockRejectedValueOnce(new Error('storage failure'));
398
-
399
- await dispatch({ type: 'parse', collection: 'posts' });
400
- await flushMicrotasks();
401
-
402
- const err = findError();
403
- expect(err).toBeDefined();
404
- expect(err!.message).toBe('storage failure');
405
- });
406
-
407
- it('includes files with empty frontmatter (data defaults to {})', async () => {
408
- await dispatch({ type: 'port' }, [makeFakePort()]);
409
-
410
- mockListFiles.mockResolvedValueOnce([
411
- { filename: 'no-fm.md', content: 'No frontmatter here' },
412
- ]);
413
-
414
- await dispatch({ type: 'parse', collection: 'posts' });
415
- await flushMicrotasks();
416
-
417
- const result = findResult();
418
- const items = result!.items as Array<{
419
- filename: string;
420
- data: Record<string, unknown>;
421
- }>;
422
- expect(items[0].data).toEqual({});
423
- });
424
-
425
- it('sorts correctly across mixed file types', async () => {
426
- await dispatch({ type: 'port' }, [makeFakePort()]);
427
-
428
- mockListFiles.mockResolvedValueOnce([
429
- { filename: 'z-post.md', content: '---\ntitle: Zebra\n---\nbody' },
430
- {
431
- filename: 'config.json',
432
- content: '{"title": "Alpha Config"}',
433
- },
434
- { filename: 'middle.yaml', content: 'title: Middle Entry' },
435
- ]);
436
-
437
- await dispatch({
438
- type: 'parse',
439
- collection: 'mixed',
440
- extensions: ['.md', '.json', '.yaml'],
441
- });
442
- await flushMicrotasks();
443
-
444
- const result = findResult();
445
- expect(result).toBeDefined();
446
- const items = result!.items as Array<{
447
- filename: string;
448
- data: Record<string, unknown>;
449
- }>;
450
- // Alpha Config < Middle Entry < Zebra
451
- expect(items[0].data.title).toBe('Alpha Config');
452
- expect(items[1].data.title).toBe('Middle Entry');
453
- expect(items[2].data.title).toBe('Zebra');
454
- });
455
-
456
- it('handles invalid JSON gracefully with empty data', async () => {
457
- await dispatch({ type: 'port' }, [makeFakePort()]);
458
-
459
- mockListFiles.mockResolvedValueOnce([
460
- { filename: 'bad.json', content: '{ invalid json' },
461
- ]);
462
-
463
- await dispatch({
464
- type: 'parse',
465
- collection: 'data',
466
- extensions: ['.json'],
467
- });
468
- await flushMicrotasks();
469
-
470
- const result = findResult();
471
- expect(result).toBeDefined();
472
- const items = result!.items as Array<{
473
- filename: string;
474
- data: Record<string, unknown>;
475
- }>;
476
- expect(items[0].data).toEqual({});
477
- });
478
- });
479
- });