@shoalrun/cli 0.1.0-beta.1 → 1.1.0

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 (483) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/CODE-REFERENCES.md +156 -0
  3. package/README.md +18 -6
  4. package/adapters/python/requirements.txt +1 -0
  5. package/adapters/python/shoalrun_reference.py +234 -0
  6. package/adapters/typescript/README.md +27 -0
  7. package/adapters/typescript/shoalrun-reference.mjs +260 -0
  8. package/agent-docs/.well-known/shoalrun/navigation/project-updates-50f26fe22670.txt +6 -2
  9. package/agent-docs/SNAPSHOT.json +5 -5
  10. package/agent-docs/about.md +3 -3
  11. package/agent-docs/api-docs/code-reference-settings.md +160 -0
  12. package/agent-docs/api-docs/code-reference-settings.sections/catalog-settings.md +50 -0
  13. package/agent-docs/api-docs/code-reference-settings.sections/complete-reference-page.md +46 -0
  14. package/agent-docs/api-docs/code-reference-settings.sections/converter-snapshot.md +58 -0
  15. package/agent-docs/api-docs/code-reference-settings.sections/descriptions-type-links-and-source-links.md +40 -0
  16. package/agent-docs/api-docs/code-reference-settings.sections/html-markdown-and-agents.md +38 -0
  17. package/agent-docs/api-docs/code-reference-settings.sections/metadata-and-selection.md +38 -0
  18. package/agent-docs/api-docs/code-reference-settings.sections/publication-sources.md +54 -0
  19. package/agent-docs/api-docs/code-reference-settings.sections/python-adapter-limits.md +38 -0
  20. package/agent-docs/api-docs/code-reference-settings.sections/related-reading.md +32 -0
  21. package/agent-docs/api-docs/code-reference-settings.sections/symbol-fields.md +56 -0
  22. package/agent-docs/api-docs/code-references.md +151 -0
  23. package/agent-docs/api-docs/code-references.sections/a-real-typescript-example.md +38 -0
  24. package/agent-docs/api-docs/code-references.sections/add-python-source.md +56 -0
  25. package/agent-docs/api-docs/code-references.sections/before-you-start.md +40 -0
  26. package/agent-docs/api-docs/code-references.sections/build-and-verify.md +47 -0
  27. package/agent-docs/api-docs/code-references.sections/choose-the-reading-layout.md +46 -0
  28. package/agent-docs/api-docs/code-references.sections/extract-and-validate-a-snapshot.md +52 -0
  29. package/agent-docs/api-docs/code-references.sections/html-markdown-and-agents.md +42 -0
  30. package/agent-docs/api-docs/code-references.sections/register-the-catalog-and-navigation.md +58 -0
  31. package/agent-docs/api-docs/code-references.sections/related-reading.md +40 -0
  32. package/agent-docs/api-docs/code-references.sections/versions-profiles-and-delivery.md +40 -0
  33. package/agent-docs/api-docs/typescript-references.md +93 -0
  34. package/agent-docs/author/agent-overview.md +2 -2
  35. package/agent-docs/author/components/for-facet.md +127 -0
  36. package/agent-docs/author/components/only.md +3 -1
  37. package/agent-docs/author/components.md +2 -1
  38. package/agent-docs/author/reader-views.md +2 -2
  39. package/agent-docs/author/reader-views.sections/configure-the-choices.md +2 -2
  40. package/agent-docs/author/reader-views.sections/connect-your-own-control.md +2 -2
  41. package/agent-docs/author/reader-views.sections/how-it-works-for-agents.md +2 -2
  42. package/agent-docs/author/reader-views.sections/mark-pages.md +2 -2
  43. package/agent-docs/author/reader-views.sections/mark-sections-and-add-an-entry-choice.md +2 -2
  44. package/agent-docs/author/reader-views.sections/place-filter-controls.md +2 -2
  45. package/agent-docs/author/reader-views.sections/try-the-controls-here.md +2 -2
  46. package/agent-docs/changelog/code-api-references.md +44 -0
  47. package/agent-docs/changelog/facet-typescript.md +54 -0
  48. package/agent-docs/changelog.md +17 -1
  49. package/agent-docs/cli.md +11 -1
  50. package/agent-docs/cli.sections/audit-a-project-and-api-sources.md +1 -1
  51. package/agent-docs/cli.sections/author-pages.md +1 -1
  52. package/agent-docs/cli.sections/build-and-serve.md +1 -1
  53. package/agent-docs/cli.sections/inspect-config-and-operations.md +1 -1
  54. package/agent-docs/cli.sections/npm-scripts-in-this-repository.md +1 -1
  55. package/agent-docs/cli.sections/related-reading.md +1 -1
  56. package/agent-docs/cli.sections/search-and-chat.md +1 -1
  57. package/agent-docs/cli.sections/start-a-project.md +1 -1
  58. package/agent-docs/cli.sections/validate-code-reference-snapshots.md +41 -0
  59. package/agent-docs/cli.sections/working-tree-authoring-tools.md +1 -1
  60. package/agent-docs/config/apis.md +5 -1
  61. package/agent-docs/config/examples.md +3 -3
  62. package/agent-docs/config/examples.sections/feature-showcase.md +3 -3
  63. package/agent-docs/config/examples.sections/minimal-site.md +2 -2
  64. package/agent-docs/config/examples.sections/multilingual-help-center.md +2 -2
  65. package/agent-docs/config/examples.sections/parcel-api-documentation.md +2 -2
  66. package/agent-docs/config/examples.sections/related-reading.md +2 -2
  67. package/agent-docs/config/examples.sections/shared-company-preset.md +2 -2
  68. package/agent-docs/config/outputs.md +12 -12
  69. package/agent-docs/config/outputs.sections/exports.md +12 -12
  70. package/agent-docs/config/outputs.sections/metadata.md +1 -1
  71. package/agent-docs/config/outputs.sections/pdf-output.md +1 -1
  72. package/agent-docs/config/outputs.sections/related-reading.md +1 -1
  73. package/agent-docs/config/site.md +17 -17
  74. package/agent-docs/config/site.sections/related-reading.md +1 -1
  75. package/agent-docs/config/site.sections/theme.md +1 -1
  76. package/agent-docs/config.md +2 -2
  77. package/agent-docs/configuration.md +2 -2
  78. package/agent-docs/configuration.sections/build-several-sites-from-shared-content.md +1 -1
  79. package/agent-docs/configuration.sections/change-inherited-lists-deliberately.md +1 -1
  80. package/agent-docs/configuration.sections/extract-a-section-with-include.md +1 -1
  81. package/agent-docs/configuration.sections/inspect-and-validate-changes.md +1 -1
  82. package/agent-docs/configuration.sections/related-reading.md +1 -1
  83. package/agent-docs/configuration.sections/separate-config-inheritance-from-page-metadata.md +1 -1
  84. package/agent-docs/configuration.sections/share-defaults-through-extends.md +1 -1
  85. package/agent-docs/configuration.sections/start-with-one-working-file.md +2 -2
  86. package/agent-docs/configuration.sections/understand-the-three-stages.md +1 -1
  87. package/agent-docs/configuration.sections/understand-where-paths-point.md +1 -1
  88. package/agent-docs/content-delivery/api.md +10 -2
  89. package/agent-docs/content-delivery/api.sections/errors.md +52 -0
  90. package/agent-docs/content-delivery/api.sections/generated-typescript-reference.md +36 -0
  91. package/agent-docs/content-delivery/api.sections/html-markdown-and-agents.md +36 -0
  92. package/agent-docs/content-delivery/api.sections/mount-html.md +42 -0
  93. package/agent-docs/content-delivery/api.sections/open-a-rest-source.md +55 -0
  94. package/agent-docs/content-delivery/api.sections/open-a-source.md +51 -0
  95. package/agent-docs/content-delivery/api.sections/read-a-snapshot.md +55 -0
  96. package/agent-docs/content-delivery/api.sections/related-reading.md +42 -0
  97. package/agent-docs/content-delivery/api.sections/validate-a-manifest.md +40 -0
  98. package/agent-docs/content-delivery/client.md +9 -1
  99. package/agent-docs/content-delivery/sdk/all.md +1772 -0
  100. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentanchor-exportedid.md +34 -0
  101. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentanchor-id.md +34 -0
  102. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentanchor-title.md +34 -0
  103. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentanchor.md +44 -0
  104. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentasset-mediatype.md +34 -0
  105. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentasset.md +40 -0
  106. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentdeliveryerror-code.md +34 -0
  107. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentdeliveryerror.md +46 -0
  108. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentdeliverylimits-manifestbytes.md +36 -0
  109. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentdeliverylimits-resourcebytes.md +36 -0
  110. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentdeliverylimits-resources.md +36 -0
  111. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentdeliverylimits.md +44 -0
  112. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contenterrorcode.md +32 -0
  113. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentfile-bytes.md +34 -0
  114. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentfile-digest.md +34 -0
  115. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentfile-path.md +34 -0
  116. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentfile.md +44 -0
  117. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentformat.md +32 -0
  118. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentlink-asset.md +34 -0
  119. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentlink-fragment.md +34 -0
  120. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentlink-href.md +34 -0
  121. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentlink-key.md +34 -0
  122. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentlink-kind.md +34 -0
  123. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentlink-query.md +34 -0
  124. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentlink-ref.md +34 -0
  125. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentlink.md +52 -0
  126. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentmanifest-assets.md +34 -0
  127. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentmanifest-diagnostics.md +34 -0
  128. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentmanifest-digest.md +34 -0
  129. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentmanifest-files.md +34 -0
  130. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentmanifest-kind.md +34 -0
  131. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentmanifest-publication.md +34 -0
  132. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentmanifest-publicbase.md +34 -0
  133. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentmanifest-resources.md +34 -0
  134. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentmanifest-review.md +34 -0
  135. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentmanifest-schemaversion.md +34 -0
  136. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentmanifest.md +68 -0
  137. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentmount-anchors.md +36 -0
  138. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentmount-links.md +36 -0
  139. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentmount-unmount.md +36 -0
  140. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentmount.md +49 -0
  141. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentpublication-channel.md +34 -0
  142. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentpublication-language.md +34 -0
  143. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentpublication-product.md +34 -0
  144. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentpublication-version.md +34 -0
  145. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentpublication.md +46 -0
  146. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentref.md +43 -0
  147. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentrefkey.md +42 -0
  148. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentrepresentation-anchors.md +34 -0
  149. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentrepresentation-links.md +34 -0
  150. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentrepresentation.md +42 -0
  151. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentresource-assets.md +34 -0
  152. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentresource-canonicalurl.md +34 -0
  153. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentresource-externaldependencies.md +34 -0
  154. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentresource-publication.md +36 -0
  155. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentresource-ref.md +36 -0
  156. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentresource-representations.md +36 -0
  157. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentresource-source.md +34 -0
  158. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentresource-summary.md +36 -0
  159. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentresource-title.md +36 -0
  160. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentresource-type.md +36 -0
  161. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentresource.md +65 -0
  162. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentresourcekey.md +42 -0
  163. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentrestentry-key.md +34 -0
  164. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentrestentry-resource.md +34 -0
  165. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentrestentry.md +42 -0
  166. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentresterror-error.md +34 -0
  167. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentresterror.md +43 -0
  168. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentresterrorcode.md +32 -0
  169. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentrestlist-publication.md +34 -0
  170. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentrestlist-resources.md +34 -0
  171. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentrestlist-revision.md +34 -0
  172. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentrestlist-schemaversion.md +34 -0
  173. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentrestlist.md +46 -0
  174. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentrestresource-key.md +34 -0
  175. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentrestresource-publication.md +34 -0
  176. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentrestresource-resource.md +34 -0
  177. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentrestresource-revision.md +34 -0
  178. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentrestresource-schemaversion.md +34 -0
  179. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentrestresource.md +48 -0
  180. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentresult-content.md +36 -0
  181. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentresult-format.md +36 -0
  182. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentresult-representation.md +36 -0
  183. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentresult-resource.md +36 -0
  184. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentresult-revision.md +36 -0
  185. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentresult.md +48 -0
  186. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentsnapshot-dispose.md +36 -0
  187. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentsnapshot-get.md +45 -0
  188. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentsnapshot-list.md +38 -0
  189. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentsnapshot-publication.md +36 -0
  190. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentsnapshot-revision.md +36 -0
  191. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-contentsnapshot.md +47 -0
  192. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-manifestcontentsourceoptions-fetch.md +36 -0
  193. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-manifestcontentsourceoptions-limits.md +36 -0
  194. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-manifestcontentsourceoptions-manifesturl.md +36 -0
  195. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-manifestcontentsourceoptions-signal.md +36 -0
  196. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-manifestcontentsourceoptions.md +46 -0
  197. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-mountcontent.md +48 -0
  198. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-openmanifestcontentsource.md +54 -0
  199. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-openrestcontentsource.md +44 -0
  200. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-restcontentsourceoptions-baseurl.md +36 -0
  201. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-restcontentsourceoptions-fetch.md +36 -0
  202. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-restcontentsourceoptions-limits.md +36 -0
  203. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-restcontentsourceoptions-publication.md +36 -0
  204. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-restcontentsourceoptions-revision.md +36 -0
  205. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-restcontentsourceoptions-signal.md +36 -0
  206. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-restcontentsourceoptions.md +50 -0
  207. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content-validatecontentmanifest.md +45 -0
  208. package/agent-docs/content-delivery/sdk/all.sections/shoalrun-content.md +65 -0
  209. package/agent-docs/content-delivery/sdk/content-anchor/exported-id.md +25 -0
  210. package/agent-docs/content-delivery/sdk/content-anchor/id.md +25 -0
  211. package/agent-docs/content-delivery/sdk/content-anchor/title.md +25 -0
  212. package/agent-docs/content-delivery/sdk/content-anchor.md +71 -0
  213. package/agent-docs/content-delivery/sdk/content-asset/media-type.md +25 -0
  214. package/agent-docs/content-delivery/sdk/content-asset.md +43 -0
  215. package/agent-docs/content-delivery/sdk/content-delivery-error/code.md +25 -0
  216. package/agent-docs/content-delivery/sdk/content-delivery-error.md +53 -0
  217. package/agent-docs/content-delivery/sdk/content-delivery-limits/manifest-bytes.md +27 -0
  218. package/agent-docs/content-delivery/sdk/content-delivery-limits/resource-bytes.md +27 -0
  219. package/agent-docs/content-delivery/sdk/content-delivery-limits/resources.md +27 -0
  220. package/agent-docs/content-delivery/sdk/content-delivery-limits.md +77 -0
  221. package/agent-docs/content-delivery/sdk/content-error-code.md +23 -0
  222. package/agent-docs/content-delivery/sdk/content-file/bytes.md +25 -0
  223. package/agent-docs/content-delivery/sdk/content-file/digest.md +25 -0
  224. package/agent-docs/content-delivery/sdk/content-file/path.md +25 -0
  225. package/agent-docs/content-delivery/sdk/content-file.md +71 -0
  226. package/agent-docs/content-delivery/sdk/content-format.md +23 -0
  227. package/agent-docs/content-delivery/sdk/content-link/asset.md +25 -0
  228. package/agent-docs/content-delivery/sdk/content-link/fragment.md +25 -0
  229. package/agent-docs/content-delivery/sdk/content-link/href.md +25 -0
  230. package/agent-docs/content-delivery/sdk/content-link/key.md +25 -0
  231. package/agent-docs/content-delivery/sdk/content-link/kind.md +25 -0
  232. package/agent-docs/content-delivery/sdk/content-link/query.md +25 -0
  233. package/agent-docs/content-delivery/sdk/content-link/ref.md +25 -0
  234. package/agent-docs/content-delivery/sdk/content-link.md +127 -0
  235. package/agent-docs/content-delivery/sdk/content-manifest/assets.md +25 -0
  236. package/agent-docs/content-delivery/sdk/content-manifest/diagnostics.md +25 -0
  237. package/agent-docs/content-delivery/sdk/content-manifest/digest.md +25 -0
  238. package/agent-docs/content-delivery/sdk/content-manifest/files.md +25 -0
  239. package/agent-docs/content-delivery/sdk/content-manifest/kind.md +25 -0
  240. package/agent-docs/content-delivery/sdk/content-manifest/public-base.md +25 -0
  241. package/agent-docs/content-delivery/sdk/content-manifest/publication.md +25 -0
  242. package/agent-docs/content-delivery/sdk/content-manifest/resources.md +25 -0
  243. package/agent-docs/content-delivery/sdk/content-manifest/review.md +25 -0
  244. package/agent-docs/content-delivery/sdk/content-manifest/schema-version.md +25 -0
  245. package/agent-docs/content-delivery/sdk/content-manifest.md +179 -0
  246. package/agent-docs/content-delivery/sdk/content-mount/anchors.md +27 -0
  247. package/agent-docs/content-delivery/sdk/content-mount/links.md +27 -0
  248. package/agent-docs/content-delivery/sdk/content-mount/unmount.md +27 -0
  249. package/agent-docs/content-delivery/sdk/content-mount.md +82 -0
  250. package/agent-docs/content-delivery/sdk/content-publication/channel.md +25 -0
  251. package/agent-docs/content-delivery/sdk/content-publication/language.md +25 -0
  252. package/agent-docs/content-delivery/sdk/content-publication/product.md +25 -0
  253. package/agent-docs/content-delivery/sdk/content-publication/version.md +25 -0
  254. package/agent-docs/content-delivery/sdk/content-publication.md +85 -0
  255. package/agent-docs/content-delivery/sdk/content-ref-key.md +34 -0
  256. package/agent-docs/content-delivery/sdk/content-ref.md +40 -0
  257. package/agent-docs/content-delivery/sdk/content-representation/anchors.md +25 -0
  258. package/agent-docs/content-delivery/sdk/content-representation/links.md +25 -0
  259. package/agent-docs/content-delivery/sdk/content-representation.md +57 -0
  260. package/agent-docs/content-delivery/sdk/content-resource/assets.md +25 -0
  261. package/agent-docs/content-delivery/sdk/content-resource/canonical-url.md +25 -0
  262. package/agent-docs/content-delivery/sdk/content-resource/external-dependencies.md +25 -0
  263. package/agent-docs/content-delivery/sdk/content-resource/publication.md +27 -0
  264. package/agent-docs/content-delivery/sdk/content-resource/ref.md +27 -0
  265. package/agent-docs/content-delivery/sdk/content-resource/representations.md +27 -0
  266. package/agent-docs/content-delivery/sdk/content-resource/source.md +25 -0
  267. package/agent-docs/content-delivery/sdk/content-resource/summary.md +27 -0
  268. package/agent-docs/content-delivery/sdk/content-resource/title.md +27 -0
  269. package/agent-docs/content-delivery/sdk/content-resource/type.md +27 -0
  270. package/agent-docs/content-delivery/sdk/content-resource-key.md +34 -0
  271. package/agent-docs/content-delivery/sdk/content-resource.md +192 -0
  272. package/agent-docs/content-delivery/sdk/content-rest-entry/key.md +25 -0
  273. package/agent-docs/content-delivery/sdk/content-rest-entry/resource.md +25 -0
  274. package/agent-docs/content-delivery/sdk/content-rest-entry.md +57 -0
  275. package/agent-docs/content-delivery/sdk/content-rest-error/error.md +25 -0
  276. package/agent-docs/content-delivery/sdk/content-rest-error-code.md +23 -0
  277. package/agent-docs/content-delivery/sdk/content-rest-error.md +46 -0
  278. package/agent-docs/content-delivery/sdk/content-rest-list/publication.md +25 -0
  279. package/agent-docs/content-delivery/sdk/content-rest-list/resources.md +25 -0
  280. package/agent-docs/content-delivery/sdk/content-rest-list/revision.md +25 -0
  281. package/agent-docs/content-delivery/sdk/content-rest-list/schema-version.md +25 -0
  282. package/agent-docs/content-delivery/sdk/content-rest-list.md +85 -0
  283. package/agent-docs/content-delivery/sdk/content-rest-resource/key.md +25 -0
  284. package/agent-docs/content-delivery/sdk/content-rest-resource/publication.md +25 -0
  285. package/agent-docs/content-delivery/sdk/content-rest-resource/resource.md +25 -0
  286. package/agent-docs/content-delivery/sdk/content-rest-resource/revision.md +25 -0
  287. package/agent-docs/content-delivery/sdk/content-rest-resource/schema-version.md +25 -0
  288. package/agent-docs/content-delivery/sdk/content-rest-resource.md +99 -0
  289. package/agent-docs/content-delivery/sdk/content-result/content.md +27 -0
  290. package/agent-docs/content-delivery/sdk/content-result/format.md +27 -0
  291. package/agent-docs/content-delivery/sdk/content-result/representation.md +27 -0
  292. package/agent-docs/content-delivery/sdk/content-result/resource.md +27 -0
  293. package/agent-docs/content-delivery/sdk/content-result/revision.md +27 -0
  294. package/agent-docs/content-delivery/sdk/content-result.md +114 -0
  295. package/agent-docs/content-delivery/sdk/content-snapshot/dispose.md +27 -0
  296. package/agent-docs/content-delivery/sdk/content-snapshot/get.md +36 -0
  297. package/agent-docs/content-delivery/sdk/content-snapshot/list.md +29 -0
  298. package/agent-docs/content-delivery/sdk/content-snapshot/publication.md +27 -0
  299. package/agent-docs/content-delivery/sdk/content-snapshot/revision.md +27 -0
  300. package/agent-docs/content-delivery/sdk/content-snapshot.md +123 -0
  301. package/agent-docs/content-delivery/sdk/exports.md +742 -0
  302. package/agent-docs/content-delivery/sdk/exports.sections/functions.md +30 -0
  303. package/agent-docs/content-delivery/sdk/exports.sections/members.md +47 -0
  304. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-contentanchor.md +41 -0
  305. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-contentasset.md +37 -0
  306. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-contentdeliveryerror.md +43 -0
  307. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-contentdeliverylimits.md +41 -0
  308. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-contenterrorcode.md +29 -0
  309. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-contentfile.md +41 -0
  310. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-contentformat.md +29 -0
  311. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-contentlink.md +49 -0
  312. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-contentmanifest.md +65 -0
  313. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-contentmount.md +46 -0
  314. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-contentpublication.md +43 -0
  315. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-contentref.md +40 -0
  316. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-contentrefkey.md +39 -0
  317. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-contentrepresentation.md +39 -0
  318. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-contentresource.md +62 -0
  319. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-contentresourcekey.md +39 -0
  320. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-contentrestentry.md +39 -0
  321. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-contentresterror.md +40 -0
  322. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-contentresterrorcode.md +29 -0
  323. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-contentrestlist.md +43 -0
  324. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-contentrestresource.md +45 -0
  325. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-contentresult.md +45 -0
  326. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-contentsnapshot.md +44 -0
  327. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-manifestcontentsourceoptions.md +43 -0
  328. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-mountcontent.md +45 -0
  329. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-openmanifestcontentsource.md +51 -0
  330. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-openrestcontentsource.md +41 -0
  331. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-restcontentsourceoptions.md +47 -0
  332. package/agent-docs/content-delivery/sdk/exports.sections/shoalrun-content-validatecontentmanifest.md +42 -0
  333. package/agent-docs/content-delivery/sdk/manifest-content-source-options/fetch.md +27 -0
  334. package/agent-docs/content-delivery/sdk/manifest-content-source-options/limits.md +27 -0
  335. package/agent-docs/content-delivery/sdk/manifest-content-source-options/manifest-url.md +27 -0
  336. package/agent-docs/content-delivery/sdk/manifest-content-source-options/signal.md +27 -0
  337. package/agent-docs/content-delivery/sdk/manifest-content-source-options.md +93 -0
  338. package/agent-docs/content-delivery/sdk/mount-content.md +46 -0
  339. package/agent-docs/content-delivery/sdk/open-manifest-content-source.md +51 -0
  340. package/agent-docs/content-delivery/sdk/open-rest-content-source.md +39 -0
  341. package/agent-docs/content-delivery/sdk/rest-content-source-options/base-url.md +28 -0
  342. package/agent-docs/content-delivery/sdk/rest-content-source-options/fetch.md +27 -0
  343. package/agent-docs/content-delivery/sdk/rest-content-source-options/limits.md +27 -0
  344. package/agent-docs/content-delivery/sdk/rest-content-source-options/publication.md +27 -0
  345. package/agent-docs/content-delivery/sdk/rest-content-source-options/revision.md +27 -0
  346. package/agent-docs/content-delivery/sdk/rest-content-source-options/signal.md +27 -0
  347. package/agent-docs/content-delivery/sdk/rest-content-source-options.md +125 -0
  348. package/agent-docs/content-delivery/sdk/validate-content-manifest.md +38 -0
  349. package/agent-docs/contribute/agent-skills.md +33 -6
  350. package/agent-docs/documents.json +7710 -530
  351. package/agent-docs/features.md +20 -18
  352. package/agent-docs/provenance.json +6 -6
  353. package/agent-docs/publish/api-references.md +3 -1
  354. package/agent-docs/publish/api-references.sections/author-the-reference-page.md +3 -1
  355. package/agent-docs/publish/api-references.sections/build-and-verify-the-output.md +3 -1
  356. package/agent-docs/publish/api-references.sections/inspect-the-machine-readable-contract.md +3 -1
  357. package/agent-docs/publish/api-references.sections/next-steps.md +3 -1
  358. package/agent-docs/publish/api-references.sections/preview-a-small-api-reference.md +3 -1
  359. package/agent-docs/publish/api-references.sections/put-the-spec-in-your-project.md +3 -1
  360. package/agent-docs/publish/api-references.sections/register-the-operation.md +3 -1
  361. package/agent-docs/publish/api-references.sections/related-reading.md +3 -1
  362. package/agent-docs/publish/api-references.sections/review-imported-content-before-publishing.md +3 -1
  363. package/agent-docs/publish/api-references.sections/what-readers-get.md +3 -1
  364. package/agent-docs/publish/content-export.md +3 -1
  365. package/agent-docs/publish/content-export.sections/assets-downloads-and-notices.md +1 -1
  366. package/agent-docs/publish/content-export.sections/check-the-result.md +1 -1
  367. package/agent-docs/publish/content-export.sections/inspect-the-manifest.md +1 -1
  368. package/agent-docs/publish/content-export.sections/prerequisites.md +1 -1
  369. package/agent-docs/publish/content-export.sections/related-reading.md +1 -1
  370. package/agent-docs/publish/content-export.sections/review-exported-api-material.md +1 -1
  371. package/agent-docs/publish/content-export.sections/try-the-help-drawer-example.md +1 -1
  372. package/agent-docs/publish/content-export.sections/what-the-representations-retain.md +1 -1
  373. package/agent-docs/publish/pdf.md +2 -2
  374. package/agent-docs/publish/pdf.sections/apply-print-styling.md +1 -1
  375. package/agent-docs/publish/pdf.sections/check-the-result.md +1 -1
  376. package/agent-docs/publish/pdf.sections/export-a-page-or-publication.md +2 -2
  377. package/agent-docs/publish/pdf.sections/html-markdown-and-agents.md +1 -1
  378. package/agent-docs/publish/pdf.sections/offer-browser-page-printing.md +1 -1
  379. package/agent-docs/publish/pdf.sections/offer-direct-downloads-through-a-node-server.md +1 -1
  380. package/agent-docs/publish/pdf.sections/prerequisites.md +1 -1
  381. package/agent-docs/publish/pdf.sections/publish-an-optional-manual-download.md +1 -1
  382. package/agent-docs/publish/single-source-sites.md +26 -2
  383. package/agent-docs/publish/single-source-sites.sections/build-and-check-each-output.md +49 -0
  384. package/agent-docs/publish/single-source-sites.sections/html-markdown-and-agents.md +33 -0
  385. package/agent-docs/publish/single-source-sites.sections/include-additional-sections-in-a-build.md +47 -0
  386. package/agent-docs/publish/single-source-sites.sections/related-reading.md +43 -0
  387. package/agent-docs/publish/single-source-sites.sections/select-the-pages-for-each-site.md +74 -0
  388. package/agent-docs/publish/single-source-sites.sections/share-the-base-configuration.md +93 -0
  389. package/agent-docs/reference/agent-skills.md +2 -2
  390. package/agent-docs/search-index.json +1 -1
  391. package/agent-docs/start.md +3 -3
  392. package/agent-docs/start.sections/add-the-page-to-navigation.md +2 -2
  393. package/agent-docs/start.sections/build-and-check-both-outputs.md +2 -2
  394. package/agent-docs/start.sections/build-this-site.md +2 -2
  395. package/agent-docs/start.sections/check-writing-style.md +2 -2
  396. package/agent-docs/start.sections/create-a-page.md +2 -2
  397. package/agent-docs/start.sections/make-it-yours.md +2 -2
  398. package/agent-docs/start.sections/migrating-from-github-packages.md +2 -2
  399. package/agent-docs/start.sections/prerequisites.md +2 -2
  400. package/agent-docs/start.sections/related-reading.md +2 -2
  401. package/agent-docs/start.sections/start-your-own-project.md +3 -3
  402. package/agent-docs/status.md +6 -4
  403. package/agent-docs/styling/themes.md +7 -3
  404. package/agent-docs/what-is-shoalrun.md +2 -2
  405. package/assets/search-lexical.js +15 -4
  406. package/dist/artifact-bundle.d.ts +1 -0
  407. package/dist/artifact-bundle.js +11 -3
  408. package/dist/cli-discovery.d.ts +1 -1
  409. package/dist/cli-discovery.js +1 -0
  410. package/dist/cli.js +7 -0
  411. package/dist/code-reference-model.d.ts +85 -0
  412. package/dist/code-reference-model.js +73 -0
  413. package/dist/code-references.d.ts +23 -0
  414. package/dist/code-references.js +371 -0
  415. package/dist/compiler-config.d.ts +1 -0
  416. package/dist/compiler.d.ts +8 -0
  417. package/dist/compiler.js +14 -7
  418. package/dist/component-names.js +1 -1
  419. package/dist/component-transform.js +14 -22
  420. package/dist/conditional-tree.d.ts +2 -0
  421. package/dist/conditional-tree.js +14 -0
  422. package/dist/config.js +1 -1
  423. package/dist/content-delivery-contract.d.ts +39 -0
  424. package/dist/content-delivery-contract.js +2 -0
  425. package/dist/content-delivery-validation.d.ts +6 -0
  426. package/dist/content-delivery-validation.js +6 -0
  427. package/dist/content-delivery.d.ts +19 -1
  428. package/dist/content-delivery.js +10 -1
  429. package/dist/content-export-command.d.ts +42 -3
  430. package/dist/content-export.d.ts +42 -3
  431. package/dist/content-export.js +15 -6
  432. package/dist/content-filter.d.ts +2 -0
  433. package/dist/content-filter.js +4 -0
  434. package/dist/content-mount.d.ts +12 -1
  435. package/dist/content-mount.js +8 -1
  436. package/dist/content-rest-client.d.ts +11 -1
  437. package/dist/content-rest-client.js +4 -1
  438. package/dist/content-rest-contract.d.ts +5 -0
  439. package/dist/content-source.d.ts +2 -0
  440. package/dist/content-workspace.d.ts +5 -1
  441. package/dist/content-workspace.js +7 -2
  442. package/dist/deployment-profile.d.ts +3 -1
  443. package/dist/deployment-profile.js +18 -19
  444. package/dist/fonts.d.ts +9 -0
  445. package/dist/fonts.js +58 -3
  446. package/dist/page-materialization.js +3 -2
  447. package/dist/page-renderer.d.ts +1 -0
  448. package/dist/page-renderer.js +3 -1
  449. package/dist/palettes.d.ts +1 -1
  450. package/dist/publication-manifest.js +1 -1
  451. package/dist/publication-render.d.ts +2 -1
  452. package/dist/publication-render.js +2 -2
  453. package/dist/representation-tree.js +12 -2
  454. package/dist/search-query.js +13 -6
  455. package/dist/section-selection.d.ts +29 -0
  456. package/dist/section-selection.js +92 -0
  457. package/dist/snippets.d.ts +1 -0
  458. package/example-configs/facet-sections/README.md +37 -0
  459. package/example-configs/facet-sections/base.yaml +29 -0
  460. package/example-configs/facet-sections/content/billing.mdx +25 -0
  461. package/example-configs/facet-sections/customer.config.yaml +4 -0
  462. package/example-configs/facet-sections/docs.config.yaml +3 -0
  463. package/example-configs/faceted-sites/README.md +4 -2
  464. package/examples/code-references/content/start.md +53 -0
  465. package/examples/code-references/docs.config.yaml +262 -0
  466. package/examples/code-references/python/orchard/__init__.py +11 -0
  467. package/examples/code-references/python/orchard/client.py +212 -0
  468. package/examples/code-references/python/orchard/errors.py +31 -0
  469. package/examples/code-references/python/orchard/models.py +69 -0
  470. package/examples/code-references/python/orchard/pagination.py +39 -0
  471. package/examples/code-references/reference.json +1244 -0
  472. package/package.json +9 -1
  473. package/schemas/code-reference.schema.json +306 -0
  474. package/skills/shoalrun-author/SKILL.md +17 -0
  475. package/skills/shoalrun-author/references/code-api-references.md +19 -0
  476. package/skills/shoalrun-author/references/facet-selection.md +48 -0
  477. package/skills/shoalrun-brand/SKILL.md +9 -0
  478. package/skills/shoalrun-component-author/SKILL.md +9 -0
  479. package/skills/shoalrun-pdf/SKILL.md +9 -0
  480. package/skills/shoalrun-recipes/SKILL.md +9 -0
  481. package/skills/shoalrun-setup/SKILL.md +9 -0
  482. package/skills/shoalrun-walkthrough/SKILL.md +9 -0
  483. package/styles/site.css +61 -2
