blume 2.1.0 → 2.1.1
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.
- package/CHANGELOG.md +94 -0
- package/dist/cli/{chunk-5cg2rzgf.js → chunk-073rdvgb.js} +19 -48
- package/dist/cli/{chunk-5cg2rzgf.js.map → chunk-073rdvgb.js.map} +4 -5
- package/dist/cli/{chunk-ga0pf4aj.js → chunk-0n9xkp3d.js} +12 -3
- package/dist/cli/{chunk-ga0pf4aj.js.map → chunk-0n9xkp3d.js.map} +3 -3
- package/dist/cli/chunk-150jk7km.js +52 -0
- package/dist/cli/chunk-150jk7km.js.map +10 -0
- package/dist/cli/{chunk-rekqz4qg.js → chunk-313vnn40.js} +16 -15
- package/dist/cli/chunk-313vnn40.js.map +10 -0
- package/dist/cli/{chunk-gp84za0h.js → chunk-3v3ffbrj.js} +2 -2
- package/dist/cli/{chunk-9xr4dgee.js → chunk-3x6x3pph.js} +29 -16
- package/dist/cli/chunk-3x6x3pph.js.map +10 -0
- package/dist/cli/{chunk-0gz36akr.js → chunk-42t4jxdx.js} +21 -5
- package/dist/cli/chunk-42t4jxdx.js.map +12 -0
- package/dist/cli/{chunk-ta27feev.js → chunk-54ztw1nj.js} +21 -2
- package/dist/cli/chunk-54ztw1nj.js.map +10 -0
- package/dist/cli/{chunk-jnwj5kjj.js → chunk-5vjtgs6e.js} +20 -7
- package/dist/cli/{chunk-jnwj5kjj.js.map → chunk-5vjtgs6e.js.map} +3 -3
- package/dist/cli/chunk-66w9j7p6.js +322 -0
- package/dist/cli/chunk-66w9j7p6.js.map +14 -0
- package/dist/cli/{chunk-nd1821sk.js → chunk-7ppf1rva.js} +32 -18
- package/dist/cli/chunk-7ppf1rva.js.map +10 -0
- package/dist/cli/{chunk-p804f3pe.js → chunk-8y2kmjv8.js} +6 -6
- package/dist/cli/{chunk-2f7n4qzt.js → chunk-c1y538kd.js} +1 -1
- package/dist/cli/{chunk-1n228xqb.js → chunk-c887fj0s.js} +2 -2
- package/dist/cli/{chunk-y5h4r2y0.js → chunk-cfyg47zg.js} +15 -5
- package/dist/cli/chunk-cfyg47zg.js.map +10 -0
- package/dist/cli/{chunk-cmtcnh9f.js → chunk-dzwehpy7.js} +2 -2
- package/dist/cli/{chunk-h2a48yhd.js → chunk-e6atmn4h.js} +119 -15
- package/dist/cli/{chunk-h2a48yhd.js.map → chunk-e6atmn4h.js.map} +10 -10
- package/dist/cli/{chunk-5ffywsmb.js → chunk-e8xw9qkh.js} +8 -6
- package/dist/cli/{chunk-5ffywsmb.js.map → chunk-e8xw9qkh.js.map} +3 -3
- package/dist/cli/{chunk-ntv4qrt7.js → chunk-e9q7a2ak.js} +14 -14
- package/dist/cli/{chunk-xkz5xbtv.js → chunk-ehweg4fr.js} +2366 -1114
- package/dist/cli/chunk-ehweg4fr.js.map +218 -0
- package/dist/cli/{chunk-zf748avv.js → chunk-ep6nd0rn.js} +176 -281
- package/dist/cli/{chunk-zf748avv.js.map → chunk-ep6nd0rn.js.map} +11 -12
- package/dist/cli/{chunk-yxmk4pec.js → chunk-fdrkhpjy.js} +16 -15
- package/dist/cli/{chunk-yxmk4pec.js.map → chunk-fdrkhpjy.js.map} +3 -3
- package/dist/cli/{chunk-5wj2qwn2.js → chunk-ft9vfys6.js} +4 -4
- package/dist/cli/{chunk-4h8z9vv5.js → chunk-gb420vvz.js} +89 -46
- package/dist/cli/chunk-gb420vvz.js.map +17 -0
- package/dist/cli/{chunk-713mngdq.js → chunk-hebn0tpx.js} +76 -10
- package/dist/cli/chunk-hebn0tpx.js.map +14 -0
- package/dist/cli/{chunk-2n4ps1b3.js → chunk-htrwgabr.js} +40 -22
- package/dist/cli/chunk-htrwgabr.js.map +15 -0
- package/dist/cli/{chunk-zhvd6adm.js → chunk-hx3xqnk9.js} +13 -13
- package/dist/cli/chunk-j134vrp2.js +65 -0
- package/dist/cli/chunk-j134vrp2.js.map +10 -0
- package/dist/cli/{chunk-y4ykbark.js → chunk-kma9f6sf.js} +2 -2
- package/dist/cli/{chunk-py62fewh.js → chunk-mrcccgnh.js} +3 -3
- package/dist/cli/{chunk-2f3ndkpw.js → chunk-n0v7m8ry.js} +3 -3
- package/dist/cli/{chunk-43zcf4gz.js → chunk-ncj7w596.js} +522 -353
- package/dist/cli/chunk-ncj7w596.js.map +35 -0
- package/dist/cli/{chunk-9geymqns.js → chunk-nq1d20w2.js} +14 -14
- package/dist/cli/{chunk-g2z9x01v.js → chunk-nrns10mj.js} +3 -3
- package/dist/cli/{chunk-e7vvk5ya.js → chunk-sds923fa.js} +3 -3
- package/dist/cli/{chunk-cy5bm0j0.js → chunk-t2m5j4pr.js} +2 -2
- package/dist/cli/{chunk-cy5bm0j0.js.map → chunk-t2m5j4pr.js.map} +1 -1
- package/dist/cli/{chunk-yj17vs39.js → chunk-tdqhyxfz.js} +5 -5
- package/dist/cli/{chunk-q3wxxq39.js → chunk-tphac74f.js} +5 -5
- package/dist/cli/{chunk-6bm0xpgd.js → chunk-w1r4vase.js} +2 -2
- package/dist/cli/index.js +24 -19
- package/dist/cli/index.js.map +3 -3
- package/dist/types/ai/ask-context.d.ts +6 -2
- package/dist/types/ai/component-markdown.d.ts +2 -0
- package/dist/types/ai/openapi-components.d.ts +4 -1
- package/dist/types/astro/integration.d.ts +5 -4
- package/dist/types/astro/markdown-negotiation.d.ts +3 -0
- package/dist/types/astro/pages.d.ts +10 -0
- package/dist/types/cli/init/scaffold.d.ts +1 -1
- package/dist/types/components/content/api-field.d.ts +4 -1
- package/dist/types/components/content/api-page.d.ts +6 -1
- package/dist/types/components/openapi/code-samples.d.ts +29 -0
- package/dist/types/components/openapi/helpers.d.ts +22 -1
- package/dist/types/components/openapi/security.d.ts +10 -0
- package/dist/types/components/openapi/snippets.d.ts +60 -0
- package/dist/types/core/changelog-index.d.ts +8 -0
- package/dist/types/core/config-input.d.ts +30 -3
- package/dist/types/core/data.d.ts +4 -0
- package/dist/types/core/i18n-ui.d.ts +2 -0
- package/dist/types/core/links.d.ts +8 -0
- package/dist/types/core/probe.d.ts +2 -0
- package/dist/types/core/project-graph.d.ts +6 -0
- package/dist/types/core/redirect-patterns.d.ts +11 -3
- package/dist/types/core/schema.d.ts +119 -0
- package/dist/types/core/sources/cache.d.ts +3 -0
- package/dist/types/core/sources/contentful-rich-text.d.ts +11 -2
- package/dist/types/core/sources/contentful.d.ts +17 -1
- package/dist/types/core/sources/lexical.d.ts +5 -0
- package/dist/types/core/sources/normalize.d.ts +20 -1
- package/dist/types/core/sources/remote.d.ts +37 -10
- package/dist/types/core/sources/sanity.d.ts +1 -1
- package/dist/types/core/types.d.ts +17 -0
- package/dist/types/deploy/adapter-output.d.ts +2 -1
- package/dist/types/deploy/adapters/cloudflare.d.ts +7 -5
- package/dist/types/deploy/adapters/node.d.ts +58 -23
- package/dist/types/deploy/adapters/registry.d.ts +10 -0
- package/dist/types/deploy/adapters/types.d.ts +3 -2
- package/dist/types/deploy/platforms/cloudflare.d.ts +10 -7
- package/dist/types/deploy/platforms/node.d.ts +3 -1
- package/dist/types/deploy/platforms/types.d.ts +18 -7
- package/dist/types/deploy/platforms/vercel.d.ts +20 -1
- package/dist/types/deploy/redirects.d.ts +17 -1
- package/dist/types/deploy/sitemap.d.ts +2 -1
- package/dist/types/deploy/vercel-negotiation.d.ts +42 -21
- package/dist/types/openapi/checks.d.ts +27 -0
- package/dist/types/openapi/graphql.d.ts +6 -0
- package/dist/types/openapi/model.d.ts +15 -4
- package/dist/types/openapi/parse.d.ts +3 -0
- package/dist/types/openapi/references.d.ts +16 -0
- package/dist/types/ratelimit/index.d.ts +1 -1
- package/dist/types/ratelimit/schema.d.ts +8 -0
- package/dist/types/ratelimit/upstash.d.ts +39 -14
- package/dist/types/reference/graphql.d.ts +76 -1
- package/dist/types/reference/index.d.ts +1 -1
- package/dist/types/reference/openapi.d.ts +2 -2
- package/dist/types/reference/options.d.ts +37 -1
- package/dist/types/reference/schema.d.ts +84 -0
- package/dist/types/search/adapters/registry.d.ts +3 -0
- package/dist/types/search/adapters/typesense.d.ts +14 -4
- package/dist/types/search/build.d.ts +3 -1
- package/dist/types/search/orama-index.d.ts +9 -9
- package/dist/types/search/sync/algolia.d.ts +5 -2
- package/dist/types/search/sync/index.d.ts +3 -1
- package/dist/types/search/sync/typesense.d.ts +11 -7
- package/dist/types/sources/contentful.d.ts +16 -0
- package/dist/types/sources/github-releases.d.ts +8 -1
- package/dist/types/sources/payload.d.ts +2 -0
- package/dist/types/sources/registry.d.ts +54 -0
- package/dist/types/sources/shared.d.ts +3 -0
- package/dist/types/sources/strapi.d.ts +2 -0
- package/docs/01-quickstart.mdx +4 -2
- package/docs/02-deployment.mdx +31 -13
- package/docs/advanced/changelog.mdx +11 -0
- package/docs/advanced/skills.mdx +1 -1
- package/docs/cli/audit.mdx +30 -7
- package/docs/cli/doctor.mdx +5 -1
- package/docs/cli/evals.mdx +4 -4
- package/docs/cli/translate.mdx +1 -0
- package/docs/cli/validate.mdx +4 -3
- package/docs/configuration/analytics.mdx +1 -1
- package/docs/configuration/assistant.mdx +6 -2
- package/docs/configuration/customization.mdx +4 -2
- package/docs/configuration/export.mdx +5 -3
- package/docs/configuration/index.mdx +3 -2
- package/docs/configuration/rate-limiting.mdx +23 -2
- package/docs/configuration/search.mdx +37 -14
- package/docs/content/components.mdx +2 -2
- package/docs/content/frontmatter.mdx +5 -3
- package/docs/content/i18n.mdx +2 -2
- package/docs/content/includes.mdx +1 -1
- package/docs/content/navigation.mdx +4 -4
- package/docs/content/sources/contentful.mdx +7 -4
- package/docs/content/sources/custom.mdx +7 -3
- package/docs/content/sources/github-releases.mdx +10 -2
- package/docs/content/sources/index.mdx +3 -3
- package/docs/content/sources/notion.mdx +1 -1
- package/docs/content/sources/obsidian.mdx +1 -1
- package/docs/content/sources/payload.mdx +3 -2
- package/docs/content/sources/remote-mdx.mdx +4 -0
- package/docs/content/sources/sanity.mdx +2 -2
- package/docs/content/sources/strapi.mdx +3 -2
- package/docs/content/syntax.mdx +2 -2
- package/docs/discoverability/agent-discovery.mdx +1 -1
- package/docs/discoverability/index.mdx +1 -1
- package/docs/discoverability/json-api.mdx +2 -0
- package/docs/discoverability/llms-txt.mdx +1 -1
- package/docs/discoverability/markdown.mdx +3 -1
- package/docs/discoverability/mcp.mdx +4 -0
- package/docs/discoverability/sitemap-and-robots.mdx +1 -1
- package/docs/references/api-pages.mdx +1 -1
- package/docs/references/asyncapi.mdx +3 -1
- package/docs/references/graphql.mdx +13 -1
- package/docs/references/openapi.mdx +50 -8
- package/package.json +9 -9
- package/skills/blume-migrate/SKILL.md +1 -1
- package/skills/blume-migrate/references/docusaurus.md +4 -4
- package/skills/blume-migrate/references/fumadocs.md +17 -13
- package/skills/blume-migrate/references/nextra.md +8 -5
- package/skills/blume-migrate/references/starlight.md +9 -7
- package/src/ai/ask-context.ts +33 -3
- package/src/ai/ask-limits.ts +13 -0
- package/src/ai/changelog-markdown.ts +11 -6
- package/src/ai/component-markdown.ts +1 -1
- package/src/ai/cors.ts +12 -3
- package/src/ai/mcp/query.ts +14 -6
- package/src/ai/openapi-components.ts +28 -4
- package/src/ai/relative-links.ts +4 -38
- package/src/astro/generate.ts +78 -48
- package/src/astro/integration.ts +16 -13
- package/src/astro/markdown-negotiation.ts +3 -0
- package/src/astro/module-types.ts +3 -1
- package/src/astro/pages.ts +23 -0
- package/src/astro/templates.ts +125 -80
- package/src/audit/catalog.ts +19 -3
- package/src/audit/checks/links.ts +14 -1
- package/src/audit/checks/network.ts +110 -6
- package/src/audit/checks/redirects.ts +6 -4
- package/src/audit/checks/robots.ts +58 -2
- package/src/audit/run.ts +3 -0
- package/src/audit/types.ts +2 -0
- package/src/audit/url.ts +14 -5
- package/src/blume-modules.d.ts +5 -1
- package/src/cli/args.ts +51 -0
- package/src/cli/build-failure.ts +23 -0
- package/src/cli/commands/audit.ts +10 -1
- package/src/cli/commands/dev.ts +18 -2
- package/src/cli/commands/doctor.ts +45 -12
- package/src/cli/commands/eval.ts +36 -4
- package/src/cli/commands/init.ts +6 -4
- package/src/cli/commands/validate.ts +10 -1
- package/src/cli/init/scaffold.ts +3 -3
- package/src/cli/prepare.ts +6 -3
- package/src/cli/required-secrets.ts +1 -1
- package/src/components/content/ApiPlayground.astro +6 -2
- package/src/components/content/api-field.ts +4 -1
- package/src/components/content/api-page.ts +31 -7
- package/src/components/content/mermaid-element.ts +15 -1
- package/src/components/islands/hooks.ts +27 -1
- package/src/components/layout/PageActions.astro +139 -24
- package/src/components/layout/RootLayout.astro +10 -2
- package/src/components/layout/Search.astro +17 -3
- package/src/components/layout/TableOfContents.astro +24 -17
- package/src/components/layout/head-scripts.ts +6 -1
- package/src/components/layout/search/algolia.ts +10 -1
- package/src/components/layout/search/analytics.ts +42 -14
- package/src/components/layout/search/endpoint.ts +48 -5
- package/src/components/layout/search/pagefind.ts +114 -5
- package/src/components/layout/search/types.ts +12 -0
- package/src/components/layout/search/typesense.ts +18 -6
- package/src/components/openapi/AsyncApiOperation.astro +14 -7
- package/src/components/openapi/Authorization.astro +10 -0
- package/src/components/openapi/GraphqlOperation.astro +5 -0
- package/src/components/openapi/Operation.astro +24 -1
- package/src/components/openapi/ParametersTable.astro +8 -4
- package/src/components/openapi/Playground.astro +7 -1
- package/src/components/openapi/RequestBody.astro +19 -2
- package/src/components/openapi/Responses.astro +1 -0
- package/src/components/openapi/SchemaTable.astro +15 -3
- package/src/components/openapi/async-snippets.ts +61 -5
- package/src/components/openapi/async.ts +123 -29
- package/src/components/openapi/graphql-helpers.ts +35 -12
- package/src/components/openapi/helpers.ts +36 -2
- package/src/components/openapi/message-model.ts +54 -11
- package/src/components/openapi/message.ts +14 -4
- package/src/components/openapi/operation-model.ts +16 -7
- package/src/components/openapi/playground-client.ts +24 -5
- package/src/components/openapi/playground-schema.ts +1 -1
- package/src/components/openapi/schema-tree.ts +44 -14
- package/src/components/openapi/security.ts +10 -0
- package/src/components/openapi/snippets.ts +5 -3
- package/src/components/openapi/validate-json.ts +4 -3
- package/src/core/changelog-index.ts +31 -1
- package/src/core/component-diagnostics.ts +53 -0
- package/src/core/component-overrides.ts +32 -0
- package/src/core/config-input.ts +31 -3
- package/src/core/data.ts +2 -0
- package/src/core/diagnostics.ts +5 -0
- package/src/core/i18n-ui.ts +2 -0
- package/src/core/includes.ts +1 -1
- package/src/core/links.ts +47 -17
- package/src/core/probe.ts +26 -6
- package/src/core/project-graph.ts +59 -18
- package/src/core/redirect-patterns.ts +36 -7
- package/src/core/schema.ts +21 -2
- package/src/core/sources/cache.ts +6 -0
- package/src/core/sources/contentful-rich-text.ts +29 -6
- package/src/core/sources/contentful.ts +135 -25
- package/src/core/sources/filesystem.ts +26 -4
- package/src/core/sources/github-releases.ts +12 -1
- package/src/core/sources/lexical.ts +15 -10
- package/src/core/sources/mdx-remote.ts +62 -10
- package/src/core/sources/normalize.ts +227 -41
- package/src/core/sources/notion.ts +7 -1
- package/src/core/sources/obsidian.ts +16 -3
- package/src/core/sources/payload.ts +38 -15
- package/src/core/sources/remote.ts +72 -15
- package/src/core/sources/resolve.ts +11 -1
- package/src/core/sources/sanity.ts +43 -25
- package/src/core/sources/strapi.ts +2 -2
- package/src/core/types.ts +18 -0
- package/src/core/ui-packs/ar.ts +1 -0
- package/src/core/ui-packs/bg.ts +1 -0
- package/src/core/ui-packs/bn.ts +1 -0
- package/src/core/ui-packs/ca.ts +1 -0
- package/src/core/ui-packs/cs.ts +1 -0
- package/src/core/ui-packs/da.ts +1 -0
- package/src/core/ui-packs/de.ts +1 -0
- package/src/core/ui-packs/el.ts +1 -0
- package/src/core/ui-packs/es.ts +1 -0
- package/src/core/ui-packs/fa.ts +1 -0
- package/src/core/ui-packs/fi.ts +1 -0
- package/src/core/ui-packs/fr.ts +1 -0
- package/src/core/ui-packs/he.ts +1 -0
- package/src/core/ui-packs/hi.ts +1 -0
- package/src/core/ui-packs/hr.ts +1 -0
- package/src/core/ui-packs/hu.ts +1 -0
- package/src/core/ui-packs/id.ts +1 -0
- package/src/core/ui-packs/it.ts +1 -0
- package/src/core/ui-packs/ja.ts +1 -0
- package/src/core/ui-packs/ko.ts +1 -0
- package/src/core/ui-packs/nl.ts +1 -0
- package/src/core/ui-packs/no.ts +1 -0
- package/src/core/ui-packs/pl.ts +1 -0
- package/src/core/ui-packs/pt-br.ts +1 -0
- package/src/core/ui-packs/pt.ts +1 -0
- package/src/core/ui-packs/ro.ts +1 -0
- package/src/core/ui-packs/ru.ts +1 -0
- package/src/core/ui-packs/sk.ts +1 -0
- package/src/core/ui-packs/sr.ts +1 -0
- package/src/core/ui-packs/sv.ts +1 -0
- package/src/core/ui-packs/th.ts +1 -0
- package/src/core/ui-packs/tr.ts +1 -0
- package/src/core/ui-packs/uk.ts +1 -0
- package/src/core/ui-packs/vi.ts +1 -0
- package/src/core/ui-packs/zh-tw.ts +1 -0
- package/src/core/ui-packs/zh.ts +1 -0
- package/src/deploy/adapter-output.ts +7 -2
- package/src/deploy/adapters/cloudflare.ts +7 -5
- package/src/deploy/adapters/node.ts +47 -9
- package/src/deploy/adapters/types.ts +7 -3
- package/src/deploy/artifacts.ts +2 -1
- package/src/deploy/platforms/cloudflare.ts +13 -9
- package/src/deploy/platforms/netlify.ts +2 -1
- package/src/deploy/platforms/node.ts +12 -2
- package/src/deploy/platforms/types.ts +21 -7
- package/src/deploy/platforms/vercel.ts +113 -16
- package/src/deploy/redirects.ts +66 -6
- package/src/deploy/rss.ts +3 -1
- package/src/deploy/sitemap.ts +39 -5
- package/src/deploy/vercel-negotiation.ts +290 -102
- package/src/eval/agents.ts +18 -1
- package/src/eval/prompts.ts +6 -3
- package/src/eval/report.ts +34 -13
- package/src/eval/run.ts +5 -0
- package/src/markdown/relative-links.ts +3 -2
- package/src/openapi/checks.ts +273 -0
- package/src/openapi/graphql-build.ts +21 -0
- package/src/openapi/graphql.ts +11 -0
- package/src/openapi/model.ts +15 -3
- package/src/openapi/parse.ts +127 -2
- package/src/openapi/references.ts +43 -3
- package/src/openapi/source.ts +39 -14
- package/src/ratelimit/index.ts +1 -1
- package/src/ratelimit/runtime.ts +37 -19
- package/src/ratelimit/upstash.ts +40 -10
- package/src/reference/graphql.ts +15 -1
- package/src/reference/index.ts +1 -0
- package/src/reference/openapi.ts +2 -2
- package/src/reference/options.ts +29 -1
- package/src/registry/eject.ts +3 -1
- package/src/search/adapters/locale-scope.ts +30 -0
- package/src/search/adapters/typesense.ts +14 -4
- package/src/search/build.ts +21 -3
- package/src/search/orama-index.ts +163 -31
- package/src/search/source-pages.ts +29 -0
- package/src/search/sync/algolia.ts +99 -9
- package/src/search/sync/index.ts +52 -13
- package/src/search/sync/typesense.ts +72 -27
- package/src/sources/contentful.ts +12 -0
- package/src/sources/github-releases.ts +7 -1
- package/src/sources/shared.ts +3 -0
- package/src/theme/entry.ts +29 -3
- package/src/translate/validate.ts +23 -1
- package/dist/cli/chunk-0gz36akr.js.map +0 -12
- package/dist/cli/chunk-2n4ps1b3.js.map +0 -15
- package/dist/cli/chunk-43zcf4gz.js.map +0 -36
- package/dist/cli/chunk-4ejxbzee.js +0 -39
- package/dist/cli/chunk-4ejxbzee.js.map +0 -10
- package/dist/cli/chunk-4h8z9vv5.js.map +0 -16
- package/dist/cli/chunk-713mngdq.js.map +0 -14
- package/dist/cli/chunk-9xr4dgee.js.map +0 -10
- package/dist/cli/chunk-amrb6hgh.js +0 -145
- package/dist/cli/chunk-amrb6hgh.js.map +0 -11
- package/dist/cli/chunk-nd1821sk.js.map +0 -10
- package/dist/cli/chunk-rekqz4qg.js.map +0 -10
- package/dist/cli/chunk-ta27feev.js.map +0 -10
- package/dist/cli/chunk-xkz5xbtv.js.map +0 -213
- package/dist/cli/chunk-y5h4r2y0.js.map +0 -10
- /package/dist/cli/{chunk-gp84za0h.js.map → chunk-3v3ffbrj.js.map} +0 -0
- /package/dist/cli/{chunk-p804f3pe.js.map → chunk-8y2kmjv8.js.map} +0 -0
- /package/dist/cli/{chunk-2f7n4qzt.js.map → chunk-c1y538kd.js.map} +0 -0
- /package/dist/cli/{chunk-1n228xqb.js.map → chunk-c887fj0s.js.map} +0 -0
- /package/dist/cli/{chunk-cmtcnh9f.js.map → chunk-dzwehpy7.js.map} +0 -0
- /package/dist/cli/{chunk-ntv4qrt7.js.map → chunk-e9q7a2ak.js.map} +0 -0
- /package/dist/cli/{chunk-5wj2qwn2.js.map → chunk-ft9vfys6.js.map} +0 -0
- /package/dist/cli/{chunk-zhvd6adm.js.map → chunk-hx3xqnk9.js.map} +0 -0
- /package/dist/cli/{chunk-y4ykbark.js.map → chunk-kma9f6sf.js.map} +0 -0
- /package/dist/cli/{chunk-py62fewh.js.map → chunk-mrcccgnh.js.map} +0 -0
- /package/dist/cli/{chunk-2f3ndkpw.js.map → chunk-n0v7m8ry.js.map} +0 -0
- /package/dist/cli/{chunk-9geymqns.js.map → chunk-nq1d20w2.js.map} +0 -0
- /package/dist/cli/{chunk-g2z9x01v.js.map → chunk-nrns10mj.js.map} +0 -0
- /package/dist/cli/{chunk-e7vvk5ya.js.map → chunk-sds923fa.js.map} +0 -0
- /package/dist/cli/{chunk-yj17vs39.js.map → chunk-tdqhyxfz.js.map} +0 -0
- /package/dist/cli/{chunk-q3wxxq39.js.map → chunk-tphac74f.js.map} +0 -0
- /package/dist/cli/{chunk-6bm0xpgd.js.map → chunk-w1r4vase.js.map} +0 -0
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { BlumeError } from "../diagnostics.ts";
|
|
2
|
+
import type { ResolvedI18nConfig, ResolvedVersionsConfig } from "../schema.ts";
|
|
3
|
+
import type { Diagnostic } from "../types.ts";
|
|
2
4
|
import {
|
|
3
5
|
assetFromEntry,
|
|
4
6
|
contentfulRichTextToMarkdown,
|
|
@@ -13,10 +15,13 @@ import {
|
|
|
13
15
|
objectsIn,
|
|
14
16
|
} from "./json.ts";
|
|
15
17
|
import { writesMdx } from "./lower.ts";
|
|
16
|
-
import
|
|
18
|
+
import { localizedRoute, resolveEntryRoute } from "./normalize.ts";
|
|
19
|
+
import type { RemoteFieldMap, RemoteFields, RestClient } from "./remote.ts";
|
|
17
20
|
import {
|
|
18
21
|
documentEntry,
|
|
22
|
+
documentSlug,
|
|
19
23
|
fetchJson,
|
|
24
|
+
missingSecretError,
|
|
20
25
|
queryString,
|
|
21
26
|
remoteSource,
|
|
22
27
|
} from "./remote.ts";
|
|
@@ -29,10 +34,24 @@ export interface ContentfulSourceOptions {
|
|
|
29
34
|
space: string;
|
|
30
35
|
/** Environment id; default `master`. */
|
|
31
36
|
environment?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Delivery API host name; default `cdn.contentful.com`. A space with EU
|
|
39
|
+
* data residency reads from `cdn.eu.contentful.com`.
|
|
40
|
+
*/
|
|
41
|
+
host?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Preview API host name for `--preview`; default `preview.contentful.com`
|
|
44
|
+
* (`preview.eu.contentful.com` for EU data residency).
|
|
45
|
+
*/
|
|
46
|
+
previewHost?: string;
|
|
32
47
|
/** The content type id whose entries become pages. */
|
|
33
48
|
contentType: string;
|
|
34
49
|
/** Locale code to fetch; omit for the space's default locale. */
|
|
35
50
|
locale?: string;
|
|
51
|
+
/** The project's i18n config, which places an entry's route by its slug. */
|
|
52
|
+
i18n?: ResolvedI18nConfig;
|
|
53
|
+
/** The project's versions config, which places an entry's route by its slug. */
|
|
54
|
+
versions?: ResolvedVersionsConfig;
|
|
36
55
|
/**
|
|
37
56
|
* Field ids mapping an entry onto Blume meta + body. Paths resolve against
|
|
38
57
|
* the entry's `fields`, with `sys` reachable as `sys.<key>`. Defaults:
|
|
@@ -53,11 +72,11 @@ export interface ContentfulSourceOptions {
|
|
|
53
72
|
fetchImpl?: typeof fetch;
|
|
54
73
|
}
|
|
55
74
|
|
|
56
|
-
const DELIVERY_HOST = "
|
|
57
|
-
const PREVIEW_HOST = "
|
|
75
|
+
const DELIVERY_HOST = "cdn.contentful.com";
|
|
76
|
+
const PREVIEW_HOST = "preview.contentful.com";
|
|
58
77
|
const PAGE_SIZE = 100;
|
|
59
78
|
|
|
60
|
-
const DEFAULT_FIELDS:
|
|
79
|
+
const DEFAULT_FIELDS: RemoteFields = {
|
|
61
80
|
body: "body",
|
|
62
81
|
description: "description",
|
|
63
82
|
lastModified: "sys.updatedAt",
|
|
@@ -71,11 +90,34 @@ const byId = (objects: JsonObject[]): Map<string, JsonObject> =>
|
|
|
71
90
|
objects.map((object) => [asString(getPath(object, "sys.id")) ?? "", object])
|
|
72
91
|
);
|
|
73
92
|
|
|
93
|
+
/** One page of the entries response: its items and what their links reach. */
|
|
94
|
+
interface EntriesPage {
|
|
95
|
+
assets: Map<string, JsonObject>;
|
|
96
|
+
items: JsonObject[];
|
|
97
|
+
linked: Map<string, JsonObject>;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** An entry's id, and the entry as its field paths read it. */
|
|
101
|
+
interface EntryView {
|
|
102
|
+
id: string;
|
|
103
|
+
/** The entry's fields, with `sys` beside them. */
|
|
104
|
+
view: JsonObject;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const entryView = (item: JsonObject): EntryView => {
|
|
108
|
+
const sys = asObject(item.sys) ?? {};
|
|
109
|
+
return {
|
|
110
|
+
id: asString(sys.id) ?? "",
|
|
111
|
+
view: { ...asObject(item.fields), sys },
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
|
|
74
115
|
/**
|
|
75
116
|
* Contentful content source. Pages through the Delivery API (the Preview API
|
|
76
117
|
* under `--preview`), maps each entry's fields to frontmatter, and lowers its
|
|
77
118
|
* rich text body to Markdown with the page's `includes` resolving asset and
|
|
78
|
-
* entry links.
|
|
119
|
+
* entry links. An entry hyperlink to another of the source's entries links
|
|
120
|
+
* to that entry's page.
|
|
79
121
|
*/
|
|
80
122
|
export const contentfulSource = (
|
|
81
123
|
options: ContentfulSourceOptions,
|
|
@@ -83,33 +125,78 @@ export const contentfulSource = (
|
|
|
83
125
|
): ContentSource => {
|
|
84
126
|
const fields = { ...DEFAULT_FIELDS, ...options.fields };
|
|
85
127
|
|
|
128
|
+
// The route an entry's page publishes at: the ref `documentEntry` names it
|
|
129
|
+
// by, through the resolver `normalizeEntry` uses, so an entry hyperlink
|
|
130
|
+
// lands on the page that's built. A slug places a page in one locale, and
|
|
131
|
+
// `.md` stands in for either extension, which the route drops.
|
|
132
|
+
const routeOf = (view: JsonObject, id: string): string => {
|
|
133
|
+
const route = resolveEntryRoute(
|
|
134
|
+
{ ref: `${documentSlug(view, fields.slug, id)}.md` },
|
|
135
|
+
".md",
|
|
136
|
+
undefined,
|
|
137
|
+
{ i18n: options.i18n, prefix: options.prefix, versions: options.versions }
|
|
138
|
+
);
|
|
139
|
+
return localizedRoute(
|
|
140
|
+
route.logicalRoute,
|
|
141
|
+
route.locales[0] ?? "",
|
|
142
|
+
options.i18n
|
|
143
|
+
);
|
|
144
|
+
};
|
|
145
|
+
|
|
86
146
|
const toEntry = (
|
|
87
147
|
item: JsonObject,
|
|
88
|
-
assets:
|
|
89
|
-
|
|
148
|
+
{ assets, linked }: EntriesPage,
|
|
149
|
+
routes: Map<string, string>,
|
|
150
|
+
warn: (diagnostic: Diagnostic) => void
|
|
90
151
|
): SourceEntry => {
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
|
|
152
|
+
const { id, view } = entryView(item);
|
|
153
|
+
// Links the response left out of `includes`: the API delivers no
|
|
154
|
+
// unpublished, archived, or deleted target, and the page renders without
|
|
155
|
+
// it.
|
|
156
|
+
const missing = new Set<string>();
|
|
157
|
+
const entry = documentEntry(
|
|
96
158
|
view,
|
|
97
159
|
fields,
|
|
98
160
|
id,
|
|
99
161
|
(body) =>
|
|
100
162
|
isJsonObject(body)
|
|
101
163
|
? contentfulRichTextToMarkdown(body, {
|
|
164
|
+
// Only an entry the source itself turns into a page has a
|
|
165
|
+
// route: one of another content type, or one `params` filters
|
|
166
|
+
// out, keeps its text.
|
|
167
|
+
entryHref: (target) =>
|
|
168
|
+
routes.get(asString(getPath(target, "sys.id")) ?? ""),
|
|
102
169
|
resolveAsset: (assetId) => {
|
|
103
170
|
const asset = assets.get(assetId);
|
|
104
|
-
|
|
171
|
+
if (!asset) {
|
|
172
|
+
missing.add(`asset "${assetId}"`);
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
return assetFromEntry(asset);
|
|
176
|
+
},
|
|
177
|
+
resolveEntry: (entryId) => {
|
|
178
|
+
const target = linked.get(entryId);
|
|
179
|
+
if (!target) {
|
|
180
|
+
missing.add(`entry "${entryId}"`);
|
|
181
|
+
}
|
|
182
|
+
return target ?? null;
|
|
105
183
|
},
|
|
106
|
-
resolveEntry: (entryId) => linked.get(entryId) ?? null,
|
|
107
184
|
serializers: options.serializers,
|
|
108
185
|
})
|
|
109
186
|
: "",
|
|
110
187
|
false,
|
|
111
188
|
writesMdx(options.serializers)
|
|
112
189
|
);
|
|
190
|
+
for (const link of missing) {
|
|
191
|
+
warn({
|
|
192
|
+
code: "BLUME_SOURCE_UNRESOLVED_LINK",
|
|
193
|
+
message: `Source "${options.name}": "${entry.ref}" links to Contentful ${link}, which the response didn't include, so the page renders without it.`,
|
|
194
|
+
severity: "warning",
|
|
195
|
+
suggestion:
|
|
196
|
+
"Publish the linked asset or entry, or remove the link: the Delivery API returns only published content.",
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
return entry;
|
|
113
200
|
};
|
|
114
201
|
|
|
115
202
|
const preview = ctx?.preview ?? false;
|
|
@@ -131,17 +218,26 @@ export const contentfulSource = (
|
|
|
131
218
|
}
|
|
132
219
|
};
|
|
133
220
|
|
|
134
|
-
const fetchEntries = async (
|
|
221
|
+
const fetchEntries = async (
|
|
222
|
+
warn: (diagnostic: Diagnostic) => void
|
|
223
|
+
): Promise<SourceEntry[]> => {
|
|
135
224
|
const token = preview
|
|
136
225
|
? previewToken()
|
|
137
226
|
: (options.token ?? process.env.CONTENTFUL_ACCESS_TOKEN);
|
|
227
|
+
// The Delivery API answers nothing without a token (`assertConfigured`
|
|
228
|
+
// already required the preview one).
|
|
229
|
+
if (!token) {
|
|
230
|
+
throw missingSecretError(options.name, "CONTENTFUL_ACCESS_TOKEN");
|
|
231
|
+
}
|
|
138
232
|
const client: RestClient = {
|
|
139
233
|
fetchImpl: options.fetchImpl,
|
|
140
|
-
headers:
|
|
234
|
+
headers: { authorization: `Bearer ${token}` },
|
|
141
235
|
};
|
|
142
|
-
const host = preview
|
|
143
|
-
|
|
144
|
-
|
|
236
|
+
const host = preview
|
|
237
|
+
? (options.previewHost ?? PREVIEW_HOST)
|
|
238
|
+
: (options.host ?? DELIVERY_HOST);
|
|
239
|
+
const base = `https://${host}/spaces/${options.space}/environments/${options.environment ?? "master"}/entries`;
|
|
240
|
+
const pages: EntriesPage[] = [];
|
|
145
241
|
let skip = 0;
|
|
146
242
|
let more = true;
|
|
147
243
|
while (more) {
|
|
@@ -160,16 +256,30 @@ export const contentfulSource = (
|
|
|
160
256
|
if (!page) {
|
|
161
257
|
throw new Error("Contentful returned a non-object response");
|
|
162
258
|
}
|
|
163
|
-
const assets = byId(objectsIn(getPath(page, "includes.Asset")));
|
|
164
|
-
const linked = byId(objectsIn(getPath(page, "includes.Entry")));
|
|
165
259
|
const items = objectsIn(page.items);
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
260
|
+
pages.push({
|
|
261
|
+
assets: byId(objectsIn(getPath(page, "includes.Asset"))),
|
|
262
|
+
items,
|
|
263
|
+
// `includes` leaves out an entry the page's `items` already hold, so
|
|
264
|
+
// a link to one of those resolves from `items`.
|
|
265
|
+
linked: byId([...objectsIn(getPath(page, "includes.Entry")), ...items]),
|
|
266
|
+
});
|
|
169
267
|
skip += items.length;
|
|
170
268
|
more = items.length > 0 && skip < (asNumber(page.total) ?? 0);
|
|
171
269
|
}
|
|
172
|
-
|
|
270
|
+
// A link can reach an entry a later page delivers, so every entry's route
|
|
271
|
+
// is known before any body lowers.
|
|
272
|
+
const routes = new Map(
|
|
273
|
+
pages.flatMap(({ items }) =>
|
|
274
|
+
items.map((item): [string, string] => {
|
|
275
|
+
const { id, view } = entryView(item);
|
|
276
|
+
return [id, routeOf(view, id)];
|
|
277
|
+
})
|
|
278
|
+
)
|
|
279
|
+
);
|
|
280
|
+
return pages.flatMap((page) =>
|
|
281
|
+
page.items.map((item) => toEntry(item, page, routes, warn))
|
|
282
|
+
);
|
|
173
283
|
};
|
|
174
284
|
|
|
175
285
|
return remoteSource(
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { existsSync, watch as fsWatch } from "node:fs";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
|
|
4
|
+
import { YAMLException } from "js-yaml";
|
|
4
5
|
import { extname, isAbsolute, join, relative, resolve } from "pathe";
|
|
5
6
|
import { glob } from "tinyglobby";
|
|
6
7
|
|
|
7
8
|
import { BlumeError } from "../diagnostics.ts";
|
|
8
9
|
import matter from "../frontmatter.ts";
|
|
9
10
|
import type { Diagnostic } from "../types.ts";
|
|
10
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
frontmatterYamlDiagnostic,
|
|
13
|
+
unloadablePathDiagnostic,
|
|
14
|
+
} from "./normalize.ts";
|
|
11
15
|
import type { ContentSource, SourceEntry, SourceLoadResult } from "./types.ts";
|
|
12
16
|
import {
|
|
13
17
|
baselineScanIgnore,
|
|
@@ -72,12 +76,22 @@ export const filesystemSource = (
|
|
|
72
76
|
}
|
|
73
77
|
}
|
|
74
78
|
|
|
75
|
-
const
|
|
76
|
-
loadable.map(async (file): Promise<SourceEntry> => {
|
|
79
|
+
const read = await Promise.all(
|
|
80
|
+
loadable.map(async (file): Promise<SourceEntry | Diagnostic> => {
|
|
77
81
|
const source = await readFile(file, "utf-8");
|
|
78
82
|
const ext = extname(file).toLowerCase();
|
|
79
83
|
const format = ext === ".mdx" ? "mdx" : "md";
|
|
80
|
-
|
|
84
|
+
// Invalid YAML leaves this one file out, reported at its line,
|
|
85
|
+
// instead of failing the whole scan.
|
|
86
|
+
let parsed: ReturnType<typeof matter>;
|
|
87
|
+
try {
|
|
88
|
+
parsed = matter(source);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
if (error instanceof YAMLException) {
|
|
91
|
+
return frontmatterYamlDiagnostic(error, file);
|
|
92
|
+
}
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
81
95
|
return {
|
|
82
96
|
body: { format, text: parsed.content },
|
|
83
97
|
data: parsed.data,
|
|
@@ -90,6 +104,14 @@ export const filesystemSource = (
|
|
|
90
104
|
};
|
|
91
105
|
})
|
|
92
106
|
);
|
|
107
|
+
const entries: SourceEntry[] = [];
|
|
108
|
+
for (const item of read) {
|
|
109
|
+
if ("body" in item) {
|
|
110
|
+
entries.push(item);
|
|
111
|
+
} else {
|
|
112
|
+
diagnostics.push(item);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
93
115
|
|
|
94
116
|
return { diagnostics, entries };
|
|
95
117
|
};
|
|
@@ -284,6 +284,17 @@ interface ChangelogFrontmatter {
|
|
|
284
284
|
type?: string;
|
|
285
285
|
}
|
|
286
286
|
|
|
287
|
+
/**
|
|
288
|
+
* The tag a release shows beside its title. A draft (read only with
|
|
289
|
+
* `drafts`) says so, since nothing else marks it as unreleased.
|
|
290
|
+
*/
|
|
291
|
+
const releaseCategory = (release: GithubRelease): string => {
|
|
292
|
+
if (release.draft) {
|
|
293
|
+
return "Draft";
|
|
294
|
+
}
|
|
295
|
+
return release.prerelease ? "Prerelease" : "Release";
|
|
296
|
+
};
|
|
297
|
+
|
|
287
298
|
/**
|
|
288
299
|
* Lower one release to a staged Markdown entry: the notes become the body,
|
|
289
300
|
* `type: changelog` frontmatter (title/date/version/category) drives the
|
|
@@ -294,7 +305,7 @@ const releaseToEntry = (release: GithubRelease, site?: string): SourceEntry => {
|
|
|
294
305
|
const version = release.tag_name.replace(LEADING_V, "");
|
|
295
306
|
const title = release.name?.trim() || release.tag_name;
|
|
296
307
|
const date = release.published_at ?? release.created_at;
|
|
297
|
-
const category = release
|
|
308
|
+
const category = releaseCategory(release);
|
|
298
309
|
// Release notes are the repository's content, not the site author's, so a
|
|
299
310
|
// link whose destination isn't a web, mail, or relative address
|
|
300
311
|
// (`javascript:`, `data:`) keeps only its label (see `safe-links.ts`), and
|
|
@@ -26,6 +26,11 @@ import {
|
|
|
26
26
|
export interface LexicalOptions {
|
|
27
27
|
/** The CMS origin a relative upload URL (`/media/x.png`) resolves against. */
|
|
28
28
|
baseUrl?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Called with the label of each node left out as a comment (a block with
|
|
31
|
+
* no serializer, a node type with no Markdown), so the source can warn.
|
|
32
|
+
*/
|
|
33
|
+
onUnsupported?: (what: string) => void;
|
|
29
34
|
/** Serializers for `block`/`inlineBlock` nodes, keyed by `fields.blockType`. */
|
|
30
35
|
serializers?: Record<string, (fields: JsonObject) => string>;
|
|
31
36
|
}
|
|
@@ -52,6 +57,12 @@ const marksOf = (node: JsonObject): InlineMarks => {
|
|
|
52
57
|
|
|
53
58
|
const children = (node: JsonObject): JsonObject[] => objectsIn(node.children);
|
|
54
59
|
|
|
60
|
+
/** The comment for a node with no Markdown, reported to `onUnsupported`. */
|
|
61
|
+
const leftOut = (what: string, options: LexicalOptions): string => {
|
|
62
|
+
options.onUnsupported?.(what);
|
|
63
|
+
return unsupported(what, writesMdx(options.serializers));
|
|
64
|
+
};
|
|
65
|
+
|
|
55
66
|
const typeOf = (node: JsonObject): string => asString(node.type) ?? "";
|
|
56
67
|
|
|
57
68
|
const customBlock = (node: JsonObject, options: LexicalOptions): string => {
|
|
@@ -61,10 +72,7 @@ const customBlock = (node: JsonObject, options: LexicalOptions): string => {
|
|
|
61
72
|
if (fields && serializer) {
|
|
62
73
|
return serializer(fields);
|
|
63
74
|
}
|
|
64
|
-
return
|
|
65
|
-
`Lexical block${blockType ? `: ${blockType}` : ""}`,
|
|
66
|
-
writesMdx(options.serializers)
|
|
67
|
-
);
|
|
75
|
+
return leftOut(`Lexical block${blockType ? `: ${blockType}` : ""}`, options);
|
|
68
76
|
};
|
|
69
77
|
|
|
70
78
|
const inlineParts = (
|
|
@@ -119,9 +127,9 @@ const renderUpload = (node: JsonObject, options: LexicalOptions): string => {
|
|
|
119
127
|
const value = asObject(node.value);
|
|
120
128
|
const url = value ? asString(value.url) : undefined;
|
|
121
129
|
if (!(value && url)) {
|
|
122
|
-
return
|
|
130
|
+
return leftOut(
|
|
123
131
|
"Lexical upload (fetch with depth 1 to populate it)",
|
|
124
|
-
|
|
132
|
+
options
|
|
125
133
|
);
|
|
126
134
|
}
|
|
127
135
|
const alt = asString(value.alt) ?? asString(value.filename) ?? "";
|
|
@@ -182,10 +190,7 @@ const renderBlock = (node: JsonObject, options: LexicalOptions): string => {
|
|
|
182
190
|
return customBlock(node, options);
|
|
183
191
|
}
|
|
184
192
|
default: {
|
|
185
|
-
return
|
|
186
|
-
`Lexical node: ${typeOf(node)}`,
|
|
187
|
-
writesMdx(options.serializers)
|
|
188
|
-
);
|
|
193
|
+
return leftOut(`Lexical node: ${typeOf(node)}`, options);
|
|
189
194
|
}
|
|
190
195
|
}
|
|
191
196
|
};
|
|
@@ -39,6 +39,26 @@ export interface MdxRemoteSourceOptions {
|
|
|
39
39
|
// thing on every source type: negation, character classes, nested braces, and
|
|
40
40
|
// extglobs included. Compiled once per enumeration, not per ref.
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Whether a ref is included, read the way tinyglobby reads an `include`
|
|
44
|
+
* array: a `!` pattern excludes what it matches, and the rest include. One
|
|
45
|
+
* picomatch matcher over the whole array would OR a negation in, and
|
|
46
|
+
* `!drafts/**` would include every other path, `.txt` files and all.
|
|
47
|
+
*/
|
|
48
|
+
const includeMatcher = (include: string[]): ((ref: string) => boolean) => {
|
|
49
|
+
// An empty pattern list matches nothing, so an array of only negations
|
|
50
|
+
// includes nothing, as in tinyglobby.
|
|
51
|
+
const included = picomatch(
|
|
52
|
+
include.filter((pattern) => !pattern.startsWith("!"))
|
|
53
|
+
);
|
|
54
|
+
const excluded = picomatch(
|
|
55
|
+
include
|
|
56
|
+
.filter((pattern) => pattern.startsWith("!"))
|
|
57
|
+
.map((pattern) => pattern.slice(1))
|
|
58
|
+
);
|
|
59
|
+
return (ref) => included(ref) && !excluded(ref);
|
|
60
|
+
};
|
|
61
|
+
|
|
42
62
|
/** A file to fetch: its source-local ref plus where to read it from. */
|
|
43
63
|
interface RemoteRef {
|
|
44
64
|
ref: string;
|
|
@@ -102,12 +122,23 @@ interface GithubTreeEntry {
|
|
|
102
122
|
type: string;
|
|
103
123
|
}
|
|
104
124
|
|
|
125
|
+
/** The files a source reads, and what the listing said about them. */
|
|
126
|
+
interface Enumeration {
|
|
127
|
+
/**
|
|
128
|
+
* The configured `path`, described, when the repository at the ref has no
|
|
129
|
+
* folder there, so the source read nothing.
|
|
130
|
+
*/
|
|
131
|
+
missing?: string;
|
|
132
|
+
refs: RemoteRef[];
|
|
133
|
+
truncated: boolean;
|
|
134
|
+
}
|
|
135
|
+
|
|
105
136
|
/** Enumerate a GitHub repo subtree, mapping blobs to remote refs. */
|
|
106
137
|
const enumerateGithub = async (
|
|
107
138
|
github: { owner: string; repo: string; ref: string; path: string },
|
|
108
139
|
include: string[],
|
|
109
140
|
doFetch: typeof fetch
|
|
110
|
-
): Promise<
|
|
141
|
+
): Promise<Enumeration> => {
|
|
111
142
|
const { owner, repo, ref } = github;
|
|
112
143
|
const base = github.path.replaceAll(/^\/|\/$/gu, "");
|
|
113
144
|
const treeUrl = `https://api.github.com/repos/${owner}/${repo}/git/trees/${ref}?recursive=1`;
|
|
@@ -119,7 +150,7 @@ const enumerateGithub = async (
|
|
|
119
150
|
truncated?: boolean;
|
|
120
151
|
};
|
|
121
152
|
const prefix = base ? `${base}/` : "";
|
|
122
|
-
const included =
|
|
153
|
+
const included = includeMatcher(include);
|
|
123
154
|
const refs = (body.tree ?? []).flatMap((node) => {
|
|
124
155
|
if (!(node.type === "blob" && node.path.startsWith(prefix))) {
|
|
125
156
|
return [];
|
|
@@ -138,7 +169,18 @@ const enumerateGithub = async (
|
|
|
138
169
|
});
|
|
139
170
|
// GitHub caps the recursive tree response (~100k entries / 7MB) and flags it
|
|
140
171
|
// with `truncated`; ignoring it would silently import only part of the repo.
|
|
141
|
-
|
|
172
|
+
const truncated = body.truncated === true;
|
|
173
|
+
// Git has no empty folders, so a complete listing with nothing under
|
|
174
|
+
// `path` means the path is wrong at this ref (a moved docs folder, a typo).
|
|
175
|
+
const found =
|
|
176
|
+
prefix === "" ||
|
|
177
|
+
truncated ||
|
|
178
|
+
(body.tree ?? []).some((node) => node.path.startsWith(prefix));
|
|
179
|
+
return {
|
|
180
|
+
missing: found ? undefined : `"${base}" in ${owner}/${repo} at ${ref}`,
|
|
181
|
+
refs,
|
|
182
|
+
truncated,
|
|
183
|
+
};
|
|
142
184
|
};
|
|
143
185
|
|
|
144
186
|
/**
|
|
@@ -169,15 +211,12 @@ export const mdxRemoteSource = (
|
|
|
169
211
|
});
|
|
170
212
|
};
|
|
171
213
|
|
|
172
|
-
const enumerate = async (): Promise<{
|
|
173
|
-
refs: RemoteRef[];
|
|
174
|
-
truncated: boolean;
|
|
175
|
-
}> => {
|
|
214
|
+
const enumerate = async (): Promise<Enumeration> => {
|
|
176
215
|
if (options.github) {
|
|
177
216
|
return await enumerateGithub(options.github, options.include, doFetch);
|
|
178
217
|
}
|
|
179
218
|
const base = (options.url ?? "").replace(/\/$/u, "");
|
|
180
|
-
const included =
|
|
219
|
+
const included = includeMatcher(options.include);
|
|
181
220
|
const refs = (options.files ?? []).flatMap((ref) =>
|
|
182
221
|
included(ref)
|
|
183
222
|
? [{ editUrl: `${base}/${ref}`, fetchUrl: `${base}/${ref}`, ref }]
|
|
@@ -209,12 +248,25 @@ export const mdxRemoteSource = (
|
|
|
209
248
|
options.name,
|
|
210
249
|
cache,
|
|
211
250
|
async () => {
|
|
212
|
-
const { refs, truncated } = await enumerate();
|
|
251
|
+
const { missing, refs, truncated } = await enumerate();
|
|
252
|
+
if (missing) {
|
|
253
|
+
skipped.push({
|
|
254
|
+
code: "BLUME_SOURCE_PATH_MISSING",
|
|
255
|
+
message: `Source "${options.name}" read no files: there is no folder ${missing}.`,
|
|
256
|
+
severity: "warning",
|
|
257
|
+
suggestion:
|
|
258
|
+
"Check github.path and github.ref against the repository.",
|
|
259
|
+
});
|
|
260
|
+
}
|
|
213
261
|
if (truncated) {
|
|
262
|
+
// The listing covers the whole repository at the ref, whatever
|
|
263
|
+
// `path` is, so narrowing it doesn't help.
|
|
214
264
|
skipped.push({
|
|
215
265
|
code: "BLUME_SOURCE_TRUNCATED",
|
|
216
|
-
message: `Source "${options.name}" hit GitHub's tree listing limit; some files were not enumerated
|
|
266
|
+
message: `Source "${options.name}" hit GitHub's tree listing limit for the whole repository; some files were not enumerated.`,
|
|
217
267
|
severity: "warning",
|
|
268
|
+
suggestion:
|
|
269
|
+
"List the files to read with { url, files } instead, or split the repository.",
|
|
218
270
|
});
|
|
219
271
|
}
|
|
220
272
|
const reasons: string[] = [];
|