blume 1.7.2 → 2.0.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 (677) hide show
  1. package/AGENTS.md +19 -0
  2. package/CHANGELOG.md +227 -0
  3. package/README.md +34 -21
  4. package/dist/cli/chunk-11j0384y.js +148 -0
  5. package/dist/cli/chunk-11j0384y.js.map +10 -0
  6. package/dist/cli/{chunk-xhtpx3ff.js → chunk-1w8dp3qb.js} +17 -16
  7. package/dist/cli/{chunk-xhtpx3ff.js.map → chunk-1w8dp3qb.js.map} +3 -3
  8. package/dist/cli/chunk-2q1dwty4.js +75 -0
  9. package/dist/cli/chunk-2q1dwty4.js.map +11 -0
  10. package/dist/cli/chunk-41za066z.js +122 -0
  11. package/dist/cli/chunk-41za066z.js.map +11 -0
  12. package/dist/cli/chunk-5a2z0198.js +133 -0
  13. package/dist/cli/chunk-5a2z0198.js.map +10 -0
  14. package/dist/cli/{chunk-9he6crym.js → chunk-6k8vp3ta.js} +25 -13
  15. package/dist/cli/{chunk-9he6crym.js.map → chunk-6k8vp3ta.js.map} +4 -4
  16. package/dist/cli/{chunk-mt76t7dj.js → chunk-79njf86q.js} +133 -54
  17. package/dist/cli/chunk-79njf86q.js.map +11 -0
  18. package/dist/cli/{chunk-3w7b2vcx.js → chunk-7ez8ny0t.js} +2 -2
  19. package/dist/cli/{chunk-688e0dde.js → chunk-88cpgt6h.js} +1 -1
  20. package/dist/cli/chunk-a9kptbw5.js +361 -0
  21. package/dist/cli/chunk-a9kptbw5.js.map +14 -0
  22. package/dist/cli/chunk-abh8yjkn.js +31 -0
  23. package/dist/cli/chunk-abh8yjkn.js.map +10 -0
  24. package/dist/cli/chunk-b5aj94ah.js +91 -0
  25. package/dist/cli/chunk-b5aj94ah.js.map +10 -0
  26. package/dist/cli/{chunk-hs3gbh8p.js → chunk-bctazmbk.js} +9 -5
  27. package/dist/cli/chunk-bctazmbk.js.map +10 -0
  28. package/dist/cli/chunk-beat36xx.js +279 -0
  29. package/dist/cli/chunk-beat36xx.js.map +10 -0
  30. package/dist/cli/chunk-bnbmcwfb.js +145 -0
  31. package/dist/cli/chunk-bnbmcwfb.js.map +11 -0
  32. package/dist/cli/{chunk-9bkjd11x.js → chunk-bw22s759.js} +15 -5
  33. package/dist/cli/{chunk-9bkjd11x.js.map → chunk-bw22s759.js.map} +4 -4
  34. package/dist/cli/chunk-by2290sx.js +39 -0
  35. package/dist/cli/chunk-by2290sx.js.map +10 -0
  36. package/dist/cli/chunk-d1tadaw7.js +79 -0
  37. package/dist/cli/chunk-d1tadaw7.js.map +10 -0
  38. package/dist/cli/{chunk-t3tj0dgr.js → chunk-d80hr03s.js} +24 -19
  39. package/dist/cli/chunk-d80hr03s.js.map +15 -0
  40. package/dist/cli/chunk-ernrthtr.js +97 -0
  41. package/dist/cli/chunk-ernrthtr.js.map +10 -0
  42. package/dist/cli/chunk-f2972sbt.js +374 -0
  43. package/dist/cli/chunk-f2972sbt.js.map +10 -0
  44. package/dist/cli/{chunk-exeeb35e.js → chunk-f7t03s3g.js} +2 -2
  45. package/dist/cli/{chunk-2z47ypj8.js → chunk-fa25z98p.js} +16 -3
  46. package/dist/cli/chunk-fa25z98p.js.map +11 -0
  47. package/dist/cli/{chunk-12dxjqk7.js → chunk-fh5hj5jt.js} +44 -21
  48. package/dist/cli/chunk-fh5hj5jt.js.map +10 -0
  49. package/dist/cli/{chunk-8cd8tj54.js → chunk-j8mw0za6.js} +86 -57
  50. package/dist/cli/chunk-j8mw0za6.js.map +35 -0
  51. package/dist/cli/chunk-jts8mvcz.js +106 -0
  52. package/dist/cli/{chunk-2mzebbbz.js.map → chunk-jts8mvcz.js.map} +6 -4
  53. package/dist/cli/{chunk-ejjx8znq.js → chunk-mnqj32sj.js} +505 -536
  54. package/dist/cli/chunk-mnqj32sj.js.map +12 -0
  55. package/dist/cli/{chunk-196vjxp9.js → chunk-mwt1k8n7.js} +100 -372
  56. package/dist/cli/chunk-mwt1k8n7.js.map +10 -0
  57. package/dist/cli/chunk-nk3ts2xk.js +51 -0
  58. package/dist/cli/chunk-nk3ts2xk.js.map +10 -0
  59. package/dist/cli/{chunk-n9sra6sy.js → chunk-pat2zzwc.js} +10 -14
  60. package/dist/cli/{chunk-n9sra6sy.js.map → chunk-pat2zzwc.js.map} +2 -2
  61. package/dist/cli/chunk-pnnvybbk.js +176 -0
  62. package/dist/cli/chunk-pnnvybbk.js.map +11 -0
  63. package/dist/cli/{chunk-cvky9gb2.js → chunk-sqn5t4q0.js} +81 -87
  64. package/dist/cli/chunk-sqn5t4q0.js.map +10 -0
  65. package/dist/cli/{chunk-eevwt1sc.js → chunk-tzne8qfq.js} +15 -15
  66. package/dist/cli/{chunk-eevwt1sc.js.map → chunk-tzne8qfq.js.map} +1 -1
  67. package/dist/cli/chunk-xaz13gwg.js +12449 -0
  68. package/dist/cli/chunk-xaz13gwg.js.map +182 -0
  69. package/dist/cli/chunk-y3e45rc8.js +102 -0
  70. package/dist/cli/chunk-y3e45rc8.js.map +10 -0
  71. package/dist/cli/chunk-z01ze5c1.js +261 -0
  72. package/dist/cli/chunk-z01ze5c1.js.map +10 -0
  73. package/dist/cli/{chunk-5n7t497w.js → chunk-z1f5arsg.js} +247 -755
  74. package/dist/cli/chunk-z1f5arsg.js.map +36 -0
  75. package/dist/cli/{chunk-hdm2dkd2.js → chunk-zg2gtj10.js} +1086 -2596
  76. package/dist/cli/chunk-zg2gtj10.js.map +35 -0
  77. package/dist/cli/{chunk-ppfvdcd4.js → chunk-zxccj738.js} +1 -1
  78. package/dist/cli/index.js +214 -57
  79. package/dist/cli/index.js.map +8 -7
  80. package/dist/types/ai/agent-readability.d.ts +52 -0
  81. package/dist/types/ai/ai-catalog.d.ts +42 -0
  82. package/dist/types/ai/api/paths.d.ts +17 -0
  83. package/dist/types/ai/api-catalog.d.ts +18 -0
  84. package/dist/types/ai/ask.d.ts +368 -0
  85. package/dist/types/ai/changelog-markdown.d.ts +2 -0
  86. package/dist/types/ai/component-markdown.d.ts +2 -2
  87. package/dist/types/ai/index.d.ts +24 -0
  88. package/dist/types/ai/link-headers.d.ts +24 -0
  89. package/dist/types/ai/llms.d.ts +25 -0
  90. package/dist/types/ai/markdown.d.ts +45 -0
  91. package/dist/types/ai/mcp/discovery.d.ts +68 -0
  92. package/dist/types/ai/mcp/tools.d.ts +16 -0
  93. package/dist/types/ai/openapi-components.d.ts +43 -0
  94. package/dist/types/ai/relative-links.d.ts +26 -0
  95. package/dist/types/ai/serializers.d.ts +15 -0
  96. package/dist/types/ai/skills.d.ts +42 -0
  97. package/dist/types/ai/tar.d.ts +25 -0
  98. package/dist/types/ai/visibility.d.ts +17 -0
  99. package/dist/types/ai/web-bot-auth.d.ts +16 -0
  100. package/dist/types/analytics/adobe.d.ts +35 -0
  101. package/dist/types/analytics/amplitude.d.ts +50 -0
  102. package/dist/types/analytics/clarity.d.ts +31 -0
  103. package/dist/types/analytics/clearbit.d.ts +29 -0
  104. package/dist/types/analytics/cloudflare.d.ts +41 -0
  105. package/dist/types/analytics/fathom.d.ts +41 -0
  106. package/dist/types/analytics/google-analytics.d.ts +44 -0
  107. package/dist/types/analytics/google-tag-manager.d.ts +40 -0
  108. package/dist/types/analytics/head.d.ts +30 -0
  109. package/dist/types/analytics/heap.d.ts +40 -0
  110. package/dist/types/analytics/hightouch.d.ts +44 -0
  111. package/dist/types/analytics/hotjar.d.ts +33 -0
  112. package/dist/types/analytics/index.d.ts +61 -0
  113. package/dist/types/analytics/inline.d.ts +17 -0
  114. package/dist/types/analytics/logrocket.d.ts +44 -0
  115. package/dist/types/analytics/mixpanel.d.ts +67 -0
  116. package/dist/types/analytics/pirsch.d.ts +42 -0
  117. package/dist/types/analytics/plausible.d.ts +56 -0
  118. package/dist/types/analytics/posthog.d.ts +45 -0
  119. package/dist/types/analytics/schema.d.ts +320 -0
  120. package/dist/types/analytics/script.d.ts +46 -0
  121. package/dist/types/analytics/segment.d.ts +50 -0
  122. package/dist/types/analytics/vercel.d.ts +48 -0
  123. package/dist/types/astro/integration.d.ts +76 -0
  124. package/dist/types/astro/markdown-negotiation.d.ts +23 -0
  125. package/dist/types/astro/module-types.d.ts +14 -0
  126. package/dist/types/astro/pages.d.ts +44 -0
  127. package/dist/types/cli/env.d.ts +12 -0
  128. package/dist/types/cli/init/scaffold.d.ts +154 -0
  129. package/dist/types/components/layout/nav-utils.d.ts +11 -0
  130. package/dist/types/core/adapter.d.ts +47 -0
  131. package/dist/types/core/api-name.d.ts +7 -0
  132. package/dist/types/core/changelog-index.d.ts +13 -0
  133. package/dist/types/core/config-input.d.ts +209 -505
  134. package/dist/types/core/config.d.ts +60 -34
  135. package/dist/types/core/content-assets.d.ts +76 -0
  136. package/dist/types/core/custom-pages.d.ts +33 -0
  137. package/dist/types/core/data.d.ts +28 -11
  138. package/dist/types/core/define-components.d.ts +12 -9
  139. package/dist/types/core/deployment-env.d.ts +6 -11
  140. package/dist/types/core/frontmatter.d.ts +10 -0
  141. package/dist/types/core/graph.d.ts +18 -0
  142. package/dist/types/core/heading-markers.d.ts +54 -0
  143. package/dist/types/core/i18n-ui.d.ts +6 -2
  144. package/dist/types/core/i18n.d.ts +87 -0
  145. package/dist/types/core/includes.d.ts +138 -0
  146. package/dist/types/core/last-modified.d.ts +47 -0
  147. package/dist/types/core/links.d.ts +95 -0
  148. package/dist/types/core/locale-links.d.ts +60 -0
  149. package/dist/types/core/manifest.d.ts +17 -0
  150. package/dist/types/core/meta.d.ts +38 -0
  151. package/dist/types/core/nav-diagnostics.d.ts +26 -0
  152. package/dist/types/core/navigation.d.ts +6 -0
  153. package/dist/types/core/node-require.d.ts +19 -0
  154. package/dist/types/core/package-json.d.ts +13 -0
  155. package/dist/types/core/probe.d.ts +42 -0
  156. package/dist/types/core/project-graph.d.ts +51 -0
  157. package/dist/types/core/project.d.ts +2 -0
  158. package/dist/types/core/safe-href.d.ts +2 -0
  159. package/dist/types/core/safe-links.d.ts +26 -0
  160. package/dist/types/core/schema.d.ts +2291 -441
  161. package/dist/types/core/site-url.d.ts +16 -0
  162. package/dist/types/core/sources/assets.d.ts +36 -0
  163. package/dist/types/core/sources/cache.d.ts +37 -0
  164. package/dist/types/core/sources/collection.d.ts +28 -0
  165. package/dist/types/core/sources/contentful-rich-text.d.ts +31 -0
  166. package/dist/types/core/sources/contentful.d.ts +40 -0
  167. package/dist/types/core/sources/filesystem.d.ts +24 -0
  168. package/dist/types/core/sources/github-releases.d.ts +31 -0
  169. package/dist/types/core/sources/json.d.ts +30 -0
  170. package/dist/types/core/sources/lexical.d.ts +19 -0
  171. package/dist/types/core/sources/lower.d.ts +75 -0
  172. package/dist/types/core/sources/mdx-remote.d.ts +28 -0
  173. package/dist/types/core/sources/normalize.d.ts +147 -0
  174. package/dist/types/core/sources/notion.d.ts +131 -0
  175. package/dist/types/core/sources/obsidian.d.ts +46 -0
  176. package/dist/types/core/sources/payload.d.ts +39 -0
  177. package/dist/types/core/sources/portable-text.d.ts +42 -0
  178. package/dist/types/core/sources/read.d.ts +23 -0
  179. package/dist/types/core/sources/remote.d.ts +74 -0
  180. package/dist/types/core/sources/resolve.d.ts +19 -0
  181. package/dist/types/core/sources/sanity.d.ts +43 -0
  182. package/dist/types/core/sources/strapi-blocks.d.ts +12 -0
  183. package/dist/types/core/sources/strapi.d.ts +33 -0
  184. package/dist/types/core/sources/types.d.ts +7 -0
  185. package/dist/types/core/sources/watch.d.ts +45 -0
  186. package/dist/types/core/text-width.d.ts +11 -0
  187. package/dist/types/core/types.d.ts +20 -1
  188. package/dist/types/core/unrecognized-keys.d.ts +7 -0
  189. package/dist/types/core/versions.d.ts +72 -0
  190. package/dist/types/core/yaml.d.ts +9 -0
  191. package/dist/types/deploy/adapter-output.d.ts +45 -0
  192. package/dist/types/deploy/adapters/cloudflare.d.ts +40 -0
  193. package/dist/types/deploy/adapters/index.d.ts +29 -0
  194. package/dist/types/deploy/adapters/netlify.d.ts +37 -0
  195. package/dist/types/deploy/adapters/node.d.ts +37 -0
  196. package/dist/types/deploy/adapters/registry.d.ts +133 -0
  197. package/dist/types/deploy/adapters/types.d.ts +71 -0
  198. package/dist/types/deploy/adapters/vercel.d.ts +38 -0
  199. package/dist/types/deploy/artifacts.d.ts +65 -0
  200. package/dist/types/deploy/cloudflare-negotiation.d.ts +196 -0
  201. package/dist/types/deploy/function-bundle.d.ts +80 -0
  202. package/dist/types/deploy/headers.d.ts +50 -0
  203. package/dist/types/deploy/node-headers.d.ts +42 -0
  204. package/dist/types/deploy/platforms/cloudflare.d.ts +40 -0
  205. package/dist/types/deploy/platforms/index.d.ts +18 -0
  206. package/dist/types/deploy/platforms/netlify.d.ts +13 -0
  207. package/dist/types/deploy/platforms/node.d.ts +11 -0
  208. package/dist/types/deploy/platforms/paths.d.ts +27 -0
  209. package/dist/types/deploy/platforms/static.d.ts +10 -0
  210. package/dist/types/deploy/platforms/types.d.ts +104 -0
  211. package/dist/types/deploy/platforms/vercel.d.ts +32 -0
  212. package/dist/types/deploy/redirects.d.ts +53 -0
  213. package/dist/types/deploy/robots.d.ts +8 -0
  214. package/dist/types/deploy/rss.d.ts +31 -0
  215. package/dist/types/deploy/sitemap.d.ts +21 -0
  216. package/dist/types/deploy/vercel-negotiation.d.ts +109 -0
  217. package/dist/types/markdown/code-title.d.ts +32 -0
  218. package/dist/types/markdown/fence-meta.d.ts +23 -0
  219. package/dist/types/markdown/themes.d.ts +3 -3
  220. package/dist/types/openapi/asyncapi.d.ts +129 -0
  221. package/dist/types/openapi/graphql-build.d.ts +8 -0
  222. package/dist/types/openapi/graphql.d.ts +122 -0
  223. package/dist/types/openapi/model.d.ts +158 -0
  224. package/dist/types/openapi/parse.d.ts +57 -0
  225. package/dist/types/openapi/references.d.ts +37 -25
  226. package/dist/types/openapi/render-mdx.d.ts +33 -0
  227. package/dist/types/openapi/sentence.d.ts +7 -0
  228. package/dist/types/openapi/signature.d.ts +10 -0
  229. package/dist/types/openapi/source.d.ts +22 -0
  230. package/dist/types/openapi/spec-dependency-error.d.ts +10 -0
  231. package/dist/types/reference/asyncapi.d.ts +166 -0
  232. package/dist/types/reference/graphql.d.ts +181 -0
  233. package/dist/types/reference/index.d.ts +32 -0
  234. package/dist/types/reference/openapi.d.ts +165 -0
  235. package/dist/types/reference/options.d.ts +157 -0
  236. package/dist/types/reference/scalar.d.ts +136 -0
  237. package/dist/types/reference/schema.d.ts +630 -0
  238. package/dist/types/search/adapters/algolia.d.ts +32 -0
  239. package/dist/types/search/adapters/flexsearch.d.ts +12 -0
  240. package/dist/types/search/adapters/index.d.ts +31 -0
  241. package/dist/types/search/adapters/mixedbread.d.ts +22 -0
  242. package/dist/types/search/adapters/orama-cloud.d.ts +33 -0
  243. package/dist/types/search/adapters/orama.d.ts +13 -0
  244. package/dist/types/search/adapters/pagefind.d.ts +12 -0
  245. package/dist/types/search/adapters/registry.d.ts +228 -0
  246. package/dist/types/search/adapters/types.d.ts +34 -0
  247. package/dist/types/search/adapters/typesense.d.ts +42 -0
  248. package/dist/types/search/build.d.ts +23 -0
  249. package/dist/types/search/documents.d.ts +90 -0
  250. package/dist/types/search/facets.d.ts +3 -0
  251. package/dist/types/search/sync/algolia.d.ts +14 -0
  252. package/dist/types/search/sync/index.d.ts +14 -0
  253. package/dist/types/search/sync/orama-cloud.d.ts +10 -0
  254. package/dist/types/search/sync/typesense.d.ts +14 -0
  255. package/dist/types/sources/contentful.d.ts +68 -0
  256. package/dist/types/sources/custom.d.ts +20 -0
  257. package/dist/types/sources/filesystem.d.ts +42 -0
  258. package/dist/types/sources/github-releases.d.ts +46 -0
  259. package/dist/types/sources/index.d.ts +48 -0
  260. package/dist/types/sources/mdx-remote.d.ts +63 -0
  261. package/dist/types/sources/notion.d.ts +65 -0
  262. package/dist/types/sources/obsidian.d.ts +34 -0
  263. package/dist/types/sources/payload.d.ts +68 -0
  264. package/dist/types/sources/registry.d.ts +1414 -0
  265. package/dist/types/sources/sanity.d.ts +69 -0
  266. package/dist/types/sources/shared.d.ts +46 -0
  267. package/dist/types/sources/strapi.d.ts +66 -0
  268. package/dist/types/theme/icon-kind.d.ts +11 -0
  269. package/dist/types/theme/icons.d.ts +20 -0
  270. package/docs/01-quickstart.mdx +18 -18
  271. package/docs/02-deployment.mdx +50 -26
  272. package/docs/03-upgrading.mdx +351 -0
  273. package/docs/04-migrating.mdx +58 -0
  274. package/docs/08-faq.mdx +3 -3
  275. package/docs/advanced/blog.mdx +13 -6
  276. package/docs/advanced/changelog.mdx +23 -35
  277. package/docs/advanced/custom-pages.mdx +20 -8
  278. package/docs/advanced/meta.ts +1 -8
  279. package/docs/advanced/skills.mdx +8 -0
  280. package/docs/cli/audit.mdx +646 -0
  281. package/docs/cli/doctor.mdx +29 -0
  282. package/docs/{reference/eval.mdx → cli/evals.mdx} +9 -8
  283. package/docs/cli/index.mdx +105 -0
  284. package/docs/cli/meta.ts +7 -0
  285. package/docs/{reference → cli}/translate.mdx +1 -1
  286. package/docs/cli/validate.mdx +41 -0
  287. package/docs/cli/version.mdx +40 -0
  288. package/docs/configuration/analytics.mdx +350 -59
  289. package/docs/configuration/ask-ai.mdx +176 -61
  290. package/docs/configuration/customization.mdx +15 -9
  291. package/docs/configuration/index.mdx +52 -31
  292. package/docs/configuration/search.mdx +75 -54
  293. package/docs/configuration/theming.mdx +24 -15
  294. package/docs/content/components.mdx +21 -5
  295. package/docs/{reference → content}/frontmatter.mdx +37 -1
  296. package/docs/content/i18n.mdx +8 -6
  297. package/docs/content/includes.mdx +2 -4
  298. package/docs/content/index.mdx +1 -1
  299. package/docs/content/islands.mdx +10 -5
  300. package/docs/content/meta.mdx +1 -1
  301. package/docs/content/meta.ts +1 -0
  302. package/docs/content/navigation.mdx +12 -7
  303. package/docs/content/sources.mdx +145 -50
  304. package/docs/content/syntax.mdx +26 -12
  305. package/docs/content/versioning.mdx +3 -3
  306. package/docs/discoverability/agent-discovery.mdx +91 -10
  307. package/docs/discoverability/index.mdx +5 -5
  308. package/docs/discoverability/json-api.mdx +4 -4
  309. package/docs/discoverability/llms-txt.mdx +6 -6
  310. package/docs/discoverability/markdown.mdx +4 -4
  311. package/docs/discoverability/mcp.mdx +11 -11
  312. package/docs/discoverability/sitemap-and-robots.mdx +3 -3
  313. package/docs/index.mdx +2 -2
  314. package/docs/references/asyncapi.mdx +59 -0
  315. package/docs/{advanced → references}/graphql.mdx +45 -32
  316. package/docs/{reference → references}/meta.ts +2 -2
  317. package/docs/references/openapi.mdx +171 -0
  318. package/docs/references/scalar.mdx +64 -0
  319. package/package.json +42 -8
  320. package/skills/blume/SKILL.md +21 -8
  321. package/skills/blume-migrate/SKILL.md +22 -21
  322. package/skills/blume-migrate/assets/oxfmt@0.67.0.patch +49 -0
  323. package/skills/blume-migrate/references/docusaurus.md +5 -4
  324. package/skills/blume-migrate/references/fumadocs.md +4 -4
  325. package/skills/blume-migrate/references/mintlify.md +23 -8
  326. package/skills/blume-migrate/references/monorepo.md +6 -6
  327. package/skills/blume-migrate/references/starlight.md +4 -4
  328. package/src/ai/agent-readability.ts +26 -22
  329. package/src/ai/ai-catalog.ts +259 -0
  330. package/src/ai/api/handlers.ts +46 -11
  331. package/src/ai/api-catalog.ts +8 -8
  332. package/src/ai/ask-data.ts +1 -1
  333. package/src/ai/ask.ts +624 -100
  334. package/src/ai/changelog-markdown.ts +91 -0
  335. package/src/ai/component-markdown.ts +328 -12
  336. package/src/ai/index.ts +45 -0
  337. package/src/ai/link-headers.ts +19 -6
  338. package/src/ai/llms.ts +26 -15
  339. package/src/ai/markdown.ts +35 -5
  340. package/src/ai/mcp/data.ts +9 -5
  341. package/src/ai/mcp/discovery.ts +1 -1
  342. package/src/ai/openapi-components.ts +4 -1
  343. package/src/ai/relative-links.ts +170 -0
  344. package/src/ai/serializers.ts +2 -2
  345. package/src/ai/skills.ts +1 -1
  346. package/src/ai/web-bot-auth.ts +2 -2
  347. package/src/analytics/adobe.ts +46 -0
  348. package/src/analytics/amplitude.ts +79 -0
  349. package/src/analytics/clarity.ts +46 -0
  350. package/src/analytics/clearbit.ts +47 -0
  351. package/src/analytics/cloudflare.ts +67 -0
  352. package/src/analytics/fathom.ts +64 -0
  353. package/src/analytics/google-analytics.ts +84 -0
  354. package/src/analytics/google-tag-manager.ts +61 -0
  355. package/src/analytics/head.ts +130 -0
  356. package/src/analytics/heap.ts +65 -0
  357. package/src/analytics/hightouch.ts +77 -0
  358. package/src/analytics/hotjar.ts +47 -0
  359. package/src/analytics/index.ts +71 -0
  360. package/src/analytics/inline.ts +21 -0
  361. package/src/analytics/logrocket.ts +71 -0
  362. package/src/analytics/mixpanel.ts +92 -0
  363. package/src/analytics/pirsch.ts +66 -0
  364. package/src/analytics/plausible.ts +83 -0
  365. package/src/analytics/posthog.ts +78 -0
  366. package/src/analytics/schema.ts +60 -0
  367. package/src/analytics/script.ts +60 -0
  368. package/src/analytics/segment.ts +85 -0
  369. package/src/analytics/vercel.ts +50 -0
  370. package/src/astro/adapter-root.ts +7 -9
  371. package/src/astro/component-slots.ts +131 -91
  372. package/src/astro/generate.ts +114 -345
  373. package/src/astro/integration.ts +2 -6
  374. package/src/astro/pages.ts +13 -101
  375. package/src/astro/render-deps.ts +379 -0
  376. package/src/astro/runtime-deps.ts +201 -0
  377. package/src/astro/templates.ts +554 -541
  378. package/src/audit/agent.ts +24 -0
  379. package/src/audit/catalog.ts +2 -2
  380. package/src/audit/checks/assets.ts +2 -2
  381. package/src/audit/checks/dns-aid.ts +1 -1
  382. package/src/audit/checks/duplicates.ts +3 -1
  383. package/src/audit/checks/i18n.ts +1 -1
  384. package/src/audit/checks/indexability.ts +7 -7
  385. package/src/audit/checks/links.ts +2 -2
  386. package/src/audit/checks/llms.ts +6 -6
  387. package/src/audit/checks/network.ts +3 -3
  388. package/src/audit/checks/og-image.ts +2 -2
  389. package/src/audit/checks/robots.ts +1 -1
  390. package/src/audit/checks/sitemap.ts +2 -2
  391. package/src/audit/checks/social.ts +1 -1
  392. package/src/audit/run.ts +4 -3
  393. package/src/audit/terms.ts +31 -0
  394. package/src/audit/url.ts +13 -13
  395. package/src/cli/command-meta.ts +10 -0
  396. package/src/cli/commands/audit.ts +39 -20
  397. package/src/cli/commands/build.ts +71 -314
  398. package/src/cli/commands/check.ts +1 -0
  399. package/src/cli/commands/dev.ts +40 -1
  400. package/src/cli/commands/doctor.ts +90 -14
  401. package/src/cli/commands/eject.ts +44 -7
  402. package/src/cli/commands/eval.ts +2 -2
  403. package/src/cli/commands/init.ts +161 -41
  404. package/src/cli/commands/migrate.ts +121 -0
  405. package/src/cli/commands/preview.ts +7 -1
  406. package/src/cli/commands/translate.ts +2 -2
  407. package/src/cli/commands/upgrade.ts +141 -0
  408. package/src/cli/commands/version.ts +57 -44
  409. package/src/cli/eject-scripts.ts +121 -6
  410. package/src/cli/index.ts +11 -1
  411. package/src/cli/init/install.ts +70 -0
  412. package/src/cli/init/questions.ts +7 -0
  413. package/src/cli/init/scaffold.ts +459 -75
  414. package/src/cli/lazy-command.ts +37 -1
  415. package/src/cli/prepare.ts +40 -6
  416. package/src/cli/required-secrets.ts +38 -11
  417. package/src/cli/unknown-flags.ts +266 -0
  418. package/src/cli/yarn-pnp.ts +52 -0
  419. package/src/components/content/AccordionItem.astro +7 -1
  420. package/src/components/content/Card.astro +4 -3
  421. package/src/components/content/ColorItem.astro +22 -4
  422. package/src/components/content/GithubInfo.astro +2 -2
  423. package/src/components/content/Prompt.astro +25 -25
  424. package/src/components/content/Tabs.astro +3 -1
  425. package/src/components/content/Tile.astro +2 -3
  426. package/src/components/content/Tooltip.astro +57 -9
  427. package/src/components/content/content-strings.ts +34 -0
  428. package/src/components/content/diff.ts +1 -1
  429. package/src/components/content/mermaid-element.ts +13 -2
  430. package/src/components/content/prompt-markdown.ts +292 -0
  431. package/src/components/content/tooltip-id.ts +41 -0
  432. package/src/components/islands/hooks.ts +75 -3
  433. package/src/components/layout/Analytics.astro +21 -79
  434. package/src/components/layout/Banner.astro +3 -1
  435. package/src/components/layout/DiscoveryLinks.astro +69 -0
  436. package/src/components/layout/Header.astro +83 -20
  437. package/src/components/layout/LanguageSwitcher.astro +4 -1
  438. package/src/components/layout/Logo.astro +23 -2
  439. package/src/components/layout/NavSelector.astro +13 -2
  440. package/src/components/layout/NavTree.astro +12 -3
  441. package/src/components/layout/NavTreeScript.astro +17 -3
  442. package/src/components/layout/PageActions.astro +3 -3
  443. package/src/components/layout/PageFeedback.astro +11 -1
  444. package/src/components/layout/PageLayout.astro +52 -5
  445. package/src/components/layout/ReferenceLayout.astro +21 -12
  446. package/src/components/layout/RootLayout.astro +69 -43
  447. package/src/components/layout/Search.astro +30 -6
  448. package/src/components/layout/WebMcp.astro +1 -1
  449. package/src/components/layout/analytics-client.ts +101 -15
  450. package/src/components/layout/drawer-inert.ts +113 -15
  451. package/src/components/layout/dropdown-clamp.ts +105 -0
  452. package/src/components/layout/head-scripts.ts +15 -6
  453. package/src/components/layout/nav-utils.ts +17 -0
  454. package/src/components/layout/search/algolia.ts +8 -8
  455. package/src/components/layout/search/orama-cloud.ts +9 -7
  456. package/src/components/layout/search/typesense.ts +11 -17
  457. package/src/components/openapi/MessageComposer.astro +2 -2
  458. package/src/components/openapi/Playground.astro +2 -2
  459. package/src/components/openapi/playground-client.ts +79 -10
  460. package/src/core/changelog-index.ts +24 -0
  461. package/src/core/component-overrides.ts +399 -154
  462. package/src/core/config-input.ts +212 -543
  463. package/src/core/config.ts +130 -41
  464. package/src/core/custom-pages.ts +105 -0
  465. package/src/core/data.ts +32 -11
  466. package/src/core/define-components.ts +12 -9
  467. package/src/core/deployment-env.ts +18 -74
  468. package/src/core/diagnostics.ts +14 -7
  469. package/src/core/graph.ts +69 -25
  470. package/src/core/i18n-ui.ts +6 -2
  471. package/src/core/i18n.ts +17 -0
  472. package/src/core/includes.ts +156 -38
  473. package/src/core/last-modified.ts +6 -11
  474. package/src/core/links.ts +166 -2
  475. package/src/core/manifest.ts +10 -3
  476. package/src/core/navigation.ts +137 -19
  477. package/src/core/new-tab.ts +35 -0
  478. package/src/core/node-require.ts +21 -0
  479. package/src/core/project-graph.ts +42 -26
  480. package/src/core/project.ts +9 -4
  481. package/src/core/request-body.ts +61 -0
  482. package/src/core/safe-href.ts +28 -0
  483. package/src/core/safe-links.ts +68 -0
  484. package/src/core/schema.ts +531 -721
  485. package/src/core/server-features.ts +8 -9
  486. package/src/core/sources/assets.ts +47 -11
  487. package/src/core/sources/collection.ts +67 -0
  488. package/src/core/sources/contentful-rich-text.ts +285 -0
  489. package/src/core/sources/contentful.ts +173 -0
  490. package/src/core/sources/github-releases.ts +51 -1
  491. package/src/core/sources/json.ts +71 -0
  492. package/src/core/sources/lexical.ts +195 -0
  493. package/src/core/sources/lower.ts +226 -0
  494. package/src/core/sources/normalize.ts +52 -2
  495. package/src/core/sources/notion.ts +39 -28
  496. package/src/core/sources/payload.ts +135 -0
  497. package/src/core/sources/portable-text.ts +11 -16
  498. package/src/core/sources/remote.ts +226 -0
  499. package/src/core/sources/resolve.ts +104 -166
  500. package/src/core/sources/sanity.ts +16 -49
  501. package/src/core/sources/strapi-blocks.ts +124 -0
  502. package/src/core/sources/strapi.ts +191 -0
  503. package/src/core/sources/types.ts +12 -1
  504. package/src/core/types.ts +20 -1
  505. package/src/core/ui-packs/ar.ts +6 -2
  506. package/src/core/ui-packs/bg.ts +6 -2
  507. package/src/core/ui-packs/bn.ts +6 -2
  508. package/src/core/ui-packs/ca.ts +3 -1
  509. package/src/core/ui-packs/cs.ts +6 -2
  510. package/src/core/ui-packs/da.ts +6 -2
  511. package/src/core/ui-packs/de.ts +6 -2
  512. package/src/core/ui-packs/el.ts +3 -1
  513. package/src/core/ui-packs/es.ts +3 -1
  514. package/src/core/ui-packs/fa.ts +6 -2
  515. package/src/core/ui-packs/fi.ts +6 -2
  516. package/src/core/ui-packs/fr.ts +3 -1
  517. package/src/core/ui-packs/he.ts +6 -2
  518. package/src/core/ui-packs/hi.ts +6 -2
  519. package/src/core/ui-packs/hr.ts +6 -2
  520. package/src/core/ui-packs/hu.ts +6 -2
  521. package/src/core/ui-packs/id.ts +6 -2
  522. package/src/core/ui-packs/it.ts +3 -1
  523. package/src/core/ui-packs/ja.ts +3 -1
  524. package/src/core/ui-packs/ko.ts +3 -1
  525. package/src/core/ui-packs/nl.ts +6 -2
  526. package/src/core/ui-packs/no.ts +6 -2
  527. package/src/core/ui-packs/pl.ts +6 -2
  528. package/src/core/ui-packs/pt-br.ts +3 -1
  529. package/src/core/ui-packs/pt.ts +3 -1
  530. package/src/core/ui-packs/ro.ts +6 -2
  531. package/src/core/ui-packs/ru.ts +6 -2
  532. package/src/core/ui-packs/sk.ts +6 -2
  533. package/src/core/ui-packs/sr.ts +6 -2
  534. package/src/core/ui-packs/sv.ts +6 -2
  535. package/src/core/ui-packs/th.ts +3 -1
  536. package/src/core/ui-packs/tr.ts +6 -2
  537. package/src/core/ui-packs/uk.ts +6 -2
  538. package/src/core/ui-packs/vi.ts +3 -1
  539. package/src/core/ui-packs/zh-tw.ts +3 -1
  540. package/src/core/ui-packs/zh.ts +3 -1
  541. package/src/core/unrecognized-keys.ts +10 -0
  542. package/src/core/version-cut.ts +116 -8
  543. package/src/deploy/adapter-output.ts +57 -97
  544. package/src/deploy/adapters/cloudflare.ts +39 -0
  545. package/src/deploy/adapters/index.ts +41 -0
  546. package/src/deploy/adapters/netlify.ts +34 -0
  547. package/src/deploy/adapters/node.ts +34 -0
  548. package/src/deploy/adapters/registry.ts +127 -0
  549. package/src/deploy/adapters/types.ts +92 -0
  550. package/src/deploy/adapters/vercel.ts +35 -0
  551. package/src/deploy/artifacts.ts +67 -28
  552. package/src/deploy/cloudflare-negotiation.ts +179 -100
  553. package/src/deploy/function-bundle.ts +18 -3
  554. package/src/deploy/headers.ts +129 -22
  555. package/src/deploy/node-headers.ts +198 -0
  556. package/src/deploy/platforms/cloudflare.ts +312 -0
  557. package/src/deploy/platforms/index.ts +67 -0
  558. package/src/deploy/platforms/netlify.ts +52 -0
  559. package/src/deploy/platforms/node.ts +40 -0
  560. package/src/deploy/platforms/paths.ts +42 -0
  561. package/src/deploy/platforms/static.ts +29 -0
  562. package/src/deploy/platforms/types.ts +112 -0
  563. package/src/deploy/platforms/vercel.ts +193 -0
  564. package/src/deploy/redirects.ts +30 -18
  565. package/src/deploy/robots.ts +3 -3
  566. package/src/deploy/rss.ts +2 -2
  567. package/src/deploy/sitemap.ts +2 -2
  568. package/src/deploy/vercel-negotiation.ts +27 -4
  569. package/src/eval/agents.ts +32 -1
  570. package/src/eval/findings.ts +19 -11
  571. package/src/eval/report.ts +10 -2
  572. package/src/markdown/external-links.ts +65 -0
  573. package/src/markdown/include.ts +45 -27
  574. package/src/markdown/index.ts +34 -9
  575. package/src/markdown/inline-code.ts +12 -6
  576. package/src/markdown/relative-links.ts +324 -0
  577. package/src/markdown/themes.ts +3 -3
  578. package/src/migrate/migrate.ts +149 -0
  579. package/src/openapi/parse.ts +64 -16
  580. package/src/openapi/proxy.ts +62 -10
  581. package/src/openapi/references.ts +147 -147
  582. package/src/openapi/render-mdx.ts +32 -10
  583. package/src/openapi/scalar.ts +15 -13
  584. package/src/openapi/sentence.ts +14 -0
  585. package/src/openapi/source.ts +37 -21
  586. package/src/openapi/spec-dependency-error.ts +15 -0
  587. package/src/reference/asyncapi.ts +83 -0
  588. package/src/reference/graphql.ts +89 -0
  589. package/src/reference/index.ts +40 -0
  590. package/src/reference/openapi.ts +83 -0
  591. package/src/reference/options.ts +201 -0
  592. package/src/reference/scalar.ts +136 -0
  593. package/src/reference/schema.ts +88 -0
  594. package/src/registry/eject.ts +97 -42
  595. package/src/search/adapters/algolia.ts +46 -0
  596. package/src/search/adapters/flexsearch.ts +29 -0
  597. package/src/search/adapters/index.ts +39 -0
  598. package/src/search/adapters/mixedbread.ts +39 -0
  599. package/src/search/adapters/orama-cloud.ts +51 -0
  600. package/src/search/adapters/orama.ts +24 -0
  601. package/src/search/adapters/pagefind.ts +27 -0
  602. package/src/search/adapters/registry.ts +131 -0
  603. package/src/search/adapters/types.ts +46 -0
  604. package/src/search/adapters/typesense.ts +57 -0
  605. package/src/search/build.ts +33 -7
  606. package/src/search/documents.ts +6 -0
  607. package/src/search/sync/algolia.ts +12 -11
  608. package/src/search/sync/index.ts +35 -20
  609. package/src/search/sync/orama-cloud.ts +12 -9
  610. package/src/search/sync/typesense.ts +15 -13
  611. package/src/sources/contentful.ts +63 -0
  612. package/src/sources/custom.ts +38 -0
  613. package/src/sources/filesystem.ts +51 -0
  614. package/src/sources/github-releases.ts +52 -0
  615. package/src/sources/index.ts +60 -0
  616. package/src/sources/mdx-remote.ts +76 -0
  617. package/src/sources/notion.ts +63 -0
  618. package/src/sources/obsidian.ts +38 -0
  619. package/src/sources/payload.ts +60 -0
  620. package/src/sources/registry.ts +182 -0
  621. package/src/sources/sanity.ts +66 -0
  622. package/src/sources/shared.ts +52 -0
  623. package/src/sources/strapi.ts +58 -0
  624. package/src/theme/entry.ts +47 -2
  625. package/src/translate/report.ts +40 -7
  626. package/src/upgrade/upgrade.ts +499 -0
  627. package/dist/cli/chunk-12dxjqk7.js.map +0 -10
  628. package/dist/cli/chunk-196vjxp9.js.map +0 -13
  629. package/dist/cli/chunk-2mzebbbz.js +0 -69
  630. package/dist/cli/chunk-2z47ypj8.js.map +0 -11
  631. package/dist/cli/chunk-30e87n55.js +0 -108
  632. package/dist/cli/chunk-30e87n55.js.map +0 -10
  633. package/dist/cli/chunk-450a7rcr.js +0 -185
  634. package/dist/cli/chunk-450a7rcr.js.map +0 -11
  635. package/dist/cli/chunk-5n7t497w.js.map +0 -40
  636. package/dist/cli/chunk-61j18dwk.js +0 -5342
  637. package/dist/cli/chunk-61j18dwk.js.map +0 -58
  638. package/dist/cli/chunk-88by27n5.js +0 -17
  639. package/dist/cli/chunk-88by27n5.js.map +0 -10
  640. package/dist/cli/chunk-8cd8tj54.js.map +0 -34
  641. package/dist/cli/chunk-aztttvb3.js +0 -381
  642. package/dist/cli/chunk-aztttvb3.js.map +0 -12
  643. package/dist/cli/chunk-cvky9gb2.js.map +0 -11
  644. package/dist/cli/chunk-ejjx8znq.js.map +0 -15
  645. package/dist/cli/chunk-fmceyezb.js +0 -1007
  646. package/dist/cli/chunk-fmceyezb.js.map +0 -13
  647. package/dist/cli/chunk-hdm2dkd2.js.map +0 -48
  648. package/dist/cli/chunk-hs3gbh8p.js.map +0 -10
  649. package/dist/cli/chunk-jbj4qhfw.js +0 -30
  650. package/dist/cli/chunk-jbj4qhfw.js.map +0 -10
  651. package/dist/cli/chunk-mqb2ka8m.js +0 -68
  652. package/dist/cli/chunk-mqb2ka8m.js.map +0 -10
  653. package/dist/cli/chunk-mt76t7dj.js.map +0 -11
  654. package/dist/cli/chunk-q4rae3bg.js +0 -60
  655. package/dist/cli/chunk-q4rae3bg.js.map +0 -10
  656. package/dist/cli/chunk-ra1v2nc2.js +0 -35
  657. package/dist/cli/chunk-ra1v2nc2.js.map +0 -10
  658. package/dist/cli/chunk-t3tj0dgr.js.map +0 -15
  659. package/dist/cli/chunk-tqa1s0k8.js +0 -69
  660. package/dist/cli/chunk-tqa1s0k8.js.map +0 -11
  661. package/dist/cli/chunk-vh9w1sgp.js +0 -73
  662. package/dist/cli/chunk-vh9w1sgp.js.map +0 -10
  663. package/dist/cli/chunk-vkrsvbr5.js +0 -107
  664. package/dist/cli/chunk-vkrsvbr5.js.map +0 -11
  665. package/dist/cli/chunk-vrfp10qk.js +0 -81
  666. package/dist/cli/chunk-vrfp10qk.js.map +0 -10
  667. package/dist/cli/chunk-wjt80jps.js +0 -1049
  668. package/dist/cli/chunk-wjt80jps.js.map +0 -24
  669. package/docs/advanced/api-reference.mdx +0 -240
  670. package/docs/reference/cli.mdx +0 -197
  671. package/skills/blume-migrate/assets/oxfmt@0.55.0.patch +0 -20
  672. package/src/components/content/changelog-element.ts +0 -69
  673. package/src/search/providers.ts +0 -91
  674. /package/dist/cli/{chunk-3w7b2vcx.js.map → chunk-7ez8ny0t.js.map} +0 -0
  675. /package/dist/cli/{chunk-688e0dde.js.map → chunk-88cpgt6h.js.map} +0 -0
  676. /package/dist/cli/{chunk-exeeb35e.js.map → chunk-f7t03s3g.js.map} +0 -0
  677. /package/dist/cli/{chunk-ppfvdcd4.js.map → chunk-zxccj738.js.map} +0 -0
