@janga/norna 0.7.16 → 0.7.17

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 (200) hide show
  1. package/README.md +6 -6
  2. package/astro.config.mjs +35 -3
  3. package/docs/README.md +10 -10
  4. package/docs/commands.md +2 -2
  5. package/docs/content.md +82 -102
  6. package/docs/design/navigation-and-theme-plan.md +115 -0
  7. package/docs/design/norna-diagram-design.md +9 -9
  8. package/docs/design/site-examples-structure.md +9 -9
  9. package/docs/engine-development.md +9 -9
  10. package/docs/getting-started.md +20 -15
  11. package/docs/images-and-metadata.md +10 -9
  12. package/docs/pages.md +134 -0
  13. package/docs/public-files.md +49 -36
  14. package/docs/publishing.md +19 -3
  15. package/docs/site-files.md +29 -28
  16. package/docs/sitewide-content.md +20 -36
  17. package/docs/theme.md +20 -20
  18. package/docs/typography.md +10 -10
  19. package/examples/README.md +2 -2
  20. package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/site.schema.json +17 -41
  21. package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/sitewide.schema.json +26 -67
  22. package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/theme.schema.json +185 -88
  23. package/examples/complete-sites/dog-shelter-multi-page/.astro/data-store.json +1 -1
  24. package/examples/complete-sites/dog-shelter-multi-page/.astro/dev-local.json +4 -4
  25. package/examples/complete-sites/dog-shelter-multi-page/.astro/dev.json +5 -5
  26. package/examples/complete-sites/dog-shelter-multi-page/.astro/dev.log +33 -23
  27. package/examples/complete-sites/dog-shelter-multi-page/README.md +1 -1
  28. package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/_metadata.json +8 -8
  29. package/examples/complete-sites/dog-shelter-multi-page/site/.norna/generated-images.json +20 -20
  30. package/examples/complete-sites/dog-shelter-multi-page/site/content.md +3 -4
  31. package/examples/complete-sites/dog-shelter-multi-page/site/{routes → pages}/010-dogs/content.md +3 -4
  32. package/examples/complete-sites/dog-shelter-multi-page/site/{routes → pages}/020-adopt/content.md +3 -4
  33. package/examples/complete-sites/dog-shelter-multi-page/site/sitewide-content.yaml +2 -4
  34. package/examples/complete-sites/dog-shelter-single-page/.astro/collections/site.schema.json +17 -41
  35. package/examples/complete-sites/dog-shelter-single-page/.astro/collections/sitewide.schema.json +26 -67
  36. package/examples/complete-sites/dog-shelter-single-page/.astro/collections/theme.schema.json +185 -88
  37. package/examples/complete-sites/dog-shelter-single-page/.astro/data-store.json +1 -1
  38. package/examples/complete-sites/dog-shelter-single-page/.astro/dev-local.json +8 -0
  39. package/examples/complete-sites/dog-shelter-single-page/.astro/dev.json +5 -5
  40. package/examples/complete-sites/dog-shelter-single-page/.astro/dev.log +16 -12
  41. package/examples/complete-sites/dog-shelter-single-page/README.md +1 -1
  42. package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/_metadata.json +8 -8
  43. package/examples/complete-sites/dog-shelter-single-page/site/.norna/generated-images.json +12 -12
  44. package/examples/complete-sites/dog-shelter-single-page/site/content.md +5 -2
  45. package/examples/complete-sites/dog-shelter-single-page/site/sitewide-content.yaml +2 -4
  46. package/examples/feature-demos/media-and-surfaces/.astro/collections/site.schema.json +17 -41
  47. package/examples/feature-demos/media-and-surfaces/.astro/collections/sitewide.schema.json +26 -67
  48. package/examples/feature-demos/media-and-surfaces/.astro/collections/theme.schema.json +185 -88
  49. package/examples/feature-demos/media-and-surfaces/.astro/data-store.json +1 -1
  50. package/examples/feature-demos/media-and-surfaces/.astro/dev.log +4 -14
  51. package/examples/feature-demos/media-and-surfaces/README.md +2 -2
  52. package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/_metadata.json +9 -9
  53. package/examples/feature-demos/media-and-surfaces/site/.norna/generated-images.json +16 -16
  54. package/examples/feature-demos/media-and-surfaces/site/content.md +4 -7
  55. package/examples/feature-demos/media-and-surfaces/site/{routes → pages}/010-media/content.md +6 -5
  56. package/examples/feature-demos/media-and-surfaces/site/{routes → pages}/020-surfaces/content.md +7 -6
  57. package/examples/feature-demos/media-and-surfaces/site/sitewide-content.yaml +0 -2
  58. package/examples/feature-demos/sitewide-content/README.md +3 -3
  59. package/examples/feature-demos/sitewide-content/site/content.md +8 -7
  60. package/examples/feature-demos/sitewide-content/site/pages/010-logo-and-navigation/content.md +17 -0
  61. package/examples/feature-demos/sitewide-content/site/{routes → pages}/020-notices/content.md +7 -6
  62. package/examples/feature-demos/sitewide-content/site/{routes → pages}/030-footer/content.md +6 -5
  63. package/examples/feature-demos/sitewide-content/site/sitewide-content.yaml +4 -13
  64. package/examples/feature-demos/theme-presets/README.md +1 -1
  65. package/examples/feature-demos/theme-presets/site/.norna/generated-images.json +60 -60
  66. package/examples/feature-demos/theme-presets/site/content.md +4 -7
  67. package/examples/feature-demos/theme-presets/site/{routes → pages}/010-portfolio/content.md +4 -7
  68. package/examples/feature-demos/theme-presets/site/{routes → pages}/020-documentation/content.md +4 -7
  69. package/examples/feature-demos/theme-presets/site/{routes → pages}/030-project/content.md +4 -7
  70. package/examples/feature-demos/theme-presets/site/{routes → pages}/040-statement/content.md +4 -7
  71. package/examples/feature-demos/theme-presets/site/sitewide-content.yaml +1 -10
  72. package/fixtures/basic/site/content.md +5 -6
  73. package/fixtures/basic/site/sitewide-content.yaml +1 -8
  74. package/fixtures/content-model-v2/site/content.md +11 -13
  75. package/fixtures/content-model-v2/site/pages/010-guide/content.md +18 -0
  76. package/fixtures/nested-pages/site/.norna/generated-images.json +10 -0
  77. package/fixtures/nested-pages/site/config.yaml +1 -0
  78. package/fixtures/nested-pages/site/content.md +15 -0
  79. package/fixtures/nested-pages/site/pages/010-guides/content.md +15 -0
  80. package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/content.md +21 -0
  81. package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/images/diagram.svg +21 -0
  82. package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/pages/010-macos/content.md +14 -0
  83. package/fixtures/nested-pages/site/pages/010-guides/pages/020-workflows/content.md +11 -0
  84. package/fixtures/nested-pages/site/pages/010-guides/theme.yaml +3 -0
  85. package/fixtures/nested-pages/site/pages/020-reference/content.md +10 -0
  86. package/fixtures/nested-pages/site/pages/020-reference/pages/010-installation/content.md +11 -0
  87. package/fixtures/nested-pages/site/theme.yaml +3 -0
  88. package/package.json +7 -4
  89. package/schemas/config.schema.json +5 -5
  90. package/schemas/content-frontmatter.schema.json +28 -63
  91. package/schemas/manifest.json +1 -0
  92. package/schemas/sitewide-content.schema.json +58 -132
  93. package/schemas/theme.schema.json +396 -86
  94. package/scripts/check-config.mjs +6 -5
  95. package/scripts/deploy-site.mjs +6 -8
  96. package/scripts/doctor.mjs +2 -2
  97. package/scripts/generate-images.mjs +11 -18
  98. package/scripts/generate-schemas.mjs +3 -217
  99. package/scripts/lib/base-path-redirect.mjs +9 -0
  100. package/scripts/lib/editor-language-service.mjs +126 -66
  101. package/scripts/lib/heading-ids.mjs +161 -0
  102. package/scripts/lib/navigation-model.mjs +51 -0
  103. package/scripts/lib/norna-markdown-blocks.mjs +3 -4
  104. package/scripts/lib/page-model.mjs +83 -0
  105. package/scripts/lib/project-config.mjs +28 -0
  106. package/scripts/lib/schema-definitions.mjs +41 -46
  107. package/scripts/lib/schema-editor-metadata.mjs +475 -0
  108. package/scripts/lib/schema-value-definitions.mjs +6 -6
  109. package/scripts/lib/site-content.mjs +124 -87
  110. package/scripts/lib/site-paths.mjs +2 -2
  111. package/scripts/lib/theme-config.mjs +9 -16
  112. package/scripts/lib/theme-presets.mjs +9 -1
  113. package/scripts/release.mjs +1 -1
  114. package/scripts/show-typography.mjs +26 -20
  115. package/scripts/sync-content-sections.mjs +106 -65
  116. package/scripts/{test-temporary-visibility.mjs → test-banner-visibility.mjs} +7 -24
  117. package/scripts/test-client-javascript.mjs +39 -42
  118. package/scripts/test-content-check.mjs +138 -54
  119. package/scripts/test-content-model-v2.mjs +445 -228
  120. package/scripts/test-documentation.mjs +6 -1
  121. package/scripts/test-editor-language-service.mjs +168 -24
  122. package/scripts/test-engine-commands.mjs +2 -1
  123. package/scripts/test-heading-ids.mjs +68 -0
  124. package/scripts/test-navigation-model.mjs +63 -0
  125. package/scripts/test-nested-pages.mjs +110 -0
  126. package/scripts/test-package-check.mjs +31 -40
  127. package/scripts/test-page-model.mjs +80 -0
  128. package/scripts/test-project-config.mjs +25 -1
  129. package/scripts/test-schemas.mjs +66 -14
  130. package/scripts/test-theme-presets.mjs +33 -24
  131. package/src/components/NavigationPageTree.astro +68 -0
  132. package/src/components/SectionNavigationScript.astro +110 -5
  133. package/src/components/SiteBreadcrumbs.astro +29 -0
  134. package/src/components/SiteNavigation.astro +65 -69
  135. package/src/components/SitePage.astro +70 -46
  136. package/src/components/SiteSection.astro +27 -20
  137. package/src/content.config.ts +9 -5
  138. package/src/layouts/BaseLayout.astro +11 -20
  139. package/src/lib/pageThemes.ts +42 -0
  140. package/src/lib/sectionContent.ts +109 -106
  141. package/src/lib/siteNavigation.ts +48 -0
  142. package/src/lib/sitePages.ts +85 -38
  143. package/src/pages/{[slug].astro → [...slug].astro} +2 -2
  144. package/src/styles/global.css +373 -55
  145. package/starters/basic/README.md +5 -7
  146. package/starters/basic/site/content.md +7 -4
  147. package/starters/basic/site/sitewide-content.yaml +1 -10
  148. package/starters/project/README.md +8 -8
  149. package/starters/project/site/content.md +5 -4
  150. package/starters/project/site/{routes → pages}/010-guide/content.md +5 -4
  151. package/starters/project/site/sitewide-content.yaml +1 -10
  152. package/docs/routes.md +0 -121
  153. package/examples/feature-demos/sitewide-content/site/routes/010-identity/content.md +0 -20
  154. package/fixtures/content-model-v2/site/routes/010-guide/content.md +0 -17
  155. package/scripts/lib/route-model.mjs +0 -17
  156. package/scripts/test-route-model.mjs +0 -32
  157. package/src/lib/routeThemes.ts +0 -41
  158. /package/examples/complete-sites/dog-shelter-multi-page/site/images/{intro/shelter-dog.jpg → shelter-dog.jpg} +0 -0
  159. /package/examples/complete-sites/dog-shelter-multi-page/site/{routes/010-dogs/images/dogs → pages/010-dogs/images}/rex.jpg +0 -0
  160. /package/examples/complete-sites/dog-shelter-multi-page/site/{routes/010-dogs/images/dogs → pages/010-dogs/images}/rover.jpg +0 -0
  161. /package/examples/complete-sites/dog-shelter-multi-page/site/{routes/020-adopt/images/adopt → pages/020-adopt/images}/adoption-dog.jpg +0 -0
  162. /package/examples/complete-sites/dog-shelter-single-page/site/images/{you-can-help/foster-dog.jpg → foster-dog.jpg} +0 -0
  163. /package/examples/complete-sites/dog-shelter-single-page/site/images/{what-we-do/rescue-dog.jpg → rescue-dog.jpg} +0 -0
  164. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/cards → pages/010-media/images}/card-carousel.svg +0 -0
  165. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/cards → pages/010-media/images}/card-stack.svg +0 -0
  166. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/cards → pages/010-media/images}/card-surfaces.svg +0 -0
  167. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/carousel → pages/010-media/images}/carousel-one.svg +0 -0
  168. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/carousel → pages/010-media/images}/carousel-three.svg +0 -0
  169. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/carousel → pages/010-media/images}/carousel-two.svg +0 -0
  170. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/stack → pages/010-media/images}/stack-one.svg +0 -0
  171. /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/stack → pages/010-media/images}/stack-two.svg +0 -0
  172. /package/examples/feature-demos/media-and-surfaces/site/{routes → pages}/020-surfaces/theme.yaml +0 -0
  173. /package/examples/feature-demos/theme-presets/site/{routes/010-portfolio/images/portfolio → pages/010-portfolio/images}/puppy-portrait.jpg +0 -0
  174. /package/examples/feature-demos/theme-presets/site/{routes/010-portfolio/images/portfolio → pages/010-portfolio/images}/shepherd-portrait.jpg +0 -0
  175. /package/examples/feature-demos/theme-presets/site/{routes/010-portfolio/images/portfolio → pages/010-portfolio/images}/white-puppy.jpg +0 -0
  176. /package/examples/feature-demos/theme-presets/site/{routes → pages}/010-portfolio/theme.yaml +0 -0
  177. /package/examples/feature-demos/theme-presets/site/{routes/020-documentation/images/documentation → pages/020-documentation/images}/black-schnauzer.jpg +0 -0
  178. /package/examples/feature-demos/theme-presets/site/{routes/020-documentation/images/documentation → pages/020-documentation/images}/retriever-portrait.jpg +0 -0
  179. /package/examples/feature-demos/theme-presets/site/{routes/020-documentation/images/documentation → pages/020-documentation/images}/schnauzer-portrait.jpg +0 -0
  180. /package/examples/feature-demos/theme-presets/site/{routes → pages}/020-documentation/theme.yaml +0 -0
  181. /package/examples/feature-demos/theme-presets/site/{routes/030-project/images/project → pages/030-project/images}/boxer-portrait.jpg +0 -0
  182. /package/examples/feature-demos/theme-presets/site/{routes/030-project/images/project → pages/030-project/images}/grass-puppy.jpg +0 -0
  183. /package/examples/feature-demos/theme-presets/site/{routes/030-project/images/project → pages/030-project/images}/grey-street-dog.jpg +0 -0
  184. /package/examples/feature-demos/theme-presets/site/{routes → pages}/030-project/theme.yaml +0 -0
  185. /package/examples/feature-demos/theme-presets/site/{routes/040-statement/images/statement → pages/040-statement/images}/black-pedigree.jpg +0 -0
  186. /package/examples/feature-demos/theme-presets/site/{routes/040-statement/images/statement → pages/040-statement/images}/sheepdog-grass.jpg +0 -0
  187. /package/examples/feature-demos/theme-presets/site/{routes/040-statement/images/statement → pages/040-statement/images}/sheepdog-wide.jpg +0 -0
  188. /package/examples/feature-demos/theme-presets/site/{routes → pages}/040-statement/theme.yaml +0 -0
  189. /package/fixtures/basic/site/images/{work/.gitkeep → .gitkeep} +0 -0
  190. /package/fixtures/content-model-v2/site/images/{card-section/adopt.svg → adopt.svg} +0 -0
  191. /package/fixtures/content-model-v2/site/images/{intro/detail.jpg → detail.jpg} +0 -0
  192. /package/fixtures/content-model-v2/site/images/{intro/duplicate.jpg → duplicate.jpg} +0 -0
  193. /package/fixtures/content-model-v2/site/images/{card-section/foster.svg → foster.svg} +0 -0
  194. /package/fixtures/content-model-v2/site/images/{intro/hero.jpg → hero.jpg} +0 -0
  195. /package/fixtures/content-model-v2/site/images/{plain/image.jpg → image.jpg} +0 -0
  196. /package/fixtures/content-model-v2/site/images/{timed/slide-one.jpg → slide-one.jpg} +0 -0
  197. /package/fixtures/content-model-v2/site/images/{timed/slide-three.jpg → slide-three.jpg} +0 -0
  198. /package/fixtures/content-model-v2/site/images/{timed/slide-two.jpg → slide-two.jpg} +0 -0
  199. /package/fixtures/content-model-v2/site/{routes/010-guide/images/intro → pages/010-guide/images}/duplicate.jpg +0 -0
  200. /package/starters/basic/site/images/{work/.gitkeep → .gitkeep} +0 -0
