@janga/norna 0.7.17 → 0.7.22

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 (533) hide show
  1. package/README.md +32 -13
  2. package/astro.config.mjs +22 -0
  3. package/bin/norna-cli.mjs +7 -1
  4. package/package.json +46 -12
  5. package/schemas/category.schema.json +20 -0
  6. package/schemas/config.schema.json +55 -4
  7. package/schemas/content-frontmatter.schema.json +5 -5
  8. package/schemas/manifest.json +4 -2
  9. package/schemas/page-theme.schema.json +192 -0
  10. package/schemas/sitewide-content.schema.json +18 -18
  11. package/schemas/theme.schema.json +364 -226
  12. package/scripts/add-site-node.mjs +251 -0
  13. package/scripts/check-config.mjs +12 -3
  14. package/scripts/deploy-site.mjs +6 -9
  15. package/scripts/generate-images.mjs +18 -29
  16. package/scripts/generate-schemas.mjs +7 -1
  17. package/scripts/init-site.mjs +35 -0
  18. package/scripts/lib/astro-command.mjs +14 -9
  19. package/scripts/lib/editor-language-service.mjs +28 -191
  20. package/scripts/lib/heading-ids.mjs +3 -1
  21. package/scripts/lib/navigation-model.mjs +23 -17
  22. package/scripts/lib/norna-markdown-blocks.mjs +64 -145
  23. package/scripts/lib/norna-markdown-render-plugin.mjs +37 -0
  24. package/scripts/lib/object.mjs +28 -0
  25. package/scripts/lib/page-markdown.mjs +282 -0
  26. package/scripts/lib/page-model.mjs +26 -7
  27. package/scripts/lib/presentation-contract.mjs +266 -0
  28. package/scripts/lib/presentation-palette-metadata.mjs +51 -0
  29. package/scripts/lib/presentation.mjs +548 -93
  30. package/scripts/lib/project-config.mjs +73 -16
  31. package/scripts/lib/schema-definitions.mjs +89 -21
  32. package/scripts/lib/schema-editor-metadata.mjs +166 -33
  33. package/scripts/lib/schema-value-definitions.mjs +32 -4
  34. package/scripts/lib/site-content.mjs +33 -223
  35. package/scripts/lib/site-conventions.mjs +1 -0
  36. package/scripts/lib/site-paths.mjs +11 -6
  37. package/scripts/lib/site-structure.mjs +189 -0
  38. package/scripts/lib/theme-config.mjs +3 -2
  39. package/scripts/lib/theme-presets.mjs +105 -101
  40. package/scripts/lib/theme-profiles.mjs +221 -0
  41. package/scripts/lib/typography.mjs +220 -35
  42. package/scripts/lib/yaml-config.mjs +46 -6
  43. package/scripts/lib/yaml-indentation.mjs +86 -0
  44. package/scripts/show-typography.mjs +3 -36
  45. package/scripts/sync-content-sections.mjs +88 -79
  46. package/src/components/DisplaySettings.astro +107 -0
  47. package/src/components/ImageCarousel.astro +34 -13
  48. package/src/components/NavigationPageTree.astro +154 -34
  49. package/src/components/PageContentsLinks.astro +40 -0
  50. package/src/components/SectionNavigationScript.astro +68 -7
  51. package/src/components/SiteBreadcrumbs.astro +24 -18
  52. package/src/components/SiteNavigation.astro +130 -46
  53. package/src/components/SitePage.astro +65 -55
  54. package/src/components/SiteSection.astro +37 -198
  55. package/src/components/SiteTreeNavigation.astro +36 -0
  56. package/src/components/TreeNavigationScript.astro +83 -0
  57. package/src/content.config.ts +2 -8
  58. package/src/layouts/BaseLayout.astro +52 -2
  59. package/src/lib/generatedImages.ts +0 -7
  60. package/src/lib/pageThemes.ts +11 -9
  61. package/src/lib/readerPreferencesScript.mjs +141 -0
  62. package/src/lib/sectionContent.ts +120 -206
  63. package/src/lib/siteNavigation.ts +38 -19
  64. package/src/lib/sitePages.ts +115 -33
  65. package/src/pages/[...slug].astro +2 -2
  66. package/src/pages/index.astro +2 -1
  67. package/src/styles/global.css +1110 -279
  68. package/starters/basic/README.md +8 -8
  69. package/starters/basic/site/theme.yaml +1 -105
  70. package/docs/README.md +0 -135
  71. package/docs/assets/norna-dog-shelter.jpg +0 -0
  72. package/docs/commands.md +0 -189
  73. package/docs/configuration.md +0 -119
  74. package/docs/content.md +0 -342
  75. package/docs/design/command-organization.md +0 -414
  76. package/docs/design/navigation-and-theme-plan.md +0 -115
  77. package/docs/design/norna-diagram-design.md +0 -159
  78. package/docs/design/site-examples-structure.md +0 -115
  79. package/docs/engine-development.md +0 -218
  80. package/docs/getting-started.md +0 -206
  81. package/docs/how-to/embedded-site.md +0 -35
  82. package/docs/images-and-metadata.md +0 -186
  83. package/docs/local-development.md +0 -82
  84. package/docs/pages.md +0 -134
  85. package/docs/public-files.md +0 -118
  86. package/docs/publishing.md +0 -117
  87. package/docs/requirements.md +0 -54
  88. package/docs/site-files.md +0 -145
  89. package/docs/sitewide-content.md +0 -73
  90. package/docs/theme.md +0 -271
  91. package/docs/typography.md +0 -180
  92. package/examples/README.md +0 -43
  93. package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/site.schema.json +0 -35
  94. package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/sitewide.schema.json +0 -97
  95. package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/theme.schema.json +0 -852
  96. package/examples/complete-sites/dog-shelter-multi-page/.astro/content-assets.mjs +0 -4
  97. package/examples/complete-sites/dog-shelter-multi-page/.astro/content-modules.mjs +0 -1
  98. package/examples/complete-sites/dog-shelter-multi-page/.astro/content.d.ts +0 -183
  99. package/examples/complete-sites/dog-shelter-multi-page/.astro/data-store.json +0 -1
  100. package/examples/complete-sites/dog-shelter-multi-page/.astro/dev-local.json +0 -8
  101. package/examples/complete-sites/dog-shelter-multi-page/.astro/dev.json +0 -13
  102. package/examples/complete-sites/dog-shelter-multi-page/.astro/dev.log +0 -36
  103. package/examples/complete-sites/dog-shelter-multi-page/.astro/settings.json +0 -5
  104. package/examples/complete-sites/dog-shelter-multi-page/.astro/types.d.ts +0 -2
  105. package/examples/complete-sites/dog-shelter-multi-page/README.md +0 -24
  106. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/_metadata.json +0 -74
  107. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro-B3JHJyiv.js +0 -434
  108. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro-B3JHJyiv.js.map +0 -1
  109. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_n_aria-query.js +0 -6390
  110. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_n_aria-query.js.map +0 -1
  111. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_n_axobject-query.js +0 -2702
  112. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_n_axobject-query.js.map +0 -1
  113. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_n_html-escaper.js +0 -65
  114. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_n_html-escaper.js.map +0 -1
  115. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +0 -455
  116. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -1
  117. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/audit-C3SVr7dT.js +0 -1534
  118. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/audit-C3SVr7dT.js.map +0 -1
  119. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/highlight-BLtvqtzO.js +0 -48
  120. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/highlight-BLtvqtzO.js.map +0 -1
  121. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/icons-C92i61-2.js +0 -42
  122. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/icons-C92i61-2.js.map +0 -1
  123. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/package.json +0 -3
  124. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +0 -4
  125. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/settings-v5GgKks_.js +0 -190
  126. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/settings-v5GgKks_.js.map +0 -1
  127. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/toolbar-BFvJVp26.js +0 -458
  128. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/toolbar-BFvJVp26.js.map +0 -1
  129. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/ui-library-Cd35oAvo.js +0 -1016
  130. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/ui-library-Cd35oAvo.js.map +0 -1
  131. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/window-vo3A6TMn.js +0 -32
  132. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/window-vo3A6TMn.js.map +0 -1
  133. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/xray-DwhzGckb.js +0 -111
  134. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/xray-DwhzGckb.js.map +0 -1
  135. package/examples/complete-sites/dog-shelter-multi-page/site/.norna/generated-images.json +0 -98
  136. package/examples/complete-sites/dog-shelter-multi-page/site/config.yaml +0 -1
  137. package/examples/complete-sites/dog-shelter-multi-page/site/content.md +0 -23
  138. package/examples/complete-sites/dog-shelter-multi-page/site/images/shelter-dog.jpg +0 -0
  139. package/examples/complete-sites/dog-shelter-multi-page/site/pages/010-dogs/content.md +0 -21
  140. package/examples/complete-sites/dog-shelter-multi-page/site/pages/010-dogs/images/rex.jpg +0 -0
  141. package/examples/complete-sites/dog-shelter-multi-page/site/pages/010-dogs/images/rover.jpg +0 -0
  142. package/examples/complete-sites/dog-shelter-multi-page/site/pages/020-adopt/content.md +0 -22
  143. package/examples/complete-sites/dog-shelter-multi-page/site/pages/020-adopt/images/adoption-dog.jpg +0 -0
  144. package/examples/complete-sites/dog-shelter-multi-page/site/public/favicon.svg +0 -10
  145. package/examples/complete-sites/dog-shelter-multi-page/site/public/logo.svg +0 -9
  146. package/examples/complete-sites/dog-shelter-multi-page/site/public/robots.txt +0 -2
  147. package/examples/complete-sites/dog-shelter-multi-page/site/sitewide-content.yaml +0 -4
  148. package/examples/complete-sites/dog-shelter-multi-page/site/theme.yaml +0 -1
  149. package/examples/complete-sites/dog-shelter-single-page/.astro/collections/site.schema.json +0 -35
  150. package/examples/complete-sites/dog-shelter-single-page/.astro/collections/sitewide.schema.json +0 -97
  151. package/examples/complete-sites/dog-shelter-single-page/.astro/collections/theme.schema.json +0 -852
  152. package/examples/complete-sites/dog-shelter-single-page/.astro/content-assets.mjs +0 -4
  153. package/examples/complete-sites/dog-shelter-single-page/.astro/content-modules.mjs +0 -1
  154. package/examples/complete-sites/dog-shelter-single-page/.astro/content.d.ts +0 -183
  155. package/examples/complete-sites/dog-shelter-single-page/.astro/data-store.json +0 -1
  156. package/examples/complete-sites/dog-shelter-single-page/.astro/dev-local.json +0 -8
  157. package/examples/complete-sites/dog-shelter-single-page/.astro/dev.json +0 -13
  158. package/examples/complete-sites/dog-shelter-single-page/.astro/dev.log +0 -18
  159. package/examples/complete-sites/dog-shelter-single-page/.astro/settings.json +0 -5
  160. package/examples/complete-sites/dog-shelter-single-page/.astro/types.d.ts +0 -2
  161. package/examples/complete-sites/dog-shelter-single-page/README.md +0 -24
  162. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/_metadata.json +0 -74
  163. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro-B3JHJyiv.js +0 -434
  164. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro-B3JHJyiv.js.map +0 -1
  165. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_aria-query.js +0 -6390
  166. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_aria-query.js.map +0 -1
  167. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_axobject-query.js +0 -2702
  168. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_axobject-query.js.map +0 -1
  169. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_html-escaper.js +0 -65
  170. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_html-escaper.js.map +0 -1
  171. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +0 -455
  172. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -1
  173. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/audit-C3SVr7dT.js +0 -1534
  174. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/audit-C3SVr7dT.js.map +0 -1
  175. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/highlight-BLtvqtzO.js +0 -48
  176. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/highlight-BLtvqtzO.js.map +0 -1
  177. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/icons-C92i61-2.js +0 -42
  178. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/icons-C92i61-2.js.map +0 -1
  179. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/package.json +0 -3
  180. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +0 -4
  181. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/settings-v5GgKks_.js +0 -190
  182. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/settings-v5GgKks_.js.map +0 -1
  183. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/toolbar-BFvJVp26.js +0 -458
  184. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/toolbar-BFvJVp26.js.map +0 -1
  185. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/ui-library-Cd35oAvo.js +0 -1016
  186. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/ui-library-Cd35oAvo.js.map +0 -1
  187. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/window-vo3A6TMn.js +0 -32
  188. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/window-vo3A6TMn.js.map +0 -1
  189. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/xray-DwhzGckb.js +0 -111
  190. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/xray-DwhzGckb.js.map +0 -1
  191. package/examples/complete-sites/dog-shelter-single-page/site/.norna/generated-images.json +0 -50
  192. package/examples/complete-sites/dog-shelter-single-page/site/config.yaml +0 -1
  193. package/examples/complete-sites/dog-shelter-single-page/site/content.md +0 -37
  194. package/examples/complete-sites/dog-shelter-single-page/site/images/foster-dog.jpg +0 -0
  195. package/examples/complete-sites/dog-shelter-single-page/site/images/rescue-dog.jpg +0 -0
  196. package/examples/complete-sites/dog-shelter-single-page/site/public/favicon.svg +0 -10
  197. package/examples/complete-sites/dog-shelter-single-page/site/public/logo.svg +0 -9
  198. package/examples/complete-sites/dog-shelter-single-page/site/public/robots.txt +0 -2
  199. package/examples/complete-sites/dog-shelter-single-page/site/sitewide-content.yaml +0 -4
  200. package/examples/complete-sites/dog-shelter-single-page/site/theme.yaml +0 -1
  201. package/examples/feature-demos/media-and-surfaces/.astro/collections/site.schema.json +0 -35
  202. package/examples/feature-demos/media-and-surfaces/.astro/collections/sitewide.schema.json +0 -97
  203. package/examples/feature-demos/media-and-surfaces/.astro/collections/theme.schema.json +0 -852
  204. package/examples/feature-demos/media-and-surfaces/.astro/content-assets.mjs +0 -4
  205. package/examples/feature-demos/media-and-surfaces/.astro/content-modules.mjs +0 -1
  206. package/examples/feature-demos/media-and-surfaces/.astro/content.d.ts +0 -183
  207. package/examples/feature-demos/media-and-surfaces/.astro/data-store.json +0 -1
  208. package/examples/feature-demos/media-and-surfaces/.astro/dev.log +0 -14
  209. package/examples/feature-demos/media-and-surfaces/.astro/settings.json +0 -5
  210. package/examples/feature-demos/media-and-surfaces/.astro/types.d.ts +0 -2
  211. package/examples/feature-demos/media-and-surfaces/README.md +0 -21
  212. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/_metadata.json +0 -80
  213. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro-B3JHJyiv.js +0 -434
  214. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro-B3JHJyiv.js.map +0 -1
  215. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_aria-query.js +0 -6390
  216. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_aria-query.js.map +0 -1
  217. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_axobject-query.js +0 -2702
  218. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_axobject-query.js.map +0 -1
  219. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_html-escaper.js +0 -65
  220. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_html-escaper.js.map +0 -1
  221. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +0 -455
  222. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -1
  223. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/audit-C3SVr7dT.js +0 -1534
  224. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/audit-C3SVr7dT.js.map +0 -1
  225. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/embla-carousel.js +0 -1389
  226. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/embla-carousel.js.map +0 -1
  227. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/highlight-BLtvqtzO.js +0 -48
  228. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/highlight-BLtvqtzO.js.map +0 -1
  229. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/icons-C92i61-2.js +0 -42
  230. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/icons-C92i61-2.js.map +0 -1
  231. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/package.json +0 -3
  232. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +0 -4
  233. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/settings-v5GgKks_.js +0 -190
  234. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/settings-v5GgKks_.js.map +0 -1
  235. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/toolbar-BFvJVp26.js +0 -458
  236. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/toolbar-BFvJVp26.js.map +0 -1
  237. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/ui-library-Cd35oAvo.js +0 -1016
  238. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/ui-library-Cd35oAvo.js.map +0 -1
  239. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/window-vo3A6TMn.js +0 -32
  240. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/window-vo3A6TMn.js.map +0 -1
  241. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/xray-DwhzGckb.js +0 -111
  242. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/xray-DwhzGckb.js.map +0 -1
  243. package/examples/feature-demos/media-and-surfaces/site/.norna/generated-images.json +0 -66
  244. package/examples/feature-demos/media-and-surfaces/site/config.yaml +0 -1
  245. package/examples/feature-demos/media-and-surfaces/site/content.md +0 -15
  246. package/examples/feature-demos/media-and-surfaces/site/pages/010-media/content.md +0 -71
  247. package/examples/feature-demos/media-and-surfaces/site/pages/010-media/images/card-carousel.svg +0 -11
  248. package/examples/feature-demos/media-and-surfaces/site/pages/010-media/images/card-stack.svg +0 -9
  249. package/examples/feature-demos/media-and-surfaces/site/pages/010-media/images/card-surfaces.svg +0 -8
  250. package/examples/feature-demos/media-and-surfaces/site/pages/010-media/images/carousel-one.svg +0 -8
  251. package/examples/feature-demos/media-and-surfaces/site/pages/010-media/images/carousel-three.svg +0 -13
  252. package/examples/feature-demos/media-and-surfaces/site/pages/010-media/images/carousel-two.svg +0 -8
  253. package/examples/feature-demos/media-and-surfaces/site/pages/010-media/images/stack-one.svg +0 -8
  254. package/examples/feature-demos/media-and-surfaces/site/pages/010-media/images/stack-two.svg +0 -9
  255. package/examples/feature-demos/media-and-surfaces/site/pages/020-surfaces/content.md +0 -41
  256. package/examples/feature-demos/media-and-surfaces/site/pages/020-surfaces/theme.yaml +0 -3
  257. package/examples/feature-demos/media-and-surfaces/site/public/robots.txt +0 -2
  258. package/examples/feature-demos/media-and-surfaces/site/sitewide-content.yaml +0 -2
  259. package/examples/feature-demos/media-and-surfaces/site/theme.yaml +0 -1
  260. package/examples/feature-demos/sitewide-content/.astro/collections/site.schema.json +0 -59
  261. package/examples/feature-demos/sitewide-content/.astro/collections/sitewide.schema.json +0 -138
  262. package/examples/feature-demos/sitewide-content/.astro/collections/theme.schema.json +0 -755
  263. package/examples/feature-demos/sitewide-content/.astro/content-assets.mjs +0 -1
  264. package/examples/feature-demos/sitewide-content/.astro/content-modules.mjs +0 -1
  265. package/examples/feature-demos/sitewide-content/.astro/content.d.ts +0 -183
  266. package/examples/feature-demos/sitewide-content/.astro/data-store.json +0 -1
  267. package/examples/feature-demos/sitewide-content/.astro/dev.json +0 -13
  268. package/examples/feature-demos/sitewide-content/.astro/dev.log +0 -18
  269. package/examples/feature-demos/sitewide-content/.astro/settings.json +0 -5
  270. package/examples/feature-demos/sitewide-content/.astro/types.d.ts +0 -2
  271. package/examples/feature-demos/sitewide-content/README.md +0 -26
  272. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/_metadata.json +0 -74
  273. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro-B3JHJyiv.js +0 -434
  274. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro-B3JHJyiv.js.map +0 -1
  275. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_aria-query.js +0 -6390
  276. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_aria-query.js.map +0 -1
  277. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_axobject-query.js +0 -2702
  278. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_axobject-query.js.map +0 -1
  279. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_html-escaper.js +0 -65
  280. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_html-escaper.js.map +0 -1
  281. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +0 -455
  282. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -1
  283. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/audit-C3SVr7dT.js +0 -1534
  284. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/audit-C3SVr7dT.js.map +0 -1
  285. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/highlight-BLtvqtzO.js +0 -48
  286. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/highlight-BLtvqtzO.js.map +0 -1
  287. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/icons-C92i61-2.js +0 -42
  288. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/icons-C92i61-2.js.map +0 -1
  289. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/package.json +0 -3
  290. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +0 -4
  291. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/settings-v5GgKks_.js +0 -190
  292. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/settings-v5GgKks_.js.map +0 -1
  293. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/toolbar-BFvJVp26.js +0 -458
  294. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/toolbar-BFvJVp26.js.map +0 -1
  295. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/ui-library-Cd35oAvo.js +0 -1016
  296. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/ui-library-Cd35oAvo.js.map +0 -1
  297. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/window-vo3A6TMn.js +0 -32
  298. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/window-vo3A6TMn.js.map +0 -1
  299. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/xray-DwhzGckb.js +0 -111
  300. package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/xray-DwhzGckb.js.map +0 -1
  301. package/examples/feature-demos/sitewide-content/site/.norna/generated-images.json +0 -1
  302. package/examples/feature-demos/sitewide-content/site/config.yaml +0 -1
  303. package/examples/feature-demos/sitewide-content/site/content.md +0 -17
  304. package/examples/feature-demos/sitewide-content/site/pages/010-logo-and-navigation/content.md +0 -17
  305. package/examples/feature-demos/sitewide-content/site/pages/020-notices/content.md +0 -23
  306. package/examples/feature-demos/sitewide-content/site/pages/030-footer/content.md +0 -18
  307. package/examples/feature-demos/sitewide-content/site/public/logo.svg +0 -6
  308. package/examples/feature-demos/sitewide-content/site/public/robots.txt +0 -2
  309. package/examples/feature-demos/sitewide-content/site/sitewide-content.yaml +0 -14
  310. package/examples/feature-demos/sitewide-content/site/theme.yaml +0 -1
  311. package/examples/feature-demos/theme-presets/.astro/collections/routeTheme.schema.json +0 -746
  312. package/examples/feature-demos/theme-presets/.astro/collections/site.schema.json +0 -59
  313. package/examples/feature-demos/theme-presets/.astro/collections/sitewide.schema.json +0 -138
  314. package/examples/feature-demos/theme-presets/.astro/collections/theme.schema.json +0 -755
  315. package/examples/feature-demos/theme-presets/.astro/content-assets.mjs +0 -4
  316. package/examples/feature-demos/theme-presets/.astro/content-modules.mjs +0 -1
  317. package/examples/feature-demos/theme-presets/.astro/content.d.ts +0 -183
  318. package/examples/feature-demos/theme-presets/.astro/data-store.json +0 -1
  319. package/examples/feature-demos/theme-presets/.astro/dev-local.json +0 -8
  320. package/examples/feature-demos/theme-presets/.astro/dev.json +0 -15
  321. package/examples/feature-demos/theme-presets/.astro/dev.log +0 -164
  322. package/examples/feature-demos/theme-presets/.astro/settings.json +0 -5
  323. package/examples/feature-demos/theme-presets/.astro/types.d.ts +0 -2
  324. package/examples/feature-demos/theme-presets/README.md +0 -18
  325. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/_metadata.json +0 -80
  326. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/astro-D_GIpJIE.js +0 -434
  327. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/astro-D_GIpJIE.js.map +0 -1
  328. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/astro_n_aria-query.js +0 -6390
  329. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/astro_n_aria-query.js.map +0 -1
  330. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/astro_n_axobject-query.js +0 -2702
  331. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/astro_n_axobject-query.js.map +0 -1
  332. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/astro_n_html-escaper.js +0 -65
  333. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/astro_n_html-escaper.js.map +0 -1
  334. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +0 -455
  335. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -1
  336. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/audit-DM9Hkl5B.js +0 -1534
  337. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/audit-DM9Hkl5B.js.map +0 -1
  338. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/embla-carousel.js +0 -1389
  339. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/embla-carousel.js.map +0 -1
  340. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/highlight-DnZ1ULOL.js +0 -48
  341. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/highlight-DnZ1ULOL.js.map +0 -1
  342. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/icons-RyebKi45.js +0 -42
  343. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/icons-RyebKi45.js.map +0 -1
  344. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/package.json +0 -3
  345. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +0 -4
  346. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/settings-DaU-gNnK.js +0 -190
  347. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/settings-DaU-gNnK.js.map +0 -1
  348. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/toolbar-63PA619H.js +0 -458
  349. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/toolbar-63PA619H.js.map +0 -1
  350. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/ui-library--bkcNSYz.js +0 -1016
  351. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/ui-library--bkcNSYz.js.map +0 -1
  352. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/window-jPkpKVcy.js +0 -32
  353. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/window-jPkpKVcy.js.map +0 -1
  354. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/xray-BXCHpEJP.js +0 -111
  355. package/examples/feature-demos/theme-presets/node_modules/.vite/deps/xray-BXCHpEJP.js.map +0 -1
  356. package/examples/feature-demos/theme-presets/site/.norna/generated-images.json +0 -290
  357. package/examples/feature-demos/theme-presets/site/config.yaml +0 -1
  358. package/examples/feature-demos/theme-presets/site/content.md +0 -14
  359. package/examples/feature-demos/theme-presets/site/pages/010-portfolio/content.md +0 -31
  360. package/examples/feature-demos/theme-presets/site/pages/010-portfolio/images/puppy-portrait.jpg +0 -0
  361. package/examples/feature-demos/theme-presets/site/pages/010-portfolio/images/shepherd-portrait.jpg +0 -0
  362. package/examples/feature-demos/theme-presets/site/pages/010-portfolio/images/white-puppy.jpg +0 -0
  363. package/examples/feature-demos/theme-presets/site/pages/010-portfolio/theme.yaml +0 -1
  364. package/examples/feature-demos/theme-presets/site/pages/020-documentation/content.md +0 -30
  365. package/examples/feature-demos/theme-presets/site/pages/020-documentation/images/black-schnauzer.jpg +0 -0
  366. package/examples/feature-demos/theme-presets/site/pages/020-documentation/images/retriever-portrait.jpg +0 -0
  367. package/examples/feature-demos/theme-presets/site/pages/020-documentation/images/schnauzer-portrait.jpg +0 -0
  368. package/examples/feature-demos/theme-presets/site/pages/020-documentation/theme.yaml +0 -1
  369. package/examples/feature-demos/theme-presets/site/pages/030-project/content.md +0 -31
  370. package/examples/feature-demos/theme-presets/site/pages/030-project/images/boxer-portrait.jpg +0 -0
  371. package/examples/feature-demos/theme-presets/site/pages/030-project/images/grass-puppy.jpg +0 -0
  372. package/examples/feature-demos/theme-presets/site/pages/030-project/images/grey-street-dog.jpg +0 -0
  373. package/examples/feature-demos/theme-presets/site/pages/030-project/theme.yaml +0 -1
  374. package/examples/feature-demos/theme-presets/site/pages/040-statement/content.md +0 -31
  375. package/examples/feature-demos/theme-presets/site/pages/040-statement/images/black-pedigree.jpg +0 -0
  376. package/examples/feature-demos/theme-presets/site/pages/040-statement/images/sheepdog-grass.jpg +0 -0
  377. package/examples/feature-demos/theme-presets/site/pages/040-statement/images/sheepdog-wide.jpg +0 -0
  378. package/examples/feature-demos/theme-presets/site/pages/040-statement/theme.yaml +0 -1
  379. package/examples/feature-demos/theme-presets/site/public/robots.txt +0 -2
  380. package/examples/feature-demos/theme-presets/site/sitewide-content.yaml +0 -3
  381. package/examples/feature-demos/theme-presets/site/theme.yaml +0 -1
  382. package/fixtures/basic/site/.norna/generated-images.json +0 -1
  383. package/fixtures/basic/site/config.yaml +0 -1
  384. package/fixtures/basic/site/content.md +0 -14
  385. package/fixtures/basic/site/public/robots.txt +0 -2
  386. package/fixtures/basic/site/sitewide-content.yaml +0 -3
  387. package/fixtures/basic/site/theme.yaml +0 -8
  388. package/fixtures/content-model-v2/.astro/collections/site.schema.json +0 -776
  389. package/fixtures/content-model-v2/.astro/collections/theme.schema.json +0 -668
  390. package/fixtures/content-model-v2/.astro/content-assets.mjs +0 -4
  391. package/fixtures/content-model-v2/.astro/content-modules.mjs +0 -1
  392. package/fixtures/content-model-v2/.astro/content.d.ts +0 -175
  393. package/fixtures/content-model-v2/.astro/data-store.json +0 -1
  394. package/fixtures/content-model-v2/.astro/dev-local.json +0 -8
  395. package/fixtures/content-model-v2/.astro/dev.json +0 -13
  396. package/fixtures/content-model-v2/.astro/dev.log +0 -231
  397. package/fixtures/content-model-v2/.astro/settings.json +0 -5
  398. package/fixtures/content-model-v2/.astro/types.d.ts +0 -2
  399. package/fixtures/content-model-v2/dist/_astro/GalleryGrid.astro_astro_type_script_index_0_lang.B0kxDyGz.js +0 -1
  400. package/fixtures/content-model-v2/dist/_astro/SitePage.BbfZub4g.css +0 -1
  401. package/fixtures/content-model-v2/dist/guide/index.html +0 -3
  402. package/fixtures/content-model-v2/dist/images/generated/intro/detail-27930b14-480.webp +0 -0
  403. package/fixtures/content-model-v2/dist/images/generated/intro/detail-27930b14-768.webp +0 -0
  404. package/fixtures/content-model-v2/dist/images/generated/intro/detail-27930b14-971.webp +0 -0
  405. package/fixtures/content-model-v2/dist/images/generated/intro/duplicate-49c98f6c-480.webp +0 -0
  406. package/fixtures/content-model-v2/dist/images/generated/intro/duplicate-49c98f6c-768.webp +0 -0
  407. package/fixtures/content-model-v2/dist/images/generated/intro/duplicate-49c98f6c-971.webp +0 -0
  408. package/fixtures/content-model-v2/dist/images/generated/intro/hero-6d588a83-480.webp +0 -0
  409. package/fixtures/content-model-v2/dist/images/generated/intro/hero-6d588a83-768.webp +0 -0
  410. package/fixtures/content-model-v2/dist/images/generated/intro/hero-6d588a83-971.webp +0 -0
  411. package/fixtures/content-model-v2/dist/images/generated/plain/image-3770d763-1080.webp +0 -0
  412. package/fixtures/content-model-v2/dist/images/generated/plain/image-3770d763-1440.webp +0 -0
  413. package/fixtures/content-model-v2/dist/images/generated/plain/image-3770d763-1600.webp +0 -0
  414. package/fixtures/content-model-v2/dist/images/generated/plain/image-3770d763-480.webp +0 -0
  415. package/fixtures/content-model-v2/dist/images/generated/plain/image-3770d763-768.webp +0 -0
  416. package/fixtures/content-model-v2/dist/images/generated/routes/010-guide/images/intro/duplicate-5cf614d2-480.webp +0 -0
  417. package/fixtures/content-model-v2/dist/images/generated/routes/010-guide/images/intro/duplicate-5cf614d2-768.webp +0 -0
  418. package/fixtures/content-model-v2/dist/images/generated/routes/010-guide/images/intro/duplicate-5cf614d2-960.webp +0 -0
  419. package/fixtures/content-model-v2/dist/images/generated/timed/slide-one-3770d763-1080.webp +0 -0
  420. package/fixtures/content-model-v2/dist/images/generated/timed/slide-one-3770d763-1440.webp +0 -0
  421. package/fixtures/content-model-v2/dist/images/generated/timed/slide-one-3770d763-1600.webp +0 -0
  422. package/fixtures/content-model-v2/dist/images/generated/timed/slide-one-3770d763-480.webp +0 -0
  423. package/fixtures/content-model-v2/dist/images/generated/timed/slide-one-3770d763-768.webp +0 -0
  424. package/fixtures/content-model-v2/dist/images/generated/timed/slide-three-5bdec65e-1080.webp +0 -0
  425. package/fixtures/content-model-v2/dist/images/generated/timed/slide-three-5bdec65e-1440.webp +0 -0
  426. package/fixtures/content-model-v2/dist/images/generated/timed/slide-three-5bdec65e-1600.webp +0 -0
  427. package/fixtures/content-model-v2/dist/images/generated/timed/slide-three-5bdec65e-480.webp +0 -0
  428. package/fixtures/content-model-v2/dist/images/generated/timed/slide-three-5bdec65e-768.webp +0 -0
  429. package/fixtures/content-model-v2/dist/images/generated/timed/slide-two-26c08aee-1080.webp +0 -0
  430. package/fixtures/content-model-v2/dist/images/generated/timed/slide-two-26c08aee-1440.webp +0 -0
  431. package/fixtures/content-model-v2/dist/images/generated/timed/slide-two-26c08aee-1600.webp +0 -0
  432. package/fixtures/content-model-v2/dist/images/generated/timed/slide-two-26c08aee-480.webp +0 -0
  433. package/fixtures/content-model-v2/dist/images/generated/timed/slide-two-26c08aee-768.webp +0 -0
  434. package/fixtures/content-model-v2/dist/index.html +0 -8
  435. package/fixtures/content-model-v2/node_modules/.vite/deps/_metadata.json +0 -80
  436. package/fixtures/content-model-v2/node_modules/.vite/deps/astro-D_GIpJIE.js +0 -434
  437. package/fixtures/content-model-v2/node_modules/.vite/deps/astro-D_GIpJIE.js.map +0 -1
  438. package/fixtures/content-model-v2/node_modules/.vite/deps/astro_n_aria-query.js +0 -6390
  439. package/fixtures/content-model-v2/node_modules/.vite/deps/astro_n_aria-query.js.map +0 -1
  440. package/fixtures/content-model-v2/node_modules/.vite/deps/astro_n_axobject-query.js +0 -2702
  441. package/fixtures/content-model-v2/node_modules/.vite/deps/astro_n_axobject-query.js.map +0 -1
  442. package/fixtures/content-model-v2/node_modules/.vite/deps/astro_n_html-escaper.js +0 -65
  443. package/fixtures/content-model-v2/node_modules/.vite/deps/astro_n_html-escaper.js.map +0 -1
  444. package/fixtures/content-model-v2/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +0 -455
  445. package/fixtures/content-model-v2/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -1
  446. package/fixtures/content-model-v2/node_modules/.vite/deps/audit-DM9Hkl5B.js +0 -1534
  447. package/fixtures/content-model-v2/node_modules/.vite/deps/audit-DM9Hkl5B.js.map +0 -1
  448. package/fixtures/content-model-v2/node_modules/.vite/deps/embla-carousel.js +0 -1389
  449. package/fixtures/content-model-v2/node_modules/.vite/deps/embla-carousel.js.map +0 -1
  450. package/fixtures/content-model-v2/node_modules/.vite/deps/highlight-DnZ1ULOL.js +0 -48
  451. package/fixtures/content-model-v2/node_modules/.vite/deps/highlight-DnZ1ULOL.js.map +0 -1
  452. package/fixtures/content-model-v2/node_modules/.vite/deps/icons-RyebKi45.js +0 -42
  453. package/fixtures/content-model-v2/node_modules/.vite/deps/icons-RyebKi45.js.map +0 -1
  454. package/fixtures/content-model-v2/node_modules/.vite/deps/package.json +0 -3
  455. package/fixtures/content-model-v2/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +0 -4
  456. package/fixtures/content-model-v2/node_modules/.vite/deps/settings-DaU-gNnK.js +0 -190
  457. package/fixtures/content-model-v2/node_modules/.vite/deps/settings-DaU-gNnK.js.map +0 -1
  458. package/fixtures/content-model-v2/node_modules/.vite/deps/toolbar-63PA619H.js +0 -458
  459. package/fixtures/content-model-v2/node_modules/.vite/deps/toolbar-63PA619H.js.map +0 -1
  460. package/fixtures/content-model-v2/node_modules/.vite/deps/ui-library--bkcNSYz.js +0 -1016
  461. package/fixtures/content-model-v2/node_modules/.vite/deps/ui-library--bkcNSYz.js.map +0 -1
  462. package/fixtures/content-model-v2/node_modules/.vite/deps/window-jPkpKVcy.js +0 -32
  463. package/fixtures/content-model-v2/node_modules/.vite/deps/window-jPkpKVcy.js.map +0 -1
  464. package/fixtures/content-model-v2/node_modules/.vite/deps/xray-BXCHpEJP.js +0 -111
  465. package/fixtures/content-model-v2/node_modules/.vite/deps/xray-BXCHpEJP.js.map +0 -1
  466. package/fixtures/content-model-v2/site/.norna/generated-images.json +0 -210
  467. package/fixtures/content-model-v2/site/config.yaml +0 -1
  468. package/fixtures/content-model-v2/site/content.md +0 -79
  469. package/fixtures/content-model-v2/site/images/adopt.svg +0 -9
  470. package/fixtures/content-model-v2/site/images/detail.jpg +0 -0
  471. package/fixtures/content-model-v2/site/images/duplicate.jpg +0 -0
  472. package/fixtures/content-model-v2/site/images/foster.svg +0 -12
  473. package/fixtures/content-model-v2/site/images/hero.jpg +0 -0
  474. package/fixtures/content-model-v2/site/images/image.jpg +0 -0
  475. package/fixtures/content-model-v2/site/images/slide-one.jpg +0 -0
  476. package/fixtures/content-model-v2/site/images/slide-three.jpg +0 -0
  477. package/fixtures/content-model-v2/site/images/slide-two.jpg +0 -0
  478. package/fixtures/content-model-v2/site/pages/010-guide/content.md +0 -18
  479. package/fixtures/content-model-v2/site/pages/010-guide/images/duplicate.jpg +0 -0
  480. package/fixtures/content-model-v2/site/theme.yaml +0 -4
  481. package/fixtures/nested-pages/site/.norna/generated-images.json +0 -10
  482. package/fixtures/nested-pages/site/config.yaml +0 -1
  483. package/fixtures/nested-pages/site/content.md +0 -15
  484. package/fixtures/nested-pages/site/pages/010-guides/content.md +0 -15
  485. package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/content.md +0 -21
  486. package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/images/diagram.svg +0 -21
  487. package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/pages/010-macos/content.md +0 -14
  488. package/fixtures/nested-pages/site/pages/010-guides/pages/020-workflows/content.md +0 -11
  489. package/fixtures/nested-pages/site/pages/010-guides/theme.yaml +0 -3
  490. package/fixtures/nested-pages/site/pages/020-reference/content.md +0 -10
  491. package/fixtures/nested-pages/site/pages/020-reference/pages/010-installation/content.md +0 -11
  492. package/fixtures/nested-pages/site/theme.yaml +0 -3
  493. package/scripts/build-pages.mjs +0 -69
  494. package/scripts/lib/example-sites.mjs +0 -37
  495. package/scripts/lib/frontmatter-yaml.mjs +0 -113
  496. package/scripts/lib/git-status.mjs +0 -7
  497. package/scripts/release.mjs +0 -153
  498. package/scripts/test-banner-visibility.mjs +0 -80
  499. package/scripts/test-ci-lockfile.mjs +0 -65
  500. package/scripts/test-cli-discovery.mjs +0 -124
  501. package/scripts/test-client-javascript.mjs +0 -218
  502. package/scripts/test-content-check.mjs +0 -621
  503. package/scripts/test-content-model-v2.mjs +0 -1629
  504. package/scripts/test-documentation.mjs +0 -187
  505. package/scripts/test-editor-language-service.mjs +0 -302
  506. package/scripts/test-engine-commands.mjs +0 -204
  507. package/scripts/test-examples.mjs +0 -24
  508. package/scripts/test-heading-ids.mjs +0 -68
  509. package/scripts/test-navigation-model.mjs +0 -63
  510. package/scripts/test-navigation-preview.mjs +0 -108
  511. package/scripts/test-navigation.mjs +0 -148
  512. package/scripts/test-nested-pages.mjs +0 -110
  513. package/scripts/test-package-check.mjs +0 -531
  514. package/scripts/test-page-model.mjs +0 -80
  515. package/scripts/test-project-config.mjs +0 -144
  516. package/scripts/test-schemas.mjs +0 -154
  517. package/scripts/test-site-public.mjs +0 -85
  518. package/scripts/test-theme-presets.mjs +0 -182
  519. package/src/components/SiteNotesScript.astro +0 -43
  520. package/starters/basic/site/images/.gitkeep +0 -1
  521. package/starters/project/.github/workflows/deploy.yml +0 -64
  522. package/starters/project/README.md +0 -84
  523. package/starters/project/package-lock.json +0 -4296
  524. package/starters/project/package.json +0 -37
  525. package/starters/project/site/config.yaml +0 -1
  526. package/starters/project/site/content.md +0 -119
  527. package/starters/project/site/pages/010-guide/content.md +0 -80
  528. package/starters/project/site/public/robots.txt +0 -2
  529. package/starters/project/site/sitewide-content.yaml +0 -3
  530. package/starters/project/site/theme.yaml +0 -31
  531. package/tsconfig.json +0 -5
  532. /package/starters/basic/site/{content.md → pages/000-home/content.md} +0 -0
  533. /package/{fixtures/basic/site → starters/basic/site/pages/000-home}/images/.gitkeep +0 -0