@@ -7,7 +7,7 @@ import {
7
7
  advanceHtmlCommentState,
8
8
  expandIncludeTarget,
9
9
  hasIncludeStatements,
10
- parseIncludeLine,
10
+ matchIncludeStatement,
11
11
  } from "../core/includes.ts";
12
12
  import type { MdastNode, MdastValue } from "./mdast.ts";
13
13
 
@@ -151,32 +151,42 @@ export const includePlugin = (options: IncludePluginOptions = {}) => {
151
151
  };
152
152
 
153
153
  /**
154
- * Splice every statement line in a text block; `null` when none matched.
155
- * Statement detection mirrors the string-level scanner's `.md` line rules
156
- * (`parseIncludeLine`, HTML comment tracking) so the rendered page and the
157
- * indexed/mirrored surfaces agree on which lines splice: a statement inside
158
- * `<!-- -->` or indented like code stays verbatim on both sides.
154
+ * Splice every statement in a text block; `null` when none matched.
155
+ * Statement detection is the string-level scanner's (`matchIncludeStatement`
156
+ * with its `.md` rules, plus HTML comment tracking), so the rendered page and
157
+ * the indexed/mirrored surfaces agree on what splices: a statement inside
158
+ * `<!-- -->` or indented like code stays verbatim on both sides, and a
159
+ * wrapped statement splices whole on both.
159
160
  */
