blume 2.1.0 → 2.1.2
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 +110 -0
- 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-43zcf4gz.js → chunk-0pmb4tr4.js} +541 -368
- package/dist/cli/chunk-0pmb4tr4.js.map +35 -0
- package/dist/cli/{chunk-9geymqns.js → chunk-0w6hs479.js} +15 -15
- package/dist/cli/{chunk-xkz5xbtv.js → chunk-124fvmzq.js} +2802 -1422
- package/dist/cli/chunk-124fvmzq.js.map +220 -0
- package/dist/cli/chunk-150jk7km.js +52 -0
- package/dist/cli/chunk-150jk7km.js.map +10 -0
- package/dist/cli/{chunk-y4ykbark.js → chunk-1f882900.js} +2 -2
- package/dist/cli/{chunk-5ffywsmb.js → chunk-297ajdcv.js} +8 -6
- package/dist/cli/{chunk-5ffywsmb.js.map → chunk-297ajdcv.js.map} +3 -3
- package/dist/cli/{chunk-h2a48yhd.js → chunk-32khwcb6.js} +120 -16
- package/dist/cli/{chunk-h2a48yhd.js.map → chunk-32khwcb6.js.map} +10 -10
- package/dist/cli/{chunk-5cg2rzgf.js → chunk-36bxs9c7.js} +20 -49
- package/dist/cli/{chunk-5cg2rzgf.js.map → chunk-36bxs9c7.js.map} +4 -5
- package/dist/cli/{chunk-py62fewh.js → chunk-53jqw8z0.js} +3 -3
- package/dist/cli/{chunk-5wj2qwn2.js → chunk-58bt3hag.js} +4 -4
- package/dist/cli/{chunk-e7vvk5ya.js → chunk-5cmts6dv.js} +3 -3
- package/dist/cli/{chunk-y5h4r2y0.js → chunk-60hz265r.js} +15 -5
- package/dist/cli/chunk-60hz265r.js.map +10 -0
- package/dist/cli/chunk-74wfhv79.js +65 -0
- package/dist/cli/chunk-74wfhv79.js.map +10 -0
- package/dist/cli/{chunk-g2z9x01v.js → chunk-9qzgg6mj.js} +3 -3
- package/dist/cli/{chunk-q3wxxq39.js → chunk-a57yh0h9.js} +5 -5
- package/dist/cli/{chunk-713mngdq.js → chunk-ave1wcbr.js} +76 -10
- package/dist/cli/chunk-ave1wcbr.js.map +14 -0
- package/dist/cli/{chunk-2n4ps1b3.js → chunk-bqxaqn5p.js} +40 -22
- package/dist/cli/chunk-bqxaqn5p.js.map +15 -0
- package/dist/cli/{chunk-jnwj5kjj.js → chunk-bxwhtvw8.js} +20 -7
- package/dist/cli/{chunk-jnwj5kjj.js.map → chunk-bxwhtvw8.js.map} +3 -3
- package/dist/cli/chunk-ckrcm08h.js +324 -0
- package/dist/cli/chunk-ckrcm08h.js.map +14 -0
- package/dist/cli/{chunk-2f3ndkpw.js → chunk-desvm72z.js} +3 -3
- package/dist/cli/{chunk-gp84za0h.js → chunk-dhwtqnnd.js} +2 -2
- package/dist/cli/{chunk-4h8z9vv5.js → chunk-dpy8qdjf.js} +93 -47
- package/dist/cli/chunk-dpy8qdjf.js.map +17 -0
- package/dist/cli/{chunk-2f7n4qzt.js → chunk-dqhg54mr.js} +1 -1
- package/dist/cli/{chunk-0gz36akr.js → chunk-dv2z0rzf.js} +21 -5
- package/dist/cli/chunk-dv2z0rzf.js.map +12 -0
- package/dist/cli/{chunk-cm89scdv.js → chunk-es8h0v3j.js} +9 -11
- package/dist/cli/{chunk-cm89scdv.js.map → chunk-es8h0v3j.js.map} +3 -3
- package/dist/cli/{chunk-zhvd6adm.js → chunk-gfc5fqvf.js} +14 -14
- package/dist/cli/{chunk-nd1821sk.js → chunk-gxtg6ed2.js} +33 -19
- package/dist/cli/chunk-gxtg6ed2.js.map +10 -0
- package/dist/cli/{chunk-p804f3pe.js → chunk-hvcxng5f.js} +6 -6
- package/dist/cli/{chunk-ta27feev.js → chunk-j1x92mx9.js} +21 -2
- package/dist/cli/chunk-j1x92mx9.js.map +10 -0
- package/dist/cli/{chunk-rekqz4qg.js → chunk-k3gr1nm9.js} +19 -16
- package/dist/cli/chunk-k3gr1nm9.js.map +10 -0
- package/dist/cli/{chunk-1n228xqb.js → chunk-kdpzw38a.js} +2 -2
- package/dist/cli/{chunk-cy5bm0j0.js → chunk-ms9z66nz.js} +2 -2
- package/dist/cli/{chunk-cy5bm0j0.js.map → chunk-ms9z66nz.js.map} +2 -2
- package/dist/cli/{chunk-zf748avv.js → chunk-nbyvgnnm.js} +193 -286
- package/dist/cli/chunk-nbyvgnnm.js.map +36 -0
- package/dist/cli/{chunk-6bm0xpgd.js → chunk-s0bdnc7v.js} +2 -2
- package/dist/cli/{chunk-yxmk4pec.js → chunk-sc93apfs.js} +17 -16
- package/dist/cli/{chunk-yxmk4pec.js.map → chunk-sc93apfs.js.map} +3 -3
- package/dist/cli/{chunk-cmtcnh9f.js → chunk-tfycddbt.js} +2 -2
- package/dist/cli/{chunk-9xr4dgee.js → chunk-twy7psdz.js} +29 -16
- package/dist/cli/chunk-twy7psdz.js.map +10 -0
- package/dist/cli/{chunk-ntv4qrt7.js → chunk-y4msrwm9.js} +15 -15
- package/dist/cli/{chunk-yj17vs39.js → chunk-ydp3065p.js} +5 -5
- 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/ask.d.ts +24 -5
- package/dist/types/ai/component-markdown.d.ts +2 -0
- package/dist/types/ai/openapi-components.d.ts +4 -1
- package/dist/types/analytics/clics.d.ts +37 -0
- package/dist/types/analytics/index.d.ts +2 -0
- package/dist/types/analytics/schema.d.ts +18 -0
- package/dist/types/astro/integration.d.ts +11 -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 +37 -6
- 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/powered-by.d.ts +12 -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 +228 -3
- 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/lower.d.ts +10 -2
- package/dist/types/core/sources/normalize.d.ts +20 -1
- package/dist/types/core/sources/notion.d.ts +8 -0
- 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/cloudflare-negotiation.d.ts +5 -2
- package/dist/types/deploy/node-headers.d.ts +12 -4
- 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 +21 -2
- 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 +44 -21
- package/dist/types/narration/build.d.ts +34 -12
- package/dist/types/narration/provider.d.ts +96 -8
- 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/openapi/sentence.d.ts +11 -1
- 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/seo/jsonld.d.ts +11 -6
- package/dist/types/sources/contentful.d.ts +16 -0
- package/dist/types/sources/github-releases.d.ts +8 -1
- package/dist/types/sources/notion.d.ts +8 -0
- package/dist/types/sources/payload.d.ts +2 -0
- package/dist/types/sources/registry.d.ts +63 -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 +59 -13
- package/docs/03-upgrading.mdx +2 -1
- package/docs/04-migrating.mdx +9 -9
- package/docs/08-faq.mdx +12 -12
- package/docs/advanced/changelog.mdx +30 -2
- package/docs/advanced/custom-pages.mdx +1 -1
- package/docs/advanced/skills.mdx +1 -1
- package/docs/cli/audit.mdx +30 -7
- package/docs/cli/doctor.mdx +6 -2
- 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 +19 -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 +4 -2
- package/docs/configuration/narration.mdx +43 -6
- 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 +8 -6
- package/docs/content/sources/contentful.mdx +9 -4
- package/docs/content/sources/custom.mdx +7 -3
- package/docs/content/sources/github-releases.mdx +12 -2
- package/docs/content/sources/index.mdx +3 -3
- package/docs/content/sources/notion.mdx +17 -2
- package/docs/content/sources/obsidian.mdx +3 -1
- package/docs/content/sources/payload.mdx +5 -2
- package/docs/content/sources/remote-mdx.mdx +6 -0
- package/docs/content/sources/sanity.mdx +4 -2
- package/docs/content/sources/strapi.mdx +5 -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 +6 -0
- package/docs/discoverability/sitemap-and-robots.mdx +1 -1
- package/docs/discoverability/structured-data.mdx +8 -6
- package/docs/references/api-pages.mdx +1 -1
- package/docs/references/asyncapi.mdx +5 -1
- package/docs/references/graphql.mdx +15 -1
- package/docs/references/openapi.mdx +64 -8
- package/package.json +9 -9
- package/skills/blume/SKILL.md +1 -1
- package/skills/blume-migrate/SKILL.md +2 -2
- package/skills/blume-migrate/assets/{oxfmt@0.67.0.patch → oxfmt@0.71.0.patch} +7 -7
- package/skills/blume-migrate/references/docusaurus.md +4 -4
- package/skills/blume-migrate/references/fumadocs.md +17 -13
- package/skills/blume-migrate/references/monorepo.md +5 -5
- 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/ask.ts +24 -6
- 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/analytics/clics.ts +58 -0
- package/src/analytics/head.ts +5 -0
- package/src/analytics/index.ts +2 -0
- package/src/analytics/schema.ts +2 -0
- package/src/astro/generate.ts +91 -56
- package/src/astro/integration.ts +72 -22
- 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/render-deps.ts +10 -5
- package/src/astro/runtime-deps.ts +23 -2
- package/src/astro/templates.ts +129 -81
- 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 +9 -6
- package/src/cli/prepare.ts +6 -3
- package/src/cli/required-secrets.ts +3 -2
- 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/content/view-switcher.ts +7 -4
- package/src/components/islands/hooks.ts +27 -1
- package/src/components/layout/NavTree.astro +49 -5
- package/src/components/layout/NavTreeScript.astro +18 -0
- package/src/components/layout/PageActions.astro +139 -24
- package/src/components/layout/PageLayout.astro +13 -3
- package/src/components/layout/RootLayout.astro +27 -14
- package/src/components/layout/Search.astro +17 -3
- package/src/components/layout/TableOfContents.astro +24 -17
- package/src/components/layout/analytics-client.ts +8 -8
- 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 +77 -58
- 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/components/powered-by-middleware.ts +33 -0
- 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 +42 -6
- 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/powered-by.ts +12 -0
- 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 +26 -6
- 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/lower.ts +19 -3
- package/src/core/sources/mdx-remote.ts +62 -10
- package/src/core/sources/normalize.ts +227 -41
- package/src/core/sources/notion.ts +34 -10
- 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/cloudflare-negotiation.ts +36 -7
- package/src/deploy/headers.ts +15 -1
- package/src/deploy/node-headers.ts +32 -20
- package/src/deploy/platforms/cloudflare.ts +14 -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 +115 -17
- 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 +325 -103
- 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/base-links.ts +15 -14
- package/src/markdown/package-commands.ts +9 -8
- package/src/markdown/relative-links.ts +3 -2
- package/src/narration/build.ts +218 -40
- package/src/narration/provider.ts +89 -9
- 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/render-mdx.ts +68 -8
- package/src/openapi/sentence.ts +29 -2
- 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 +8 -2
- 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/seo/jsonld.ts +38 -20
- package/src/sources/contentful.ts +12 -0
- package/src/sources/github-releases.ts +7 -1
- package/src/sources/notion.ts +7 -0
- package/src/sources/shared.ts +3 -0
- package/src/theme/color.ts +9 -10
- package/src/theme/entry.ts +43 -6
- 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-zf748avv.js.map +0 -37
- /package/dist/cli/{chunk-9geymqns.js.map → chunk-0w6hs479.js.map} +0 -0
- /package/dist/cli/{chunk-y4ykbark.js.map → chunk-1f882900.js.map} +0 -0
- /package/dist/cli/{chunk-py62fewh.js.map → chunk-53jqw8z0.js.map} +0 -0
- /package/dist/cli/{chunk-5wj2qwn2.js.map → chunk-58bt3hag.js.map} +0 -0
- /package/dist/cli/{chunk-e7vvk5ya.js.map → chunk-5cmts6dv.js.map} +0 -0
- /package/dist/cli/{chunk-g2z9x01v.js.map → chunk-9qzgg6mj.js.map} +0 -0
- /package/dist/cli/{chunk-q3wxxq39.js.map → chunk-a57yh0h9.js.map} +0 -0
- /package/dist/cli/{chunk-2f3ndkpw.js.map → chunk-desvm72z.js.map} +0 -0
- /package/dist/cli/{chunk-gp84za0h.js.map → chunk-dhwtqnnd.js.map} +0 -0
- /package/dist/cli/{chunk-2f7n4qzt.js.map → chunk-dqhg54mr.js.map} +0 -0
- /package/dist/cli/{chunk-zhvd6adm.js.map → chunk-gfc5fqvf.js.map} +0 -0
- /package/dist/cli/{chunk-p804f3pe.js.map → chunk-hvcxng5f.js.map} +0 -0
- /package/dist/cli/{chunk-1n228xqb.js.map → chunk-kdpzw38a.js.map} +0 -0
- /package/dist/cli/{chunk-6bm0xpgd.js.map → chunk-s0bdnc7v.js.map} +0 -0
- /package/dist/cli/{chunk-cmtcnh9f.js.map → chunk-tfycddbt.js.map} +0 -0
- /package/dist/cli/{chunk-ntv4qrt7.js.map → chunk-y4msrwm9.js.map} +0 -0
- /package/dist/cli/{chunk-yj17vs39.js.map → chunk-ydp3065p.js.map} +0 -0
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
i18nDiagnostics,
|
|
7
7
|
blumeReferences,
|
|
8
8
|
frontmatter_default,
|
|
9
|
+
resolveLocalizable,
|
|
9
10
|
resolveDocsCollection,
|
|
10
11
|
CHANGELOG_INDEX_ROUTE,
|
|
11
12
|
hasChangelogIndex,
|
|
@@ -22,6 +23,7 @@ import {
|
|
|
22
23
|
pagesByRef,
|
|
23
24
|
buildNavigation,
|
|
24
25
|
PUBLIC_API_URL,
|
|
26
|
+
isPatternPath,
|
|
25
27
|
pathsUnderPattern,
|
|
26
28
|
hasVariables,
|
|
27
29
|
substituteVariables,
|
|
@@ -33,6 +35,7 @@ import {
|
|
|
33
35
|
slugify,
|
|
34
36
|
slugifyPath,
|
|
35
37
|
unloadablePathDiagnostic,
|
|
38
|
+
frontmatterYamlDiagnostic,
|
|
36
39
|
extractHeadings,
|
|
37
40
|
strippedLineOffset,
|
|
38
41
|
isStringValue,
|
|
@@ -47,6 +50,7 @@ import {
|
|
|
47
50
|
escapeMarkdownText,
|
|
48
51
|
guardBlockStart,
|
|
49
52
|
renderInline,
|
|
53
|
+
renderInlineMdx,
|
|
50
54
|
destination,
|
|
51
55
|
linkParts,
|
|
52
56
|
headingPrefix,
|
|
@@ -73,7 +77,7 @@ import {
|
|
|
73
77
|
createModuleLoader,
|
|
74
78
|
resolveProjectContext,
|
|
75
79
|
loadConfig
|
|
76
|
-
} from "./chunk-
|
|
80
|
+
} from "./chunk-124fvmzq.js";
|
|
77
81
|
import {
|
|
78
82
|
getBlumeVersion,
|
|
79
83
|
BlumeError,
|
|
@@ -81,6 +85,7 @@ import {
|
|
|
81
85
|
} from "./index.js";
|
|
82
86
|
import {
|
|
83
87
|
trimChar,
|
|
88
|
+
normalizePath,
|
|
84
89
|
isInternalPath,
|
|
85
90
|
withBasePath,
|
|
86
91
|
mountBasePath
|
|
@@ -93,6 +98,232 @@ import {
|
|
|
93
98
|
ignoringWatchListener
|
|
94
99
|
} from "./chunk-kwrg63tm.js";
|
|
95
100
|
|
|
101
|
+
// src/theme/icon-kind.ts
|
|
102
|
+
var IMAGE_ICON = /^(?:https?:\/\/|data:image\/|\/|\.{1,2}\/)|\.(?:avif|gif|jpe?g|png|svg|webp)$/iu;
|
|
103
|
+
var INLINE_SVG = /^\s*<svg[\s\S]*<\/svg>\s*$/u;
|
|
104
|
+
var isImageIcon = (value) => IMAGE_ICON.test(value);
|
|
105
|
+
var isInlineSvg = (value) => INLINE_SVG.test(value);
|
|
106
|
+
var isAssetIcon = (value) => isInlineSvg(value) || isImageIcon(value);
|
|
107
|
+
|
|
108
|
+
// src/theme/icons.ts
|
|
109
|
+
import { createRequire } from "node:module";
|
|
110
|
+
import { getIconData, iconToSVG } from "@iconify/utils";
|
|
111
|
+
var requireJson = createRequire(import.meta.url);
|
|
112
|
+
var loadSet = (pkg) => requireJson(pkg);
|
|
113
|
+
var SETS = {
|
|
114
|
+
lucide: loadSet("@iconify-json/lucide/icons.json")
|
|
115
|
+
};
|
|
116
|
+
var DEFAULT_SET = "lucide";
|
|
117
|
+
var PREFIX_SETS = {
|
|
118
|
+
lucide: "lucide"
|
|
119
|
+
};
|
|
120
|
+
var ownEntry = (map, key) => Object.hasOwn(map, key) ? map[key] : undefined;
|
|
121
|
+
var normalize = (name) => name.trim().toLowerCase().replaceAll(/[\s_]+/gu, "-");
|
|
122
|
+
var fromSet = (setName, iconName) => {
|
|
123
|
+
const set = ownEntry(SETS, setName);
|
|
124
|
+
const data = set && getIconData(set, iconName);
|
|
125
|
+
if (!data) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
const { attributes, body } = iconToSVG(data, { height: "auto" });
|
|
129
|
+
return { body, name: iconName, viewBox: attributes.viewBox };
|
|
130
|
+
};
|
|
131
|
+
var resolveIcon = (name) => {
|
|
132
|
+
const normalized = normalize(name);
|
|
133
|
+
const colon = normalized.indexOf(":");
|
|
134
|
+
if (colon > 0) {
|
|
135
|
+
const setName = ownEntry(PREFIX_SETS, normalized.slice(0, colon));
|
|
136
|
+
return setName ? fromSet(setName, normalized.slice(colon + 1)) : null;
|
|
137
|
+
}
|
|
138
|
+
return fromSet(DEFAULT_SET, normalized);
|
|
139
|
+
};
|
|
140
|
+
var hasIcon = (name) => resolveIcon(name) !== null;
|
|
141
|
+
|
|
142
|
+
// src/core/nav-diagnostics.ts
|
|
143
|
+
var ICON_FORMAT_HINT = "Use a built-in icon name, an image path/URL, or inline SVG markup.";
|
|
144
|
+
var flattenNodes = (nodes) => nodes.flatMap((node) => node.kind === "group" ? [node, ...flattenNodes(node.children)] : [node]);
|
|
145
|
+
var collectIcons = (navigation) => {
|
|
146
|
+
const icons = [];
|
|
147
|
+
const push = (icon, where) => {
|
|
148
|
+
if (icon) {
|
|
149
|
+
icons.push({ icon, where });
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
for (const tab of navigation.tabs) {
|
|
153
|
+
push(tab.icon, `tab "${tab.label}"`);
|
|
154
|
+
for (const item of tab.items ?? []) {
|
|
155
|
+
push(item.icon, `tab item "${item.label}"`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
for (const selector of navigation.selectors) {
|
|
159
|
+
for (const item of selector.items) {
|
|
160
|
+
push(item.icon, `selector "${item.label}"`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
for (const link of navigation.featured) {
|
|
164
|
+
push(link.icon, `featured link "${link.label}"`);
|
|
165
|
+
}
|
|
166
|
+
const sidebars = [navigation.sidebar];
|
|
167
|
+
for (const sidebar of sidebars) {
|
|
168
|
+
for (const node of flattenNodes(sidebar)) {
|
|
169
|
+
push(node.icon, `"${node.label}"`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return icons;
|
|
173
|
+
};
|
|
174
|
+
var unknownIconDiagnostics = (icons, suggestion) => {
|
|
175
|
+
const seen = new Set;
|
|
176
|
+
const diagnostics = [];
|
|
177
|
+
for (const { icon, where } of icons) {
|
|
178
|
+
if (isAssetIcon(icon) || hasIcon(icon) || seen.has(icon)) {
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
seen.add(icon);
|
|
182
|
+
const message = icon.trimStart().startsWith("<") ? `Icon markup "${icon}" (${where}) isn't a complete inline <svg> element, so it won't render.` : `Unknown icon "${icon}" (${where}) — it isn't in Blume's icon set.`;
|
|
183
|
+
diagnostics.push({
|
|
184
|
+
code: "BLUME_UNKNOWN_ICON",
|
|
185
|
+
message,
|
|
186
|
+
severity: "warning",
|
|
187
|
+
suggestion
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
return diagnostics;
|
|
191
|
+
};
|
|
192
|
+
var validateNavIcons = (navigation) => unknownIconDiagnostics(collectIcons(navigation), ICON_FORMAT_HINT);
|
|
193
|
+
var validateSearchPopularIcons = (popular) => {
|
|
194
|
+
const icons = popular.flatMap((link) => link.icon ? [{ icon: link.icon, where: `popular link "${link.label}"` }] : []);
|
|
195
|
+
return unknownIconDiagnostics(icons, ICON_FORMAT_HINT);
|
|
196
|
+
};
|
|
197
|
+
var resolvesToPages = (routes, path) => routes.has(path) || [...routes].some((route) => route.startsWith(`${path}/`));
|
|
198
|
+
var validateNavTargets = (navigation, routes) => {
|
|
199
|
+
const targets = [
|
|
200
|
+
...navigation.tabs.map((tab) => ({ label: tab.label, path: tab.path })),
|
|
201
|
+
...navigation.selectors.flatMap((selector) => selector.items.map((item) => ({ label: item.label, path: item.path }))),
|
|
202
|
+
...navigation.featured.map((link) => ({
|
|
203
|
+
label: link.label,
|
|
204
|
+
path: link.href
|
|
205
|
+
})),
|
|
206
|
+
...(navigation.actions ?? []).map((action) => ({
|
|
207
|
+
label: action.label,
|
|
208
|
+
path: action.href
|
|
209
|
+
})),
|
|
210
|
+
...navigation.cta ? [{ label: navigation.cta.label, path: navigation.cta.href }] : []
|
|
211
|
+
];
|
|
212
|
+
const diagnostics = [];
|
|
213
|
+
const seen = new Set;
|
|
214
|
+
for (const { label, path } of targets) {
|
|
215
|
+
if (!isInternalPath(path) || path.startsWith("/#") || seen.has(path)) {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
if (!resolvesToPages(routes, path.split(/[?#]/u)[0] ?? path)) {
|
|
219
|
+
seen.add(path);
|
|
220
|
+
diagnostics.push({
|
|
221
|
+
code: "BLUME_NAV_MISSING_PAGE",
|
|
222
|
+
message: `Navigation entry "${label}" points to ${path}, but no page matches it.`,
|
|
223
|
+
severity: "warning",
|
|
224
|
+
suggestion: "Fix the path, or add a page at that route."
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return diagnostics;
|
|
229
|
+
};
|
|
230
|
+
var validateSidebarItems = (items, resolves) => {
|
|
231
|
+
const diagnostics = [];
|
|
232
|
+
const walk = (list) => {
|
|
233
|
+
for (const item of list) {
|
|
234
|
+
if (isPageRef(item)) {
|
|
235
|
+
if (!resolves(normalizeRef(item))) {
|
|
236
|
+
diagnostics.push({
|
|
237
|
+
code: "BLUME_NAV_MISSING_PAGE",
|
|
238
|
+
message: `Sidebar entry "${item}" matches no page, so it's left out of the sidebar.`,
|
|
239
|
+
severity: "warning",
|
|
240
|
+
suggestion: "Fix the route, or add a page at it."
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
if (item.root && !resolves(normalizeRef(item.root))) {
|
|
246
|
+
diagnostics.push({
|
|
247
|
+
code: "BLUME_NAV_MISSING_PAGE",
|
|
248
|
+
message: `Sidebar entry "${item.label}" has root "${item.root}", but no page matches it, so its link leads nowhere.`,
|
|
249
|
+
severity: "warning",
|
|
250
|
+
suggestion: "Fix the root, or add a page at that route."
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
if (item.items) {
|
|
254
|
+
walk(item.items);
|
|
255
|
+
} else if (!(item.root || item.href)) {
|
|
256
|
+
diagnostics.push({
|
|
257
|
+
code: "BLUME_NAV_EMPTY_ITEM",
|
|
258
|
+
message: `Sidebar entry "${item.label}" has no page, href, root, or items, so it's left out of the sidebar.`,
|
|
259
|
+
severity: "warning",
|
|
260
|
+
suggestion: "Give it an href or a root to link somewhere, or items to make it a group."
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
walk(items);
|
|
266
|
+
return diagnostics;
|
|
267
|
+
};
|
|
268
|
+
var duplicateLabelDiagnostics = (navigation) => {
|
|
269
|
+
const diagnostics = [];
|
|
270
|
+
const checkLevel = (nodes, where) => {
|
|
271
|
+
const counts = new Map;
|
|
272
|
+
for (const node of nodes) {
|
|
273
|
+
counts.set(node.label, (counts.get(node.label) ?? 0) + 1);
|
|
274
|
+
}
|
|
275
|
+
for (const [label, count] of counts) {
|
|
276
|
+
if (count > 1) {
|
|
277
|
+
diagnostics.push({
|
|
278
|
+
code: "BLUME_NAV_DUPLICATE_LABEL",
|
|
279
|
+
message: `Duplicate sidebar label "${label}" appears ${count} times ${where}.`,
|
|
280
|
+
severity: "warning",
|
|
281
|
+
suggestion: "Give the entries distinct titles."
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
for (const node of nodes) {
|
|
286
|
+
if (node.kind === "group") {
|
|
287
|
+
checkLevel(node.children, `under "${node.label}"`);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
const sidebars = [
|
|
292
|
+
{ nodes: navigation.sidebar, where: "at the top level" }
|
|
293
|
+
];
|
|
294
|
+
for (const { nodes, where } of sidebars) {
|
|
295
|
+
checkLevel(nodes, where);
|
|
296
|
+
}
|
|
297
|
+
return diagnostics;
|
|
298
|
+
};
|
|
299
|
+
var hiddenInSidebarDiagnostics = (navigation, pages) => {
|
|
300
|
+
const hidden = new Set(pages.flatMap((page) => page.meta.sidebar.hidden ? [page.id] : []));
|
|
301
|
+
if (hidden.size === 0) {
|
|
302
|
+
return [];
|
|
303
|
+
}
|
|
304
|
+
const sidebars = [navigation.sidebar];
|
|
305
|
+
const diagnostics = [];
|
|
306
|
+
const seen = new Set;
|
|
307
|
+
for (const sidebar of sidebars) {
|
|
308
|
+
for (const node of flattenNodes(sidebar)) {
|
|
309
|
+
if (node.kind === "page" && hidden.has(node.pageId) && !seen.has(node.pageId)) {
|
|
310
|
+
seen.add(node.pageId);
|
|
311
|
+
diagnostics.push({
|
|
312
|
+
code: "BLUME_NAV_HIDDEN_IN_SIDEBAR",
|
|
313
|
+
message: `Page "${node.label}" is marked hidden but appears in the sidebar (and its pagination).`,
|
|
314
|
+
severity: "warning",
|
|
315
|
+
suggestion: "Remove it from the navigation config, or unset sidebar.hidden."
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return diagnostics;
|
|
321
|
+
};
|
|
322
|
+
var validateNavStructure = (navigation, pages) => [
|
|
323
|
+
...duplicateLabelDiagnostics(navigation),
|
|
324
|
+
...hiddenInSidebarDiagnostics(navigation, pages)
|
|
325
|
+
];
|
|
326
|
+
|
|
96
327
|
// src/core/manifest.ts
|
|
97
328
|
var versionAlternateKey = (versionKey, locale) => `${versionKey}\x00${locale}`;
|
|
98
329
|
var versionAlternatesFor = (byKey, versionKey, locale) => {
|
|
@@ -251,304 +482,69 @@ var LITERAL_MARKERS = new Map([
|
|
|
251
482
|
var labelSource = (label) => label.length > 0 ? `[${mdastToString(label, { includeImageAlt: false })}]` : "";
|
|
252
483
|
var attributeSource = (node) => {
|
|
253
484
|
const attributes = Object.entries(node.attributes ?? {}).map(([key, value]) => value ? `${key}="${value}"` : key);
|
|
254
|
-
return attributes.length > 0 ? `{${attributes.join(" ")}}` : "";
|
|
255
|
-
};
|
|
256
|
-
var spannedSource = (node, source) => {
|
|
257
|
-
const start = node.position?.start?.offset;
|
|
258
|
-
const end = node.position?.end?.offset;
|
|
259
|
-
return start !== undefined && end !== undefined ? source.slice(start, end) : null;
|
|
260
|
-
};
|
|
261
|
-
var directiveSource = (node, marker, source) => {
|
|
262
|
-
const opening = `${marker}${node.name}`;
|
|
263
|
-
const slice = spannedSource(node, source);
|
|
264
|
-
if (slice?.startsWith(opening)) {
|
|
265
|
-
return slice;
|
|
266
|
-
}
|
|
267
|
-
return `${opening}${labelSource(node.children ?? [])}${attributeSource(node)}`;
|
|
268
|
-
};
|
|
269
|
-
|
|
270
|
-
// src/core/directive-diagnostics.ts
|
|
271
|
-
var CONTAINER_OPENING = /^[\t >]*:{3,}(?<name>[a-z][\w-]*)/gimu;
|
|
272
|
-
var codeList = (names) => [...names].map((name) => `\`${name}\``).join(", ");
|
|
273
|
-
var CALLOUT_NAMES = `${codeList(CALLOUT_TYPES)} (or the aliases ${codeList(Object.keys(CALLOUT_ALIASES))})`;
|
|
274
|
-
var unknownContainers = (text) => {
|
|
275
|
-
const named = [...text.matchAll(CONTAINER_OPENING)].some((match) => calloutTypeFor(match.groups?.name ?? "") === null);
|
|
276
|
-
if (!named) {
|
|
277
|
-
return [];
|
|
278
|
-
}
|
|
279
|
-
let tree;
|
|
280
|
-
try {
|
|
281
|
-
tree = mdxToMdast(text, { features: MDX_BODY_FEATURES });
|
|
282
|
-
} catch {
|
|
283
|
-
return [];
|
|
284
|
-
}
|
|
285
|
-
const found = [];
|
|
286
|
-
const walk = (node) => {
|
|
287
|
-
if (node.type === "containerDirective" && calloutTypeFor(node.name) === null) {
|
|
288
|
-
found.push({ line: node.position?.start.line ?? 1, name: node.name });
|
|
289
|
-
}
|
|
290
|
-
if ("children" in node) {
|
|
291
|
-
for (const child of node.children) {
|
|
292
|
-
walk(child);
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
};
|
|
296
|
-
walk(tree);
|
|
297
|
-
return found;
|
|
298
|
-
};
|
|
299
|
-
var unknownDirectiveDiagnostics = (entry, sourceName) => {
|
|
300
|
-
if (entry.body.format !== "mdx") {
|
|
301
|
-
return [];
|
|
302
|
-
}
|
|
303
|
-
const page = entry.sourcePath ?? `${sourceName}:${entry.ref}`;
|
|
304
|
-
const offset = entry.bodyLineOffset ?? strippedLineOffset(entry.raw, entry.body.text);
|
|
305
|
-
return unknownContainers(entry.expanded?.text ?? entry.body.text).map(({ line, name }) => {
|
|
306
|
-
const origin = entry.expanded?.origins[line - 1];
|
|
307
|
-
return {
|
|
308
|
-
code: "BLUME_UNKNOWN_DIRECTIVE",
|
|
309
|
-
file: origin?.file ?? page,
|
|
310
|
-
line: origin?.line ?? line + offset,
|
|
311
|
-
message: `\`:::${name}\` isn't a callout type, so the page shows its \`:::\` lines as written around its content.`,
|
|
312
|
-
severity: "warning",
|
|
313
|
-
suggestion: `Use a callout type — ${CALLOUT_NAMES} — or remove the \`:::\` lines to keep the content as plain prose.`
|
|
314
|
-
};
|
|
315
|
-
});
|
|
316
|
-
};
|
|
317
|
-
|
|
318
|
-
// src/core/localizable.ts
|
|
319
|
-
var isSingleLabel = (label) => typeof label === "string";
|
|
320
|
-
var resolveLocalizable = (label, locale, defaultLocale) => {
|
|
321
|
-
if (isSingleLabel(label)) {
|
|
322
|
-
return label;
|
|
323
|
-
}
|
|
324
|
-
return (locale === undefined ? undefined : label[locale]) ?? (defaultLocale === undefined ? undefined : label[defaultLocale]) ?? Object.values(label)[0] ?? "";
|
|
325
|
-
};
|
|
326
|
-
|
|
327
|
-
// src/theme/icon-kind.ts
|
|
328
|
-
var IMAGE_ICON = /^(?:https?:\/\/|data:image\/|\/|\.{1,2}\/)|\.(?:avif|gif|jpe?g|png|svg|webp)$/iu;
|
|
329
|
-
var INLINE_SVG = /^\s*<svg[\s\S]*<\/svg>\s*$/u;
|
|
330
|
-
var isImageIcon = (value) => IMAGE_ICON.test(value);
|
|
331
|
-
var isInlineSvg = (value) => INLINE_SVG.test(value);
|
|
332
|
-
var isAssetIcon = (value) => isInlineSvg(value) || isImageIcon(value);
|
|
333
|
-
|
|
334
|
-
// src/theme/icons.ts
|
|
335
|
-
import { createRequire } from "node:module";
|
|
336
|
-
import { getIconData, iconToSVG } from "@iconify/utils";
|
|
337
|
-
var requireJson = createRequire(import.meta.url);
|
|
338
|
-
var loadSet = (pkg) => requireJson(pkg);
|
|
339
|
-
var SETS = {
|
|
340
|
-
lucide: loadSet("@iconify-json/lucide/icons.json")
|
|
341
|
-
};
|
|
342
|
-
var DEFAULT_SET = "lucide";
|
|
343
|
-
var PREFIX_SETS = {
|
|
344
|
-
lucide: "lucide"
|
|
345
|
-
};
|
|
346
|
-
var ownEntry = (map, key) => Object.hasOwn(map, key) ? map[key] : undefined;
|
|
347
|
-
var normalize = (name) => name.trim().toLowerCase().replaceAll(/[\s_]+/gu, "-");
|
|
348
|
-
var fromSet = (setName, iconName) => {
|
|
349
|
-
const set = ownEntry(SETS, setName);
|
|
350
|
-
const data = set && getIconData(set, iconName);
|
|
351
|
-
if (!data) {
|
|
352
|
-
return null;
|
|
353
|
-
}
|
|
354
|
-
const { attributes, body } = iconToSVG(data, { height: "auto" });
|
|
355
|
-
return { body, name: iconName, viewBox: attributes.viewBox };
|
|
356
|
-
};
|
|
357
|
-
var resolveIcon = (name) => {
|
|
358
|
-
const normalized = normalize(name);
|
|
359
|
-
const colon = normalized.indexOf(":");
|
|
360
|
-
if (colon > 0) {
|
|
361
|
-
const setName = ownEntry(PREFIX_SETS, normalized.slice(0, colon));
|
|
362
|
-
return setName ? fromSet(setName, normalized.slice(colon + 1)) : null;
|
|
363
|
-
}
|
|
364
|
-
return fromSet(DEFAULT_SET, normalized);
|
|
365
|
-
};
|
|
366
|
-
var hasIcon = (name) => resolveIcon(name) !== null;
|
|
367
|
-
|
|
368
|
-
// src/core/nav-diagnostics.ts
|
|
369
|
-
var ICON_FORMAT_HINT = "Use a built-in icon name, an image path/URL, or inline SVG markup.";
|
|
370
|
-
var flattenNodes = (nodes) => nodes.flatMap((node) => node.kind === "group" ? [node, ...flattenNodes(node.children)] : [node]);
|
|
371
|
-
var collectIcons = (navigation) => {
|
|
372
|
-
const icons = [];
|
|
373
|
-
const push = (icon, where) => {
|
|
374
|
-
if (icon) {
|
|
375
|
-
icons.push({ icon, where });
|
|
376
|
-
}
|
|
377
|
-
};
|
|
378
|
-
for (const tab of navigation.tabs) {
|
|
379
|
-
push(tab.icon, `tab "${tab.label}"`);
|
|
380
|
-
for (const item of tab.items ?? []) {
|
|
381
|
-
push(item.icon, `tab item "${item.label}"`);
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
for (const selector of navigation.selectors) {
|
|
385
|
-
for (const item of selector.items) {
|
|
386
|
-
push(item.icon, `selector "${item.label}"`);
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
for (const link of navigation.featured) {
|
|
390
|
-
push(link.icon, `featured link "${link.label}"`);
|
|
391
|
-
}
|
|
392
|
-
const sidebars = [navigation.sidebar];
|
|
393
|
-
for (const sidebar of sidebars) {
|
|
394
|
-
for (const node of flattenNodes(sidebar)) {
|
|
395
|
-
push(node.icon, `"${node.label}"`);
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
return icons;
|
|
399
|
-
};
|
|
400
|
-
var unknownIconDiagnostics = (icons, suggestion) => {
|
|
401
|
-
const seen = new Set;
|
|
402
|
-
const diagnostics = [];
|
|
403
|
-
for (const { icon, where } of icons) {
|
|
404
|
-
if (isAssetIcon(icon) || hasIcon(icon) || seen.has(icon)) {
|
|
405
|
-
continue;
|
|
406
|
-
}
|
|
407
|
-
seen.add(icon);
|
|
408
|
-
const message = icon.trimStart().startsWith("<") ? `Icon markup "${icon}" (${where}) isn't a complete inline <svg> element, so it won't render.` : `Unknown icon "${icon}" (${where}) — it isn't in Blume's icon set.`;
|
|
409
|
-
diagnostics.push({
|
|
410
|
-
code: "BLUME_UNKNOWN_ICON",
|
|
411
|
-
message,
|
|
412
|
-
severity: "warning",
|
|
413
|
-
suggestion
|
|
414
|
-
});
|
|
415
|
-
}
|
|
416
|
-
return diagnostics;
|
|
485
|
+
return attributes.length > 0 ? `{${attributes.join(" ")}}` : "";
|
|
417
486
|
};
|
|
418
|
-
var
|
|
419
|
-
|
|
420
|
-
const
|
|
421
|
-
return
|
|
487
|
+
var spannedSource = (node, source) => {
|
|
488
|
+
const start = node.position?.start?.offset;
|
|
489
|
+
const end = node.position?.end?.offset;
|
|
490
|
+
return start !== undefined && end !== undefined ? source.slice(start, end) : null;
|
|
422
491
|
};
|
|
423
|
-
var
|
|
424
|
-
|
|
425
|
-
const
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
...navigation.featured.map((link) => ({
|
|
429
|
-
label: link.label,
|
|
430
|
-
path: link.href
|
|
431
|
-
})),
|
|
432
|
-
...(navigation.actions ?? []).map((action) => ({
|
|
433
|
-
label: action.label,
|
|
434
|
-
path: action.href
|
|
435
|
-
})),
|
|
436
|
-
...navigation.cta ? [{ label: navigation.cta.label, path: navigation.cta.href }] : []
|
|
437
|
-
];
|
|
438
|
-
const diagnostics = [];
|
|
439
|
-
const seen = new Set;
|
|
440
|
-
for (const { label, path } of targets) {
|
|
441
|
-
if (!isInternalPath(path) || path.startsWith("/#") || seen.has(path)) {
|
|
442
|
-
continue;
|
|
443
|
-
}
|
|
444
|
-
if (!resolvesToPages(routes, path.split(/[?#]/u)[0] ?? path)) {
|
|
445
|
-
seen.add(path);
|
|
446
|
-
diagnostics.push({
|
|
447
|
-
code: "BLUME_NAV_MISSING_PAGE",
|
|
448
|
-
message: `Navigation entry "${label}" points to ${path}, but no page matches it.`,
|
|
449
|
-
severity: "warning",
|
|
450
|
-
suggestion: "Fix the path, or add a page at that route."
|
|
451
|
-
});
|
|
452
|
-
}
|
|
492
|
+
var directiveSource = (node, marker, source) => {
|
|
493
|
+
const opening = `${marker}${node.name}`;
|
|
494
|
+
const slice = spannedSource(node, source);
|
|
495
|
+
if (slice?.startsWith(opening)) {
|
|
496
|
+
return slice;
|
|
453
497
|
}
|
|
454
|
-
return
|
|
455
|
-
};
|
|
456
|
-
var validateSidebarItems = (items, resolves) => {
|
|
457
|
-
const diagnostics = [];
|
|
458
|
-
const walk = (list) => {
|
|
459
|
-
for (const item of list) {
|
|
460
|
-
if (isPageRef(item)) {
|
|
461
|
-
if (!resolves(normalizeRef(item))) {
|
|
462
|
-
diagnostics.push({
|
|
463
|
-
code: "BLUME_NAV_MISSING_PAGE",
|
|
464
|
-
message: `Sidebar entry "${item}" matches no page, so it's left out of the sidebar.`,
|
|
465
|
-
severity: "warning",
|
|
466
|
-
suggestion: "Fix the route, or add a page at it."
|
|
467
|
-
});
|
|
468
|
-
}
|
|
469
|
-
continue;
|
|
470
|
-
}
|
|
471
|
-
if (item.root && !resolves(normalizeRef(item.root))) {
|
|
472
|
-
diagnostics.push({
|
|
473
|
-
code: "BLUME_NAV_MISSING_PAGE",
|
|
474
|
-
message: `Sidebar entry "${item.label}" has root "${item.root}", but no page matches it, so its link leads nowhere.`,
|
|
475
|
-
severity: "warning",
|
|
476
|
-
suggestion: "Fix the root, or add a page at that route."
|
|
477
|
-
});
|
|
478
|
-
}
|
|
479
|
-
if (item.items) {
|
|
480
|
-
walk(item.items);
|
|
481
|
-
} else if (!(item.root || item.href)) {
|
|
482
|
-
diagnostics.push({
|
|
483
|
-
code: "BLUME_NAV_EMPTY_ITEM",
|
|
484
|
-
message: `Sidebar entry "${item.label}" has no page, href, root, or items, so it's left out of the sidebar.`,
|
|
485
|
-
severity: "warning",
|
|
486
|
-
suggestion: "Give it an href or a root to link somewhere, or items to make it a group."
|
|
487
|
-
});
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
};
|
|
491
|
-
walk(items);
|
|
492
|
-
return diagnostics;
|
|
498
|
+
return `${opening}${labelSource(node.children ?? [])}${attributeSource(node)}`;
|
|
493
499
|
};
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
500
|
+
|
|
501
|
+
// src/core/directive-diagnostics.ts
|
|
502
|
+
var CONTAINER_OPENING = /^[\t >]*:{3,}(?<name>[a-z][\w-]*)/gimu;
|
|
503
|
+
var codeList = (names) => [...names].map((name) => `\`${name}\``).join(", ");
|
|
504
|
+
var CALLOUT_NAMES = `${codeList(CALLOUT_TYPES)} (or the aliases ${codeList(Object.keys(CALLOUT_ALIASES))})`;
|
|
505
|
+
var unknownContainers = (text) => {
|
|
506
|
+
const named = [...text.matchAll(CONTAINER_OPENING)].some((match) => calloutTypeFor(match.groups?.name ?? "") === null);
|
|
507
|
+
if (!named) {
|
|
508
|
+
return [];
|
|
509
|
+
}
|
|
510
|
+
let tree;
|
|
511
|
+
try {
|
|
512
|
+
tree = mdxToMdast(text, { features: MDX_BODY_FEATURES });
|
|
513
|
+
} catch {
|
|
514
|
+
return [];
|
|
515
|
+
}
|
|
516
|
+
const found = [];
|
|
517
|
+
const walk = (node) => {
|
|
518
|
+
if (node.type === "containerDirective" && calloutTypeFor(node.name) === null) {
|
|
519
|
+
found.push({ line: node.position?.start.line ?? 1, name: node.name });
|
|
510
520
|
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
521
|
+
if ("children" in node) {
|
|
522
|
+
for (const child of node.children) {
|
|
523
|
+
walk(child);
|
|
514
524
|
}
|
|
515
525
|
}
|
|
516
526
|
};
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
];
|
|
520
|
-
for (const { nodes, where } of sidebars) {
|
|
521
|
-
checkLevel(nodes, where);
|
|
522
|
-
}
|
|
523
|
-
return diagnostics;
|
|
527
|
+
walk(tree);
|
|
528
|
+
return found;
|
|
524
529
|
};
|
|
525
|
-
var
|
|
526
|
-
|
|
527
|
-
if (hidden.size === 0) {
|
|
530
|
+
var unknownDirectiveDiagnostics = (entry, sourceName) => {
|
|
531
|
+
if (entry.body.format !== "mdx") {
|
|
528
532
|
return [];
|
|
529
533
|
}
|
|
530
|
-
const
|
|
531
|
-
const
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
return diagnostics;
|
|
534
|
+
const page = entry.sourcePath ?? `${sourceName}:${entry.ref}`;
|
|
535
|
+
const offset = entry.bodyLineOffset ?? strippedLineOffset(entry.raw, entry.body.text);
|
|
536
|
+
return unknownContainers(entry.expanded?.text ?? entry.body.text).map(({ line, name }) => {
|
|
537
|
+
const origin = entry.expanded?.origins[line - 1];
|
|
538
|
+
return {
|
|
539
|
+
code: "BLUME_UNKNOWN_DIRECTIVE",
|
|
540
|
+
file: origin?.file ?? page,
|
|
541
|
+
line: origin?.line ?? line + offset,
|
|
542
|
+
message: `\`:::${name}\` isn't a callout type, so the page shows its \`:::\` lines as written around its content.`,
|
|
543
|
+
severity: "warning",
|
|
544
|
+
suggestion: `Use a callout type — ${CALLOUT_NAMES} — or remove the \`:::\` lines to keep the content as plain prose.`
|
|
545
|
+
};
|
|
546
|
+
});
|
|
547
547
|
};
|
|
548
|
-
var validateNavStructure = (navigation, pages) => [
|
|
549
|
-
...duplicateLabelDiagnostics(navigation),
|
|
550
|
-
...hiddenInSidebarDiagnostics(navigation, pages)
|
|
551
|
-
];
|
|
552
548
|
|
|
553
549
|
// src/core/graph.ts
|
|
554
550
|
var collectRoutes = (pages) => {
|
|
@@ -1016,7 +1012,9 @@ var assetFromEntry = (asset) => {
|
|
|
1016
1012
|
return null;
|
|
1017
1013
|
}
|
|
1018
1014
|
return {
|
|
1015
|
+
contentType: asString(getPath(asset, "fields.file.contentType")),
|
|
1019
1016
|
description: asString(getPath(asset, "fields.description")),
|
|
1017
|
+
fileName: asString(getPath(asset, "fields.file.fileName")),
|
|
1020
1018
|
title: asString(getPath(asset, "fields.title")),
|
|
1021
1019
|
url: absoluteUrl(url)
|
|
1022
1020
|
};
|
|
@@ -1084,6 +1082,11 @@ var inlineNodeParts = (node, options) => {
|
|
|
1084
1082
|
case "asset-hyperlink": {
|
|
1085
1083
|
return linkParts(inlineParts(children(node), options), linkedAsset(node, options)?.url);
|
|
1086
1084
|
}
|
|
1085
|
+
case "entry-hyperlink": {
|
|
1086
|
+
const entry = linkedTarget(node, options.resolveEntry);
|
|
1087
|
+
const href = entry ? options.entryHref?.(entry) : undefined;
|
|
1088
|
+
return linkParts(inlineParts(children(node), options), href);
|
|
1089
|
+
}
|
|
1087
1090
|
case "embedded-entry-inline": {
|
|
1088
1091
|
return [{ markdown: embeddedEntry(node, options) }];
|
|
1089
1092
|
}
|
|
@@ -1135,7 +1138,14 @@ var renderBlock = (node, options) => {
|
|
|
1135
1138
|
}
|
|
1136
1139
|
case "embedded-asset-block": {
|
|
1137
1140
|
const asset = linkedAsset(node, options);
|
|
1138
|
-
|
|
1141
|
+
if (!asset) {
|
|
1142
|
+
return "";
|
|
1143
|
+
}
|
|
1144
|
+
if (asset.contentType && !asset.contentType.startsWith("image/")) {
|
|
1145
|
+
const label = asset.title ?? asset.fileName ?? asset.url;
|
|
1146
|
+
return renderInline(linkParts([{ marks: {}, text: label }], asset.url));
|
|
1147
|
+
}
|
|
1148
|
+
return image(asset.description ?? asset.title ?? "", asset.url);
|
|
1139
1149
|
}
|
|
1140
1150
|
case "embedded-entry-block": {
|
|
1141
1151
|
return embeddedEntry(node, options);
|
|
@@ -1157,9 +1167,17 @@ var remoteSource = (options, ctx) => {
|
|
|
1157
1167
|
let snapshot = new Map;
|
|
1158
1168
|
const load = async (refresh = ctx?.refresh ?? true) => {
|
|
1159
1169
|
options.assertConfigured?.();
|
|
1160
|
-
|
|
1170
|
+
let warnings = [];
|
|
1171
|
+
const result = await loadWithCache(options.name, cache, async () => {
|
|
1172
|
+
const found = [];
|
|
1173
|
+
const entries = await options.fetchEntries((diagnostic) => {
|
|
1174
|
+
found.push(diagnostic);
|
|
1175
|
+
});
|
|
1176
|
+
warnings = found;
|
|
1177
|
+
return entries;
|
|
1178
|
+
}, refresh);
|
|
1161
1179
|
snapshot = new Map(result.entries.map((entry) => [entry.ref, entry]));
|
|
1162
|
-
return result;
|
|
1180
|
+
return { ...result, diagnostics: [...result.diagnostics, ...warnings] };
|
|
1163
1181
|
};
|
|
1164
1182
|
const read = async (ref) => {
|
|
1165
1183
|
const cached = snapshot.get(ref);
|
|
@@ -1190,6 +1208,12 @@ var stagedEntry = (slug, data, markdown, lastModified, format = "md") => {
|
|
|
1190
1208
|
ref: `${slug}.${format}`
|
|
1191
1209
|
};
|
|
1192
1210
|
};
|
|
1211
|
+
var missingSecretError = (name, env) => new BlumeError({
|
|
1212
|
+
code: "BLUME_MISSING_SECRET",
|
|
1213
|
+
message: `Source "${name}" needs ${env}, which is not set.`,
|
|
1214
|
+
severity: "error",
|
|
1215
|
+
suggestion: `Set ${env} in .env.local for local dev, or in your host's environment for production.`
|
|
1216
|
+
});
|
|
1193
1217
|
var REMOTE_TIMEOUT_MS = 30000;
|
|
1194
1218
|
var fetchJson = async (url, client) => {
|
|
1195
1219
|
const doFetch = client.fetchImpl ?? globalThis.fetch;
|
|
@@ -1211,9 +1235,9 @@ var queryString = (params) => {
|
|
|
1211
1235
|
}
|
|
1212
1236
|
return search.toString();
|
|
1213
1237
|
};
|
|
1238
|
+
var documentSlug = (doc, slugField, id) => slugifyPath(asString(getPath(doc, slugField)) ?? id) || slugify(id) || "untitled";
|
|
1214
1239
|
var documentEntry = (doc, fields, id, lower, draft = false, lowersToMdx = false) => {
|
|
1215
|
-
const
|
|
1216
|
-
const slug = slugifyPath(slugValue) || slugify(id) || "untitled";
|
|
1240
|
+
const slug = documentSlug(doc, fields.slug, id);
|
|
1217
1241
|
const data = {};
|
|
1218
1242
|
const title = asString(getPath(doc, fields.title));
|
|
1219
1243
|
const description = asString(getPath(doc, fields.description));
|
|
@@ -1226,6 +1250,10 @@ var documentEntry = (doc, fields, id, lower, draft = false, lowersToMdx = false)
|
|
|
1226
1250
|
if (draft) {
|
|
1227
1251
|
data.draft = true;
|
|
1228
1252
|
}
|
|
1253
|
+
const order = fields.order ? asNumber(getPath(doc, fields.order)) : undefined;
|
|
1254
|
+
if (order !== undefined) {
|
|
1255
|
+
data.sidebar = { order };
|
|
1256
|
+
}
|
|
1229
1257
|
const body = getPath(doc, fields.body);
|
|
1230
1258
|
let markdown = "";
|
|
1231
1259
|
let format = "md";
|
|
@@ -1240,8 +1268,8 @@ var documentEntry = (doc, fields, id, lower, draft = false, lowersToMdx = false)
|
|
|
1240
1268
|
};
|
|
1241
1269
|
|
|
1242
1270
|
// src/core/sources/contentful.ts
|
|
1243
|
-
var DELIVERY_HOST = "
|
|
1244
|
-
var PREVIEW_HOST = "
|
|
1271
|
+
var DELIVERY_HOST = "cdn.contentful.com";
|
|
1272
|
+
var PREVIEW_HOST = "preview.contentful.com";
|
|
1245
1273
|
var PAGE_SIZE = 100;
|
|
1246
1274
|
var DEFAULT_FIELDS = {
|
|
1247
1275
|
body: "body",
|
|
@@ -1251,20 +1279,50 @@ var DEFAULT_FIELDS = {
|
|
|
1251
1279
|
title: "title"
|
|
1252
1280
|
};
|
|
1253
1281
|
var byId = (objects) => new Map(objects.map((object) => [asString(getPath(object, "sys.id")) ?? "", object]));
|
|
1282
|
+
var entryView = (item) => {
|
|
1283
|
+
const sys = asObject(item.sys) ?? {};
|
|
1284
|
+
return {
|
|
1285
|
+
id: asString(sys.id) ?? "",
|
|
1286
|
+
view: { ...asObject(item.fields), sys }
|
|
1287
|
+
};
|
|
1288
|
+
};
|
|
1254
1289
|
var contentfulSource = (options, ctx) => {
|
|
1255
1290
|
const fields = { ...DEFAULT_FIELDS, ...options.fields };
|
|
1256
|
-
const
|
|
1257
|
-
const
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1291
|
+
const routeOf = (view, id) => {
|
|
1292
|
+
const route = resolveEntryRoute({ ref: `${documentSlug(view, fields.slug, id)}.md` }, ".md", undefined, { i18n: options.i18n, prefix: options.prefix, versions: options.versions });
|
|
1293
|
+
return localizedRoute(route.logicalRoute, route.locales[0] ?? "", options.i18n);
|
|
1294
|
+
};
|
|
1295
|
+
const toEntry = (item, { assets, linked }, routes, warn) => {
|
|
1296
|
+
const { id, view } = entryView(item);
|
|
1297
|
+
const missing = new Set;
|
|
1298
|
+
const entry = documentEntry(view, fields, id, (body) => isJsonObject(body) ? contentfulRichTextToMarkdown(body, {
|
|
1299
|
+
entryHref: (target) => routes.get(asString(getPath(target, "sys.id")) ?? ""),
|
|
1261
1300
|
resolveAsset: (assetId) => {
|
|
1262
1301
|
const asset = assets.get(assetId);
|
|
1263
|
-
|
|
1302
|
+
if (!asset) {
|
|
1303
|
+
missing.add(`asset "${assetId}"`);
|
|
1304
|
+
return null;
|
|
1305
|
+
}
|
|
1306
|
+
return assetFromEntry(asset);
|
|
1307
|
+
},
|
|
1308
|
+
resolveEntry: (entryId) => {
|
|
1309
|
+
const target = linked.get(entryId);
|
|
1310
|
+
if (!target) {
|
|
1311
|
+
missing.add(`entry "${entryId}"`);
|
|
1312
|
+
}
|
|
1313
|
+
return target ?? null;
|
|
1264
1314
|
},
|
|
1265
|
-
resolveEntry: (entryId) => linked.get(entryId) ?? null,
|
|
1266
1315
|
serializers: options.serializers
|
|
1267
1316
|
}) : "", false, writesMdx(options.serializers));
|
|
1317
|
+
for (const link of missing) {
|
|
1318
|
+
warn({
|
|
1319
|
+
code: "BLUME_SOURCE_UNRESOLVED_LINK",
|
|
1320
|
+
message: `Source "${options.name}": "${entry.ref}" links to Contentful ${link}, which the response didn't include, so the page renders without it.`,
|
|
1321
|
+
severity: "warning",
|
|
1322
|
+
suggestion: "Publish the linked asset or entry, or remove the link: the Delivery API returns only published content."
|
|
1323
|
+
});
|
|
1324
|
+
}
|
|
1325
|
+
return entry;
|
|
1268
1326
|
};
|
|
1269
1327
|
const preview = ctx?.preview ?? false;
|
|
1270
1328
|
const previewToken = () => options.previewToken ?? process.env.CONTENTFUL_PREVIEW_TOKEN;
|
|
@@ -1278,15 +1336,18 @@ var contentfulSource = (options, ctx) => {
|
|
|
1278
1336
|
});
|
|
1279
1337
|
}
|
|
1280
1338
|
};
|
|
1281
|
-
const fetchEntries = async () => {
|
|
1339
|
+
const fetchEntries = async (warn) => {
|
|
1282
1340
|
const token = preview ? previewToken() : options.token ?? process.env.CONTENTFUL_ACCESS_TOKEN;
|
|
1341
|
+
if (!token) {
|
|
1342
|
+
throw missingSecretError(options.name, "CONTENTFUL_ACCESS_TOKEN");
|
|
1343
|
+
}
|
|
1283
1344
|
const client = {
|
|
1284
1345
|
fetchImpl: options.fetchImpl,
|
|
1285
|
-
headers:
|
|
1346
|
+
headers: { authorization: `Bearer ${token}` }
|
|
1286
1347
|
};
|
|
1287
|
-
const host = preview ? PREVIEW_HOST : DELIVERY_HOST;
|
|
1288
|
-
const base =
|
|
1289
|
-
const
|
|
1348
|
+
const host = preview ? options.previewHost ?? PREVIEW_HOST : options.host ?? DELIVERY_HOST;
|
|
1349
|
+
const base = `https://${host}/spaces/${options.space}/environments/${options.environment ?? "master"}/entries`;
|
|
1350
|
+
const pages = [];
|
|
1290
1351
|
let skip = 0;
|
|
1291
1352
|
let more = true;
|
|
1292
1353
|
while (more) {
|
|
@@ -1302,16 +1363,20 @@ var contentfulSource = (options, ctx) => {
|
|
|
1302
1363
|
if (!page) {
|
|
1303
1364
|
throw new Error("Contentful returned a non-object response");
|
|
1304
1365
|
}
|
|
1305
|
-
const assets = byId(objectsIn(getPath(page, "includes.Asset")));
|
|
1306
|
-
const linked = byId(objectsIn(getPath(page, "includes.Entry")));
|
|
1307
1366
|
const items = objectsIn(page.items);
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1367
|
+
pages.push({
|
|
1368
|
+
assets: byId(objectsIn(getPath(page, "includes.Asset"))),
|
|
1369
|
+
items,
|
|
1370
|
+
linked: byId([...objectsIn(getPath(page, "includes.Entry")), ...items])
|
|
1371
|
+
});
|
|
1311
1372
|
skip += items.length;
|
|
1312
1373
|
more = items.length > 0 && skip < (asNumber(page.total) ?? 0);
|
|
1313
1374
|
}
|
|
1314
|
-
|
|
1375
|
+
const routes = new Map(pages.flatMap(({ items }) => items.map((item) => {
|
|
1376
|
+
const { id, view } = entryView(item);
|
|
1377
|
+
return [id, routeOf(view, id)];
|
|
1378
|
+
})));
|
|
1379
|
+
return pages.flatMap((page) => page.items.map((item) => toEntry(item, page, routes, warn)));
|
|
1315
1380
|
};
|
|
1316
1381
|
return remoteSource({
|
|
1317
1382
|
assertConfigured,
|
|
@@ -1326,6 +1391,7 @@ var contentfulSource = (options, ctx) => {
|
|
|
1326
1391
|
// src/core/sources/filesystem.ts
|
|
1327
1392
|
import { existsSync, watch as fsWatch } from "node:fs";
|
|
1328
1393
|
import { readFile } from "node:fs/promises";
|
|
1394
|
+
import { YAMLException } from "js-yaml";
|
|
1329
1395
|
import { extname, isAbsolute, join as join2, relative as relative3, resolve } from "pathe";
|
|
1330
1396
|
import { glob as glob2 } from "tinyglobby";
|
|
1331
1397
|
var filesystemSource = (options) => {
|
|
@@ -1348,11 +1414,19 @@ var filesystemSource = (options) => {
|
|
|
1348
1414
|
loadable.push(file);
|
|
1349
1415
|
}
|
|
1350
1416
|
}
|
|
1351
|
-
const
|
|
1417
|
+
const read = await Promise.all(loadable.map(async (file) => {
|
|
1352
1418
|
const source = await readFile(file, "utf-8");
|
|
1353
1419
|
const ext = extname(file).toLowerCase();
|
|
1354
1420
|
const format = ext === ".mdx" ? "mdx" : "md";
|
|
1355
|
-
|
|
1421
|
+
let parsed;
|
|
1422
|
+
try {
|
|
1423
|
+
parsed = frontmatter_default(source);
|
|
1424
|
+
} catch (error) {
|
|
1425
|
+
if (error instanceof YAMLException) {
|
|
1426
|
+
return frontmatterYamlDiagnostic(error, file);
|
|
1427
|
+
}
|
|
1428
|
+
throw error;
|
|
1429
|
+
}
|
|
1356
1430
|
return {
|
|
1357
1431
|
body: { format, text: parsed.content },
|
|
1358
1432
|
data: parsed.data,
|
|
@@ -1361,6 +1435,14 @@ var filesystemSource = (options) => {
|
|
|
1361
1435
|
sourcePath: file
|
|
1362
1436
|
};
|
|
1363
1437
|
}));
|
|
1438
|
+
const entries = [];
|
|
1439
|
+
for (const item of read) {
|
|
1440
|
+
if ("body" in item) {
|
|
1441
|
+
entries.push(item);
|
|
1442
|
+
} else {
|
|
1443
|
+
diagnostics.push(item);
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1364
1446
|
return { diagnostics, entries };
|
|
1365
1447
|
};
|
|
1366
1448
|
const validate = () => {
|
|
@@ -1526,11 +1608,17 @@ var githubHeaders = () => {
|
|
|
1526
1608
|
}
|
|
1527
1609
|
return headers;
|
|
1528
1610
|
};
|
|
1611
|
+
var releaseCategory = (release) => {
|
|
1612
|
+
if (release.draft) {
|
|
1613
|
+
return "Draft";
|
|
1614
|
+
}
|
|
1615
|
+
return release.prerelease ? "Prerelease" : "Release";
|
|
1616
|
+
};
|
|
1529
1617
|
var releaseToEntry = (release, site) => {
|
|
1530
1618
|
const version = release.tag_name.replace(LEADING_V, "");
|
|
1531
1619
|
const title = release.name?.trim() || release.tag_name;
|
|
1532
1620
|
const date = release.published_at ?? release.created_at;
|
|
1533
|
-
const category = release
|
|
1621
|
+
const category = releaseCategory(release);
|
|
1534
1622
|
const body = liftHeadings(relativizeOwnLinks(neutralizeUnsafeLinks((release.body ?? "").replaceAll(`\r
|
|
1535
1623
|
`, `
|
|
1536
1624
|
`)).trim(), site));
|
|
@@ -1641,6 +1729,11 @@ var githubReleasesSource = (options, ctx) => {
|
|
|
1641
1729
|
|
|
1642
1730
|
// src/core/sources/mdx-remote.ts
|
|
1643
1731
|
import picomatch from "picomatch";
|
|
1732
|
+
var includeMatcher = (include) => {
|
|
1733
|
+
const included = picomatch(include.filter((pattern) => !pattern.startsWith("!")));
|
|
1734
|
+
const excluded = picomatch(include.filter((pattern) => pattern.startsWith("!")).map((pattern) => pattern.slice(1)));
|
|
1735
|
+
return (ref) => included(ref) && !excluded(ref);
|
|
1736
|
+
};
|
|
1644
1737
|
var GITHUB_HOSTS = new Set(["api.github.com", "raw.githubusercontent.com"]);
|
|
1645
1738
|
var githubHeaders2 = (url) => {
|
|
1646
1739
|
const token = process.env.GITHUB_TOKEN;
|
|
@@ -1679,7 +1772,7 @@ var enumerateGithub = async (github, include, doFetch) => {
|
|
|
1679
1772
|
const text = await fetchText(treeUrl, doFetch);
|
|
1680
1773
|
const body = JSON.parse(text);
|
|
1681
1774
|
const prefix = base ? `${base}/` : "";
|
|
1682
|
-
const included =
|
|
1775
|
+
const included = includeMatcher(include);
|
|
1683
1776
|
const refs = (body.tree ?? []).flatMap((node) => {
|
|
1684
1777
|
if (!(node.type === "blob" && node.path.startsWith(prefix))) {
|
|
1685
1778
|
return [];
|
|
@@ -1696,7 +1789,13 @@ var enumerateGithub = async (github, include, doFetch) => {
|
|
|
1696
1789
|
}
|
|
1697
1790
|
];
|
|
1698
1791
|
});
|
|
1699
|
-
|
|
1792
|
+
const truncated = body.truncated === true;
|
|
1793
|
+
const found = prefix === "" || truncated || (body.tree ?? []).some((node) => node.path.startsWith(prefix));
|
|
1794
|
+
return {
|
|
1795
|
+
missing: found ? undefined : `"${base}" in ${owner}/${repo} at ${ref}`,
|
|
1796
|
+
refs,
|
|
1797
|
+
truncated
|
|
1798
|
+
};
|
|
1700
1799
|
};
|
|
1701
1800
|
var mdxRemoteSource = (options, ctx) => {
|
|
1702
1801
|
const doFetch = options.fetchImpl ?? globalThis.fetch;
|
|
@@ -1717,7 +1816,7 @@ var mdxRemoteSource = (options, ctx) => {
|
|
|
1717
1816
|
return await enumerateGithub(options.github, options.include, doFetch);
|
|
1718
1817
|
}
|
|
1719
1818
|
const base = (options.url ?? "").replace(/\/$/u, "");
|
|
1720
|
-
const included =
|
|
1819
|
+
const included = includeMatcher(options.include);
|
|
1721
1820
|
const refs = (options.files ?? []).flatMap((ref) => included(ref) ? [{ editUrl: `${base}/${ref}`, fetchUrl: `${base}/${ref}`, ref }] : []);
|
|
1722
1821
|
return { refs, truncated: false };
|
|
1723
1822
|
};
|
|
@@ -1738,12 +1837,21 @@ var mdxRemoteSource = (options, ctx) => {
|
|
|
1738
1837
|
assertConfigured();
|
|
1739
1838
|
const skipped = [];
|
|
1740
1839
|
const result = await loadWithCache(options.name, cache, async () => {
|
|
1741
|
-
const { refs, truncated } = await enumerate();
|
|
1840
|
+
const { missing, refs, truncated } = await enumerate();
|
|
1841
|
+
if (missing) {
|
|
1842
|
+
skipped.push({
|
|
1843
|
+
code: "BLUME_SOURCE_PATH_MISSING",
|
|
1844
|
+
message: `Source "${options.name}" read no files: there is no folder ${missing}.`,
|
|
1845
|
+
severity: "warning",
|
|
1846
|
+
suggestion: "Check github.path and github.ref against the repository."
|
|
1847
|
+
});
|
|
1848
|
+
}
|
|
1742
1849
|
if (truncated) {
|
|
1743
1850
|
skipped.push({
|
|
1744
1851
|
code: "BLUME_SOURCE_TRUNCATED",
|
|
1745
|
-
message: `Source "${options.name}" hit GitHub's tree listing limit; some files were not enumerated
|
|
1746
|
-
severity: "warning"
|
|
1852
|
+
message: `Source "${options.name}" hit GitHub's tree listing limit for the whole repository; some files were not enumerated.`,
|
|
1853
|
+
severity: "warning",
|
|
1854
|
+
suggestion: "List the files to read with { url, files } instead, or split the repository."
|
|
1747
1855
|
});
|
|
1748
1856
|
}
|
|
1749
1857
|
const reasons = [];
|
|
@@ -1965,7 +2073,7 @@ var materializeAssets = async (markdown, ctx) => {
|
|
|
1965
2073
|
};
|
|
1966
2074
|
|
|
1967
2075
|
// src/core/sources/notion.ts
|
|
1968
|
-
var richToMarkdown = (rich = []) => {
|
|
2076
|
+
var richToMarkdown = (rich = [], mdx = false) => {
|
|
1969
2077
|
const linked = [];
|
|
1970
2078
|
for (const { annotations = {}, href, plain_text: text } of rich) {
|
|
1971
2079
|
const run = {
|
|
@@ -1984,8 +2092,10 @@ var richToMarkdown = (rich = []) => {
|
|
|
1984
2092
|
linked.push({ href: href ?? undefined, runs: [run] });
|
|
1985
2093
|
}
|
|
1986
2094
|
}
|
|
1987
|
-
|
|
2095
|
+
const parts = linked.flatMap(({ href, runs }) => linkParts(runs, href, mdx));
|
|
2096
|
+
return mdx ? renderInlineMdx(parts) : renderInline(parts);
|
|
1988
2097
|
};
|
|
2098
|
+
var blockText2 = (rich, mdx) => mdx ? richToMarkdown(rich, true) : guardBlockStart(richToMarkdown(rich));
|
|
1989
2099
|
var isBlockPayload = (value) => typeof value === "object";
|
|
1990
2100
|
var payloadOf = (block) => {
|
|
1991
2101
|
const value = block[block.type];
|
|
@@ -2044,9 +2154,9 @@ var renderVideo = (data) => {
|
|
|
2044
2154
|
${media}
|
|
2045
2155
|
</Frame>` : media;
|
|
2046
2156
|
};
|
|
2047
|
-
var renderLeaf = (block) => {
|
|
2157
|
+
var renderLeaf = (block, mdx) => {
|
|
2048
2158
|
const data = payloadOf(block) ?? {};
|
|
2049
|
-
const text =
|
|
2159
|
+
const text = blockText2(blockField(block), mdx);
|
|
2050
2160
|
switch (block.type) {
|
|
2051
2161
|
case "paragraph": {
|
|
2052
2162
|
return text;
|
|
@@ -2092,6 +2202,7 @@ var renderLeaf = (block) => {
|
|
|
2092
2202
|
};
|
|
2093
2203
|
var notionSource = (options, ctx) => {
|
|
2094
2204
|
const props = options.properties ?? {};
|
|
2205
|
+
const textAsMdx = options.mdx ?? false;
|
|
2095
2206
|
const limit = pLimit(Math.max(1, options.concurrency ?? DEFAULT_CONCURRENCY));
|
|
2096
2207
|
const downloads = pLimit(ASSET_DOWNLOAD_CONCURRENCY);
|
|
2097
2208
|
const inFlight = new Map;
|
|
@@ -2115,7 +2226,11 @@ var notionSource = (options, ctx) => {
|
|
|
2115
2226
|
severity: "error"
|
|
2116
2227
|
});
|
|
2117
2228
|
}
|
|
2118
|
-
|
|
2229
|
+
const auth = options.token ?? process.env.NOTION_TOKEN;
|
|
2230
|
+
if (!auth) {
|
|
2231
|
+
throw missingSecretError(options.name, "NOTION_TOKEN");
|
|
2232
|
+
}
|
|
2233
|
+
return new Client({ auth });
|
|
2119
2234
|
};
|
|
2120
2235
|
const childrenOf = (client, blockId) => collectAll((cursor) => notionCall(() => client.blocks.children.list({ block_id: blockId, start_cursor: cursor })));
|
|
2121
2236
|
const renderContainer = async (client, block, render) => {
|
|
@@ -2127,7 +2242,7 @@ var notionSource = (options, ctx) => {
|
|
|
2127
2242
|
};
|
|
2128
2243
|
if (block.type === "callout") {
|
|
2129
2244
|
const body = [
|
|
2130
|
-
|
|
2245
|
+
blockText2(blockField(block), textAsMdx),
|
|
2131
2246
|
await children(block)
|
|
2132
2247
|
].filter(Boolean).join(`
|
|
2133
2248
|
|
|
@@ -2158,7 +2273,7 @@ ${rendered.join(`
|
|
|
2158
2273
|
};
|
|
2159
2274
|
const renderBlocks = async (client, blocks) => {
|
|
2160
2275
|
const parts = await Promise.all(blocks.map(async (block) => {
|
|
2161
|
-
const leaf = renderLeaf(block);
|
|
2276
|
+
const leaf = renderLeaf(block, textAsMdx);
|
|
2162
2277
|
if (leaf === null) {
|
|
2163
2278
|
return renderContainer(client, block, renderBlocks);
|
|
2164
2279
|
}
|
|
@@ -2311,6 +2426,7 @@ ${nested}`;
|
|
|
2311
2426
|
// src/core/sources/obsidian.ts
|
|
2312
2427
|
import { existsSync as existsSync2, watch as fsWatch2, statSync } from "node:fs";
|
|
2313
2428
|
import { readdir as readdir2, readFile as readFile2, stat } from "node:fs/promises";
|
|
2429
|
+
import { YAMLException as YAMLException2 } from "js-yaml";
|
|
2314
2430
|
import { basename as basename2, isAbsolute as isAbsolute2, join as join5, relative as relative4, resolve as resolve2 } from "pathe";
|
|
2315
2431
|
var MARKDOWN_FILE = /\.md$/iu;
|
|
2316
2432
|
var OBSIDIAN_COMMENT = /%%.*?%%/gu;
|
|
@@ -2643,6 +2759,9 @@ var readNote = async (vaultDir, rel, options) => {
|
|
|
2643
2759
|
rel
|
|
2644
2760
|
};
|
|
2645
2761
|
} catch (error) {
|
|
2762
|
+
if (error instanceof YAMLException2) {
|
|
2763
|
+
return frontmatterYamlDiagnostic(error, absPath);
|
|
2764
|
+
}
|
|
2646
2765
|
if (error.code === "ENOENT") {
|
|
2647
2766
|
return null;
|
|
2648
2767
|
}
|
|
@@ -2733,7 +2852,8 @@ var obsidianSource = (options, ctx) => {
|
|
|
2733
2852
|
}
|
|
2734
2853
|
}
|
|
2735
2854
|
const read = await Promise.all(files.map((rel) => readNote(vaultDir, rel, options)));
|
|
2736
|
-
const notes = read.filter((note) => note !== null);
|
|
2855
|
+
const notes = read.filter((note) => note !== null && ("rel" in note));
|
|
2856
|
+
skipped.push(...read.filter((note) => note !== null && ("code" in note)));
|
|
2737
2857
|
const { index, pairs } = buildLinkIndex(notes, options);
|
|
2738
2858
|
const unresolved = noTargets();
|
|
2739
2859
|
const entries = pairs.map((pair) => noteToEntry(pair, index, options, unresolved));
|
|
@@ -2809,6 +2929,10 @@ var marksOf2 = (node) => {
|
|
|
2809
2929
|
};
|
|
2810
2930
|
};
|
|
2811
2931
|
var children2 = (node) => objectsIn(node.children);
|
|
2932
|
+
var leftOut = (what, options) => {
|
|
2933
|
+
options.onUnsupported?.(what);
|
|
2934
|
+
return unsupported(what, writesMdx(options.serializers));
|
|
2935
|
+
};
|
|
2812
2936
|
var typeOf = (node) => asString(node.type) ?? "";
|
|
2813
2937
|
var customBlock = (node, options) => {
|
|
2814
2938
|
const fields = asObject(node.fields);
|
|
@@ -2817,7 +2941,7 @@ var customBlock = (node, options) => {
|
|
|
2817
2941
|
if (fields && serializer) {
|
|
2818
2942
|
return serializer(fields);
|
|
2819
2943
|
}
|
|
2820
|
-
return
|
|
2944
|
+
return leftOut(`Lexical block${blockType ? `: ${blockType}` : ""}`, options);
|
|
2821
2945
|
};
|
|
2822
2946
|
var inlineParts2 = (nodes, options) => nodes.flatMap((node) => inlineNodeParts2(node, options));
|
|
2823
2947
|
var inlineNodeParts2 = (node, options) => {
|
|
@@ -2845,12 +2969,12 @@ var inlineNodeParts2 = (node, options) => {
|
|
|
2845
2969
|
}
|
|
2846
2970
|
};
|
|
2847
2971
|
var inlineText = (nodes, options) => guardBlockStart(renderInline(inlineParts2(nodes, options)));
|
|
2848
|
-
var
|
|
2972
|
+
var blockText3 = (node, options) => inlineText(children2(node), options);
|
|
2849
2973
|
var renderUpload = (node, options) => {
|
|
2850
2974
|
const value = asObject(node.value);
|
|
2851
2975
|
const url = value ? asString(value.url) : undefined;
|
|
2852
2976
|
if (!(value && url)) {
|
|
2853
|
-
return
|
|
2977
|
+
return leftOut("Lexical upload (fetch with depth 1 to populate it)", options);
|
|
2854
2978
|
}
|
|
2855
2979
|
const alt = asString(value.alt) ?? asString(value.filename) ?? "";
|
|
2856
2980
|
return image(alt, absoluteUrl(url, options.baseUrl));
|
|
@@ -2887,14 +3011,14 @@ ${sub}` : line));
|
|
|
2887
3011
|
var renderBlock2 = (node, options) => {
|
|
2888
3012
|
switch (typeOf(node)) {
|
|
2889
3013
|
case "paragraph": {
|
|
2890
|
-
return
|
|
3014
|
+
return blockText3(node, options);
|
|
2891
3015
|
}
|
|
2892
3016
|
case "heading": {
|
|
2893
3017
|
const level = Number((asString(node.tag) ?? "h1").slice(1));
|
|
2894
|
-
return `${headingPrefix(level)}${
|
|
3018
|
+
return `${headingPrefix(level)}${blockText3(node, options)}`;
|
|
2895
3019
|
}
|
|
2896
3020
|
case "quote": {
|
|
2897
|
-
return blockquote(
|
|
3021
|
+
return blockquote(blockText3(node, options));
|
|
2898
3022
|
}
|
|
2899
3023
|
case "list": {
|
|
2900
3024
|
return renderList2(node, options);
|
|
@@ -2909,7 +3033,7 @@ var renderBlock2 = (node, options) => {
|
|
|
2909
3033
|
return customBlock(node, options);
|
|
2910
3034
|
}
|
|
2911
3035
|
default: {
|
|
2912
|
-
return
|
|
3036
|
+
return leftOut(`Lexical node: ${typeOf(node)}`, options);
|
|
2913
3037
|
}
|
|
2914
3038
|
}
|
|
2915
3039
|
};
|
|
@@ -2930,11 +3054,26 @@ var DEFAULT_FIELDS2 = {
|
|
|
2930
3054
|
var payloadSource = (options, ctx) => {
|
|
2931
3055
|
const fields = { ...DEFAULT_FIELDS2, ...options.fields };
|
|
2932
3056
|
const origin = options.url.replace(/\/+$/u, "");
|
|
2933
|
-
const lower = (body) => lexicalToMarkdown(body, {
|
|
3057
|
+
const lower = (body, leftOut) => lexicalToMarkdown(body, {
|
|
2934
3058
|
baseUrl: origin,
|
|
3059
|
+
onUnsupported: (what) => leftOut.add(what),
|
|
2935
3060
|
serializers: options.serializers
|
|
2936
3061
|
});
|
|
2937
|
-
const
|
|
3062
|
+
const toEntry = (doc, draft, warn) => {
|
|
3063
|
+
const leftOut = new Set;
|
|
3064
|
+
const id = asString(doc.id) ?? String(doc.id ?? "");
|
|
3065
|
+
const entry = documentEntry(doc, fields, id, (body) => isJsonObject(body) ? lower(body, leftOut) : "", draft, writesMdx(options.serializers));
|
|
3066
|
+
for (const what of leftOut) {
|
|
3067
|
+
warn({
|
|
3068
|
+
code: "BLUME_SOURCE_UNSUPPORTED_NODE",
|
|
3069
|
+
message: `Source "${options.name}": "${entry.ref}" has content Blume has no Markdown for (${what}), left out as a comment.`,
|
|
3070
|
+
severity: "warning",
|
|
3071
|
+
suggestion: "Map a block type to a component with a serializer on payloadSource, passed to custom(); other nodes have no Markdown equivalent."
|
|
3072
|
+
});
|
|
3073
|
+
}
|
|
3074
|
+
return entry;
|
|
3075
|
+
};
|
|
3076
|
+
const fetchEntries = async (warn) => {
|
|
2938
3077
|
const preview = ctx?.preview ?? false;
|
|
2939
3078
|
const token = options.token ?? process.env.PAYLOAD_API_KEY;
|
|
2940
3079
|
const client = {
|
|
@@ -2964,8 +3103,7 @@ var payloadSource = (options, ctx) => {
|
|
|
2964
3103
|
if (draft && !preview) {
|
|
2965
3104
|
continue;
|
|
2966
3105
|
}
|
|
2967
|
-
|
|
2968
|
-
entries.push(documentEntry(doc, fields, id, (body) => isJsonObject(body) ? lower(body) : "", draft, writesMdx(options.serializers)));
|
|
3106
|
+
entries.push(toEntry(doc, draft, warn));
|
|
2969
3107
|
}
|
|
2970
3108
|
more = result.hasNextPage === true;
|
|
2971
3109
|
page += 1;
|
|
@@ -3126,15 +3264,22 @@ var sanitySource = (options, ctx) => {
|
|
|
3126
3264
|
if (description) {
|
|
3127
3265
|
data.description = description;
|
|
3128
3266
|
}
|
|
3129
|
-
const
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
})
|
|
3137
|
-
|
|
3267
|
+
const body = getPath(doc, fields.body ?? "body");
|
|
3268
|
+
let markdown = "";
|
|
3269
|
+
let format = writesMdx(options.serializers) ? "mdx" : "md";
|
|
3270
|
+
if (isStringValue2(body)) {
|
|
3271
|
+
markdown = neutralizeUnsafeLinks(`${body.trimEnd()}
|
|
3272
|
+
`);
|
|
3273
|
+
format = "md";
|
|
3274
|
+
} else if (Array.isArray(body)) {
|
|
3275
|
+
markdown = portableTextToMarkdown(body, {
|
|
3276
|
+
imageUrl: (block) => {
|
|
3277
|
+
const ref = block.asset?._ref;
|
|
3278
|
+
return ref ? imageUrlFromRef(ref, options.projectId, options.dataset) : null;
|
|
3279
|
+
},
|
|
3280
|
+
serializers: options.serializers
|
|
3281
|
+
});
|
|
3282
|
+
}
|
|
3138
3283
|
const raw = frontmatter_default.stringify(markdown, data);
|
|
3139
3284
|
return {
|
|
3140
3285
|
body: { format, text: markdown },
|
|
@@ -3146,13 +3291,22 @@ var sanitySource = (options, ctx) => {
|
|
|
3146
3291
|
};
|
|
3147
3292
|
};
|
|
3148
3293
|
const load = async (refresh = ctx?.refresh ?? true) => {
|
|
3294
|
+
const empty = [];
|
|
3149
3295
|
const result = await loadWithCache(options.name, cache, async () => {
|
|
3150
3296
|
const client = resolveClient(options, ctx?.preview ?? false);
|
|
3151
3297
|
const docs = await client.fetch(options.query);
|
|
3298
|
+
if (docs.length === 0 && !(options.token ?? process.env.SANITY_TOKEN)) {
|
|
3299
|
+
empty.push({
|
|
3300
|
+
code: "BLUME_MISSING_SECRET",
|
|
3301
|
+
message: `Source "${options.name}" found no documents, and SANITY_TOKEN is not set. A private dataset returns nothing to a query without a token.`,
|
|
3302
|
+
severity: "warning",
|
|
3303
|
+
suggestion: "Set SANITY_TOKEN to a token with read access if the dataset is private."
|
|
3304
|
+
});
|
|
3305
|
+
}
|
|
3152
3306
|
return docs.map(toEntry);
|
|
3153
3307
|
}, refresh);
|
|
3154
3308
|
snapshot = new Map(result.entries.map((entry) => [entry.ref, entry]));
|
|
3155
|
-
return result;
|
|
3309
|
+
return { ...result, diagnostics: [...result.diagnostics, ...empty] };
|
|
3156
3310
|
};
|
|
3157
3311
|
const read = async (ref) => {
|
|
3158
3312
|
const cached = snapshot.get(ref);
|
|
@@ -3200,12 +3354,12 @@ var inlineNodeParts3 = (node) => {
|
|
|
3200
3354
|
}
|
|
3201
3355
|
}
|
|
3202
3356
|
};
|
|
3203
|
-
var
|
|
3357
|
+
var blockText4 = (nodes) => guardBlockStart(renderInline(inlineParts3(nodes)));
|
|
3204
3358
|
var renderList3 = (node) => {
|
|
3205
3359
|
const ordered = asString(node.format) === "ordered";
|
|
3206
3360
|
return children3(node).map((item, index) => {
|
|
3207
3361
|
const kids = children3(item);
|
|
3208
|
-
const line =
|
|
3362
|
+
const line = blockText4(kids.filter((kid) => typeOf2(kid) !== "list"));
|
|
3209
3363
|
const sub = kids.filter((kid) => typeOf2(kid) === "list").map((list) => renderList3(list)).join(`
|
|
3210
3364
|
`);
|
|
3211
3365
|
const body = sub ? `${line}
|
|
@@ -3225,13 +3379,13 @@ var renderImage = (node, options) => {
|
|
|
3225
3379
|
var renderBlock4 = (node, options) => {
|
|
3226
3380
|
switch (typeOf2(node)) {
|
|
3227
3381
|
case "paragraph": {
|
|
3228
|
-
return
|
|
3382
|
+
return blockText4(children3(node));
|
|
3229
3383
|
}
|
|
3230
3384
|
case "heading": {
|
|
3231
|
-
return `${headingPrefix(asNumber(node.level) ?? 1)}${
|
|
3385
|
+
return `${headingPrefix(asNumber(node.level) ?? 1)}${blockText4(children3(node))}`;
|
|
3232
3386
|
}
|
|
3233
3387
|
case "quote": {
|
|
3234
|
-
return blockquote(
|
|
3388
|
+
return blockquote(blockText4(children3(node)));
|
|
3235
3389
|
}
|
|
3236
3390
|
case "list": {
|
|
3237
3391
|
return renderList3(node);
|
|
@@ -3389,7 +3543,12 @@ var buildSource = (adapter, name, config, context, runtime) => {
|
|
|
3389
3543
|
return notionSource({ ...adapter.options, name }, ctx());
|
|
3390
3544
|
}
|
|
3391
3545
|
case "contentful": {
|
|
3392
|
-
return contentfulSource({
|
|
3546
|
+
return contentfulSource({
|
|
3547
|
+
...adapter.options,
|
|
3548
|
+
i18n: config.i18n,
|
|
3549
|
+
name,
|
|
3550
|
+
versions: config.versions
|
|
3551
|
+
}, ctx());
|
|
3393
3552
|
}
|
|
3394
3553
|
case "payload": {
|
|
3395
3554
|
return payloadSource({ ...adapter.options, name }, ctx());
|
|
@@ -3543,7 +3702,20 @@ var substituteEntryVariables = (entry, variables) => {
|
|
|
3543
3702
|
};
|
|
3544
3703
|
var substituteLoadedVariables = (loaded, variables) => hasVariables(variables) ? loaded.flatMap(({ entries }) => entries.flatMap((entry) => substituteEntryVariables(entry, variables))) : [];
|
|
3545
3704
|
var redirectPageDiagnostics = (config, pages, configFile) => config.redirects.flatMap((redirect) => {
|
|
3546
|
-
const
|
|
3705
|
+
const from = withBasePath(config.basePath, redirect.from);
|
|
3706
|
+
if (!isPatternPath(redirect.from)) {
|
|
3707
|
+
const page = normalizePath(from);
|
|
3708
|
+
return pages.includes(page) ? [
|
|
3709
|
+
{
|
|
3710
|
+
code: "BLUME_REDIRECT_MATCHES_PAGE",
|
|
3711
|
+
file: configFile ?? undefined,
|
|
3712
|
+
message: `The redirect from ${redirect.from} is also the page ${page}, which never publishes: its URL redirects to ${redirect.to} instead.`,
|
|
3713
|
+
severity: "warning",
|
|
3714
|
+
suggestion: "If the page moved, delete it or give it a new slug; otherwise remove the redirect."
|
|
3715
|
+
}
|
|
3716
|
+
] : [];
|
|
3717
|
+
}
|
|
3718
|
+
const matched = pathsUnderPattern(from, pages);
|
|
3547
3719
|
const [first] = matched;
|
|
3548
3720
|
if (first === undefined) {
|
|
3549
3721
|
return [];
|
|
@@ -3560,6 +3732,14 @@ var redirectPageDiagnostics = (config, pages, configFile) => config.redirects.fl
|
|
|
3560
3732
|
];
|
|
3561
3733
|
});
|
|
3562
3734
|
var bannerLinkHref = (banner) => banner === undefined || isBannerShorthand(banner) ? undefined : banner.link?.href;
|
|
3735
|
+
var validatedSources = (config, context, runtime, beforeSources) => {
|
|
3736
|
+
beforeSources?.(config);
|
|
3737
|
+
const sources = resolveSources(config, context, runtime);
|
|
3738
|
+
for (const source of sources) {
|
|
3739
|
+
source.validate?.();
|
|
3740
|
+
}
|
|
3741
|
+
return sources;
|
|
3742
|
+
};
|
|
3563
3743
|
var scanProject = async (root, options = {}) => {
|
|
3564
3744
|
const mode = options.mode ?? "dev";
|
|
3565
3745
|
const preview = options.preview ?? false;
|
|
@@ -3570,14 +3750,7 @@ var scanProject = async (root, options = {}) => {
|
|
|
3570
3750
|
const context = resolveProjectContext(root, config, {
|
|
3571
3751
|
runtimeDir: options.runtimeDir
|
|
3572
3752
|
});
|
|
3573
|
-
const sources =
|
|
3574
|
-
mode,
|
|
3575
|
-
preview,
|
|
3576
|
-
refresh: options.refresh
|
|
3577
|
-
});
|
|
3578
|
-
for (const source of sources) {
|
|
3579
|
-
source.validate?.();
|
|
3580
|
-
}
|
|
3753
|
+
const sources = validatedSources(config, context, { mode, preview, refresh: options.refresh }, options.beforeSources);
|
|
3581
3754
|
const metaSources = sources.flatMap((source) => source.staged || !source.contentRoot ? [] : [
|
|
3582
3755
|
{
|
|
3583
3756
|
exclude: source.exclude,
|
|
@@ -3681,7 +3854,7 @@ var scanProject = async (root, options = {}) => {
|
|
|
3681
3854
|
};
|
|
3682
3855
|
};
|
|
3683
3856
|
|
|
3684
|
-
export { directiveSource,
|
|
3857
|
+
export { directiveSource, validateSearchPopularIcons, validateNavTargets, contentIndexable, buildManifest, findFolderMetaFiles, isWithin, scanProject };
|
|
3685
3858
|
|
|
3686
|
-
//# debugId=
|
|
3687
|
-
//# sourceMappingURL=chunk-
|
|
3859
|
+
//# debugId=D6EC9010B970FDF164756E2164756E21
|
|
3860
|
+
//# sourceMappingURL=chunk-0pmb4tr4.js.map
|