@@ -1,4 +1,3 @@
1
- import { Buffer } from 'node:buffer';
2
1
  import { documentationLink } from './documentation-links.mjs';
3
2
 
4
3
  const field = (description, options = {}) => Object.freeze({ description, ...options });
@@ -55,13 +54,12 @@ export const nornaMarkdownBlockDefinitions = Object.freeze({
55
54
  xl: value('Extra large', 'Use the largest card and image size.'),
56
55
  }),
57
56
  }),
58
- width: field('Limit the width of the complete card list. Defaults to normal.', {
59
- default: 'normal',
57
+ width: field('Override the root theme\'s maximum width for this card list.', {
60
58
  values: Object.freeze({
61
- text: value('Text', 'Match the active body-text width.'),
62
- narrow: value('Narrow', 'Use a narrow card-list width.'),
63
- normal: value('Normal', 'Use the balanced default card-list width.'),
64
- wide: value('Wide', 'Allow the card list to use more horizontal space.'),
59
+ text: value('Text', 'Match the active body-text width, including a reader-selected reading width.'),
60
+ narrow: value('Narrow', 'Limit the complete card list to at most 48rem.'),
61
+ normal: value('Normal', 'Limit the complete card list to at most 56rem.'),
62
+ wide: value('Wide', 'Allow the complete card list to use the available page-layout width.'),
65
63
  }),
66
64
  }),
67
65
  }),