@@ -1,10 +1,11 @@
1
1
  ---
2
- title: Your project
3
- description: A compact project site starter for an open source developer tool.
4
- navigation:
5
- label: Home
2
+ page:
3
+ description: A compact project site starter for an open source developer tool.
6
4
  ---
7
5
 
6
+ # Your project
7
+
8
+
8
9
  ## `<Your project> - <short value proposition>` {#intro}
9
10
 
10
11
  Describe the project in one short, concrete phrase. Focus on what it helps the
@@ -1,10 +1,11 @@
1
1
  ---
2
- title: Guide
3
- description: Adapt this compact guide for normal project use.
4
- navigation:
5
- label: Guide
2
+ page:
3
+ description: Adapt this compact guide for normal project use.
6
4
  ---
7
5
 
6
+ # Guide
7
+
8
+
8
9
  ## Quickstart {#quickstart}
9
10
 
10
11
  Show the shortest path from installation to a useful result.
@@ -1,12 +1,3 @@
1
- navigation:
2
- label: Project Name
3
1
  footer:
4
2
  copyrightMessage: (c) Project contributors.
5
- buildInfo:
6
- enabled: true
7
- text: Built
8
- dateTimeFormat:
9
- locale: en-GB
10
- timeZone: UTC
11
- dateStyle: short
12
- timeStyle: short
3
+ buildInfo: true
package/docs/routes.md DELETED
@@ -1,121 +0,0 @@
1
- # Routes
2
-
3
- `site/content.md` is the homepage and builds to `/`. Optional route pages live
4
- under `site/routes/<NNN-route-id>/content.md` and build to first-level
5
- URLs.
6
-
7
- Routes use the same page frontmatter, optional section metadata, Norna-managed
8
- Norna blocks, and Markdown section model as the homepage. See [Content](content.md)
9
- for the page and section model.
10
-
11
- Route directories can contain route content, route-local images, and
12
- an optional route-local `theme.yaml`. The route theme replaces the root visual
13
- theme for that route and can select any complete top-level theme preset. Route
14
- directories cannot contain `config.yaml` or `sitewide-content.yaml`; technical
15
- configuration and shared identity remain at the selected site's top level.
16
-
17
- ## Route Directory Format
18
-
19
- Route directories must use:
20
-
21
- ```text
22
- NNN-route-id
23
- ```
24
-
25
- `NNN` is a three-digit presentation order from `001` through `999`.
26
- `route-id` becomes the route identity and URL segment.
27
-
28
- Valid examples:
29
-
30
- ```text
31
- 010-getting-started
32
- 020-concepts
33
- 120-api-reference
34
- ```
35
-
36
- Invalid examples:
37
-
38
- ```text
39
- 10-about
40
- 000-home
41
- 010_About
42
- 010-About
43
- 010-about-
44
- 010-about--team
45
- ```
46
-
47
- The route id may contain only lowercase `a-z`, numbers, and single hyphens
48
- between alphanumeric groups. The numeric prefix is not part of the route id or
49
- URL.
50
-
51
- Renaming `030-contact/` to `015-contact/` changes navigation order but keeps
52
- the route id `contact` and URL `/contact/`.
53
-
54
- ## Route File
55
-
56
- Add a first-level route by creating:
57
-
58
- ```text
59
- site/routes/010-about/content.md
60
- ```
61
-
62
- Minimal route page:
63
-
64
- ```md
65
- ---
66
- title: About
67
- description: About this site.
68
- navigation:
69
- label: About
70
- ---
71
-
72
- ## Intro {#intro}
73
-
74
- Text...
75
- ```
76
-
77
- The example above builds to `/about/`.
78
-
79
- ## Navigation
80
-
81
- `navigation` may contain:
82
-
83
- - `include`: optional boolean. Defaults to `true`.
84
- - `label`: optional string. Defaults to `title`.
85
-
86
- Route order comes from the directory prefix. The homepage is always first.
87
-
88
- Current route navigation is intended for small sites. This guidance may change
89
- as route support matures, but the present model is:
90
-
91
- - A single-page site should normally use only page navigation between sections.
92
- - A small multi-page site may use site navigation between routes plus page
93
- navigation between sections on the current page.
94
- - If a site needs many routes, deeply nested routes, or several navigation
95
- levels, it has probably outgrown the current sticky-navigation model and may
96
- need a different site structure or navigation system.
97
-
98
- ## Route Images
99
-
100
- Route images live under the physical route directory:
101
-
102
- ```text
103
- site/routes/010-about/images/intro/image.jpg
104
- ```
105
-
106
- Image references in route content still use only the filename:
107
-
108
- ````md
109
- ```norna-image-stack
110
- - image: image.jpg
111
- alt: Intro image.
112
- ```
113
- ````
114
-
115
- The image directory segment after `images/` should match the section id.
116
- If the section id or route folder changes, run `norna content:check` to find
117
- misplaced images and `norna content:sync` to move unambiguous files into the
118
- expected section folder. `content:sync` can move images between route image
119
- roots when the filename is unambiguous across the site and the move will not
120
- break another reference; these cross-route writes require a clean Git working
121
- tree.
@@ -1,20 +0,0 @@
1
- ---
2
- title: Identity
3
- description: See how a convention-based logo and shared identity work across a Norna site.
4
- navigation:
5
- label: Identity
6
- ---
7
-
8
- ## One identity across routes {#identity}
9
-
10
- The logo in the navigation is discovered from `public/logo.svg`. Its alt text
11
- and display height belong to `sitewide-content.yaml`, because the identity is
12
- shared by every route.
13
-
14
- If a site has no logo file, Norna shows the navigation label as text instead. A
15
- route cannot replace the shared navigation identity.
16
-
17
- ## Navigation context {#navigation}
18
-
19
- The route links come from the site's page structure. The shared logo returns to
20
- Home, while the active route is indicated in the same navigation row.
@@ -1,17 +0,0 @@
1
- ---
2
- title: Guide
3
- description: Internal route fixture for content model v2.
4
- navigation:
5
- label: Guide
6
- ---
7
-
8
- ## Intro {#intro}
9
-
10
- Routes may use the same section id and image filename as other pages without
11
- making the site invalid.
12
-
13
- ```norna-image-stack
14
- - image: duplicate.jpg
15
- alt: A route-local duplicated filename.
16
- caption: This file is resolved in the route image root.
17
- ```
@@ -1,17 +0,0 @@
1
- export const routeDirectoryPattern = /^(?!000)(\d{3})-([a-z0-9]+(?:-[a-z0-9]+)*)$/;
2
-
3
- export const parseRouteDirectory = (routeDirectory, label = 'route directory') => {
4
- const match = routeDirectory.match(routeDirectoryPattern);
5
-
6
- if (!match) {
7
- throw new Error(
8
- `Invalid ${label} "${routeDirectory}". Route directories must use the form NNN-route-id, for example 010-getting-started. The prefix must be 001-999 and route-id may contain only lowercase letters, numbers, and single hyphens.`,
9
- );
10
- }
11
-
12
- return {
13
- routeDirectory,
14
- routeOrder: Number.parseInt(match[1], 10),
15
- routeId: match[2],
16
- };
17
- };
@@ -1,32 +0,0 @@
1
- import assert from 'node:assert/strict';
2
- import { parseRouteDirectory } from './lib/route-model.mjs';
3
-
4
- assert.deepEqual(parseRouteDirectory('010-getting-started'), {
5
- routeDirectory: '010-getting-started',
6
- routeOrder: 10,
7
- routeId: 'getting-started',
8
- });
9
-
10
- assert.deepEqual(parseRouteDirectory('120-api-reference'), {
11
- routeDirectory: '120-api-reference',
12
- routeOrder: 120,
13
- routeId: 'api-reference',
14
- });
15
-
16
- for (const routeDirectory of [
17
- '000-home',
18
- '10-about',
19
- '010_About',
20
- '010-About',
21
- '010-about-',
22
- '010-about--team',
23
- '010-om-oss!',
24
- ]) {
25
- assert.throws(
26
- () => parseRouteDirectory(routeDirectory),
27
- /Route directories must use the form NNN-route-id/,
28
- `${routeDirectory} should be rejected`,
29
- );
30
- }
31
-
32
- console.log('Route model test passed.');
@@ -1,41 +0,0 @@
1
- import { readFile } from 'node:fs/promises';
2
- import path from 'node:path';
3
- import {
4
- validateRouteThemeYamlStructure,
5
- } from '../../scripts/lib/site-content.mjs';
6
- import { siteRoutesDir, siteRoutesLabel, sitewideContentLabel } from '../../scripts/lib/site-paths.mjs';
7
- import { parseYamlConfig } from '../../scripts/lib/yaml-config.mjs';
8
-
9
- type RouteTheme = {
10
- id: string;
11
- data: Record<string, unknown>;
12
- };
13
-
14
- export const getRouteTheme = async (routeDirectory: string | null): Promise<RouteTheme | null> => {
15
- if (!routeDirectory) return null;
16
-
17
- const segments = routeDirectory.split(/[\\/]/).filter(Boolean);
18
- for (let length = segments.length; length > 0; length -= 1) {
19
- const themeSegments = segments.slice(0, length);
20
- const themePath = path.join(siteRoutesDir, ...themeSegments, 'theme.yaml');
21
- const source = await readFile(themePath, 'utf8').catch((error) => {
22
- if (error?.code === 'ENOENT') return null;
23
- throw error;
24
- });
25
- if (!source) continue;
26
- const themeLabel = `${siteRoutesLabel}/${themeSegments.join('/')}/theme.yaml`;
27
-
28
- const data = parseYamlConfig(source, themeLabel, {
29
- validateStructure: validateRouteThemeYamlStructure,
30
- });
31
- if (Object.hasOwn(data, 'navigation')) {
32
- throw new Error(`${themeLabel} may not define navigation. The site label and logo settings belong in ${sitewideContentLabel}.`);
33
- }
34
- return {
35
- id: `routes/${themeSegments.join('/')}/theme`,
36
- data,
37
- };
38
- }
39
-
40
- return null;
41
- };