@@ -1,18 +1,22 @@
1
+ import { createSectionSelection } from './section-selection.js';
1
2
  import { documentKey } from './publication-identity.js';
2
3
  import { matchesFeatures } from './deployment-profile.js';
3
4
  import path from 'node:path';
4
5
  import { readFile } from 'node:fs/promises';
5
6
  import { parse } from './content.js';
6
7
  import { planAuthoredDocuments } from './publication-plan.js';
8
+ import { materializeCodeReferences } from './code-references.js';
7
9
  import { materializeApiReferences } from './api-publication-plan.js';
8
10
  import { explainSegments } from './config.js';
9
11
  import { validateSnippetConfig } from './snippets.js';
10
12
  const keyFor = documentKey;
11
13
  /** Shared source resolution. No website navigation, styles, hosting or provider setup. */
12
- export async function prepareContentWorkspace({ base, basePath, config, loaded, variants, language, readerFilters, contentFilter, metadataProvider, metadataDependencies, sourceOverrides, authoringFiles, allowRouteCollisions }) {
14
+ export async function prepareContentWorkspace({ base, basePath, config, loaded, variants, language, readerFilters, contentFilter, metadataProvider, metadataDependencies, sourceOverrides, authoringFiles, allowRouteCollisions, sectionSelection: suppliedSectionSelection }) {
15
+ const sectionSelection = suppliedSectionSelection ?? createSectionSelection(readerFilters, contentFilter, config.publications);
13
16
  const { docs, knownDocumentIds, knownDocumentTypes, authoredOperationIds, routeOwners, contentDir } = await planAuthoredDocuments({
14
17
  base, basePath, config, variants, language, readerFilters, contentFilter, featureContext: loaded.deployment?.context, metadataProvider, metadataDependencies, sourceOverrides, authoringFiles, allowRouteCollisions
15
18
  });
19
+ await materializeCodeReferences({ config, loaded, plan: { docs, knownDocumentIds, knownDocumentTypes, authoredOperationIds, routeOwners, contentDir }, base, basePath, variants, language, readerFilters, contentFilter, dependencies: metadataDependencies, allowRouteCollisions });
16
20
  if (config.snippets !== undefined && (!config.snippets || typeof config.snippets !== 'object' || Array.isArray(config.snippets)))
17
21
  throw new Error('snippets must be a mapping');
18
22
  const snippets = new Map();
@@ -32,6 +36,7 @@ export async function prepareContentWorkspace({ base, basePath, config, loaded,
32
36
  });
33
37
  const { api, sourceForVariant, knownOperations } = apiPlan;
34
38
  for (const [key, doc] of docs) {
39
+ doc.sectionSelection = sectionSelection;
35
40
  doc.featureContext = loaded.deployment?.context;
36
41
  for (const operationId of doc.frontmatter.operations ?? []) {
37
42
  const known = knownOperations.get(operationId);
@@ -82,6 +87,6 @@ export async function prepareContentWorkspace({ base, basePath, config, loaded,
82
87
  throw new Error(`no OpenAPI source for ${variant.channel}/${variant.version} (${operationId})`);
83
88
  return { ...binding, sourceOperationId: operation.sourceOperationId };
84
89
  };
85
- return { docs, knownDocumentIds, knownDocumentTypes, authoredOperationIds, routeOwners, contentDir, snippets,
90
+ return { sectionSelection, docs, knownDocumentIds, knownDocumentTypes, authoredOperationIds, routeOwners, contentDir, snippets,
86
91
  apiPlan, api, sourceForVariant, knownOperations, relatedApiTargets, guidesByApi, sourceForOperation };
87
92
  }
@@ -34,7 +34,9 @@ export type ProfileResolution = {
34
34
  export declare function validateFeatureClassification(source: Record<string, unknown>, context: FeatureContext | undefined, label: string): void;
35
35
  export declare function featureRequirements(value: unknown, context: FeatureContext | undefined, label: string): FeatureRequirements | undefined;
36
36
  export declare function matchesFeatures(value: unknown, context: FeatureContext | undefined, label: string, kind?: 'page' | 'section'): boolean;
37
- /** Validate every condition, but never resolve a dependency in an excluded branch. */
37
+ /** Evaluate a feature guard without expanding its children. */
38
+ export declare function evaluateFeatureGuard(node: any, context: FeatureContext | undefined, file: string, ancestorIncluded?: boolean, record?: boolean): boolean | undefined;
39
+ /** Compatibility entry point for consumers that only select feature grants. */
38
40
  export declare function pruneFeatureTree(tree: any, context: FeatureContext | undefined, file: string): any;
39
41
  /** Returned to the caller or written under .shoalrun, never a served artifact. */
40
42
  export declare function profileSelection(resolution: ProfileResolution | undefined): {
@@ -1,3 +1,4 @@
1
+ import { pruneConditionalTree } from './conditional-tree.js';
1
2
  import { resolvePublication } from './compiler-config.js';
2
3
  import { publicationKey } from './publication-identity.js';
3
4
  import { readFile, lstat, realpath } from 'node:fs/promises';
@@ -69,26 +70,24 @@ export function matchesFeatures(value, context, label, kind = 'page') {
69
70
  context?.decisions.push({ kind, id: label, included, ...(requirement ? { requires: requirement } : {}) });
70
71
  return included;
71
72
  }
72
- /** Validate every condition, but never resolve a dependency in an excluded branch. */
73
+ /** Evaluate a feature guard without expanding its children. */
74
+ export function evaluateFeatureGuard(node, context, file, ancestorIncluded = true, record = true) {
75
+ if (node.name !== 'ForFeature')
76
+ return;
77
+ const label = `${file}:${node.position?.start?.line ?? 1}: <ForFeature>`;
78
+ const attributes = node.attributes ?? [];
79
+ if (node.type !== 'mdxJsxFlowElement' || !node.children?.length || !attributes.length || attributes.some((item) => item.type !== 'mdxJsxAttribute' || !['allOf', 'anyOf'].includes(item.name) || typeof item.value !== 'string') || new Set(attributes.map((item) => item.name)).size !== attributes.length)
80
+ throw new Error(`${label} needs block content and distinct literal allOf/anyOf attributes`);
81
+ const requirements = Object.fromEntries(attributes.map((item) => [item.name, item.value.trim().split(/\s+/).filter(Boolean)]));
82
+ const target = !record && context ? { ...context, decisions: [] } : context;
83
+ const included = matchesFeatures(requirements, target, label, 'section');
84
+ if (!ancestorIncluded && target?.decisions.length)
85
+ target.decisions[target.decisions.length - 1].included = false;
86
+ return included;
87
+ }
88
+ /** Compatibility entry point for consumers that only select feature grants. */
73
89
  export function pruneFeatureTree(tree, context, file) {
74
- const walk = (node, parentIncluded = true) => {
75
- if (!node || typeof node !== 'object')
76
- return [node];
77
- if (node.name === 'ForFeature') {
78
- const label = `${file}:${node.position?.start?.line ?? 1}: <ForFeature>`;
79
- const attributes = node.attributes ?? [];
80
- if (node.type !== 'mdxJsxFlowElement' || !node.children?.length || !attributes.length || attributes.some((item) => item.type !== 'mdxJsxAttribute' || !['allOf', 'anyOf'].includes(item.name) || typeof item.value !== 'string') || new Set(attributes.map((item) => item.name)).size !== attributes.length)
81
- throw new Error(`${label} needs block content and distinct literal allOf/anyOf attributes`);
82
- const requirements = Object.fromEntries(attributes.map((item) => [item.name, item.value.trim().split(/\s+/).filter(Boolean)]));
83
- const included = matchesFeatures(requirements, context, label, 'section');
84
- if (!parentIncluded && context?.decisions.length)
85
- context.decisions[context.decisions.length - 1].included = false;
86
- const children = node.children.flatMap((child) => walk(child, parentIncluded && included));
87
- return included && parentIncluded ? children : [];
88
- }
89
- return [{ ...node, ...(node.children ? { children: node.children.flatMap((child) => walk(child, parentIncluded)) } : {}) }];
90
- };
91
- return walk(tree)[0];
90
+ return pruneConditionalTree(tree, (node, ancestorIncluded) => evaluateFeatureGuard(node, context, file, ancestorIncluded));
92
91
  }
93
92
  /** Returned to the caller or written under .shoalrun, never a served artifact. */
94
93
  export function profileSelection(resolution) {
package/dist/fonts.d.ts CHANGED
@@ -6,12 +6,18 @@ export type FontFace = {
6
6
  style: 'normal' | 'italic';
7
7
  weight: string;
8
8
  };
9
+ export type FontPreload = {
10
+ href: string;
11
+ type: string;
12
+ };
9
13
  export type SiteFonts = {
10
14
  bundled: boolean;
11
15
  faces: FontFace[];
12
16
  tokens: Partial<Record<FontRole, string>>;
13
17
  preload?: string;
18
+ preloadFaces?: FontFace[];
14
19
  };
20
+ export declare const fontMediaType: (file: string) => string | undefined;
15
21
  export declare const bundledFonts: readonly [{
16
22
  readonly family: "Inter";
17
23
  readonly file: "inter.woff2";
@@ -51,4 +57,7 @@ export declare const bundledFonts: readonly [{
51
57
  }];
52
58
  export declare const bundledFontLicenses: string[];
53
59
  export declare function resolveFonts(value: unknown, preset: string, declaringFile: string): SiteFonts;
60
+ /** Pin project font URLs to the same bytes that will be emitted by this build. */
61
+ export declare function prepareFontAssets(fonts: SiteFonts): Promise<Map<string, Buffer>>;
62
+ export declare function customFontPreloads(fonts: SiteFonts): FontPreload[];
54
63
  export declare function fontsCss(fonts: SiteFonts): string | undefined;
package/dist/fonts.js CHANGED
@@ -1,4 +1,7 @@
1
1
  import path from 'node:path';
2
+ import { readFile } from 'node:fs/promises';
3
+ import { createHash } from 'node:crypto';
4
+ export const fontMediaType = (file) => ({ '.woff2': 'font/woff2', '.woff': 'font/woff', '.ttf': 'font/ttf', '.otf': 'font/otf' }[path.extname(file).toLowerCase()]);
2
5
  // Latin variable fonts from Fontsource, all under the SIL Open Font License. Readers download only the faces a page uses.
3
6
  export const bundledFonts = [
4
7
  { family: 'Inter', file: 'inter.woff2', style: 'normal' },
@@ -22,7 +25,7 @@ const fallbackFaces = [
22
25
  { family: 'Jost', src: localSans, size: '95.84%', ascent: '111.65%', descent: '39.13%' }
23
26
  ];
24
27
  export const bundledFontLicenses = ['inter', 'figtree', 'source-serif-4', 'jetbrains-mono', 'jost'].map(name => `${name}-LICENSE.txt`);
25
- // The body font each preset preloads so the first paint uses it.
28
+ // Begin fetching the preset's body font before the browser discovers its CSS rule.
26
29
  const presetBodyFont = { shoal: 'inter.woff2', reef: 'figtree.woff2', ledger: 'source-serif-4.woff2', vice: 'figtree.woff2' };
27
30
  const fallbacks = {
28
31
  body: 'ui-sans-serif, system-ui, sans-serif',
@@ -45,6 +48,8 @@ export function resolveFonts(value, preset, declaringFile) {
45
48
  if (unknown.length)
46
49
  throw new Error(`theme.fonts accepts only body, headings, and code; remove ${unknown.join(', ')}`);
47
50
  const faces = [];
51
+ const preloadFaces = [];
52
+ const families = {};
48
53
  const tokens = {};
49
54
  for (const role of roles) {
50
55
  const entry = value[role];
@@ -56,6 +61,7 @@ export function resolveFonts(value, preset, declaringFile) {
56
61
  if (typeof spec.family !== 'string' || !familyName.test(spec.family))
57
62
  throw new Error(`theme.fonts.${role}.family must be a font name using letters, numbers, spaces, dots, dashes, or underscores`);
58
63
  const files = spec.files ?? [];
64
+ families[role] = spec.family;
59
65
  if (!Array.isArray(files))
60
66
  throw new Error(`theme.fonts.${role}.files must be a list`);
61
67
  for (const [index, item] of files.entries()) {
@@ -74,11 +80,60 @@ export function resolveFonts(value, preset, declaringFile) {
74
80
  const file = path.resolve(path.dirname(declaringFile), face.file);
75
81
  if (!/^[\w.-]+$/.test(path.basename(file)))
76
82
  throw new Error(`${where} file name may use only letters, numbers, dots, dashes, and underscores`);
77
- faces.push({ family: spec.family, file, route: `/assets/fonts/project/${path.basename(file)}`, style, weight });
83
+ const registration = { family: spec.family, file, route: `/assets/fonts/project/${path.basename(file)}`, style, weight };
84
+ faces.push(registration);
78
85
  }
79
86
  tokens[role] = `"${spec.family}", ${fallbacks[role]}`;
80
87
  }
81
- return { bundled: true, faces, tokens, preload: tokens.body ? undefined : presetBodyFont[preset] };
88
+ // CSS resolves style before weight and prefers the last equivalent registration.
89
+ const registrations = [...bundledFonts.map(font => ({ family: font.family, file: font.file, route: `/assets/fonts/${font.file}`, style: font.style, weight: '100 900' })), ...faces];
90
+ for (const role of ['body', 'headings']) {
91
+ if (!families[role])
92
+ continue;
93
+ const target = role === 'body' ? 400 : preset === 'vice' ? 800 : 700;
94
+ const style = role === 'headings' && preset === 'vice' ? 'italic' : 'normal';
95
+ const family = registrations.filter(face => face.family === families[role]);
96
+ const exactStyle = family.filter(face => face.style === style);
97
+ const rank = (face) => {
98
+ const [min, max = min] = face.weight.split(' ').map(Number);
99
+ if (min <= target && max >= target)
100
+ return [0, 0];
101
+ if (target >= 400 && target <= 500) {
102
+ if (min > target && min <= 500)
103
+ return [1, min - target];
104
+ return max < target ? [2, target - max] : [3, min - target];
105
+ }
106
+ if (target < 400)
107
+ return max < target ? [1, target - max] : [2, min - target];
108
+ return min > target ? [1, min - target] : [2, target - max];
109
+ };
110
+ const candidates = (exactStyle.length ? exactStyle : family).map((face, index) => ({ face, index, rank: rank(face) }));
111
+ candidates.sort((a, b) => a.rank[0] - b.rank[0] || a.rank[1] - b.rank[1] || b.index - a.index);
112
+ if (candidates[0])
113
+ preloadFaces.push(candidates[0].face);
114
+ }
115
+ return { bundled: true, faces, tokens, preload: tokens.body ? undefined : presetBodyFont[preset], preloadFaces };
116
+ }
117
+ /** Pin project font URLs to the same bytes that will be emitted by this build. */
118
+ export async function prepareFontAssets(fonts) {
119
+ const files = new Map();
120
+ const assets = new Map();
121
+ for (const face of fonts.faces) {
122
+ let bytes = files.get(face.file);
123
+ if (!bytes) {
124
+ bytes = await readFile(face.file);
125
+ files.set(face.file, bytes);
126
+ }
127
+ const extension = path.extname(face.file).toLowerCase();
128
+ const name = path.basename(face.file, path.extname(face.file));
129
+ const hash = createHash('sha256').update(bytes).digest('hex');
130
+ face.route = `/assets/fonts/project/${name}-${hash}${extension}`;
131
+ assets.set(face.route, bytes);
132
+ }
133
+ return assets;
134
+ }
135
+ export function customFontPreloads(fonts) {
136
+ return [...new Map((fonts.preloadFaces ?? []).map(face => [face.route, { href: face.route, type: fontMediaType(face.file) }])).values()];
82
137
  }
83
138
  const face = (family, url, style, weight, format) => `@font-face{font-family:"${family}";src:url("${url}") format("${format}");font-style:${style};font-weight:${weight};font-display:swap}`;
84
139
  export function fontsCss(fonts) {
@@ -1,3 +1,4 @@
1
+ import { renderCodeReference } from './code-references.js';
1
2
  import { documentKey, publicationKey } from './publication-identity.js';
2
3
  import { createHash } from 'node:crypto';
3
4
  import path from 'node:path';
@@ -28,8 +29,8 @@ export async function materializePages({ variables, frontmatterConfig, publicati
28
29
  for (const other of linkDocuments.values())
29
30
  if (keyFor(other.frontmatter.id, doc.variant) === keyFor(other.frontmatter.id, other.variant))
30
31
  local.set(other.frontmatter.id, other);
31
- const parsed = parse.parse(doc.body);
32
- const tree = await resolveApiEmbedTree(transformMdx(parsed, doc, local, snippets, variables, snippetUses, calloutTypes, base, readerFilters, frontmatterConfig, publications, badgeVariants, componentPlugins, linkDocuments), api, operationId => sourceForOperation(operationId, doc.variant), apiId => {
32
+ const parsed = doc.codeReference ? null : parse.parse(doc.body);
33
+ const tree = doc.codeReference ? renderCodeReference(doc.codeReference, doc, linkDocuments) : await resolveApiEmbedTree(transformMdx(parsed, doc, local, snippets, variables, snippetUses, calloutTypes, base, readerFilters, frontmatterConfig, publications, badgeVariants, componentPlugins, linkDocuments), api, operationId => sourceForOperation(operationId, doc.variant), apiId => {
33
34
  if (doc.featureContext?.grants)
34
35
  throw new Error('Standalone API schema embeds require an explicitly scoped source and are not supported in profiled builds; select an operation instead');
35
36
  const definition = apiPlan.apiDefinitions[apiId];
@@ -36,6 +36,7 @@ export type PageShell = {
36
36
  themeSwitcher?: string;
37
37
  fontsCss?: boolean;
38
38
  preloadFont?: string;
39
+ preloadFonts?: import('./fonts.js').FontPreload[];
39
40
  masthead?: string;
40
41
  share?: {
41
42
  route: string;
@@ -38,6 +38,8 @@ export function shareCardText(doc, config) {
38
38
  return { title, summary: String(summary), type: typeLabel(doc.frontmatter.type) };
39
39
  }
40
40
  export function typeLabel(type) {
41
+ if (type === 'code-reference')
42
+ return 'Code API reference';
41
43
  const words = String(type).split('-').filter(Boolean).map(word => word === 'api' ? 'API' : word);
42
44
  const label = words.join(' ');
43
45
  return label.charAt(0).toUpperCase() + label.slice(1);
@@ -192,6 +194,6 @@ export function buildHtmlPage(doc, tree, markdownUrl, siteTitle, navigation, exa
192
194
  const menu = side || sectionNavigation ? `<a class="mobile-menu" href="#${side ? 'docs-navigation' : 'docs-sections'}">Menu</a>` : '';
193
195
  const rail = toc || panel ? `<aside class="page-rail">${doc.endpoint ? `${panel}${toc}` : `${toc}${panel}`}</aside>` : '';
194
196
  const breadcrumbs = (shell.breadcrumbs?.length ?? 0) > 1 && !hero ? `<nav class="doc-breadcrumbs" aria-label="Breadcrumb"><ol>${shell.breadcrumbs.map((item, index) => `<li>${index === shell.breadcrumbs.length - 1 ? `<span aria-current="page">${esc(item.label)}</span>` : item.url ? `<a href="${esc(item.url)}">${esc(item.label)}</a>` : `<span>${esc(item.label)}</span>`}</li>`).join('')}</ol></nav>` : '';
195
- const markup = `<!doctype html><html lang="${esc(doc.variant.language)}"${shell.themeCss || shell.paletteCss ? ` data-theme="${esc(shell.preset ?? 'shoal')}" data-palette="${esc(shell.palette ?? '')}"` : ''}${shell.masthead ? ` data-masthead="${esc(shell.masthead)}"` : ''}${layout === 'docs' ? '' : ` data-layout="${layout}"`}><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="color-scheme" content="${shell.mode === 'system' ? 'light dark' : shell.mode ?? 'light'}">${shell.indexing === false || doc.frontmatter.seo?.noindex === true ? '<meta name="robots" content="noindex">' : ''}${shell.origin ? `<link rel="canonical" href="${esc(absolute(doc.route))}">` : ''}${shell.toggle ? '<script src="/assets/mode.js"></script>' : ''}<title>${esc(String(title))}</title>${description ? `<meta name="description" content="${esc(String(description))}">` : ''}${socialDescription ? `<meta property="og:description" content="${esc(socialDescription)}">` : ''}${social}<link rel="alternate" type="text/markdown" href="${esc(markdownUrl)}"><link rel="describedby" href="/llms.min.txt" title="Documentation index">${icons}${shell.preloadFont ? `<link rel="preload" href="/assets/fonts/${esc(shell.preloadFont)}" as="font" type="font/woff2" crossorigin>` : ''}<link rel="stylesheet" href="/assets/site.css">${article.includes('data-theme-preview') ? '<link rel="stylesheet" href="/assets/theme-preview.css">' : ''}${shell.themeCss ? '<link rel="stylesheet" href="/assets/theme.css" data-theme-link="theme">' : ''}${shell.paletteCss ? '<link rel="stylesheet" href="/assets/palette.css" data-theme-link="palette">' : ''}${shell.badgesCss ? '<link rel="stylesheet" href="/assets/badges.css">' : ''}${shell.themeSwitcher ? `<script src="/assets/theme-switcher.js" data-themes="${esc(shell.themeSwitcher)}"></script>` : ''}${shell.fontsCss ? '<link rel="stylesheet" href="/assets/fonts.css">' : ''}${customCss ? '<link rel="stylesheet" href="/assets/project.css">' : ''}</head><body><a class="skip" href="#main">Skip to content</a>${agent.mode === 'disclosure' ? '' : agentBlock}<header class="mast"><div class="mast-inner">${shell.home ? `<a class="${brandClass}" href="/">${brand}</a>` : `<span class="${brandClass}">${brand}</span>`}${publicationPicker(shell, esc)}${editionLabel && !shell.publicationChoices?.length && (shell.publicationAlternates?.length ?? 0) < 2 ? `<span class="edition">${esc(editionLabel)}</span>` : ''}${menu}${headerTools(shell, doc.variant, esc, readerConfig)}${agent.mode === 'disclosure' ? agentBlock : ''}</div></header>${sectionNavigation}${shortcuts}<div class="layout${layout === 'docs' ? '' : ` layout-${layout}`}${rail ? ' has-rail' : ''}${panel ? ' has-examples' : ''}${doc.endpoint ? ' api-reference' : ''}"><main id="main" class="content" tabindex="-1" data-document-type="${esc(doc.frontmatter.type)}"${readerConfig ? ` data-reader-page="${esc(readerFilterAttribute(doc.readerFilters ?? {}))}"` : ''}>${breadcrumbs}${hero ? '' : `<header class="page-head"><span class="eyebrow">${esc(typeLabel(doc.frontmatter.type))}</span>${doc.endpoint ? '' : badge(doc.frontmatter.subjectLifecycle)}<h1>${esc(doc.frontmatter.title)}${doc.endpoint ? badge(doc.frontmatter.subjectLifecycle) : ''}</h1>${pageHeader && !routeSummary ? `<p class="summary">${esc(pageHeader)}</p>` : ''}${pageDates}${endpoint}${audienceBadges}</header>`}${hero ? (pdfLink ? `<div class="page-formats">${pdfLink}</div>` : '') : `<div class="page-formats">${pdfAction?.placement === 'before' ? pdfLink : ''}<a class="formats" data-markdown-link href="${esc(markdownUrl)}">Read as Markdown</a><button type="button" class="formats" data-copy-markdown hidden>Copy as Markdown</button><span role="status" data-copy-markdown-status></span>${pdfAction?.placement === 'after' ? pdfLink : ''}</div>`}${toc ? '<div class="mobile-outline-slot"></div>' : ''}${jumps}${readerBanner}<article>${article}</article></main>${rail}${side}</div>${footer}${analyticsBootstrap}${readerBootstrap}${pdfAction?.mode === 'print' ? '<script type="module" src="/assets/print.js"></script>' : ''}<script type="module" src="/assets/copy-markdown.js"></script><script type="module" src="/assets/navigation.js"></script><script type="module" src="/assets/reader.js"></script><script type="module" src="/assets/tabs.js"></script>${shell.search ? '<script type="module" src="/assets/search.js"></script>' : ''}${article.includes('data-tooltip') ? '<script type="module" src="/assets/tooltips.js"></script>' : ''}${article.includes('data-component-module') ? '<script type="module" src="/assets/components.js"></script>' : ''}${article.includes('data-file-tree') ? '<script type="module" src="/assets/file-tree.js"></script>' : ''}${article.includes('data-image-expand') ? '<script type="module" src="/assets/image-viewer.js"></script>' : ''}${article.includes('data-table-filter') || article.includes('data-definition-filter') ? '<script type="module" src="/assets/table-filter.js"></script>' : ''}${article.includes('data-walkthrough') ? '<script type="module" src="/assets/walkthrough.js"></script>' : ''}${article.includes('data-cookbook-chooser') ? '<script type="module" src="/assets/cookbook-chooser.js"></script>' : ''}${article.includes('data-theme-preview') ? '<script type="module" src="/assets/theme-preview.js"></script>' : ''}${panel ? '<script type="module" src="/assets/example-panel.js"></script>' : ''}${panel.includes('data-code-samples') ? '<script type="module" src="/assets/code-samples.js"></script>' : ''}</body></html>`;
197
+ const markup = `<!doctype html><html lang="${esc(doc.variant.language)}"${shell.themeCss || shell.paletteCss ? ` data-theme="${esc(shell.preset ?? 'shoal')}" data-palette="${esc(shell.palette ?? '')}"` : ''}${shell.masthead ? ` data-masthead="${esc(shell.masthead)}"` : ''}${layout === 'docs' ? '' : ` data-layout="${layout}"`}><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="color-scheme" content="${shell.mode === 'system' ? 'light dark' : shell.mode ?? 'light'}">${shell.indexing === false || doc.frontmatter.seo?.noindex === true ? '<meta name="robots" content="noindex">' : ''}${shell.origin ? `<link rel="canonical" href="${esc(absolute(doc.route))}">` : ''}${shell.toggle ? '<script src="/assets/mode.js"></script>' : ''}<title>${esc(String(title))}</title>${description ? `<meta name="description" content="${esc(String(description))}">` : ''}${socialDescription ? `<meta property="og:description" content="${esc(socialDescription)}">` : ''}${social}<link rel="alternate" type="text/markdown" href="${esc(markdownUrl)}"><link rel="describedby" href="/llms.min.txt" title="Documentation index">${icons}${shell.preloadFont ? `<link rel="preload" href="/assets/fonts/${esc(shell.preloadFont)}" as="font" type="font/woff2" crossorigin>` : ''}${(shell.preloadFonts ?? []).map(font => `<link rel="preload" href="${esc(font.href)}" as="font" type="${esc(font.type)}" crossorigin>`).join('')}<link rel="stylesheet" href="/assets/site.css">${article.includes('data-theme-preview') ? '<link rel="stylesheet" href="/assets/theme-preview.css">' : ''}${shell.themeCss ? '<link rel="stylesheet" href="/assets/theme.css" data-theme-link="theme">' : ''}${shell.paletteCss ? '<link rel="stylesheet" href="/assets/palette.css" data-theme-link="palette">' : ''}${shell.badgesCss ? '<link rel="stylesheet" href="/assets/badges.css">' : ''}${shell.themeSwitcher ? `<script src="/assets/theme-switcher.js" data-themes="${esc(shell.themeSwitcher)}"></script>` : ''}${shell.fontsCss ? '<link rel="stylesheet" href="/assets/fonts.css">' : ''}${customCss ? '<link rel="stylesheet" href="/assets/project.css">' : ''}</head><body><a class="skip" href="#main">Skip to content</a>${agent.mode === 'disclosure' ? '' : agentBlock}<header class="mast"><div class="mast-inner">${shell.home ? `<a class="${brandClass}" href="/">${brand}</a>` : `<span class="${brandClass}">${brand}</span>`}${publicationPicker(shell, esc)}${editionLabel && !shell.publicationChoices?.length && (shell.publicationAlternates?.length ?? 0) < 2 ? `<span class="edition">${esc(editionLabel)}</span>` : ''}${menu}${headerTools(shell, doc.variant, esc, readerConfig)}${agent.mode === 'disclosure' ? agentBlock : ''}</div></header>${sectionNavigation}${shortcuts}<div class="layout${layout === 'docs' ? '' : ` layout-${layout}`}${rail ? ' has-rail' : ''}${panel ? ' has-examples' : ''}${doc.endpoint ? ' api-reference' : ''}"><main id="main" class="content" tabindex="-1" data-document-type="${esc(doc.frontmatter.type)}"${readerConfig ? ` data-reader-page="${esc(readerFilterAttribute(doc.readerFilters ?? {}))}"` : ''}>${breadcrumbs}${hero ? '' : `<header class="page-head"><span class="eyebrow">${esc(typeLabel(doc.frontmatter.type))}</span>${doc.endpoint ? '' : badge(doc.frontmatter.subjectLifecycle)}<h1>${esc(doc.frontmatter.title)}${doc.endpoint ? badge(doc.frontmatter.subjectLifecycle) : ''}</h1>${pageHeader && !routeSummary ? `<p class="summary">${esc(pageHeader)}</p>` : ''}${pageDates}${endpoint}${audienceBadges}</header>`}${hero ? (pdfLink ? `<div class="page-formats">${pdfLink}</div>` : '') : `<div class="page-formats">${pdfAction?.placement === 'before' ? pdfLink : ''}<a class="formats" data-markdown-link href="${esc(markdownUrl)}">Read as Markdown</a><button type="button" class="formats" data-copy-markdown hidden>Copy as Markdown</button><span role="status" data-copy-markdown-status></span>${pdfAction?.placement === 'after' ? pdfLink : ''}</div>`}${toc ? '<div class="mobile-outline-slot"></div>' : ''}${jumps}${readerBanner}<article>${article}</article></main>${rail}${side}</div>${footer}${analyticsBootstrap}${readerBootstrap}${pdfAction?.mode === 'print' ? '<script type="module" src="/assets/print.js"></script>' : ''}<script type="module" src="/assets/copy-markdown.js"></script><script type="module" src="/assets/navigation.js"></script><script type="module" src="/assets/reader.js"></script><script type="module" src="/assets/tabs.js"></script>${shell.search ? '<script type="module" src="/assets/search.js"></script>' : ''}${article.includes('data-tooltip') ? '<script type="module" src="/assets/tooltips.js"></script>' : ''}${article.includes('data-component-module') ? '<script type="module" src="/assets/components.js"></script>' : ''}${article.includes('data-file-tree') ? '<script type="module" src="/assets/file-tree.js"></script>' : ''}${article.includes('data-image-expand') ? '<script type="module" src="/assets/image-viewer.js"></script>' : ''}${article.includes('data-table-filter') || article.includes('data-definition-filter') ? '<script type="module" src="/assets/table-filter.js"></script>' : ''}${article.includes('data-walkthrough') ? '<script type="module" src="/assets/walkthrough.js"></script>' : ''}${article.includes('data-cookbook-chooser') ? '<script type="module" src="/assets/cookbook-chooser.js"></script>' : ''}${article.includes('data-theme-preview') ? '<script type="module" src="/assets/theme-preview.js"></script>' : ''}${panel ? '<script type="module" src="/assets/example-panel.js"></script>' : ''}${panel.includes('data-code-samples') ? '<script type="module" src="/assets/code-samples.js"></script>' : ''}</body></html>`;
196
198
  return basePath ? markup.replace(/((?:href|src)=")\/(assets\/|llms(?:\.min)?\.txt|apple-touch-icon\.png)/g, `$1${basePath}/$2`).replace('href="/"', `href="${basePath}/"`) : markup;
197
199
  }
@@ -1,4 +1,4 @@
1
- export declare const paletteTokens: readonly ["text", "page", "surface", "link", "link-hover", "focus", "ink", "accent", "accent-contrast", "header-muted", "header-border", "border", "border-soft", "border-nested", "field-surface", "field-border", "field-accent", "presence-bg", "presence-text", "optional-bg", "optional-text", "muted", "nav-heading", "section-heading", "nav-text", "nav-hover", "nav-active", "nav-active-text", "deprecated-bg", "deprecated-text", "beta-bg", "beta-text", "development-bg", "development-text", "experimental-bg", "experimental-text", "emphasis", "summary", "code-bg", "code-text", "code-muted", "code-border", "code-block", "callout-line", "callout-bg", ...("callout-note-line" | "callout-tip-line" | "callout-important-line" | "callout-warning-line" | "callout-caution-line" | "callout-note-bg" | "callout-tip-bg" | "callout-important-bg" | "callout-warning-bg" | "callout-caution-bg" | "callout-note-text" | "callout-tip-text" | "callout-important-text" | "callout-warning-text" | "callout-caution-text")[], "strong-surface", "strong-text"];
1
+ export declare const paletteTokens: readonly ["text", "page", "surface", "link", "link-hover", "focus", "ink", "accent", "accent-contrast", "header-muted", "header-border", "border", "border-soft", "border-nested", "field-surface", "field-border", "field-accent", "presence-bg", "presence-text", "optional-bg", "optional-text", "muted", "nav-heading", "section-heading", "nav-text", "nav-hover", "nav-active", "nav-active-text", "deprecated-bg", "deprecated-text", "beta-bg", "beta-text", "development-bg", "development-text", "experimental-bg", "experimental-text", "emphasis", "summary", "code-bg", "code-text", "code-muted", "code-border", "code-block", "callout-line", "callout-bg", ...("callout-warning-line" | "callout-note-line" | "callout-tip-line" | "callout-important-line" | "callout-caution-line" | "callout-warning-bg" | "callout-note-bg" | "callout-tip-bg" | "callout-important-bg" | "callout-caution-bg" | "callout-warning-text" | "callout-note-text" | "callout-tip-text" | "callout-important-text" | "callout-caution-text")[], "strong-surface", "strong-text"];
2
2
  export type Token = typeof paletteTokens[number];
3
3
  export type Mode = 'light' | 'dark';
4
4
  export type Palette = {
@@ -34,7 +34,7 @@ export function buildPublicationManifest({ configPublications, fictionalDocument
34
34
  ...(taxonomy ? { taxonomy } : {}),
35
35
  dependencies,
36
36
  ...(tabs.length ? { navigationTabs: tabs } : {}),
37
- documents: rendered.map(({ doc, markdown, sections }) => ({ id: doc.frontmatter.id, demo: fictionalDocuments.has(doc), type: doc.frontmatter.type, title: doc.frontmatter.title, summary: doc.frontmatter.summary, subjectLifecycle: doc.frontmatter.subjectLifecycle ?? null, ...(doc.change ? { change: doc.change } : {}), ...(doc.subjectDeprecation ? { subjectDeprecation: doc.subjectDeprecation } : {}), variant: doc.variant, url: doc.route, markdownUrl: doc.markdownRoute, ...tabFor(doc), indexable: indexable(doc), ...(updatedFor(doc) ? { updated: updatedFor(doc) } : {}), ...(doc.frontmatter.availability ? { availability: doc.frontmatter.availability } : {}), ...(doc.frontmatter.verified ? { verified: doc.frontmatter.verified } : {}), contentDigest: doc.contentDigest, breadcrumbs: navigationPath(resolvedNavigation.get(publicationKey(doc.variant)) ?? [], doc.route), ...(doc.frontmatter.product !== undefined ? { product: doc.frontmatter.product } : {}), ...(doc.frontmatter.area !== undefined ? { area: doc.frontmatter.area } : {}), ...(doc.frontmatter.subarea !== undefined ? { subarea: doc.frontmatter.subarea } : {}), ...(readerFilters ? { readerFilters: doc.readerFilters ?? {} } : {}), cardTargets: cardUses.get(doc)?.targets ?? [], cardQueries: cardUses.get(doc)?.queries ?? [], snippets: [...new Set(snippetUses.filter(use => use.documentId === doc.frontmatter.id).map(use => use.id))], apiEmbeds: apiEmbedUses.filter(use => use.documentKey === keyFor(doc.frontmatter.id, doc.variant)).map(({ sourceFile, documentKey, ...request }) => request), focusedContractUrl: doc.focusedContractUrl ?? null, focusedContractBytes: doc.focusedContractUrl ? focusedContracts.get(doc.focusedContractUrl)?.bytes : null, focusedContractDigest: doc.focusedContractUrl ? focusedContracts.get(doc.focusedContractUrl)?.digest : null, sections: (sections ?? []).map(({ content, ...record }) => record), ...markdownSize(markdown), digest: digest(markdown) })),
37
+ documents: rendered.map(({ doc, markdown, sections }) => ({ id: doc.frontmatter.id, demo: fictionalDocuments.has(doc), type: doc.frontmatter.type, title: doc.frontmatter.title, summary: doc.frontmatter.summary, subjectLifecycle: doc.frontmatter.subjectLifecycle ?? null, ...(doc.change ? { change: doc.change } : {}), ...(doc.subjectDeprecation ? { subjectDeprecation: doc.subjectDeprecation } : {}), variant: doc.variant, url: doc.route, markdownUrl: doc.markdownRoute, ...tabFor(doc), indexable: indexable(doc), ...(updatedFor(doc) ? { updated: updatedFor(doc) } : {}), ...(doc.frontmatter.availability ? { availability: doc.frontmatter.availability } : {}), ...(doc.frontmatter.verified ? { verified: doc.frontmatter.verified } : {}), contentDigest: doc.contentDigest, breadcrumbs: navigationPath(resolvedNavigation.get(publicationKey(doc.variant)) ?? [], doc.route), ...(doc.frontmatter.product !== undefined ? { product: doc.frontmatter.product } : {}), ...(doc.frontmatter.area !== undefined ? { area: doc.frontmatter.area } : {}), ...(doc.frontmatter.subarea !== undefined ? { subarea: doc.frontmatter.subarea } : {}), ...(readerFilters ? { readerFilters: doc.readerFilters ?? {} } : {}), cardTargets: cardUses.get(doc)?.targets ?? [], cardQueries: cardUses.get(doc)?.queries ?? [], snippets: [...new Set(snippetUses.filter(use => (use.documentKey ? use.documentKey === keyFor(doc.frontmatter.id, doc.variant) : use.documentId === doc.frontmatter.id)).map(use => use.id))], apiEmbeds: apiEmbedUses.filter(use => use.documentKey === keyFor(doc.frontmatter.id, doc.variant)).map(({ sourceFile, documentKey, ...request }) => request), focusedContractUrl: doc.focusedContractUrl ?? null, focusedContractBytes: doc.focusedContractUrl ? focusedContracts.get(doc.focusedContractUrl)?.bytes : null, focusedContractDigest: doc.focusedContractUrl ? focusedContracts.get(doc.focusedContractUrl)?.digest : null, sections: (sections ?? []).map(({ content, ...record }) => record), ...markdownSize(markdown), digest: digest(markdown) })),
38
38
  operations,
39
39
  relationships: publishedRelationships,
40
40
  redirects,
@@ -8,7 +8,7 @@ import type { ReaderFiltersConfig } from './reader-filters.js';
8
8
  import type { CodeHighlighter } from './highlight.js';
9
9
  import type { MaterializedPage } from './page-materialization.js';
10
10
  import type { ResolvedCompilerConfig, CompilerSiteConfig, CompilerPublicationsConfig } from './compiler-config.js';
11
- export declare function renderPublicationPages({ rendered, docs, relationships, knownOperations, cardUses, publishedRelationships, cookbooks, documentRoutes, basePath, siteOrigin, colorMode, config, highlighter, editionLabel, customStyleFile, themePreset, palette, themeStyleFile, generatedPaletteCss, generatedBadgeCss, themeSwitcherData, generatedFontsCss, fontsPreload, shareFor, faviconRoute, logoRoute, modeToggle, header, footer, search, readerFilters, variants, externalDocuments, externalSiteLinks, navigationSpec, navigationEntries, navigationTagOrder, freshness }: {
11
+ export declare function renderPublicationPages({ rendered, docs, relationships, knownOperations, cardUses, publishedRelationships, cookbooks, documentRoutes, basePath, siteOrigin, colorMode, config, highlighter, editionLabel, customStyleFile, themePreset, palette, themeStyleFile, generatedPaletteCss, generatedBadgeCss, themeSwitcherData, generatedFontsCss, fontsPreload, customFontPreloads, shareFor, faviconRoute, logoRoute, modeToggle, header, footer, search, readerFilters, variants, externalDocuments, externalSiteLinks, navigationSpec, navigationEntries, navigationTagOrder, freshness }: {
12
12
  freshness?: Freshness;
13
13
  rendered: MaterializedPage[];
14
14
  docs: Map<string, Document>;
@@ -41,6 +41,7 @@ export declare function renderPublicationPages({ rendered, docs, relationships,
41
41
  themeSwitcherData?: string;
42
42
  generatedFontsCss?: string;
43
43
  fontsPreload?: string;
44
+ customFontPreloads?: import('./fonts.js').FontPreload[];
44
45
  shareFor: (doc: Document) => {
45
46
  route: string;
46
47
  generated: boolean;
@@ -12,7 +12,7 @@ import { navigationPath, navigationTab, navigationTabRecord, resolveProjectNavig
12
12
  import { outputUrl, publicTree, resolveOutputLinks } from './representation-tree.js';
13
13
  import { presetCatalog } from './palettes.js';
14
14
  const keyFor = documentKey;
15
- export function renderPublicationPages({ rendered, docs, relationships, knownOperations, cardUses, publishedRelationships, cookbooks, documentRoutes, basePath, siteOrigin, colorMode, config, highlighter, editionLabel, customStyleFile, themePreset, palette, themeStyleFile, generatedPaletteCss, generatedBadgeCss, themeSwitcherData, generatedFontsCss, fontsPreload, shareFor, faviconRoute, logoRoute, modeToggle, header, footer, search, readerFilters, variants, externalDocuments, externalSiteLinks, navigationSpec, navigationEntries, navigationTagOrder, freshness }) {
15
+ export function renderPublicationPages({ rendered, docs, relationships, knownOperations, cardUses, publishedRelationships, cookbooks, documentRoutes, basePath, siteOrigin, colorMode, config, highlighter, editionLabel, customStyleFile, themePreset, palette, themeStyleFile, generatedPaletteCss, generatedBadgeCss, themeSwitcherData, generatedFontsCss, fontsPreload, customFontPreloads, shareFor, faviconRoute, logoRoute, modeToggle, header, footer, search, readerFilters, variants, externalDocuments, externalSiteLinks, navigationSpec, navigationEntries, navigationTagOrder, freshness }) {
16
16
  const resolvedNavigation = new Map();
17
17
  const selector = config.site.publicationSelector;
18
18
  if (selector !== undefined && (!isConfigMapping(selector) || Object.keys(selector).some(key => key !== 'showLanguage') || (selector.showLanguage !== undefined && typeof selector.showLanguage !== 'boolean')))
@@ -102,7 +102,7 @@ export function renderPublicationPages({ rendered, docs, relationships, knownOpe
102
102
  const group = variant.product === undefined ? config.site.title : config.publications.products?.[variant.product]?.label ?? variant.product;
103
103
  return [{ group, label: `${group} · ${variant.channel} · ${variant.version}${showLanguage ? ` · ${variant.language}` : ''}`, url: target.route, current: samePublication(page.doc.variant, variant) }];
104
104
  }) : [];
105
- page.html = buildHtmlPage(page.doc, page.htmlTree, page.doc.markdownRoute, config.site.title, navigation, page.pageExamples, page.pageShapes, highlighter, editionLabel(page.doc.variant), !!customStyleFile, { preset: themePreset, palette: palette.name, themeCss: !!themeStyleFile, paletteCss: !!generatedPaletteCss, badgesCss: !!generatedBadgeCss, themeSwitcher: themeSwitcherData, fontsCss: !!generatedFontsCss, preloadFont: fontsPreload, masthead: presetCatalog.find(preset => preset.name === themePreset)?.masthead, share: shareFor(page.doc), favicon: faviconRoute, logo: logoRoute, touchIcon: !faviconRoute.endsWith('.png'), origin: siteOrigin, indexing: config.site.indexing !== false, home: hasHome, mode: colorMode, toggle: modeToggle, header, footer, search: search.provider !== 'none', publicationChoices, publicationAlternates, breadcrumbs }, page.pageCurl, page.pageSamples, { ...config, readerFilters });
105
+ page.html = buildHtmlPage(page.doc, page.htmlTree, page.doc.markdownRoute, config.site.title, navigation, page.pageExamples, page.pageShapes, highlighter, editionLabel(page.doc.variant), !!customStyleFile, { preset: themePreset, palette: palette.name, themeCss: !!themeStyleFile, paletteCss: !!generatedPaletteCss, badgesCss: !!generatedBadgeCss, themeSwitcher: themeSwitcherData, fontsCss: !!generatedFontsCss, preloadFont: fontsPreload, preloadFonts: customFontPreloads, masthead: presetCatalog.find(preset => preset.name === themePreset)?.masthead, share: shareFor(page.doc), favicon: faviconRoute, logo: logoRoute, touchIcon: !faviconRoute.endsWith('.png'), origin: siteOrigin, indexing: config.site.indexing !== false, home: hasHome, mode: colorMode, toggle: modeToggle, header, footer, search: search.provider !== 'none', publicationChoices, publicationAlternates, breadcrumbs }, page.pageCurl, page.pageSamples, { ...config, readerFilters });
106
106
  }
107
107
  return resolvedNavigation;
108
108
  }
@@ -20,8 +20,14 @@ export function publicTree(tree, representation, documentRoutes, mode = 'light',
20
20
  element('div', { 'data-component-content': '' }, children)
21
21
  ])];
22
22
  }
23
- if (node.type === 'docRepresentation')
24
- return node.representation === representation ? node.children.flatMap(walk) : [];
23
+ if (node.type === 'docRepresentation') {
24
+ if (node.representation !== representation)
25
+ return [];
26
+ const children = node.children.flatMap(walk);
27
+ // Mark HTML-only content so agent-parity checks can distinguish intentional
28
+ // format-specific prose from accidental content loss in the Markdown twin.
29
+ return representation === 'html' ? [element('div', { 'data-markdown-ignore': '' }, children)] : children;
30
+ }
25
31
  if (node.type === 'docCookbookChooser') {
26
32
  const prompt = node.mode === 'single' ? 'Choose one recipe.' : 'Choose one or more recipes.';
27
33
  const details = (option) => [option.when ? `Use when: ${option.when}` : option.summary, option.needs ? `You need: ${option.needs}` : '', option.outcome ? `You will have: ${option.outcome}` : ''].filter(Boolean);
@@ -66,6 +72,10 @@ export function publicTree(tree, representation, documentRoutes, mode = 'light',
66
72
  if (node.type === 'docReaderFilter') {
67
73
  return representation === 'markdown' ? [] : [element('div', { className: ['reader-filter-slot'], 'data-reader-filter': JSON.stringify(node.control) }, [])];
68
74
  }
75
+ if (node.type === 'table' && node.data?.referenceTableLabel && representation === 'html') {
76
+ const table = { ...node, children: node.children.flatMap(walk) };
77
+ return [element('div', { className: ['code-reference-table-scroll'], role: 'region', 'aria-label': node.data.referenceTableLabel, tabIndex: 0 }, [table])];
78
+ }
69
79
  if (node.type === 'docTable') {
70
80
  const table = node.children.flatMap(walk);
71
81
  if (representation === 'markdown')
@@ -64,7 +64,7 @@ export async function queryBuiltSite(directory, query, options = {}) {
64
64
  return [];
65
65
  const termScore = (term) => weight(title, term, title.startsWith(term.term) ? 12 : 8, true) || weight(summary, term, 4) || (headings.some(heading => match(heading, term)) ? 3 : 0) || weight(body, term, 1);
66
66
  let score = terms.reduce((total, term) => total + termScore(term), 0);
67
- const contentScore = terms.filter(term => !fallbackStopWords.has(term.term)).reduce((total, term) => total + termScore(term), 0);
67
+ let contentScore = terms.filter(term => !fallbackStopWords.has(term.term)).reduce((total, term) => total + termScore(term), 0);
68
68
  const prominentMatches = terms.filter(term => !fallbackStopWords.has(term.term) && (matchTitle(title, term) || match(summary, term) || headings.some(heading => match(heading, term)))).length;
69
69
  const section = terms.every(term => matchTitle(title, term)) ? undefined : doc.headings.find((heading, at) => terms.every(term => match(headings[at], term)));
70
70
  // Use only query terms with meaning, and require a unique matching section.
@@ -77,8 +77,10 @@ export async function queryBuiltSite(directory, query, options = {}) {
77
77
  // older indexes and unreviewed sections conservatively retain the full page.
78
78
  const selected = candidates.length === 1 && candidates[0].standalone === true ? candidates[0] : undefined;
79
79
  // A complete multiword section-title match outranks incidental page-title words.
80
- if (meaningful.length >= 2 && candidates.some(candidate => meaningful.every(term => match(candidate.title.toLocaleLowerCase(), term))))
80
+ if (meaningful.length >= 2 && candidates.some(candidate => meaningful.every(term => match(candidate.title.toLocaleLowerCase(), term)))) {
81
81
  score += 20;
82
+ contentScore += 20;
83
+ }
82
84
  const { product, channel, version, language } = parsePublicationKey(doc.variant);
83
85
  const tokens = selected?.markdownTokens ?? doc.markdownTokens;
84
86
  const read = { tool: selected ? 'get_section' : 'get_page', arguments: {
@@ -87,15 +89,20 @@ export async function queryBuiltSite(directory, query, options = {}) {
87
89
  } };
88
90
  return [{ score, contentScore, prominentMatches, matched: matched.length, partialMatched: matched.filter(term => !fallbackStopWords.has(term.term)).length, id: doc.id, type: doc.type, title: doc.title, summary: doc.summary, url: section ? `${doc.url}#${section.id}` : doc.url, markdownUrl: selected?.markdownUrl ?? doc.markdownUrl, pageMarkdownUrl: doc.markdownUrl, read, ...(tokens !== undefined ? { markdownTokens: tokens, markdownBytes: selected?.markdownBytes ?? doc.markdownBytes, markdownTokenEncoding: doc.markdownTokenEncoding } : {}), ...(selected || section ? { section: selected?.title ?? section?.title } : {}), snippet: excerpt(doc.text, terms.flatMap(unit => [unit.term, ...unit.alternatives])) }];
89
91
  });
90
- const complete = hits.filter(hit => hit.matched === terms.length);
92
+ const contentTerms = terms.filter(term => !fallbackStopWords.has(term.term)).length;
93
+ // Filler words shape the sentence, not the subject. A page that covers every
94
+ // content term is complete even when it omits "how", "do", or "the"; otherwise
95
+ // a page that happens to repeat filler words can hide the focused result.
96
+ const complete = contentTerms === 0
97
+ ? hits.filter(hit => hit.matched === terms.length)
98
+ : hits.filter(hit => hit.partialMatched === contentTerms);
91
99
  // Relax the all-words gate only when complete matches are entirely incidental
92
100
  // body matches. A near-complete result must cover all but one content term and
93
101
  // have a stronger non-filler field score. Title/summary/heading matches on any
94
102
  // complete result preserve the original preference; filler cannot earn promotion.
95
- const contentTerms = terms.filter(term => !fallbackStopWords.has(term.term)).length;
96
103
  const bestCompleteContent = Math.max(...complete.map(hit => hit.contentScore));
97
104
  const stronger = complete.length && contentTerms >= 3 && complete.every(hit => hit.prominentMatches === 0)
98
- ? hits.filter(hit => hit.matched < terms.length && hit.partialMatched >= contentTerms - 1
105
+ ? hits.filter(hit => hit.partialMatched < contentTerms && hit.partialMatched >= contentTerms - 1
99
106
  && hit.prominentMatches > 0 && hit.contentScore > bestCompleteContent) : [];
100
107
  const ranked = complete.length ? [...complete, ...stronger] : hits.filter(hit => hit.partialMatched > 0);
101
108
  // In partial fallback, one extra incidental word must not outweigh a focused
@@ -114,7 +121,7 @@ export async function queryBuiltSite(directory, query, options = {}) {
114
121
  if (aNear && a.contentScore !== b.contentScore)
115
122
  return b.contentScore - a.contentScore;
116
123
  }
117
- return (complete.length ? b.matched - a.matched : b.partialMatched - a.partialMatched) || b.score - a.score || a.title.localeCompare(b.title) || a.id.localeCompare(b.id);
124
+ return (complete.length ? b.contentScore - a.contentScore : b.partialMatched - a.partialMatched) || b.score - a.score || a.title.localeCompare(b.title) || a.id.localeCompare(b.id);
118
125
  });
119
126
  const publication = parsePublicationKey(variants[0]);
120
127
  return { status: 'ok', query: query.trim(), publication, total: ranked.length, matchMode: stronger.length ? 'mixed' : complete.length ? 'all' : 'partial', results: ranked.slice(0, limit).map(({ matched, partialMatched, contentScore, prominentMatches, ...result }) => result) };
@@ -0,0 +1,29 @@
1
+ import { type ReaderFiltersConfig, type ReaderSelection } from './reader-filters.js';
2
+ import type { CompilerPublicationsConfig } from './compiler-config.js';
3
+ import type { Document } from './content-source.js';
4
+ export type SectionSelection = {
5
+ facets?: ReaderFiltersConfig;
6
+ selection?: ReaderSelection;
7
+ decisions: Map<string, Record<string, unknown>>;
8
+ warnings: Map<string, {
9
+ code: string;
10
+ message: string;
11
+ }>;
12
+ hasConditions: boolean;
13
+ publications?: CompilerPublicationsConfig;
14
+ };
15
+ export declare function createSectionSelection(facets?: ReaderFiltersConfig, selection?: ReaderSelection, publications?: CompilerPublicationsConfig): SectionSelection;
16
+ /** Share publication validation with pruning so receipts reflect every build-time ancestor. */
17
+ export declare function evaluatePublicationGuard(node: any, doc: Document, file: string, publications?: CompilerPublicationsConfig): boolean | undefined;
18
+ export declare function pruneSelectedTree(tree: any, doc: Document, file?: string, record?: boolean): any;
19
+ export declare function warnReaderSection(doc: Document, file: string, line: number, requirements: ReaderSelection): void;
20
+ export declare function sectionSelectionReport(context: SectionSelection): {
21
+ selection: ReaderSelection | null;
22
+ decisions: Record<string, unknown>[];
23
+ warnings: {
24
+ code: string;
25
+ message: string;
26
+ }[];
27
+ };
28
+ /** Keep receipts private, atomic, and keyed by artifact so nested exports can't replace a site's record. */
29
+ export declare function writeSectionSelectionReport(base: string, context: SectionSelection, artifact: Record<string, unknown>): Promise<void>;
@@ -0,0 +1,92 @@
1
+ import { createHash, randomUUID } from 'node:crypto';
2
+ import { mkdir, writeFile, rename, rm } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { pruneConditionalTree } from './conditional-tree.js';
5
+ import { evaluateFeatureGuard } from './deployment-profile.js';
6
+ import { matchesSectionContentFilter } from './content-filter.js';
7
+ import { validateReaderSelection } from './reader-filters.js';
8
+ import { documentKey } from './publication-identity.js';
9
+ export function createSectionSelection(facets, selection, publications) {
10
+ return { facets, selection, publications, decisions: new Map(), warnings: new Map(), hasConditions: false };
11
+ }
12
+ /** Share publication validation with pruning so receipts reflect every build-time ancestor. */
13
+ export function evaluatePublicationGuard(node, doc, file, publications) {
14
+ if (node.name !== 'ForPublication')
15
+ return;
16
+ const attributes = node.attributes ?? [];
17
+ const allowed = ['product', 'channel', 'version', 'language'];
18
+ if (node.type !== 'mdxJsxFlowElement' || !node.children?.length || !attributes.length || attributes.some((item) => item.type !== 'mdxJsxAttribute' || typeof item.value !== 'string' || !allowed.includes(item.name) || !item.value.trim()) || new Set(attributes.map((item) => item.name)).size !== attributes.length)
19
+ throw new Error(`${file}: <ForPublication> needs block content and distinct literal product, channel, version, or language attributes`);
20
+ const product = attributes.find((item) => item.name === 'product')?.value ?? doc.variant.product;
21
+ for (const item of attributes) {
22
+ const catalog = item.name === 'product' ? publications?.products : item.name === 'channel' ? publications?.channels : item.name === 'version' ? (product ? publications?.products?.[product]?.versions : publications?.versions) : undefined;
23
+ if (publications && item.name !== 'language' && (!catalog || !Object.hasOwn(catalog, item.value)))
24
+ throw new Error(`${file}: <ForPublication> names unknown ${item.name} ${item.value}`);
25
+ }
26
+ return !attributes.some((item) => doc.variant[item.name] !== item.value);
27
+ }
28
+ export function pruneSelectedTree(tree, doc, file = doc.file, record = true) {
29
+ const context = doc.sectionSelection;
30
+ return pruneConditionalTree(tree, (node, ancestorIncluded) => {
31
+ if (node.name === 'ForPublication')
32
+ return evaluatePublicationGuard(node, doc, file, context?.publications);
33
+ if (node.name === 'ForFeature')
34
+ return evaluateFeatureGuard(node, doc.featureContext, file, ancestorIncluded, record);
35
+ if (node.name !== 'ForFacet')
36
+ return;
37
+ const label = `${file}:${node.position?.start?.line ?? 1}: <ForFacet>`;
38
+ const attributes = node.attributes ?? [];
39
+ if (node.type !== 'mdxJsxFlowElement' || !node.children?.length || !attributes.length || attributes.some((item) => item.type !== 'mdxJsxAttribute' || typeof item.value !== 'string' || !item.value.trim()) || new Set(attributes.map((item) => item.name)).size !== attributes.length)
40
+ throw new Error(`${label} needs block content and distinct nonempty literal facet attributes`);
41
+ if (!context?.facets)
42
+ throw new Error(`${label} needs configured readerFilters.facets`);
43
+ const requirements = validateReaderSelection(Object.fromEntries(attributes.map((item) => [item.name, item.value.trim().split(/\s+/)])), context.facets, label);
44
+ context.hasConditions = true;
45
+ const match = matchesSectionContentFilter(requirements, context.selection);
46
+ if (record) {
47
+ const line = node.position?.start?.line ?? 1;
48
+ const key = JSON.stringify([documentKey(doc.frontmatter.id, doc.variant), file, line, requirements, ancestorIncluded]);
49
+ context.decisions.set(key, { documentId: doc.frontmatter.id, publication: doc.variant, source: file, line, requirements, localMatch: match, included: ancestorIncluded && match, reason: !ancestorIncluded ? 'ancestor-excluded' : match ? 'matched' : 'facet-mismatch' });
50
+ }
51
+ return match;
52
+ });
53
+ }
54
+ export function warnReaderSection(doc, file, line, requirements) {
55
+ const context = doc.sectionSelection;
56
+ if (!context?.selection)
57
+ return;
58
+ const overlap = Object.keys(requirements).filter(facet => context.selection?.[facet]);
59
+ if (!overlap.length)
60
+ return;
61
+ const key = JSON.stringify([file, line, overlap]);
62
+ if (context.warnings.has(key))
63
+ return;
64
+ const message = `${file}:${line}: <ReaderSection> uses build-selected facet(s) ${overlap.join(', ')} but only changes reader visibility; its content remains in the output. Use <ForFacet> to omit unmatched content during this build.`;
65
+ context.warnings.set(key, { code: 'reader-section-build-facet', message });
66
+ process.stderr.write(`warning [reader-section-build-facet] ${message}\n`);
67
+ }
68
+ export function sectionSelectionReport(context) {
69
+ return { selection: context.selection ?? null, decisions: [...context.decisions.values()], warnings: [...context.warnings.values()] };
70
+ }
71
+ /** Keep receipts private, atomic, and keyed by artifact so nested exports can't replace a site's record. */
72
+ export async function writeSectionSelectionReport(base, context, artifact) {
73
+ const folder = path.join(base, '.shoalrun');
74
+ await mkdir(folder, { recursive: true });
75
+ const file = path.join(folder, 'content-selection.json');
76
+ const key = createHash('sha256').update(JSON.stringify(artifact.target)).digest('hex');
77
+ const receipt = { schemaVersion: 1, ...artifact, ...sectionSelectionReport(context) };
78
+ const receipts = path.join(folder, 'content-selection');
79
+ await mkdir(receipts, { recursive: true });
80
+ const atomic = async (destination, value) => {
81
+ const temporary = path.join(folder, `.content-selection-${randomUUID()}.json`);
82
+ try {
83
+ await writeFile(temporary, JSON.stringify(value, null, 2) + '\n');
84
+ await rename(temporary, destination);
85
+ }
86
+ finally {
87
+ await rm(temporary, { force: true });
88
+ }
89
+ };
90
+ await atomic(path.join(receipts, key + '.json'), receipt);
91
+ await atomic(file, { ...receipt, receipt: `content-selection/${key}.json` });
92
+ }
@@ -13,6 +13,7 @@ export type SnippetUse = {
13
13
  id: string;
14
14
  file: string;
15
15
  documentId: string;
16
+ documentKey?: string;
16
17
  };
17
18
  export declare function validateSnippetConfig(id: string, definition: any): Record<string, SnippetVariable>;
18
19
  export declare function snippetAttribute(attribute: any, label: string): unknown;