@@ -87,7 +85,6 @@ const blockTypeLabels = {
87
85
 
88
86
  const knownBlockTypeList = Array.from(nornaBlockTypes).join(', ');
89
87
  const imageNameRegex = /^[a-z0-9][a-z0-9.-]*\.(jpe?g|png|svg)$/i;
90
- const markerTagName = 'norna-block';
91
88
  const imageStackExample = [
92
89
  '```norna-image-stack',
93
90
  '- image: filename.jpg',
@@ -98,7 +95,6 @@ const cardListExample = [
98
95
  'layout: image-top',
99
96
  'flow: grid',
100
97
  'size: m',
101
- 'width: normal',
102
98
  '',
103
99
  '- title: Adopt',
104
100
  ' text: Give a dog a new home.',
@@ -203,6 +199,35 @@ const getFenceCloseInfo = (line, opening) => {
203
199
  return fence;
204
200
  };
205
201
 
202
+ export const getOpenMarkdownFenceAtLine = (markdown, lineIndex) => {
203
+ const lines = normalizeLines(markdown);
204
+ let open = null;
205
+
206
+ for (let index = 0; index <= Math.min(lineIndex, lines.length - 1); index += 1) {
207
+ const fence = getFenceInfo(lines[index]);
208
+ if (!fence || fence.length < 3) continue;
209
+
210
+ if (!open) {
211
+ open = {
212
+ character: fence.markerCharacter,
213
+ length: fence.length,
214
+ line: index,
215
+ type: fence.info.split(/\s+/)[0] ?? '',
216
+ };
217
+ continue;
218
+ }
219
+
220
+ if (getFenceCloseInfo(lines[index], {
221
+ length: open.length,
222
+ markerCharacter: open.character,
223
+ })) {
224
+ open = null;
225
+ }
226
+ }
227
+
228
+ return open;
229
+ };
230
+
206
231
  const getNornaLineAttempt = (line) => {
207
232
  const match = line.match(/^ {0,3}([`~]{0,2})(norna-[a-z0-9-]+)\s*$/);
208
233
  if (!match) return null;
@@ -226,7 +251,14 @@ const getUnclosedNornaBlockMessage = (opening) =>
226
251
  `This Norna block was started on line ${opening.line} but not closed. Add a closing ${opening.markerCharacter.repeat(opening.length)} line after the last entry.`;
227
252
 
228
253
  const scanMarkdownFencedBlocks = (markdown, options = {}) => {
229
- const lines = normalizeLines(markdown);
254
+ const normalizedMarkdown = markdown.replace(/\r\n?/g, '\n');
255
+ const lines = normalizedMarkdown.split('\n');
256
+ const lineOffsets = [];
257
+ let nextLineOffset = 0;
258
+ for (const line of lines) {
259
+ lineOffsets.push(nextLineOffset);
260
+ nextLineOffset += line.length + 1;
261
+ }
230
262
  const lineOffset = options.lineOffset ?? 0;
231
263
  const blocks = [];
232
264
  const errors = [];
@@ -242,6 +274,7 @@ const scanMarkdownFencedBlocks = (markdown, options = {}) => {
242
274
  if (attempt) {
243
275
  errors.push({
244
276
  blockType: attempt.type,
277
+ code: 'invalid-norna-block-start',
245
278
  line: lineNumber,
246
279
  source: '',
247
280
  message: failMessage(getNornaFenceStartMessage(attempt.type, attempt.marker), { ...options, line: lineNumber }),
@@ -257,6 +290,7 @@ const scanMarkdownFencedBlocks = (markdown, options = {}) => {
257
290
  if (attempt) {
258
291
  errors.push({
259
292
  blockType: attempt.type,
293
+ code: 'invalid-norna-block-start',
260
294
  line: lineNumber,
261
295
  source: '',
262
296
  message: failMessage(getNornaFenceStartMessage(attempt.type, attempt.marker), { ...options, line: lineNumber }),
@@ -288,7 +322,10 @@ const scanMarkdownFencedBlocks = (markdown, options = {}) => {
288
322
  if (isNornaLike) {
289
323
  errors.push({
290
324
  blockType: type,
325
+ code: 'unclosed-norna-block',
326
+ endOffset: normalizedMarkdown.length,
291
327
  line: lineNumber,
328
+ startOffset: lineOffsets[index],
292
329
  source: lines.slice(bodyStartIndex).join('\n'),
293
330
  message: failMessage(getUnclosedNornaBlockMessage(opening), { ...options, line: lineNumber }),
294
331
  });
@@ -301,13 +338,19 @@ const scanMarkdownFencedBlocks = (markdown, options = {}) => {
301
338
  if (nornaBlockTypes.has(type)) {
302
339
  blocks.push({
303
340
  blockType: type,
341
+ endLine: lineOffset + closingIndex + 1,
342
+ endOffset: lineOffsets[closingIndex] + lines[closingIndex].length,
304
343
  line: lineNumber,
344
+ startOffset: lineOffsets[index],
305
345
  source,
346
+ sourceEndOffset: lineOffsets[closingIndex],
306
347
  sourceLine: lineNumber + 1,
348
+ sourceStartOffset: lineOffsets[bodyStartIndex],
307
349
  });
308
350
  } else {
309
351
  errors.push({
310
352
  blockType: type,
353
+ code: 'unknown-norna-block',
311
354
  line: lineNumber,
312
355
  source,
313
356
  message: failMessage(getUnknownNornaBlockMessage(type), { ...options, line: lineNumber }),
@@ -337,7 +380,7 @@ const parseImageListBlock = (source, options = {}) => {
337
380
  const lineNumber = (options.line ?? 1) + index;
338
381
  const itemMatch = line.match(/^(\s*)-\s+image:\s*(.*?)\s*$/);
339
382
  if (itemMatch) {
340
- current = { image: decodeScalar(itemMatch[2]) };
383
+ current = { image: decodeScalar(itemMatch[2]), line: lineNumber };
341
384
  images.push(current);
342
385
  continue;
343
386
  }
@@ -375,7 +418,7 @@ const parseCardListBlock = (source, options = {}) => {
375
418
  let layout = cardListDefinition.options.layout.default;
376
419
  let flow = cardListDefinition.options.flow.default;
377
420
  let size = cardListDefinition.options.size.default;
378
- let width = cardListDefinition.options.width.default;
421
+ let width;
379
422
  let current = null;
380
423
 
381
424
  for (const [index, line] of normalizeLines(source).entries()) {
@@ -384,7 +427,7 @@ const parseCardListBlock = (source, options = {}) => {
384
427
  const lineNumber = (options.line ?? 1) + index;
385
428
  const itemMatch = line.match(/^(\s*)-\s+title:\s*(.*?)\s*$/);
386
429
  if (itemMatch) {
387
- current = { title: decodeScalar(itemMatch[2]) };
430
+ current = { title: decodeScalar(itemMatch[2]), line: lineNumber };
388
431
  cards.push(current);
389
432
  continue;
390
433
  }
@@ -486,26 +529,6 @@ export const parseNornaMarkdownBlock = (type, source, options = {}) => {
486
529
 
487
530
  const getLineNumber = (source, index) => source.slice(0, index).split(/\r?\n/).length;
488
531
 
489
- export const extractNornaMarkdownBlocks = (markdown, options = {}) => {
490
- const blocks = [];
491
- const { blocks: scannedBlocks, errors } = scanMarkdownFencedBlocks(markdown, options);
492
-
493
- if (errors.length > 0) {
494
- throw new Error(errors[0].message);
495
- }
496
-
497
- for (const block of scannedBlocks) {
498
- blocks.push({
499
- ...parseNornaMarkdownBlock(block.blockType, block.source, { ...options, line: block.sourceLine }),
500
- blockType: block.blockType,
501
- line: block.line,
502
- source: block.source,
503
- });
504
- }
505
-
506
- return blocks;
507
- };
508
-
509
532
  export const extractNornaMarkdownBlockDiagnostics = (markdown, options = {}) => {
510
533
  const blocks = [];
511
534
  const { blocks: scannedBlocks, errors } = scanMarkdownFencedBlocks(markdown, options);
@@ -515,12 +538,18 @@ export const extractNornaMarkdownBlockDiagnostics = (markdown, options = {}) =>
515
538
  blocks.push({
516
539
  ...parseNornaMarkdownBlock(block.blockType, block.source, { ...options, line: block.sourceLine }),
517
540
  blockType: block.blockType,
541
+ endLine: block.endLine,
542
+ endOffset: block.endOffset,
518
543
  line: block.line,
544
+ startOffset: block.startOffset,
519
545
  source: block.source,
546
+ sourceEndOffset: block.sourceEndOffset,
547
+ sourceStartOffset: block.sourceStartOffset,
520
548
  });
521
549
  } catch (error) {
522
550
  errors.push({
523
551
  blockType: block.blockType,
552
+ code: 'invalid-norna-block',
524
553
  line: block.line,
525
554
  source: block.source,
526
555
  message: error instanceof Error ? error.message : String(error),
@@ -570,18 +599,6 @@ const maskFencedCodeBlocks = (markdown) => {
570
599
  const isExternalImageTarget = (target) => /^[a-z][a-z0-9+.-]*:/i.test(target) || target.startsWith('//');
571
600
  const isRootRelativePublicTarget = (target) => target.startsWith('/');
572
601
 
573
- const stripTags = (value) => value.replace(/<[^>]*>/g, '');
574
-
575
- const decodeHtmlEntities = (value) =>
576
- value
577
- .replace(/&amp;/g, '&')
578
- .replace(/&lt;/g, '<')
579
- .replace(/&gt;/g, '>')
580
- .replace(/&quot;/g, '"')
581
- .replace(/&#39;/g, "'")
582
- .replace(/&#x([0-9a-f]+);/gi, (_match, hex) => String.fromCodePoint(Number.parseInt(hex, 16)))
583
- .replace(/&#(\d+);/g, (_match, decimal) => String.fromCodePoint(Number.parseInt(decimal, 10)));
584
-
585
602
  export const extractMarkdownImageReferences = (markdown) => {
586
603
  const masked = maskFencedCodeBlocks(markdown);
587
604
  const references = [];
@@ -610,7 +627,7 @@ export const getNornaBlockImageReferences = (blocks) =>
610
627
  alt: card.title,
611
628
  blockType: block.blockType,
612
629
  blockDisplayType: block.type,
613
- line: block.line,
630
+ line: card.line ?? block.line,
614
631
  }));
615
632
  }
616
633
 
@@ -618,54 +635,10 @@ export const getNornaBlockImageReferences = (blocks) =>
618
635
  ...image,
619
636
  blockType: block.blockType,
620
637
  blockDisplayType: block.type,
621
- line: block.line,
638
+ line: image.line ?? block.line,
622
639
  }));
623
640
  });
624
641
 
625
- export const createNornaMarkdownBlockMarker = (type, source) => {
626
- const encodedSource = Buffer.from(source, 'utf8').toString('base64');
627
- return `<${markerTagName} data-type="${type}" data-source="${encodedSource}"></${markerTagName}>`;
628
- };
629
-
630
- export const splitNornaMarkdownBlockMarkers = (html, options = {}) => {
631
- const blocks = [];
632
- const markerRegex = /<norna-block\s+data-type="([^"]+)"\s+data-source="([^"]*)"\s*><\/norna-block>|<pre\b([^>]*)>\s*<code\b([^>]*)>([\s\S]*?)<\/code>\s*<\/pre>/g;
633
- let cursor = 0;
634
-
635
- for (const match of html.matchAll(markerRegex)) {
636
- const start = match.index ?? 0;
637
- if (start > cursor) {
638
- blocks.push({ type: 'html', html: html.slice(cursor, start) });
639
- }
640
-
641
- if (match[1]) {
642
- const blockType = match[1];
643
- const source = Buffer.from(match[2] ?? '', 'base64').toString('utf8');
644
- blocks.push(parseNornaMarkdownBlock(blockType, source, options));
645
- } else {
646
- const attributes = `${match[3] ?? ''} ${match[4] ?? ''}`;
647
- const blockType = attributes.match(/\blanguage-(norna-[a-z0-9-]+)\b/)?.[1]
648
- ?? attributes.match(/\bdata-language="(norna-[a-z0-9-]+)"/)?.[1];
649
- if (!nornaBlockTypes.has(blockType)) {
650
- blocks.push({ type: 'html', html: match[0] });
651
- } else {
652
- const source = decodeHtmlEntities(stripTags(match[5] ?? ''));
653
- blocks.push(parseNornaMarkdownBlock(blockType, source, options));
654
- }
655
- }
656
-
657
- cursor = start + match[0].length;
658
- }
659
-
660
- if (cursor < html.length) {
661
- blocks.push({ type: 'html', html: html.slice(cursor) });
662
- }
663
-
664
- return blocks.filter((block) => block.type !== 'html' || block.html.trim());
665
- };
666
-
667
- const normalizeBlockSource = (source) => source.replace(/\r\n?/g, '\n').trim();
668
-
669
642
  const inlineNoteReferenceRegex = /\{note-ref\}/g;
670
643
  const inlineNoteDeclarationOpeningRegex = /^\s*\{note:\s*(.*)$/;
671
644
  const inlineNoteDeclarationClosingRegex = /^(.*?)\}\s*$/;
@@ -918,57 +891,3 @@ export const extractInlineNoteDiagnostics = (markdown, options = {}) => {
918
891
 
919
892
  return { notes, errors };
920
893
  };
921
-
922
- export const splitNornaRenderedCodeBlocks = (html, rawBlocks, options = {}) => {
923
- const blocks = [];
924
- const renderedCodeRegex = /<pre\b[^>]*>\s*<code\b[^>]*>([\s\S]*?)<\/code>\s*<\/pre>/g;
925
- let cursor = 0;
926
- let rawIndex = 0;
927
-
928
- for (const match of html.matchAll(renderedCodeRegex)) {
929
- const start = match.index ?? 0;
930
- if (start > cursor) {
931
- blocks.push({ type: 'html', html: html.slice(cursor, start) });
932
- }
933
-
934
- const rawBlock = rawBlocks[rawIndex];
935
- const renderedSource = normalizeBlockSource(decodeHtmlEntities(stripTags(match[1] ?? '')));
936
- const rawSource = normalizeBlockSource(rawBlock?.source ?? '');
937
-
938
- if (rawBlock && renderedSource === rawSource) {
939
- blocks.push(parseNornaMarkdownBlock(rawBlock.blockType, rawBlock.source, options));
940
- rawIndex += 1;
941
- } else {
942
- blocks.push({ type: 'html', html: match[0] });
943
- }
944
-
945
- cursor = start + match[0].length;
946
- }
947
-
948
- if (cursor < html.length) {
949
- blocks.push({ type: 'html', html: html.slice(cursor) });
950
- }
951
-
952
- return blocks.filter((block) => block.type !== 'html' || block.html.trim());
953
- };
954
-
955
- const visitCodeBlocks = (node) => {
956
- if (!node || typeof node !== 'object') return;
957
-
958
- if (Array.isArray(node.children)) {
959
- for (const child of node.children) {
960
- visitCodeBlocks(child);
961
- }
962
- }
963
-
964
- if (node.type !== 'code' || !nornaBlockTypes.has(node.lang)) return;
965
-
966
- node.type = 'html';
967
- node.value = createNornaMarkdownBlockMarker(node.lang, node.value ?? '');
968
- delete node.lang;
969
- delete node.meta;
970
- };
971
-
972
- export const nornaMarkdownBlocksRemarkPlugin = () => (tree) => {
973
- visitCodeBlocks(tree);
974
- };
@@ -0,0 +1,37 @@
1
+ import { defineMdastPlugin } from 'satteri';
2
+ import { nornaBlockTypes } from './norna-markdown-blocks.mjs';
3
+
4
+ const stateKey = 'nornaMarkdownRender';
5
+
6
+ const getState = (context) => {
7
+ if (!context.data[stateKey]) {
8
+ context.data[stateKey] = { blockIndex: 0, regionIndex: 0 };
9
+ }
10
+ return context.data[stateKey];
11
+ };
12
+
13
+ export const nornaMarkdownRenderPlugin = defineMdastPlugin({
14
+ name: 'norna-markdown-render',
15
+ code(node, context) {
16
+ if (!nornaBlockTypes.has(node.lang)) return;
17
+
18
+ const state = getState(context);
19
+ const blockIndex = state.blockIndex;
20
+ state.blockIndex += 1;
21
+ context.replaceNode(node, {
22
+ type: 'html',
23
+ value: `<norna-block data-index="${blockIndex}"></norna-block>`,
24
+ });
25
+ },
26
+ heading(node, context) {
27
+ if (node.depth !== 1 && node.depth !== 2) return;
28
+ const state = getState(context);
29
+ const regionIndex = state.regionIndex;
30
+ state.blockIndex = 0;
31
+ state.regionIndex += 1;
32
+ context.replaceNode(node, {
33
+ type: 'html',
34
+ value: `<norna-region data-index="${regionIndex}"></norna-region>`,
35
+ });
36
+ },
37
+ });
@@ -0,0 +1,28 @@
1
+ export const isPlainObject = (value) => (
2
+ value !== null
3
+ && typeof value === 'object'
4
+ && !Array.isArray(value)
5
+ );
6
+
7
+ export const freezeDeep = (value) => {
8
+ if (value === null || typeof value !== 'object' || Object.isFrozen(value)) return value;
9
+
10
+ for (const child of Object.values(value)) freezeDeep(child);
11
+ return Object.freeze(value);
12
+ };
13
+
14
+ export const mergeDeep = (base, override) => {
15
+ if (!isPlainObject(override)) return structuredClone(base);
16
+
17
+ const merged = structuredClone(base);
18
+
19
+ for (const [key, value] of Object.entries(override)) {
20
+ if (isPlainObject(value) && isPlainObject(merged[key])) {
21
+ merged[key] = mergeDeep(merged[key], value);
22
+ } else if (value !== undefined) {
23
+ merged[key] = value;
24
+ }
25
+ }
26
+
27
+ return merged;
28
+ };
@@ -0,0 +1,282 @@
1
+ import {
2
+ getHeadingIdentifierIssues,
3
+ getMarkdownHeadings,
4
+ } from './heading-ids.mjs';
5
+ import {
6
+ extractInlineNoteDiagnostics,
7
+ extractMarkdownImageReferences,
8
+ extractNornaMarkdownBlockDiagnostics,
9
+ getNornaBlockImageReferences,
10
+ } from './norna-markdown-blocks.mjs';
11
+
12
+ const normalizeMarkdown = (source) => source.replace(/\r\n?/g, '\n');
13
+
14
+ const hasContent = (source) => source.trim().length > 0;
15
+
16
+ export const splitPageMarkdownSource = (source) => {
17
+ const normalizedSource = normalizeMarkdown(source);
18
+ const lines = normalizedSource.split('\n');
19
+ if (lines[0]?.trim() !== '---') {
20
+ return {
21
+ body: normalizedSource,
22
+ bodyOffset: 0,
23
+ frontmatter: '',
24
+ frontmatterUnclosed: false,
25
+ lineOffset: 0,
26
+ };
27
+ }
28
+
29
+ const closingIndex = lines.findIndex((line, index) => index > 0 && line.trim() === '---');
30
+ if (closingIndex < 0) {
31
+ return {
32
+ body: '',
33
+ bodyOffset: normalizedSource.length,
34
+ frontmatter: normalizedSource,
35
+ frontmatterUnclosed: true,
36
+ lineOffset: lines.length,
37
+ };
38
+ }
39
+
40
+ const frontmatterLines = lines.slice(0, closingIndex + 1);
41
+ const frontmatter = frontmatterLines.join('\n');
42
+ const bodyOffset = frontmatter.length + (closingIndex < lines.length - 1 ? 1 : 0);
43
+ return {
44
+ body: normalizedSource.slice(bodyOffset),
45
+ bodyOffset,
46
+ frontmatter,
47
+ frontmatterUnclosed: false,
48
+ lineOffset: closingIndex + 1,
49
+ };
50
+ };
51
+
52
+ const getPageStructureDiagnostics = ({ headings, pageHeadings, prelude }, lineOffset) => {
53
+ const diagnostics = [];
54
+
55
+ if (pageHeadings.length === 0) {
56
+ diagnostics.push({
57
+ code: 'missing-page-title',
58
+ line: lineOffset + 1,
59
+ message: 'The page is missing its Markdown H1 title.',
60
+ severity: 'error',
61
+ fix: 'Add exactly one page title before any sections, for example "# About".',
62
+ });
63
+ } else if (pageHeadings.length > 1) {
64
+ for (const heading of pageHeadings.slice(1)) {
65
+ diagnostics.push({
66
+ code: 'duplicate-page-title',
67
+ line: lineOffset + heading.line,
68
+ message: `The page contains ${pageHeadings.length} Markdown H1 headings.`,
69
+ severity: 'error',
70
+ fix: 'Keep exactly one H1 page title. Use level 2 headings with explicit ids for sections.',
71
+ });
72
+ }
73
+ }
74
+
75
+ if (headings[0] && headings[0].depth !== 1) {
76
+ diagnostics.push({
77
+ code: 'page-title-order',
78
+ line: lineOffset + headings[0].line,
79
+ message: `The first content heading is "${headings[0].title}", but a Norna page must start with its H1 title.`,
80
+ severity: 'error',
81
+ fix: 'Move the single H1 page title before every section.',
82
+ });
83
+ }
84
+
85
+ if (hasContent(prelude)) {
86
+ diagnostics.push({
87
+ code: 'page-title-order',
88
+ line: lineOffset + 1,
89
+ message: 'The page contains content before its first heading.',
90
+ severity: 'error',
91
+ fix: 'Make the Markdown H1 page title the first content after optional frontmatter.',
92
+ });
93
+ }
94
+
95
+ return diagnostics;
96
+ };
97
+
98
+ const getHeadingDiagnostics = (headings, lineOffset) => getHeadingIdentifierIssues(headings).map((issue) => ({
99
+ code: issue.code,
100
+ heading: issue.heading,
101
+ line: lineOffset + issue.heading.line,
102
+ message: issue.message,
103
+ otherHeading: issue.otherHeading,
104
+ otherLine: issue.otherHeading ? lineOffset + issue.otherHeading.line : null,
105
+ severity: 'error',
106
+ fix: issue.fix,
107
+ }));
108
+
109
+ const getRegionContent = (regionMarkdown, blocks, regionOffset) => {
110
+ const content = [];
111
+ let cursor = 0;
112
+
113
+ for (const block of blocks) {
114
+ if (block.startOffset > cursor) {
115
+ content.push({
116
+ kind: 'markdown',
117
+ markdown: regionMarkdown.slice(cursor, block.startOffset),
118
+ range: {
119
+ start: regionOffset + cursor,
120
+ end: regionOffset + block.startOffset,
121
+ },
122
+ });
123
+ }
124
+
125
+ content.push({
126
+ kind: 'norna-block',
127
+ block,
128
+ range: {
129
+ start: regionOffset + block.startOffset,
130
+ end: regionOffset + block.endOffset,
131
+ },
132
+ });
133
+ cursor = block.endOffset;
134
+ }
135
+
136
+ if (cursor < regionMarkdown.length) {
137
+ content.push({
138
+ kind: 'markdown',
139
+ markdown: regionMarkdown.slice(cursor),
140
+ range: {
141
+ start: regionOffset + cursor,
142
+ end: regionOffset + regionMarkdown.length,
143
+ },
144
+ });
145
+ }
146
+
147
+ return content.filter((item) => item.kind !== 'markdown' || item.markdown.length > 0);
148
+ };
149
+
150
+ const createRegion = ({ heading, nextHeading, headings, source, label, lineOffset }) => {
151
+ const endOffset = nextHeading?.index ?? source.length;
152
+ const markdown = source.slice(heading.index, endOffset).trimEnd();
153
+ const regionLineOffset = lineOffset + heading.line - 1;
154
+ const blockResult = extractNornaMarkdownBlockDiagnostics(markdown, {
155
+ label,
156
+ lineOffset: regionLineOffset,
157
+ });
158
+ const noteResult = extractInlineNoteDiagnostics(markdown, {
159
+ label,
160
+ lineOffset: regionLineOffset,
161
+ });
162
+ const markdownImages = extractMarkdownImageReferences(markdown).map((reference) => ({
163
+ ...reference,
164
+ line: regionLineOffset + reference.line,
165
+ }));
166
+ const regionHeadings = headings.filter((candidate) => (
167
+ candidate.index >= heading.index
168
+ && candidate.index < endOffset
169
+ ));
170
+
171
+ return {
172
+ bodyMarkdown: source.slice(heading.index + heading.source.length, endOffset).trimEnd(),
173
+ blocks: blockResult.blocks,
174
+ blockErrors: blockResult.errors,
175
+ content: getRegionContent(markdown, blockResult.blocks, heading.index),
176
+ endOffset,
177
+ heading,
178
+ headings: regionHeadings,
179
+ id: heading.id,
180
+ kind: heading.depth === 1 ? 'page-intro' : 'section',
181
+ bodyLine: heading.line,
182
+ line: lineOffset + heading.line,
183
+ managedImages: getNornaBlockImageReferences(blockResult.blocks),
184
+ markdown,
185
+ markdownImages,
186
+ notes: noteResult.notes,
187
+ noteErrors: noteResult.errors,
188
+ startOffset: heading.index,
189
+ title: heading.title,
190
+ };
191
+ };
192
+
193
+ export const parsePageMarkdown = async (markdown, options = {}) => {
194
+ const source = normalizeMarkdown(markdown);
195
+ const label = options.label ?? 'Markdown';
196
+ const lineOffset = options.lineOffset ?? 0;
197
+ const { headings } = await getMarkdownHeadings(source);
198
+ const structuralHeadings = headings.filter((heading) => heading.depth <= 2);
199
+ const prelude = structuralHeadings.length > 0
200
+ ? source.slice(0, structuralHeadings[0].index)
201
+ : source;
202
+ const pageHeadings = structuralHeadings.filter((heading) => heading.depth === 1);
203
+ const regions = structuralHeadings.map((heading, index) => createRegion({
204
+ heading,
205
+ nextHeading: structuralHeadings[index + 1],
206
+ headings,
207
+ label,
208
+ lineOffset,
209
+ source,
210
+ }));
211
+ const headingIssues = getHeadingIdentifierIssues(headings);
212
+ const headingDiagnostics = getHeadingDiagnostics(headings, lineOffset);
213
+ const structureDiagnostics = getPageStructureDiagnostics({ headings, pageHeadings, prelude }, lineOffset);
214
+ const blockDiagnostics = regions.flatMap((region) => region.blockErrors.map((error) => ({
215
+ code: error.code ?? 'invalid-norna-block',
216
+ line: error.line,
217
+ message: error.message,
218
+ regionId: region.id,
219
+ severity: 'error',
220
+ })));
221
+ const noteDiagnostics = regions.flatMap((region) => region.noteErrors.map((error) => ({
222
+ code: 'invalid-inline-note',
223
+ line: error.line,
224
+ message: error.message,
225
+ regionId: region.id,
226
+ severity: 'error',
227
+ })));
228
+ const navigationHeadings = [];
229
+ let parentId = null;
230
+ for (const heading of headings) {
231
+ if (heading.depth === 2) parentId = heading.id;
232
+ if ((heading.depth !== 2 && heading.depth !== 3) || !heading.id) continue;
233
+ navigationHeadings.push({
234
+ depth: heading.depth,
235
+ id: heading.id,
236
+ line: lineOffset + heading.line,
237
+ parentId: heading.depth === 3 ? parentId : null,
238
+ title: heading.title,
239
+ });
240
+ }
241
+
242
+ return {
243
+ blocks: regions.flatMap((region) => region.blocks),
244
+ diagnostics: [
245
+ ...structureDiagnostics,
246
+ ...headingDiagnostics,
247
+ ...blockDiagnostics,
248
+ ...noteDiagnostics,
249
+ ],
250
+ headings,
251
+ headingIssues,
252
+ intro: regions.find((region) => region.kind === 'page-intro') ?? null,
253
+ label,
254
+ lineOffset,
255
+ managedImages: regions.flatMap((region) => region.managedImages),
256
+ markdownImages: regions.flatMap((region) => region.markdownImages),
257
+ navigationHeadings,
258
+ notes: regions.flatMap((region) => region.notes),
259
+ pageTitle: pageHeadings[0] ?? null,
260
+ pageHeadings,
261
+ prelude,
262
+ regions,
263
+ sections: regions.filter((region) => region.kind === 'section'),
264
+ source,
265
+ };
266
+ };
267
+
268
+ export const parsePageMarkdownSource = async (source, options = {}) => {
269
+ const split = splitPageMarkdownSource(source);
270
+ const model = await parsePageMarkdown(split.body, {
271
+ ...options,
272
+ lineOffset: (options.lineOffset ?? 0) + split.lineOffset,
273
+ });
274
+
275
+ return {
276
+ ...model,
277
+ bodyOffset: split.bodyOffset,
278
+ frontmatter: split.frontmatter,
279
+ frontmatterUnclosed: split.frontmatterUnclosed,
280
+ fullSource: normalizeMarkdown(source),
281
+ };
282
+ };