160
161
  const spliceLines = async (
161
162
  node: MdastNode,
162
163
  text: string,
163
164
  ctx: IncludeVisitorContext
164
165
  ): Promise<string | null> => {
166
+ const source = text.split("\n");
167
+ const pieces: (string | Promise<string>)[] = [];
165
168
  let matched = false;
166
169
  let inComment = false;
167
- const lines = await Promise.all(
168
- text.split("\n").map((line) => {
169
- const wasInComment = inComment;
170
- inComment = advanceHtmlCommentState(line, inComment);
171
- const statement = wasInComment ? null : parseIncludeLine(line);
172
- if (!statement) {
173
- return line;
174
- }
175
- matched = true;
176
- return splice(node, statement, ctx);
177
- })
178
- );
179
- return matched ? lines.join("\n") : null;
170
+ for (let index = 0; index < source.length; index += 1) {
171
+ const line = source[index] ?? "";
172
+ const wasInComment = inComment;
173
+ inComment = advanceHtmlCommentState(line, inComment);
174
+ const match = wasInComment
175
+ ? null
176
+ : matchIncludeStatement(source, index, "md");
177
+ if (match?.kind !== "statement") {
178
+ pieces.push(line);
179
+ continue;
180
+ }
181
+ matched = true;
182
+ pieces.push(splice(node, match.statement, ctx));
183
+ index = match.end;
184
+ }
185
+ if (!matched) {
186
+ return null;
187
+ }
188
+ const spliced = await Promise.all(pieces);
189
+ return spliced.join("\n");
180
190
  };
181
191
 
182
192
  return {
@@ -195,17 +205,25 @@ export const includePlugin = (options: IncludePluginOptions = {}) => {
195
205
  if (node.name !== "include") {
196
206
  return;
197
207
  }
198
- // The string-level scanner (search, mirrors, llms-full.txt, the HMR
199
- // graph) only recognizes single-line statements; a wrapped element
200
- // would render content those surfaces never see, so reject it loudly
201
- // instead of splicing it invisibly.
208
+ // A wrapped element splices only when the string-level scanner (search,
209
+ // mirrors, llms-full.txt, the HMR graph) reads the same lines as one
210
+ // statement; anything it can't read would render content those surfaces
211
+ // never see, so it's rejected loudly instead of spliced invisibly.
202
212
  const start = node.position?.start?.line;
203
213
  const end = node.position?.end?.line;
204
214
  if (start !== undefined && end !== undefined && start !== end) {
205
- const message =
206
- "<include> must be written on a single line: <include>./path.mdx</include>.";
207
- ctx.report({ message, node, severity: "warning" });
208
- ctx.replaceNode(node, { raw: errorBlock(message) });
215
+ const lines = ctx.source.split("\n").slice(start - 1, end);
216
+ const match = matchIncludeStatement(lines, 0, "mdx");
217
+ if (match.kind !== "statement" || match.end !== lines.length - 1) {
218
+ const message =
219
+ "<include> must sit on a line of its own, or wrap with the path on its own line and no blank lines: <include>./path.mdx</include>.";
220
+ ctx.report({ message, node, severity: "warning" });
221
+ ctx.replaceNode(node, { raw: errorBlock(message) });
222
+ return;
223
+ }
224
+ ctx.replaceNode(node, {
225
+ raw: await splice(node, match.statement, ctx),
226
+ });
209
227
  return;
210
228
  }
211
229
  ctx.replaceNode(node, {
@@ -12,6 +12,7 @@ import { codeToHtml } from "shiki";
12
12
  import { baseLinksPlugin } from "./base-links.ts";
13
13
  import { codeTitleTransformer } from "./code-title.ts";
14
14
  import { directiveToCalloutPlugin } from "./directives.ts";
15
+ import { externalLinksPlugin } from "./external-links.ts";
15
16
  import { MARKDOWN_FEATURES, MDX_FEATURES } from "./features.ts";
16
17
  import { headingAnchorPlugin } from "./heading-anchors.ts";
17
18
  import { includePlugin } from "./include.ts";
@@ -20,6 +21,7 @@ import { languageIconTransformer } from "./language-icon.ts";
20
21
  import { mathPlugin } from "./math.ts";
21
22
  import { mermaidPlugin } from "./mermaid.ts";
22
23
  import { packageInstallPlugin } from "./package-install.ts";
24
+ import { relativeLinksPlugin } from "./relative-links.ts";
23
25
  import { tableWrapPlugin } from "./table-wrap.ts";
24
26
  import { DEFAULT_CODE_THEMES } from "./themes.ts";
25
27
  import type { CodeThemes } from "./themes.ts";
@@ -87,12 +89,14 @@ const asShikiTransformer = (transformer: { name: string }): ShikiTransformer =>
87
89
  * (`[#custom-id]`, `[!toc]`, `[toc]`), which must parse regardless of config —
88
90
  * while `markdown.headingAnchors: false` only turns off the self-linking
89
91
  * anchor wrap on `<h2>`–`<h6>`. Inline code runs first so the anchor wrap
90
- * re-refs already-highlighted code.
92
+ * re-refs already-highlighted code. The external-link plugin is added only
93
+ * when `markdown.externalLinks` is on, so off stays today's exact output.
91
94
  */
92
95
  const blumeHastPlugins = (options: BlumeMarkdownOptions): HastPlugin[] => [
93
96
  asHastPlugin(inlineCodeHighlightPlugin(options.codeThemes)),
94
97
  asHastPlugin(tableWrapPlugin()),
95
98
  asHastPlugin(headingAnchorPlugin({ wrap: options.headingAnchors !== false })),
99
+ ...(options.externalLinks ? [asHastPlugin(externalLinksPlugin())] : []),
96
100
  ];
97
101
 
98
102
  /**
@@ -196,7 +200,7 @@ export interface HighlightCodeOptions extends BlumeShikiOptions {
196
200
  /** Extra `<pre>` class names, e.g. `blume-source` for a height-capped pane. */
197
201
  className?: string;
198
202
  /**
199
- * Light/dark Shiki themes (`markdown.codeBlocks.theme`). Defaults to the same
203
+ * Light/dark Shiki themes (`markdown.code.theme`). Defaults to the same
200
204
  * github pair fenced code uses, so out-of-pipeline code stays in lockstep.
201
205
  */
202
206
  themes?: CodeThemes;
@@ -248,9 +252,14 @@ export const highlightCode = async (
248
252
  export interface BlumeMarkdownOptions {
249
253
  /**
250
254
  * Light/dark Shiki themes for inline `` `code`{:lang} `` highlighting
251
- * (`markdown.codeBlocks.theme`). Defaults to the github pair fenced code uses.
255
+ * (`markdown.code.theme`). Defaults to the github pair fenced code uses.
252
256
  */
253
257
  codeThemes?: CodeThemes;
258
+ /**
259
+ * Open external links in a new tab, marked with an arrow icon and a
260
+ * screen-reader hint (`markdown.externalLinks`). Off unless `true`.
261
+ */
262
+ externalLinks?: boolean;
254
263
  /**
255
264
  * Wrap `<h2>`–`<h6>` in self-linking anchors (`markdown.headingAnchors`).
256
265
  * On unless explicitly `false`.
@@ -271,25 +280,41 @@ export interface BlumeMarkdownOptions {
271
280
  /**
272
281
  * The docs content root, bounding `<include>` target resolution (and
273
282
  * anchoring `/`-leading include paths). When unset, relative includes still
274
- * resolve from the including file.
283
+ * resolve from the including file. Also the base the `docs` collection's
284
+ * entry ids are relative to, which relative page links resolve through.
275
285
  */
276
286
  contentRoot?: string;
287
+ /**
288
+ * The `blume:data` snapshot file an ejected app aliases. Relative page links
289
+ * resolve through the snapshot the CLI publishes; with no CLI in the
290
+ * process, they read this file instead.
291
+ */
292
+ dataFile?: string;
277
293
  }
278
294
 
279
295
  /**
280
- * MDAST plugins that apply to both `.md` and `.mdx`: the base-path link
281
- * rewrite (added only when a `basePath` or `deployBase` is configured).
296
+ * MDAST plugins that apply to both `.md` and `.mdx`: relative page links
297
+ * rewritten to the root-relative route they mean, then the base-path link
298
+ * rewrite (added only when a `basePath` or `deployBase` is configured), which
299
+ * layers `deployment.base` over the rewritten routes.
282
300
  */
283
301
  const blumeSharedMdastPlugins = (
284
302
  options: BlumeMarkdownOptions
285
- ): MdastPlugin[] =>
286
- options.basePath || options.deployBase
303
+ ): MdastPlugin[] => [
304
+ asMdastPlugin(
305
+ relativeLinksPlugin({
306
+ contentRoot: options.contentRoot,
307
+ dataFile: options.dataFile,
308
+ })
309
+ ),
310
+ ...(options.basePath || options.deployBase
287
311
  ? [
288
312
  asMdastPlugin(
289
313
  baseLinksPlugin(options.deployBase ?? "", options.basePath ?? "")
290
314
  ),
291
315
  ]
292
- : [];
316
+ : []),
317
+ ];
293
318
 
294
319
  /**
295
320
  * The `<include>` splice. Always first: its mutations apply before the next
@@ -7,11 +7,14 @@
7
7
  * marker and replaces the code's text with Shiki tokens (dual github-light/dark
8
8
  * via CSS variables, like fenced blocks).
9
9
  *
10
- * Shiki is imported lazily, so it loads only on pages that actually use inline
10
+ * Shiki is loaded lazily, so it loads only on pages that actually use inline
11
11
  * highlighting — and never when `markdown.code.inline` is off (the plugin is not
12
12
  * added to the pipeline at all).
13
13
  */
14
14
 
15
+ import type * as ShikiModule from "shiki";
16
+
17
+ import { nodeRequire } from "../core/node-require.ts";
15
18
  import { DEFAULT_CODE_THEMES } from "./themes.ts";
16
19
  import type { CodeThemes } from "./themes.ts";
17
20
 
@@ -77,13 +80,16 @@ type InlineHighlighter = (
77
80
  }
78
81
  ) => Promise<{ children: HastNode[] }>;
79
82
 
80
- // `import()` caches the module, so this dedupes Shiki across calls on its own.
81
- const loadHighlighter = async (): Promise<InlineHighlighter> => {
82
- const mod = await import("shiki");
83
+ // `require` caches the module, so this dedupes Shiki across calls on its own.
84
+ // Not `import()`: the plugin runs after Astro has closed the module runner an
85
+ // installed Blume's config was evaluated in (see `core/node-require.ts`), so
86
+ // every inline snippet would silently lose its highlighting.
87
+ const loadHighlighter = (): InlineHighlighter => {
88
+ const { codeToHast }: typeof ShikiModule = nodeRequire("shiki");
83
89
  // SAFETY: Shiki accepts arbitrary lang/theme strings at runtime (an unknown
84
90
  // one rejects the promise, which the caller catches); only its bundled types
85
91
  // constrain them to known ids, so the loose signature narrows nothing real.
86
- return mod.codeToHast as InlineHighlighter;
92
+ return codeToHast as InlineHighlighter;
87
93
  };
88
94
 
89
95
  /** Build the plugin. Highlights inline `` `code{:lang}` `` snippets. */
@@ -102,7 +108,7 @@ export const inlineCodeHighlightPlugin = (
102
108
  return;
103
109
  }
104
110
  try {
105
- const codeToHast = await loadHighlighter();
111
+ const codeToHast = loadHighlighter();
106
112
  const root = await codeToHast(parsed.code, {
107
113
  defaultColor: false,
108
114
  lang: parsed.lang,
@@ -0,0 +1,324 @@
1
+ import { readFileSync, statSync } from "node:fs";
2
+ import { fileURLToPath } from "node:url";
3
+
4
+ import { dirname, normalize, relative, resolve } from "pathe";
5
+
6
+ import { readRuntimeModule } from "../astro/runtime-modules.ts";
7
+ import { isIndexFileName, resolveRelativeHref } from "../core/links.ts";
8
+ import type { RelativeLinkBase } from "../core/links.ts";
9
+ import type { MdastNode, MdastValue } from "./mdast.ts";
10
+
11
+ interface UrlNode extends MdastNode {
12
+ url?: string | null;
13
+ }
14
+
15
+ /** An MDX JSX attribute, as the plugin reads it. */
16
+ interface JsxAttribute {
17
+ [key: string]: MdastValue;
18
+ name?: string;
19
+ type?: string;
20
+ value?: MdastValue;
21
+ }
22
+
23
+ /** An MDX JSX element (`<Card href="./install" />`), as the plugin reads it. */
24
+ interface JsxNode extends MdastNode {
25
+ attributes?: JsxAttribute[];
26
+ children?: MdastValue[];
27
+ name?: string | null;
28
+ }
29
+
30
+ /** The visitor-context slice this plugin uses (see `mdast.ts` for the model). */
31
+ interface RelativeLinksContext {
32
+ fileURL: URL | undefined;
33
+ replaceNode: (node: MdastNode, replacement: MdastNode) => void;
34
+ setProperty: (node: MdastNode, key: "url", value: string) => void;
35
+ }
36
+
37
+ /** The slice of the `blume:data` snapshot the plugin reads. */
38
+ interface RouteData {
39
+ config: {
40
+ i18n?: { defaultLocale: string; locales: { code: string }[] } | null;
41
+ };
42
+ routes: {
43
+ collection: string;
44
+ entryId: string;
45
+ fallback: boolean;
46
+ locale: string;
47
+ path: string;
48
+ }[];
49
+ }
50
+
51
+ /** What the plugin knows about where content files publish. */
52
+ interface RouteIndex {
53
+ /** `collection` + NUL + `entryId` → the route that entry publishes at. */
54
+ routes: Map<string, string>;
55
+ /** Every route the site serves, fallback copies included. */
56
+ paths: Set<string>;
57
+ /** Tokens an index file name may carry before its extension. */
58
+ localeTokens: string[];
59
+ /** The locale folders beside the default tree (every locale but the default). */
60
+ localeFolders: string[];
61
+ }
62
+
63
+ /** A content file, located: its page, and how to find the files beside it. */
64
+ interface LocatedPage extends RelativeLinkBase {
65
+ /** The route a sibling file publishes at, from its path relative to `file`. */
66
+ routeOf: (path: string) => string | undefined;
67
+ /** Every route the site serves, for dotted page names (`./node.js`). */
68
+ routes: ReadonlySet<string>;
69
+ }
70
+
71
+ /** A JSX component name (`Card`, `Tree.File`), as opposed to an HTML tag. */
72
+ const COMPONENT_NAME = /^[A-Z]/u;
73
+
74
+ /** A plain string attribute value; an expression value isn't a link target. */
75
+ const isStringValue = (value: MdastValue): value is string =>
76
+ typeof value === "string";
77
+
78
+ const entryKey = (collection: string, entryId: string): string =>
79
+ `${collection}\0${entryId}`;
80
+
81
+ /**
82
+ * Index the snapshot's routes by collection entry. A file shared by every
83
+ * locale publishes once per locale; the default locale's route stands for it,
84
+ * and the rendered link moves into the reader's locale afterwards (see
85
+ * `LocaleLinks.astro`). Fallback copies render another locale's file, so they
86
+ * never stand for it.
87
+ */
88
+ const indexRoutes = (data: RouteData): RouteIndex => {
89
+ const defaultLocale = data.config.i18n?.defaultLocale;
90
+ const routes = new Map<string, string>();
91
+ for (const route of data.routes) {
92
+ if (route.fallback) {
93
+ continue;
94
+ }
95
+ const key = entryKey(route.collection, route.entryId);
96
+ if (!routes.has(key) || route.locale === defaultLocale) {
97
+ routes.set(key, route.path);
98
+ }
99
+ }
100
+ const locales = data.config.i18n?.locales.map((locale) => locale.code) ?? [];
101
+ return {
102
+ localeFolders: locales.filter((code) => code !== defaultLocale),
103
+ localeTokens: data.config.i18n ? ["$", ...locales] : [],
104
+ paths: new Set(data.routes.map((route) => route.path)),
105
+ routes,
106
+ };
107
+ };
108
+
109
+ /**
110
+ * The same entry path in the default tree: a page in a locale folder that
111
+ * links a sibling not translated yet (`fr/guides/setup.mdx` missing) means
112
+ * the default tree's file (`guides/setup.mdx`), whose route — its own `slug`
113
+ * included — moves into the reader's locale afterwards, onto the fallback
114
+ * copy (see `LocaleLinks.astro`).
115
+ */
116
+ const defaultTreePath = (
117
+ entryId: string,
118
+ localeFolders: readonly string[]
119
+ ): string | undefined => {
120
+ const slash = entryId.indexOf("/");
121
+ return slash !== -1 && localeFolders.includes(entryId.slice(0, slash))
122
+ ? entryId.slice(slash + 1)
123
+ : undefined;
124
+ };
125
+
126
+ export interface RelativeLinksPluginOptions {
127
+ /** The `docs` collection's base directory, which entry ids are relative to. */
128
+ contentRoot?: string;
129
+ /**
130
+ * The `blume:data` JSON file, for an ejected app: with no CLI in the process
131
+ * to publish the snapshot, the plugin reads the file eject writes instead.
132
+ */
133
+ dataFile?: string;
134
+ }
135
+
136
+ /**
137
+ * Satteri MDAST plugin that rewrites relative page links (`[Install](./install)`,
138
+ * `[Setup](../guides/setup.md)`) to the root-relative route they mean, using
139
+ * the same file-style reading `blume validate` checks them against
140
+ * (`resolveRelativeHref`). Left as written, the browser resolves them against
141
+ * the page's slashless URL — so `./install` on an index page (`/guides`) lands
142
+ * on `/install`, and a `.md` link opens the raw Markdown source instead of the
143
+ * page. The page's own route, and a linked file's, come from the `blume:data`
144
+ * snapshot the CLI publishes (or, ejected, the file eject writes), keyed by
145
+ * collection entry: `docs` entries by their path under `contentRoot`, staged
146
+ * entries (remote sources) by the longest trailing path that names one. A file
147
+ * the snapshot doesn't know keeps its links as written.
148
+ *
149
+ * Runs before the base-links plugin, whose `basePath` layering is idempotent,
150
+ * so a rewritten route (which already carries `basePath`) only gains the
151
+ * `deployment.base` prefix.
152
+ */
153
+ export const relativeLinksPlugin = (
154
+ options: RelativeLinksPluginOptions = {}
155
+ ) => {
156
+ const contentRoot = options.contentRoot
157
+ ? resolve(options.contentRoot)
158
+ : undefined;
159
+ const dataFile = options.dataFile ? resolve(options.dataFile) : undefined;
160
+
161
+ // Parsed once per published snapshot: the CLI republishes on regeneration,
162
+ // and an unchanged snapshot is the same string, so every page compiled
163
+ // between regenerations reuses one index.
164
+ let cached: { index: RouteIndex; text: string } | undefined;
165
+ let fileStamp: number | undefined;
166
+ let fileText: string | undefined;
167
+
168
+ /** The ejected snapshot file's text, re-read only when it changes. */
169
+ const readDataFile = (path: string): string | undefined => {
170
+ let stamp: number;
171
+ try {
172
+ stamp = statSync(path).mtimeMs;
173
+ } catch {
174
+ return undefined;
175
+ }
176
+ if (stamp !== fileStamp) {
177
+ fileStamp = stamp;
178
+ fileText = readFileSync(path, "utf-8");
179
+ }
180
+ return fileText;
181
+ };
182
+
183
+ const routeIndex = (): RouteIndex | undefined => {
184
+ const text =
185
+ readRuntimeModule("blume:data") ??
186
+ (dataFile ? readDataFile(dataFile) : undefined);
187
+ if (text === undefined) {
188
+ return undefined;
189
+ }
190
+ if (cached?.text !== text) {
191
+ const data: RouteData = JSON.parse(text);
192
+ cached = { index: indexRoutes(data), text };
193
+ }
194
+ return cached.index;
195
+ };
196
+
197
+ /** The page `file` renders, with a resolver for the files beside it. */
198
+ const locate = (file: string, index: RouteIndex): LocatedPage | undefined => {
199
+ const locateIn = (
200
+ collection: string,
201
+ base: string
202
+ ): LocatedPage | undefined => {
203
+ const entryId = relative(base, file);
204
+ const route = index.routes.get(entryKey(collection, entryId));
205
+ if (route === undefined) {
206
+ return undefined;
207
+ }
208
+ return {
209
+ isIndex: isIndexFileName(entryId, index.localeTokens),
210
+ route,
211
+ routeOf: (path) => {
212
+ const target = relative(base, resolve(dirname(file), path));
213
+ const inDefaultTree = defaultTreePath(target, index.localeFolders);
214
+ return (
215
+ index.routes.get(entryKey(collection, target)) ??
216
+ (inDefaultTree === undefined
217
+ ? undefined
218
+ : index.routes.get(entryKey(collection, inDefaultTree)))
219
+ );
220
+ },
221
+ routes: index.paths,
222
+ };
223
+ };
224
+ if (contentRoot && !relative(contentRoot, file).startsWith("../")) {
225
+ return locateIn("docs", contentRoot);
226
+ }
227
+ // A staged entry's id is its path under the staging dir, which the plugin
228
+ // isn't told: the longest trailing path naming a staged entry wins.
229
+ const segments = file.split("/");
230
+ for (let start = 1; start < segments.length; start += 1) {
231
+ const staged = locateIn(
232
+ "staged",
233
+ segments.slice(0, start).join("/") || "/"
234
+ );
235
+ if (staged) {
236
+ return staged;
237
+ }
238
+ }
239
+ return undefined;
240
+ };
241
+
242
+ /** The route `url` means on the page at `fileURL`, when it's relative. */
243
+ const resolveUrl = (
244
+ url: string,
245
+ fileURL: URL | undefined
246
+ ): string | undefined => {
247
+ // Cheap first: a target that can't be relative never needs the index. A
248
+ // dotted name (`./node.js`) passes, since only the index knows its route.
249
+ if (
250
+ !fileURL ||
251
+ resolveRelativeHref(
252
+ url,
253
+ { isIndex: false, route: "/" },
254
+ undefined,
255
+ () => true
256
+ ) === undefined
257
+ ) {
258
+ return undefined;
259
+ }
260
+ const index = routeIndex();
261
+ const page = index && locate(normalize(fileURLToPath(fileURL)), index);
262
+ if (!page) {
263
+ return undefined;
264
+ }
265
+ const next = resolveRelativeHref(url, page, page.routeOf, (route) =>
266
+ page.routes.has(route)
267
+ );
268
+ return next === url ? undefined : next;
269
+ };
270
+
271
+ const rewrite = (node: UrlNode, ctx: RelativeLinksContext): void => {
272
+ const { url } = node;
273
+ const next = isStringValue(url) ? resolveUrl(url, ctx.fileURL) : undefined;
274
+ if (next !== undefined) {
275
+ ctx.setProperty(node, "url", next);
276
+ }
277
+ };
278
+
279
+ // A component's string `href` (`<Card href="./install">`) is the same kind
280
+ // of link, and `blume validate` reads it as one. Lowercase elements are
281
+ // raw HTML in a `.md` page, which neither rewrites nor checks, so only
282
+ // components are rewritten; an expression-valued `href={…}` is left alone.
283
+ const rewriteHref = (node: JsxNode, ctx: RelativeLinksContext): void => {
284
+ if (!node.name || !COMPONENT_NAME.test(node.name)) {
285
+ return;
286
+ }
287
+ const attributes = node.attributes ?? [];
288
+ const at = attributes.findIndex(
289
+ (attribute) =>
290
+ attribute.type === "mdxJsxAttribute" &&
291
+ attribute.name === "href" &&
292
+ isStringValue(attribute.value)
293
+ );
294
+ const value = attributes[at]?.value;
295
+ const next = isStringValue(value)
296
+ ? resolveUrl(value, ctx.fileURL)
297
+ : undefined;
298
+ if (next !== undefined) {
299
+ // Sätteri can't set a JSX element's attributes in place, so the element
300
+ // is swapped for a copy; its children carry over and are still visited.
301
+ ctx.replaceNode(node, {
302
+ attributes: attributes.map((attribute, position) =>
303
+ position === at
304
+ ? { name: attribute.name, type: attribute.type, value: next }
305
+ : attribute
306
+ ),
307
+ children: node.children ?? [],
308
+ name: node.name,
309
+ type: node.type,
310
+ });
311
+ }
312
+ };
313
+
314
+ // `link` covers inline links; `definition` covers reference-style
315
+ // definitions (`[x]: ./install`). Images stay with the image pipeline, which
316
+ // resolves relative embeds from beside the page source.
317
+ return {
318
+ definition: rewrite,
319
+ link: rewrite,
320
+ mdxJsxFlowElement: rewriteHref,
321
+ mdxJsxTextElement: rewriteHref,
322
+ name: "blume-relative-links",
323
+ };
324
+ };
@@ -2,7 +2,7 @@
2
2
  * The light/dark Shiki themes Blume highlights code with. Every Shiki surface —
3
3
  * fenced code (the generated Astro `shikiConfig.themes`), inline `` `code`{:lang} ``,
4
4
  * out-of-pipeline `highlightCode`, and `<Diff>` — resolves to the same pair so a
5
- * project's `markdown.codeBlocks.theme` shifts them all in lockstep. This is the
5
+ * project's `markdown.code.theme` shifts them all in lockstep. This is the
6
6
  * single home for the github fallback used when nothing is configured.
7
7
  */
8
8
 
@@ -12,7 +12,7 @@ import type { ThemeRegistrationAny } from "shiki";
12
12
  export type CodeTheme = string | ThemeRegistrationAny;
13
13
 
14
14
  /**
15
- * A light/dark Shiki theme pair (`markdown.codeBlocks.theme`). A `type` (not an
15
+ * A light/dark Shiki theme pair (`markdown.code.theme`). A `type` (not an
16
16
  * `interface`) so it keeps the implicit index signature Shiki's `themes`
17
17
  * parameter (`Partial<Record<string, …>>`) expects.
18
18
  */
@@ -22,7 +22,7 @@ export type CodeThemes = {
22
22
  light: CodeTheme;
23
23
  };
24
24
 
25
- /** The default pair, used when `markdown.codeBlocks.theme` is unset. */
25
+ /** The default pair, used when `markdown.code.theme` is unset. */
26
26
  export const DEFAULT_CODE_THEMES: CodeThemes = {
27
27
  dark: "github-dark",
28
28
  light: "github-light",