blume 2.0.1 → 2.0.3
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 +147 -0
- package/dist/cli/{chunk-qwsrynx5.js → chunk-1d7ve1dm.js} +38 -19
- package/dist/cli/{chunk-qwsrynx5.js.map → chunk-1d7ve1dm.js.map} +4 -4
- package/dist/cli/{chunk-s6jhgk0q.js → chunk-2eytanqx.js} +2 -2
- package/dist/cli/{chunk-kdp5q7ke.js → chunk-2hsdwb9n.js} +18 -19
- package/dist/cli/{chunk-kdp5q7ke.js.map → chunk-2hsdwb9n.js.map} +2 -2
- package/dist/cli/{chunk-hdpx1tax.js → chunk-2z928egk.js} +5 -5
- package/dist/cli/{chunk-jwyddg7y.js → chunk-35d4wj9f.js} +30 -24
- package/dist/cli/chunk-35d4wj9f.js.map +15 -0
- package/dist/cli/{chunk-ah61y8py.js → chunk-364znk6q.js} +2 -2
- package/dist/cli/{chunk-jts8mvcz.js → chunk-3em5wd2y.js} +25 -6
- package/dist/cli/{chunk-jts8mvcz.js.map → chunk-3em5wd2y.js.map} +3 -3
- package/dist/cli/{chunk-s1p84fyh.js → chunk-5f86nr5m.js} +63 -22
- package/dist/cli/chunk-5f86nr5m.js.map +11 -0
- package/dist/cli/{chunk-2hn4b8z7.js → chunk-5m5nmvyq.js} +170 -76
- package/dist/cli/chunk-5m5nmvyq.js.map +13 -0
- package/dist/cli/{chunk-epjnccmv.js → chunk-5xvm6tfj.js} +18 -15
- package/dist/cli/chunk-5xvm6tfj.js.map +10 -0
- package/dist/cli/{chunk-fz5wtpmh.js → chunk-6dsbexzp.js} +18 -15
- package/dist/cli/chunk-6dsbexzp.js.map +10 -0
- package/dist/cli/{chunk-vtk4a6dg.js → chunk-8ktnccpt.js} +1 -1
- package/dist/cli/{chunk-6hsn950k.js → chunk-9t7a85s3.js} +178 -48
- package/dist/cli/chunk-9t7a85s3.js.map +10 -0
- package/dist/cli/{chunk-fxypxtvm.js → chunk-a58773jm.js} +2 -2
- package/dist/cli/{chunk-mb2919y2.js → chunk-acanzt5p.js} +17 -6
- package/dist/cli/chunk-acanzt5p.js.map +10 -0
- package/dist/cli/{chunk-27g6wdth.js → chunk-akbpwfxc.js} +90 -26
- package/dist/cli/chunk-akbpwfxc.js.map +10 -0
- package/dist/cli/{chunk-wm7js3j9.js → chunk-b07cmahc.js} +2 -2
- package/dist/cli/{chunk-wgm7m9qk.js → chunk-c8chx29p.js} +179 -51
- package/dist/cli/chunk-c8chx29p.js.map +36 -0
- package/dist/cli/{chunk-qs4q5p4e.js → chunk-crgn1q09.js} +32 -14
- package/dist/cli/chunk-crgn1q09.js.map +10 -0
- package/dist/cli/chunk-e04dxsz1.js +39 -0
- package/dist/cli/chunk-e04dxsz1.js.map +10 -0
- package/dist/cli/{chunk-yt5n7ppj.js → chunk-ey84smr6.js} +17 -7
- package/dist/cli/chunk-ey84smr6.js.map +10 -0
- package/dist/cli/{chunk-f2z5v128.js → chunk-g4hq16wv.js} +14 -15
- package/dist/cli/{chunk-f2z5v128.js.map → chunk-g4hq16wv.js.map} +2 -2
- package/dist/cli/{chunk-fa25z98p.js → chunk-ga0pf4aj.js} +9 -8
- package/dist/cli/chunk-ga0pf4aj.js.map +11 -0
- package/dist/cli/{chunk-kpf8rrjc.js → chunk-hm3vjy5s.js} +109 -58
- package/dist/cli/chunk-hm3vjy5s.js.map +19 -0
- package/dist/cli/{chunk-fs23ddbb.js → chunk-j85vccga.js} +625 -750
- package/dist/cli/chunk-j85vccga.js.map +36 -0
- package/dist/cli/{chunk-ch6g3ar0.js → chunk-p3v96n38.js} +6 -6
- package/dist/cli/{chunk-ch6g3ar0.js.map → chunk-p3v96n38.js.map} +3 -3
- package/dist/cli/{chunk-q5163e60.js → chunk-p73c0m7w.js} +21 -19
- package/dist/cli/chunk-p73c0m7w.js.map +11 -0
- package/dist/cli/{chunk-dh8cwk36.js → chunk-pehfxfta.js} +24 -9
- package/dist/cli/chunk-pehfxfta.js.map +10 -0
- package/dist/cli/{chunk-qkqwkpte.js → chunk-pv29h0wf.js} +3688 -1313
- package/dist/cli/chunk-pv29h0wf.js.map +190 -0
- package/dist/cli/{chunk-6vm74dry.js → chunk-q58y5e6a.js} +10 -10
- package/dist/cli/{chunk-6vm74dry.js.map → chunk-q58y5e6a.js.map} +3 -3
- package/dist/cli/{chunk-zxcczpyx.js → chunk-r20tn01b.js} +1 -1
- package/dist/cli/{chunk-m3vmjgmq.js → chunk-r9rcc4w7.js} +16 -8
- package/dist/cli/chunk-r9rcc4w7.js.map +10 -0
- package/dist/cli/{chunk-5shv93fd.js → chunk-tkacnehg.js} +2 -2
- package/dist/cli/{chunk-zxh4d9vy.js → chunk-tzmab476.js} +4 -4
- package/dist/cli/{chunk-yw7dm696.js → chunk-vg9r4eb9.js} +24 -11
- package/dist/cli/chunk-vg9r4eb9.js.map +14 -0
- package/dist/cli/{chunk-79jhk4py.js → chunk-wrr3j9w9.js} +260 -132
- package/dist/cli/chunk-wrr3j9w9.js.map +35 -0
- package/dist/cli/{chunk-6crbhc3x.js → chunk-yfyb25rh.js} +54 -27
- package/dist/cli/chunk-yfyb25rh.js.map +14 -0
- package/dist/cli/index.js +162 -35
- package/dist/cli/index.js.map +4 -4
- package/dist/types/ai/agent-surface.d.ts +32 -0
- package/dist/types/ai/api-catalog.d.ts +7 -1
- package/dist/types/ai/ask-context.d.ts +7 -0
- package/dist/types/ai/component-markdown.d.ts +4 -4
- package/dist/types/ai/link-headers.d.ts +8 -1
- package/dist/types/ai/openapi-components.d.ts +5 -2
- package/dist/types/ai/relative-links.d.ts +11 -4
- package/dist/types/ai/skills.d.ts +4 -1
- package/dist/types/ai/static-expression.d.ts +28 -0
- package/dist/types/ai/tar.d.ts +1 -3
- package/dist/types/analytics/databuddy.d.ts +43 -0
- package/dist/types/analytics/index.d.ts +4 -0
- package/dist/types/analytics/one-dollar-stats.d.ts +48 -0
- package/dist/types/analytics/schema.d.ts +28 -0
- package/dist/types/astro/integration.d.ts +3 -2
- package/dist/types/cli/env.d.ts +5 -0
- package/dist/types/cli/init/scaffold.d.ts +19 -3
- package/dist/types/cli/init/starter-spec.d.ts +11 -0
- package/dist/types/core/base-path.d.ts +24 -1
- package/dist/types/core/config-input.d.ts +13 -11
- package/dist/types/core/config.d.ts +2 -2
- package/dist/types/core/directive-diagnostics.d.ts +12 -0
- package/dist/types/core/graph.d.ts +2 -0
- package/dist/types/core/heading-markers.d.ts +5 -7
- package/dist/types/core/i18n-ui.d.ts +31 -0
- package/dist/types/core/i18n.d.ts +9 -1
- package/dist/types/core/last-modified.d.ts +10 -0
- package/dist/types/core/links.d.ts +3 -1
- package/dist/types/core/load-module.d.ts +10 -0
- package/dist/types/core/locale-links.d.ts +12 -2
- package/dist/types/core/meta.d.ts +13 -1
- package/dist/types/core/nav-diagnostics.d.ts +10 -0
- package/dist/types/core/navigation.d.ts +38 -0
- package/dist/types/core/ordering-prefix.d.ts +4 -0
- package/dist/types/core/safe-links.d.ts +3 -1
- package/dist/types/core/schema.d.ts +59 -13
- package/dist/types/core/sources/github-releases.d.ts +5 -0
- package/dist/types/core/sources/lower.d.ts +38 -13
- package/dist/types/core/sources/normalize.d.ts +23 -2
- package/dist/types/core/sources/remote.d.ts +11 -1
- package/dist/types/core/sources/resolve.d.ts +12 -0
- package/dist/types/core/sources/types.d.ts +31 -0
- package/dist/types/core/sources/watch.d.ts +12 -5
- package/dist/types/core/standard-schema.d.ts +5 -0
- package/dist/types/core/types.d.ts +9 -0
- package/dist/types/deploy/adapters/node.d.ts +5 -2
- package/dist/types/deploy/adapters/types.d.ts +7 -0
- package/dist/types/deploy/artifacts.d.ts +6 -4
- package/dist/types/deploy/cloudflare-negotiation.d.ts +3 -2
- package/dist/types/deploy/headers.d.ts +36 -7
- package/dist/types/deploy/node-headers.d.ts +43 -8
- package/dist/types/deploy/platforms/netlify.d.ts +27 -2
- package/dist/types/deploy/platforms/node.d.ts +6 -5
- package/dist/types/deploy/platforms/types.d.ts +15 -0
- package/dist/types/deploy/platforms/vercel.d.ts +3 -2
- package/dist/types/deploy/redirects.d.ts +31 -15
- package/dist/types/deploy/vercel-negotiation.d.ts +3 -2
- package/dist/types/markdown/directives.d.ts +62 -0
- package/dist/types/markdown/features.d.ts +21 -0
- package/dist/types/markdown/mdast.d.ts +63 -0
- package/dist/types/openapi/asyncapi.d.ts +4 -2
- package/dist/types/openapi/model.d.ts +20 -6
- package/dist/types/search/sync/algolia.d.ts +3 -1
- package/docs/01-quickstart.mdx +3 -2
- package/docs/02-deployment.mdx +20 -9
- package/docs/08-faq.mdx +10 -3
- package/docs/advanced/changelog.mdx +1 -1
- package/docs/advanced/custom-pages.mdx +7 -5
- package/docs/cli/audit.mdx +19 -3
- package/docs/cli/doctor.mdx +2 -2
- package/docs/cli/evals.mdx +4 -4
- package/docs/cli/index.mdx +4 -1
- package/docs/cli/translate.mdx +4 -4
- package/docs/cli/version.mdx +1 -1
- package/docs/configuration/analytics.mdx +42 -2
- package/docs/configuration/assistant.mdx +1 -1
- package/docs/configuration/customization.mdx +6 -3
- package/docs/configuration/index.mdx +5 -3
- package/docs/configuration/search.mdx +2 -2
- package/docs/content/components.mdx +2 -2
- package/docs/content/frontmatter.mdx +5 -1
- package/docs/content/i18n.mdx +3 -1
- package/docs/content/index.mdx +8 -4
- package/docs/content/islands.mdx +1 -1
- package/docs/content/meta.mdx +7 -3
- package/docs/content/navigation.mdx +29 -4
- package/docs/content/sources.mdx +18 -16
- package/docs/content/syntax.mdx +14 -0
- package/docs/content/versioning.mdx +2 -1
- package/docs/discoverability/agent-discovery.mdx +22 -8
- package/docs/discoverability/index.mdx +4 -3
- package/docs/discoverability/llms-txt.mdx +2 -5
- package/docs/discoverability/markdown.mdx +6 -4
- package/docs/discoverability/mcp.mdx +4 -0
- package/docs/discoverability/metadata.mdx +3 -2
- package/docs/discoverability/open-graph.mdx +8 -4
- package/docs/discoverability/rss.mdx +4 -2
- package/docs/references/asyncapi.mdx +2 -2
- package/docs/references/graphql.mdx +2 -2
- package/docs/references/openapi.mdx +6 -4
- package/package.json +1 -1
- package/skills/blume-migrate/SKILL.md +6 -6
- package/skills/blume-migrate/references/docusaurus.md +6 -6
- package/skills/blume-migrate/references/fumadocs.md +1 -1
- package/skills/blume-migrate/references/mintlify.md +3 -3
- package/skills/blume-migrate/references/monorepo.md +1 -1
- package/skills/blume-migrate/references/nextra.md +2 -2
- package/skills/blume-migrate/references/starlight.md +5 -5
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +9 -4
- package/skills/blume-update-docs/references/audit-checklist.md +1 -1
- package/src/ai/agent-readability.ts +2 -2
- package/src/ai/agent-surface.ts +56 -0
- package/src/ai/ai-catalog.ts +6 -2
- package/src/ai/api/handlers.ts +2 -2
- package/src/ai/api/spec.ts +17 -4
- package/src/ai/api-catalog.ts +13 -3
- package/src/ai/ask-context.ts +14 -2
- package/src/ai/ask-data.ts +26 -12
- package/src/ai/changelog-markdown.ts +2 -2
- package/src/ai/component-markdown.ts +43 -37
- package/src/ai/link-headers.ts +22 -8
- package/src/ai/llms.ts +22 -10
- package/src/ai/markdown.ts +23 -11
- package/src/ai/mcp/discovery.ts +2 -2
- package/src/ai/mcp/query.ts +2 -2
- package/src/ai/mcp/server.ts +80 -9
- package/src/ai/openapi-components.ts +22 -6
- package/src/ai/relative-links.ts +99 -15
- package/src/ai/serializers.ts +2 -1
- package/src/ai/skills.ts +14 -1
- package/src/ai/static-expression.ts +416 -0
- package/src/ai/tar.ts +139 -12
- package/src/ai/visibility.ts +45 -14
- package/src/analytics/databuddy.ts +67 -0
- package/src/analytics/head.ts +8 -0
- package/src/analytics/index.ts +7 -0
- package/src/analytics/one-dollar-stats.ts +86 -0
- package/src/analytics/posthog.ts +21 -3
- package/src/analytics/schema.ts +4 -0
- package/src/astro/generate.ts +72 -28
- package/src/astro/include-hmr.ts +31 -12
- package/src/astro/include-refresh.ts +19 -8
- package/src/astro/integration.ts +108 -14
- package/src/astro/runtime-modules.ts +28 -13
- package/src/astro/templates.ts +139 -57
- package/src/audit/catalog.ts +2 -2
- package/src/audit/checks/assets.ts +25 -5
- package/src/audit/checks/content.ts +20 -2
- package/src/audit/checks/i18n.ts +46 -8
- package/src/audit/checks/indexability.ts +39 -19
- package/src/audit/checks/links.ts +22 -1
- package/src/audit/checks/llms.ts +6 -3
- package/src/audit/checks/network.ts +3 -1
- package/src/audit/checks/og-image.ts +10 -0
- package/src/audit/checks/robots.ts +6 -1
- package/src/audit/checks/sitemap.ts +56 -31
- package/src/audit/checks/social.ts +21 -2
- package/src/audit/crawl.ts +88 -15
- package/src/audit/graph.ts +3 -1
- package/src/audit/report.ts +54 -17
- package/src/audit/run.ts +13 -9
- package/src/audit/snapshot.ts +5 -0
- package/src/audit/types.ts +18 -0
- package/src/audit/url.ts +37 -6
- package/src/cli/args.ts +32 -0
- package/src/cli/build-failure.ts +50 -0
- package/src/cli/commands/audit.ts +11 -1
- package/src/cli/commands/build.ts +19 -5
- package/src/cli/commands/check.ts +2 -0
- package/src/cli/commands/doctor.ts +3 -1
- package/src/cli/commands/eval.ts +20 -18
- package/src/cli/commands/init.ts +15 -5
- package/src/cli/commands/preview.ts +15 -0
- package/src/cli/commands/sync.ts +2 -0
- package/src/cli/commands/translate.ts +18 -18
- package/src/cli/commands/upgrade.ts +11 -0
- package/src/cli/commands/validate.ts +3 -1
- package/src/cli/dev-lock.ts +157 -37
- package/src/cli/eject-scripts.ts +32 -7
- package/src/cli/env.ts +12 -1
- package/src/cli/init/scaffold.ts +117 -11
- package/src/cli/init/starter-spec.ts +235 -0
- package/src/cli/report-format.ts +11 -6
- package/src/components/colors.ts +19 -0
- package/src/components/content/AccordionItem.astro +26 -22
- package/src/components/content/Badge.astro +7 -12
- package/src/components/content/Card.astro +2 -2
- package/src/components/content/Component.astro +11 -5
- package/src/components/content/Expandable.astro +5 -1
- package/src/components/content/Frame.astro +2 -7
- package/src/components/content/GithubInfo.astro +12 -2
- package/src/components/content/Prompt.astro +2 -7
- package/src/components/content/Tab.astro +0 -1
- package/src/components/content/Tabs.astro +58 -5
- package/src/components/content/Tile.astro +1 -1
- package/src/components/content/Tooltip.astro +69 -7
- package/src/components/content/Tree.astro +7 -2
- package/src/components/content/TypeTable.astro +10 -5
- package/src/components/content/Update.astro +8 -2
- package/src/components/content/auto-type-table.ts +4 -1
- package/src/components/content/badge-color.ts +20 -0
- package/src/components/content/base-href.ts +14 -22
- package/src/components/content/inline-markdown.ts +27 -7
- package/src/components/copy-feedback.ts +35 -8
- package/src/components/islands/assistant.tsx +37 -6
- package/src/components/islands/base-path.ts +47 -10
- package/src/components/islands/hooks.ts +42 -21
- package/src/components/islands/webmcp.ts +16 -10
- package/src/components/layout/Banner.astro +23 -4
- package/src/components/layout/Breadcrumbs.astro +5 -2
- package/src/components/layout/DiscoveryLinks.astro +9 -5
- package/src/components/layout/Header.astro +23 -10
- package/src/components/layout/LanguageSwitcher.astro +2 -2
- package/src/components/layout/Logo.astro +5 -0
- package/src/components/layout/NavSelector.astro +8 -3
- package/src/components/layout/NavTabMenu.astro +133 -0
- package/src/components/layout/NavTree.astro +31 -12
- package/src/components/layout/NavTreeCache.astro +5 -2
- package/src/components/layout/NavTreeScript.astro +45 -5
- package/src/components/layout/PageActions.astro +4 -3
- package/src/components/layout/PageLayout.astro +28 -13
- package/src/components/layout/Pagination.astro +3 -3
- package/src/components/layout/ReferenceLayout.astro +4 -1
- package/src/components/layout/RootLayout.astro +25 -12
- package/src/components/layout/Search.astro +38 -14
- package/src/components/layout/VersionBanner.astro +2 -2
- package/src/components/layout/analytics-client.ts +14 -0
- package/src/components/layout/toc-active.ts +41 -0
- package/src/components/layout/toc-element.ts +8 -14
- package/src/components/openapi/ApiTagOperations.astro +2 -2
- package/src/components/openapi/AsyncApiOperation.astro +7 -4
- package/src/components/openapi/GraphqlChip.astro +2 -2
- package/src/components/openapi/GraphqlType.astro +11 -3
- package/src/components/openapi/MessageComposer.astro +1 -1
- package/src/components/openapi/Operation.astro +23 -5
- package/src/components/openapi/PanelTabs.astro +4 -1
- package/src/components/openapi/Playground.astro +8 -2
- package/src/components/openapi/RequestPanel.astro +13 -6
- package/src/components/openapi/SchemaProperty.astro +11 -33
- package/src/components/openapi/SchemaTable.astro +34 -52
- package/src/components/openapi/async.ts +38 -6
- package/src/components/openapi/helpers.ts +100 -12
- package/src/components/openapi/message-composer.ts +14 -1
- package/src/components/openapi/message-model.ts +12 -2
- package/src/components/openapi/message.ts +21 -3
- package/src/components/openapi/operation-model.ts +119 -17
- package/src/components/openapi/panel.ts +31 -5
- package/src/components/openapi/param-style.ts +181 -0
- package/src/components/openapi/playground-client.ts +110 -23
- package/src/components/openapi/playground-schema.ts +25 -6
- package/src/components/openapi/request.ts +192 -26
- package/src/components/openapi/schema-tree.ts +209 -0
- package/src/components/openapi/snippets.ts +113 -19
- package/src/components/openapi/validate-json.ts +1 -1
- package/src/components/openapi/ws-client.ts +18 -2
- package/src/core/base-path.ts +69 -8
- package/src/core/config-input.ts +13 -11
- package/src/core/config.ts +18 -4
- package/src/core/diagnostics.ts +219 -30
- package/src/core/directive-diagnostics.ts +99 -0
- package/src/core/frontmatter.ts +21 -18
- package/src/core/graph.ts +120 -11
- package/src/core/heading-markers.ts +5 -18
- package/src/core/i18n-ui.ts +39 -2
- package/src/core/i18n.ts +44 -5
- package/src/core/last-modified.ts +25 -3
- package/src/core/links.ts +7 -4
- package/src/core/load-module.ts +20 -0
- package/src/core/locale-links.ts +22 -18
- package/src/core/manifest.ts +3 -2
- package/src/core/meta.ts +89 -12
- package/src/core/nav-diagnostics.ts +56 -1
- package/src/core/navigation.ts +272 -83
- package/src/core/ordering-prefix.ts +27 -0
- package/src/core/project-graph.ts +50 -6
- package/src/core/safe-href.ts +53 -1
- package/src/core/safe-links.ts +11 -2
- package/src/core/schema.ts +94 -18
- package/src/core/sources/assets.ts +83 -41
- package/src/core/sources/contentful-rich-text.ts +28 -20
- package/src/core/sources/contentful.ts +25 -12
- package/src/core/sources/filesystem.ts +25 -3
- package/src/core/sources/github-releases.ts +131 -11
- package/src/core/sources/lexical.ts +30 -20
- package/src/core/sources/lower.ts +276 -56
- package/src/core/sources/mdx-remote.ts +52 -16
- package/src/core/sources/normalize.ts +456 -119
- package/src/core/sources/notion.ts +77 -34
- package/src/core/sources/obsidian.ts +40 -9
- package/src/core/sources/payload.ts +1 -0
- package/src/core/sources/portable-text.ts +85 -49
- package/src/core/sources/remote.ts +18 -2
- package/src/core/sources/resolve.ts +52 -33
- package/src/core/sources/sanity.ts +1 -0
- package/src/core/sources/strapi-blocks.ts +28 -19
- package/src/core/sources/strapi.ts +1 -0
- package/src/core/sources/types.ts +31 -0
- package/src/core/sources/watch.ts +20 -7
- package/src/core/standard-schema.ts +10 -6
- package/src/core/types.ts +9 -0
- package/src/core/ui-packs/ar.ts +13 -0
- package/src/core/ui-packs/bg.ts +13 -0
- package/src/core/ui-packs/bn.ts +13 -0
- package/src/core/ui-packs/ca.ts +13 -0
- package/src/core/ui-packs/cs.ts +13 -0
- package/src/core/ui-packs/da.ts +13 -0
- package/src/core/ui-packs/de.ts +13 -0
- package/src/core/ui-packs/el.ts +13 -0
- package/src/core/ui-packs/es.ts +13 -0
- package/src/core/ui-packs/fa.ts +13 -0
- package/src/core/ui-packs/fi.ts +13 -0
- package/src/core/ui-packs/fr.ts +13 -0
- package/src/core/ui-packs/he.ts +13 -0
- package/src/core/ui-packs/hi.ts +13 -0
- package/src/core/ui-packs/hr.ts +13 -0
- package/src/core/ui-packs/hu.ts +13 -0
- package/src/core/ui-packs/id.ts +13 -0
- package/src/core/ui-packs/it.ts +13 -0
- package/src/core/ui-packs/ja.ts +13 -0
- package/src/core/ui-packs/ko.ts +13 -0
- package/src/core/ui-packs/nl.ts +13 -0
- package/src/core/ui-packs/no.ts +13 -0
- package/src/core/ui-packs/pl.ts +13 -0
- package/src/core/ui-packs/pt-br.ts +13 -0
- package/src/core/ui-packs/pt.ts +13 -0
- package/src/core/ui-packs/ro.ts +13 -0
- package/src/core/ui-packs/ru.ts +13 -0
- package/src/core/ui-packs/sk.ts +13 -0
- package/src/core/ui-packs/sr.ts +13 -0
- package/src/core/ui-packs/sv.ts +13 -0
- package/src/core/ui-packs/th.ts +13 -0
- package/src/core/ui-packs/tr.ts +13 -0
- package/src/core/ui-packs/uk.ts +13 -0
- package/src/core/ui-packs/vi.ts +13 -0
- package/src/core/ui-packs/zh-tw.ts +13 -0
- package/src/core/ui-packs/zh.ts +13 -0
- package/src/core/version-cut.ts +69 -17
- package/src/core/versions.ts +4 -1
- package/src/deploy/adapters/node.ts +5 -2
- package/src/deploy/adapters/registry.ts +2 -1
- package/src/deploy/adapters/types.ts +13 -1
- package/src/deploy/artifacts.ts +52 -11
- package/src/deploy/cloudflare-negotiation.ts +27 -16
- package/src/deploy/headers.ts +75 -55
- package/src/deploy/node-headers.ts +148 -27
- package/src/deploy/platforms/cloudflare.ts +13 -3
- package/src/deploy/platforms/netlify.ts +83 -5
- package/src/deploy/platforms/node.ts +8 -5
- package/src/deploy/platforms/static.ts +2 -0
- package/src/deploy/platforms/types.ts +15 -0
- package/src/deploy/platforms/vercel.ts +10 -3
- package/src/deploy/redirects.ts +68 -21
- package/src/deploy/robots.ts +2 -2
- package/src/deploy/rss.ts +4 -3
- package/src/deploy/sitemap.ts +7 -5
- package/src/deploy/vercel-negotiation.ts +35 -3
- package/src/eval/agents.ts +10 -2
- package/src/eval/run.ts +25 -0
- package/src/markdown/base-links.ts +74 -29
- package/src/markdown/directives.ts +242 -36
- package/src/markdown/features.ts +17 -0
- package/src/markdown/index.ts +13 -9
- package/src/markdown/mdast.ts +5 -2
- package/src/markdown/relative-links.ts +15 -27
- package/src/markdown/route-snapshot.ts +37 -0
- package/src/og/card.ts +149 -9
- package/src/og/derive.ts +156 -5
- package/src/og/index.ts +1 -0
- package/src/openapi/asyncapi.ts +4 -2
- package/src/openapi/graphql-build.ts +28 -2
- package/src/openapi/model.ts +99 -27
- package/src/openapi/proxy.ts +63 -10
- package/src/openapi/render-mdx.ts +51 -3
- package/src/registry/eject.ts +297 -43
- package/src/search/adapters/version-scope.ts +30 -0
- package/src/search/documents.ts +89 -27
- package/src/search/popular.ts +2 -1
- package/src/search/sync/algolia.ts +36 -2
- package/src/seo/jsonld.ts +7 -3
- package/src/sources/registry.ts +5 -0
- package/src/theme/entry.ts +11 -4
- package/src/translate/agents.ts +6 -1
- package/src/translate/ledger.ts +26 -3
- package/src/translate/meta.ts +76 -24
- package/src/translate/run.ts +14 -8
- package/src/translate/validate.ts +14 -2
- package/src/translate/work-list.ts +91 -19
- package/src/upgrade/upgrade.ts +36 -4
- package/dist/cli/chunk-27g6wdth.js.map +0 -10
- package/dist/cli/chunk-2hn4b8z7.js.map +0 -12
- package/dist/cli/chunk-6crbhc3x.js.map +0 -14
- package/dist/cli/chunk-6hsn950k.js.map +0 -10
- package/dist/cli/chunk-79jhk4py.js.map +0 -35
- package/dist/cli/chunk-82bbrxdn.js +0 -51
- package/dist/cli/chunk-82bbrxdn.js.map +0 -10
- package/dist/cli/chunk-abh8yjkn.js +0 -31
- package/dist/cli/chunk-abh8yjkn.js.map +0 -10
- package/dist/cli/chunk-ce574jw2.js +0 -23
- package/dist/cli/chunk-ce574jw2.js.map +0 -10
- package/dist/cli/chunk-dh8cwk36.js.map +0 -10
- package/dist/cli/chunk-epjnccmv.js.map +0 -10
- package/dist/cli/chunk-fa25z98p.js.map +0 -11
- package/dist/cli/chunk-fs23ddbb.js.map +0 -35
- package/dist/cli/chunk-fz5wtpmh.js.map +0 -10
- package/dist/cli/chunk-jwyddg7y.js.map +0 -15
- package/dist/cli/chunk-kpf8rrjc.js.map +0 -19
- package/dist/cli/chunk-m3vmjgmq.js.map +0 -10
- package/dist/cli/chunk-mb2919y2.js.map +0 -10
- package/dist/cli/chunk-q5163e60.js.map +0 -11
- package/dist/cli/chunk-qkqwkpte.js.map +0 -182
- package/dist/cli/chunk-qs4q5p4e.js.map +0 -10
- package/dist/cli/chunk-s1p84fyh.js.map +0 -10
- package/dist/cli/chunk-wgm7m9qk.js.map +0 -36
- package/dist/cli/chunk-yt5n7ppj.js.map +0 -10
- package/dist/cli/chunk-yw7dm696.js.map +0 -14
- /package/dist/cli/{chunk-s6jhgk0q.js.map → chunk-2eytanqx.js.map} +0 -0
- /package/dist/cli/{chunk-hdpx1tax.js.map → chunk-2z928egk.js.map} +0 -0
- /package/dist/cli/{chunk-ah61y8py.js.map → chunk-364znk6q.js.map} +0 -0
- /package/dist/cli/{chunk-vtk4a6dg.js.map → chunk-8ktnccpt.js.map} +0 -0
- /package/dist/cli/{chunk-fxypxtvm.js.map → chunk-a58773jm.js.map} +0 -0
- /package/dist/cli/{chunk-wm7js3j9.js.map → chunk-b07cmahc.js.map} +0 -0
- /package/dist/cli/{chunk-zxcczpyx.js.map → chunk-r20tn01b.js.map} +0 -0
- /package/dist/cli/{chunk-5shv93fd.js.map → chunk-tkacnehg.js.map} +0 -0
- /package/dist/cli/{chunk-zxh4d9vy.js.map → chunk-tzmab476.js.map} +0 -0
package/src/og/card.ts
CHANGED
|
@@ -2,7 +2,13 @@ import { readFile } from "node:fs/promises";
|
|
|
2
2
|
|
|
3
3
|
import { render } from "takumi-js";
|
|
4
4
|
import type { RenderOptions } from "takumi-js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
collectCodepoints,
|
|
7
|
+
container,
|
|
8
|
+
googleFonts,
|
|
9
|
+
image,
|
|
10
|
+
text,
|
|
11
|
+
} from "takumi-js/helpers";
|
|
6
12
|
import type { FontSubset, GoogleFontFamily, Node } from "takumi-js/helpers";
|
|
7
13
|
|
|
8
14
|
import { svgDimensions } from "../core/svg-dimensions.ts";
|
|
@@ -42,6 +48,9 @@ export type OgFont =
|
|
|
42
48
|
}
|
|
43
49
|
| OgLocalFont;
|
|
44
50
|
|
|
51
|
+
/** An OG font fetched from Google Fonts (a bare family name or the object form). */
|
|
52
|
+
export type OgGoogleFont = Exclude<OgFont, OgLocalFont>;
|
|
53
|
+
|
|
45
54
|
/**
|
|
46
55
|
* Which loaded family each card role renders in. Takumi still falls back
|
|
47
56
|
* across every loaded font per glyph, so a family that misses a script
|
|
@@ -106,6 +115,12 @@ export interface OgCardOptions {
|
|
|
106
115
|
* from disk instead of Google Fonts.
|
|
107
116
|
*/
|
|
108
117
|
fonts?: OgFont[];
|
|
118
|
+
/**
|
|
119
|
+
* Script fallbacks, tried after `fonts` for glyphs nothing else draws. A
|
|
120
|
+
* card loads them only when its text needs one, so a Latin-only card never
|
|
121
|
+
* fetches them — see {@link fallbackSubsets}.
|
|
122
|
+
*/
|
|
123
|
+
fallbacks?: OgGoogleFont[];
|
|
109
124
|
/** Per-role families from the loaded fonts (title vs body text). */
|
|
110
125
|
families?: OgFontFamilies;
|
|
111
126
|
}
|
|
@@ -145,9 +160,7 @@ const fontSubsetCache = new Map<string, Promise<FontSubset[]>>();
|
|
|
145
160
|
* fetch failure rejects, failing the build with the cause rather than silently
|
|
146
161
|
* shipping tofu — the same fail-fast the OG accent relies on.
|
|
147
162
|
*/
|
|
148
|
-
const loadFonts = (
|
|
149
|
-
fonts: Exclude<OgFont, OgLocalFont>[]
|
|
150
|
-
): Promise<FontSubset[]> => {
|
|
163
|
+
const loadFonts = (fonts: OgGoogleFont[]): Promise<FontSubset[]> => {
|
|
151
164
|
const key = JSON.stringify(fonts);
|
|
152
165
|
let pending = fontSubsetCache.get(key);
|
|
153
166
|
if (!pending) {
|
|
@@ -160,6 +173,113 @@ const loadFonts = (
|
|
|
160
173
|
return pending;
|
|
161
174
|
};
|
|
162
175
|
|
|
176
|
+
/**
|
|
177
|
+
* The code points Takumi's built-in Geist draws: whitespace, printable ASCII,
|
|
178
|
+
* Latin-1 except `µ`, a few Latin extras French needs, and the typographic
|
|
179
|
+
* punctuation English copy leans on. Probed against the renderer, and
|
|
180
|
+
* `og-card.test.ts` renders every one, so a Takumi upgrade that drops a glyph
|
|
181
|
+
* fails there instead of shipping tofu.
|
|
182
|
+
*/
|
|
183
|
+
export const BUILT_IN_GLYPHS: [number, number][] = [
|
|
184
|
+
[0x09, 0x0d],
|
|
185
|
+
[0x20, 0x7e],
|
|
186
|
+
[0xa0, 0xb4],
|
|
187
|
+
[0xb6, 0xff],
|
|
188
|
+
[0x1_31, 0x1_31],
|
|
189
|
+
[0x1_52, 0x1_53],
|
|
190
|
+
[0x1_78, 0x1_78],
|
|
191
|
+
[0x20_00, 0x20_0f],
|
|
192
|
+
[0x20_13, 0x20_14],
|
|
193
|
+
[0x20_18, 0x20_1a],
|
|
194
|
+
[0x20_1c, 0x20_1e],
|
|
195
|
+
[0x20_20, 0x20_22],
|
|
196
|
+
[0x20_26, 0x20_26],
|
|
197
|
+
[0x20_28, 0x20_30],
|
|
198
|
+
[0x20_32, 0x20_33],
|
|
199
|
+
[0x20_39, 0x20_3a],
|
|
200
|
+
[0x20_44, 0x20_44],
|
|
201
|
+
[0x20_5f, 0x20_6f],
|
|
202
|
+
[0x20_ac, 0x20_ac],
|
|
203
|
+
[0x21_22, 0x21_22],
|
|
204
|
+
[0x21_91, 0x21_91],
|
|
205
|
+
[0x21_93, 0x21_93],
|
|
206
|
+
[0x22_12, 0x22_12],
|
|
207
|
+
];
|
|
208
|
+
|
|
209
|
+
/** Emoji render as Twemoji images, never from a font. */
|
|
210
|
+
const EMOJI = /\p{Emoji_Presentation}|\p{Emoji_Component}/u;
|
|
211
|
+
|
|
212
|
+
/** Whether a card draws `codePoint` without any loaded font. */
|
|
213
|
+
const drawnWithoutFonts = (codePoint: number): boolean =>
|
|
214
|
+
BUILT_IN_GLYPHS.some(([from, to]) => codePoint >= from && codePoint <= to) ||
|
|
215
|
+
EMOJI.test(String.fromCodePoint(codePoint));
|
|
216
|
+
|
|
217
|
+
/** Whether `subset` claims `codePoint` (a subset without ranges claims all). */
|
|
218
|
+
const subsetClaims = (subset: FontSubset, codePoint: number): boolean =>
|
|
219
|
+
subset.ranges.length === 0 ||
|
|
220
|
+
subset.ranges.some(([from, to]) => codePoint >= from && codePoint <= to);
|
|
221
|
+
|
|
222
|
+
/** `family`'s subsets that claim any of `codePoints`. */
|
|
223
|
+
const familySubsets = (
|
|
224
|
+
subsets: FontSubset[],
|
|
225
|
+
family: string,
|
|
226
|
+
codePoints: number[]
|
|
227
|
+
): FontSubset[] =>
|
|
228
|
+
subsets.filter(
|
|
229
|
+
(subset) =>
|
|
230
|
+
subset.subsetOf === family &&
|
|
231
|
+
codePoints.some((codePoint) => subsetClaims(subset, codePoint))
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* The scripts only the CJK families draw. Google slices those fonts by the
|
|
236
|
+
* glyphs each one really has, so the first family claiming such a character
|
|
237
|
+
* draws it. Other claims follow Google's shared subset definitions whatever
|
|
238
|
+
* the font holds — every family's `latin` claims `※`, Arabic's `symbols`
|
|
239
|
+
* claims `→` — so a claim there proves nothing.
|
|
240
|
+
*/
|
|
241
|
+
const CJK_SCRIPTS =
|
|
242
|
+
/[\p{Script=Bopomofo}\p{Script=Han}\p{Script=Hangul}\p{Script=Hiragana}\p{Script=Katakana}]/u;
|
|
243
|
+
|
|
244
|
+
/** Whether a claim on `codePoint` means the claiming family draws it. */
|
|
245
|
+
const claimIsExact = (codePoint: number): boolean =>
|
|
246
|
+
CJK_SCRIPTS.test(String.fromCodePoint(codePoint));
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* The fallback subsets a card's text needs. Nothing loads, and nothing is
|
|
250
|
+
* fetched, when the built-in font draws every glyph, so a Latin-only card
|
|
251
|
+
* builds offline. Otherwise only subsets claiming a glyph beyond the built-in
|
|
252
|
+
* font load (not every family's `latin`), and a CJK character stops at the
|
|
253
|
+
* first family that claims it: all four CJK families claim most Han, so left
|
|
254
|
+
* to `render` each would download its matching slices although only the
|
|
255
|
+
* first ever paints them.
|
|
256
|
+
*/
|
|
257
|
+
const fallbackSubsets = async (
|
|
258
|
+
fallbacks: OgGoogleFont[] | undefined,
|
|
259
|
+
node: Node
|
|
260
|
+
): Promise<FontSubset[]> => {
|
|
261
|
+
let missing = [...collectCodepoints(node)].filter(
|
|
262
|
+
(codePoint) => !drawnWithoutFonts(codePoint)
|
|
263
|
+
);
|
|
264
|
+
if (!fallbacks?.length || missing.length === 0) {
|
|
265
|
+
return [];
|
|
266
|
+
}
|
|
267
|
+
const subsets = await loadFonts(fallbacks);
|
|
268
|
+
const needed: FontSubset[] = [];
|
|
269
|
+
for (const family of new Set(subsets.map((subset) => subset.subsetOf))) {
|
|
270
|
+
const matching = familySubsets(subsets, family, missing);
|
|
271
|
+
needed.push(...matching);
|
|
272
|
+
missing = missing.filter(
|
|
273
|
+
(codePoint) =>
|
|
274
|
+
!(
|
|
275
|
+
claimIsExact(codePoint) &&
|
|
276
|
+
matching.some((subset) => subsetClaims(subset, codePoint))
|
|
277
|
+
)
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
return needed;
|
|
281
|
+
};
|
|
282
|
+
|
|
163
283
|
/**
|
|
164
284
|
* A lazy loader for a local font file, matching the shape `render` accepts
|
|
165
285
|
* alongside Google subsets. Keyed by path so the shared renderer reads and
|
|
@@ -261,11 +381,23 @@ const logoMark = (svg: string, foreground: string): Node => {
|
|
|
261
381
|
};
|
|
262
382
|
|
|
263
383
|
// Fallback mark when no SVG logo is configured: an accent tile with the brand's
|
|
264
|
-
// initial, matching the docs favicon aesthetic.
|
|
265
|
-
|
|
384
|
+
// initial, matching the docs favicon aesthetic. The initial takes the headline's
|
|
385
|
+
// family, so it matches the title rather than whichever loaded font comes first.
|
|
386
|
+
const initialMark = (
|
|
387
|
+
accent: string,
|
|
388
|
+
initial: string,
|
|
389
|
+
family: { fontFamily?: string }
|
|
390
|
+
): Node =>
|
|
266
391
|
container({
|
|
267
392
|
children: initial
|
|
268
|
-
? [
|
|
393
|
+
? [
|
|
394
|
+
text(initial, {
|
|
395
|
+
color: "#ffffff",
|
|
396
|
+
fontSize: 32,
|
|
397
|
+
fontWeight: 600,
|
|
398
|
+
...family,
|
|
399
|
+
}),
|
|
400
|
+
]
|
|
269
401
|
: [],
|
|
270
402
|
style: {
|
|
271
403
|
alignItems: "center",
|
|
@@ -319,7 +451,11 @@ export const renderOgImage = async (
|
|
|
319
451
|
if (logo === false) {
|
|
320
452
|
return [];
|
|
321
453
|
}
|
|
322
|
-
return [
|
|
454
|
+
return [
|
|
455
|
+
logo
|
|
456
|
+
? logoMark(logo, foreground)
|
|
457
|
+
: initialMark(accent, initial, titleFamily),
|
|
458
|
+
];
|
|
323
459
|
};
|
|
324
460
|
const header = container({
|
|
325
461
|
children: mark(),
|
|
@@ -406,7 +542,11 @@ export const renderOgImage = async (
|
|
|
406
542
|
const fontSubsets = googleFamilies.length
|
|
407
543
|
? await loadFonts(googleFamilies)
|
|
408
544
|
: [];
|
|
409
|
-
const cardFonts = [
|
|
545
|
+
const cardFonts = [
|
|
546
|
+
...fontSubsets,
|
|
547
|
+
...localFonts.map(localFontLoader),
|
|
548
|
+
...(await fallbackSubsets(options.fallbacks, node)),
|
|
549
|
+
];
|
|
410
550
|
|
|
411
551
|
return render(node, {
|
|
412
552
|
fonts: cardFonts.length ? cardFonts : undefined,
|
package/src/og/derive.ts
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
* Bridges `theme.fonts` into the OG card renderer. A site that explicitly
|
|
3
3
|
* picks its typefaces gets matching cards (and non-Latin coverage) without
|
|
4
4
|
* configuring `seo.og.fonts`; untouched defaults derive nothing, so plain
|
|
5
|
-
* sites keep Takumi's built-in font
|
|
5
|
+
* sites keep Takumi's built-in font. Either way every card gets a Noto
|
|
6
|
+
* fallback stack for the scripts that font can't draw (Japanese, Hindi,
|
|
7
|
+
* Russian, …), which it fetches only when its text needs one.
|
|
6
8
|
*/
|
|
7
9
|
|
|
8
10
|
import { existsSync } from "node:fs";
|
|
@@ -14,12 +16,13 @@ import type {
|
|
|
14
16
|
FontValue,
|
|
15
17
|
LocalFontConfig,
|
|
16
18
|
} from "../theme/fonts.ts";
|
|
17
|
-
import { GOOGLE_FONTS, isFontSlug } from "../theme/fonts.ts";
|
|
19
|
+
import { GOOGLE_FONTS, isFontSlug, localeFontSubsets } from "../theme/fonts.ts";
|
|
18
20
|
import type { OgFont, OgFontFamilies, OgLocalFont } from "./card.ts";
|
|
19
21
|
|
|
20
|
-
/** Fonts
|
|
22
|
+
/** Fonts, script fallbacks, and per-role families for the OG endpoint. */
|
|
21
23
|
export interface DerivedOgFonts {
|
|
22
24
|
families?: OgFontFamilies;
|
|
25
|
+
fallbacks?: OgFallbackFont[];
|
|
23
26
|
fonts: OgFont[];
|
|
24
27
|
}
|
|
25
28
|
|
|
@@ -160,6 +163,149 @@ export const deriveOgFonts = (
|
|
|
160
163
|
return result;
|
|
161
164
|
};
|
|
162
165
|
|
|
166
|
+
/**
|
|
167
|
+
* The family Takumi renders a card in when no font is loaded: its embedded
|
|
168
|
+
* Geist, which covers Latin only. Naming it keeps a card's Latin text in that
|
|
169
|
+
* face once fallbacks are loaded, since Takumi otherwise tries loaded fonts
|
|
170
|
+
* first; a glyph Geist lacks still falls back to them. Were Takumi to rename
|
|
171
|
+
* it, the name would resolve to nothing and cards would fall back to the
|
|
172
|
+
* loaded fonts, never to tofu.
|
|
173
|
+
*/
|
|
174
|
+
const BUILT_IN_FAMILY = "Geist";
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* The Google Noto family that draws each language's script, keyed by BCP 47
|
|
178
|
+
* language subtag, for scripts beyond the Latin, Cyrillic, Greek, and
|
|
179
|
+
* Vietnamese that `Noto Sans` covers (see {@link localeFamily}). Keep keys
|
|
180
|
+
* alphabetical.
|
|
181
|
+
*/
|
|
182
|
+
const SCRIPT_FAMILIES = {
|
|
183
|
+
am: "Noto Sans Ethiopic",
|
|
184
|
+
ar: "Noto Sans Arabic",
|
|
185
|
+
as: "Noto Sans Bengali",
|
|
186
|
+
bn: "Noto Sans Bengali",
|
|
187
|
+
ckb: "Noto Sans Arabic",
|
|
188
|
+
fa: "Noto Sans Arabic",
|
|
189
|
+
gu: "Noto Sans Gujarati",
|
|
190
|
+
he: "Noto Sans Hebrew",
|
|
191
|
+
hi: "Noto Sans Devanagari",
|
|
192
|
+
hy: "Noto Sans Armenian",
|
|
193
|
+
ja: "Noto Sans JP",
|
|
194
|
+
ka: "Noto Sans Georgian",
|
|
195
|
+
km: "Noto Sans Khmer",
|
|
196
|
+
kn: "Noto Sans Kannada",
|
|
197
|
+
ko: "Noto Sans KR",
|
|
198
|
+
lo: "Noto Sans Lao",
|
|
199
|
+
ml: "Noto Sans Malayalam",
|
|
200
|
+
mr: "Noto Sans Devanagari",
|
|
201
|
+
my: "Noto Sans Myanmar",
|
|
202
|
+
ne: "Noto Sans Devanagari",
|
|
203
|
+
or: "Noto Sans Oriya",
|
|
204
|
+
pa: "Noto Sans Gurmukhi",
|
|
205
|
+
ps: "Noto Sans Arabic",
|
|
206
|
+
sa: "Noto Sans Devanagari",
|
|
207
|
+
si: "Noto Sans Sinhala",
|
|
208
|
+
ta: "Noto Sans Tamil",
|
|
209
|
+
te: "Noto Sans Telugu",
|
|
210
|
+
th: "Noto Sans Thai",
|
|
211
|
+
ti: "Noto Sans Ethiopic",
|
|
212
|
+
ur: "Noto Sans Arabic",
|
|
213
|
+
yi: "Noto Sans Hebrew",
|
|
214
|
+
zh: "Noto Sans SC",
|
|
215
|
+
} satisfies Record<string, string>;
|
|
216
|
+
|
|
217
|
+
/** Type guard: does `language` have an entry in the script table? */
|
|
218
|
+
const isScriptLanguage = (
|
|
219
|
+
language: string
|
|
220
|
+
): language is keyof typeof SCRIPT_FAMILIES =>
|
|
221
|
+
Object.hasOwn(SCRIPT_FAMILIES, language);
|
|
222
|
+
|
|
223
|
+
/** A script fallback: a Google family at the weights the card renders. */
|
|
224
|
+
export interface OgFallbackFont {
|
|
225
|
+
name: string;
|
|
226
|
+
weight: number[];
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** Subtags that write Chinese in traditional characters (`zh-Hant`, `zh-TW`). */
|
|
230
|
+
const TRADITIONAL_CHINESE = new Set(["hant", "hk", "mo", "tw"]);
|
|
231
|
+
|
|
232
|
+
/** The Noto family for one locale's script, or null when Geist covers it. */
|
|
233
|
+
const localeFamily = (locale: string): string | null => {
|
|
234
|
+
const [language = "", ...subtags] = locale.toLowerCase().split("-");
|
|
235
|
+
if (
|
|
236
|
+
language === "zh" &&
|
|
237
|
+
subtags.some((tag) => TRADITIONAL_CHINESE.has(tag))
|
|
238
|
+
) {
|
|
239
|
+
return "Noto Sans TC";
|
|
240
|
+
}
|
|
241
|
+
if (isScriptLanguage(language)) {
|
|
242
|
+
return SCRIPT_FAMILIES[language];
|
|
243
|
+
}
|
|
244
|
+
// Anything past plain `latin` in the theme's subset table (Polish, Russian,
|
|
245
|
+
// Greek, Vietnamese, …) needs glyphs Geist lacks and `Noto Sans` has.
|
|
246
|
+
return localeFontSubsets([locale]).length > 1 ? "Noto Sans" : null;
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Every script's fallback, in the order a card tries them: `Noto Sans` for
|
|
251
|
+
* extended Latin, Cyrillic, Greek, and Vietnamese, then a family per script.
|
|
252
|
+
* The CJK families all draw Han ideographs, so the first one wins them —
|
|
253
|
+
* Japanese forms, unless a configured locale moves its own family ahead.
|
|
254
|
+
*/
|
|
255
|
+
const DEFAULT_FALLBACKS = [
|
|
256
|
+
"Noto Sans",
|
|
257
|
+
...new Set(Object.values(SCRIPT_FAMILIES)),
|
|
258
|
+
"Noto Sans TC",
|
|
259
|
+
];
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* The card's script fallbacks, at the card's weights: each configured
|
|
263
|
+
* locale's family first, so a Chinese site draws Han in Chinese forms, then
|
|
264
|
+
* every other script's, so a page in a language the site never configured
|
|
265
|
+
* still renders instead of tofu. Takumi's built-in font covers only basic
|
|
266
|
+
* Latin; the card fetches these only when its text needs a glyph beyond it,
|
|
267
|
+
* and then only the families and subsets that glyph needs.
|
|
268
|
+
*/
|
|
269
|
+
export const ogFallbackFonts = (locales: string[]): OgFallbackFont[] => {
|
|
270
|
+
const names = new Set<string>();
|
|
271
|
+
for (const family of [...locales.map(localeFamily), ...DEFAULT_FALLBACKS]) {
|
|
272
|
+
if (family) {
|
|
273
|
+
names.add(family);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return [...names].map((name) => ({ name, weight: CARD_WEIGHTS }));
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
/** A bare Google family name entry (as opposed to the object forms). */
|
|
280
|
+
const isGoogleFamilyName = (font: OgFont): font is string =>
|
|
281
|
+
typeof font === "string";
|
|
282
|
+
|
|
283
|
+
/** The family an OG font entry registers under. */
|
|
284
|
+
const ogFontName = (font: OgFont): string =>
|
|
285
|
+
isGoogleFamilyName(font) ? font : font.name;
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* `derived` plus the script fallbacks it doesn't already load. A card that
|
|
289
|
+
* names no family is pinned to {@link BUILT_IN_FAMILY}, so its Latin text
|
|
290
|
+
* keeps the face it had before any fallback was loaded.
|
|
291
|
+
*/
|
|
292
|
+
const withFallbacks = (
|
|
293
|
+
derived: DerivedOgFonts,
|
|
294
|
+
locales: string[]
|
|
295
|
+
): DerivedOgFonts => {
|
|
296
|
+
const loaded = new Set(derived.fonts.map(ogFontName));
|
|
297
|
+
return {
|
|
298
|
+
fallbacks: ogFallbackFonts(locales).filter(
|
|
299
|
+
(font) => !loaded.has(font.name)
|
|
300
|
+
),
|
|
301
|
+
families: derived.families ?? {
|
|
302
|
+
body: BUILT_IN_FAMILY,
|
|
303
|
+
title: BUILT_IN_FAMILY,
|
|
304
|
+
},
|
|
305
|
+
fonts: derived.fonts,
|
|
306
|
+
};
|
|
307
|
+
};
|
|
308
|
+
|
|
163
309
|
/** Explicit `seo.og.fonts` with local `src` paths resolved to absolute. */
|
|
164
310
|
export const resolveOgFontSources = (fonts: OgFont[], root: string): OgFont[] =>
|
|
165
311
|
fonts.map((font) =>
|
|
@@ -170,10 +316,14 @@ export const resolveOgFontSources = (fonts: OgFont[], root: string): OgFont[] =>
|
|
|
170
316
|
* The fonts baked into the generated OG endpoint. An explicit `seo.og.fonts`
|
|
171
317
|
* always wins (including `[]` to opt out, keeping the card's role styling
|
|
172
318
|
* untouched); otherwise a site that explicitly set `theme.fonts` gets its
|
|
173
|
-
* display/body fonts derived so cards match the site without extra config
|
|
319
|
+
* display/body fonts derived so cards match the site without extra config,
|
|
320
|
+
* and either way every card gets the script fallbacks, the configured
|
|
321
|
+
* locales' first.
|
|
174
322
|
*/
|
|
175
323
|
export const resolveOgFonts = (
|
|
176
324
|
options: {
|
|
325
|
+
/** The site's configured locale codes (none without `i18n`). */
|
|
326
|
+
locales?: string[];
|
|
177
327
|
/** Explicit `seo.og.fonts`, or undefined when unset. */
|
|
178
328
|
ogFonts: OgFont[] | undefined;
|
|
179
329
|
themeFonts: FontsConfig;
|
|
@@ -185,9 +335,10 @@ export const resolveOgFonts = (
|
|
|
185
335
|
if (options.ogFonts) {
|
|
186
336
|
return { fonts: resolveOgFontSources(options.ogFonts, root) };
|
|
187
337
|
}
|
|
188
|
-
|
|
338
|
+
const derived = options.themeFontsConfigured
|
|
189
339
|
? deriveOgFonts(options.themeFonts, root)
|
|
190
340
|
: { fonts: [] };
|
|
341
|
+
return withFallbacks(derived, options.locales ?? []);
|
|
191
342
|
};
|
|
192
343
|
|
|
193
344
|
/**
|
package/src/og/index.ts
CHANGED
package/src/openapi/asyncapi.ts
CHANGED
|
@@ -46,7 +46,8 @@ export interface AsyncApiChannelObject {
|
|
|
46
46
|
messages?: Record<string, AsyncApiRefLike>;
|
|
47
47
|
parameters?: Record<string, AsyncApiRefLike>;
|
|
48
48
|
servers?: AsyncApiRefLike[];
|
|
49
|
-
|
|
49
|
+
/** Protocol-keyed binding objects, or a `$ref` to a components entry. */
|
|
50
|
+
bindings?: Record<string, AsyncApiSpecValue>;
|
|
50
51
|
[key: string]: AsyncApiSpecValue;
|
|
51
52
|
}
|
|
52
53
|
|
|
@@ -61,7 +62,8 @@ export interface AsyncApiOperationObject {
|
|
|
61
62
|
tags?: { name?: string; description?: string }[];
|
|
62
63
|
security?: AsyncApiRefLike[];
|
|
63
64
|
messages?: AsyncApiRefLike[];
|
|
64
|
-
|
|
65
|
+
/** Protocol-keyed binding objects, or a `$ref` to a components entry. */
|
|
66
|
+
bindings?: Record<string, AsyncApiSpecValue>;
|
|
65
67
|
[key: string]: AsyncApiSpecValue;
|
|
66
68
|
}
|
|
67
69
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
DocumentNode,
|
|
2
3
|
GraphQLArgument,
|
|
3
4
|
GraphQLEnumType,
|
|
4
5
|
GraphQLField,
|
|
@@ -12,8 +13,8 @@ import type {
|
|
|
12
13
|
GraphQLUnionType,
|
|
13
14
|
} from "graphql";
|
|
14
15
|
import {
|
|
16
|
+
buildASTSchema,
|
|
15
17
|
buildClientSchema,
|
|
16
|
-
buildSchema,
|
|
17
18
|
getNamedType,
|
|
18
19
|
isEnumType,
|
|
19
20
|
isInputObjectType,
|
|
@@ -21,7 +22,11 @@ import {
|
|
|
21
22
|
isObjectType,
|
|
22
23
|
isSpecifiedScalarType,
|
|
23
24
|
isUnionType,
|
|
25
|
+
Kind,
|
|
26
|
+
parse,
|
|
24
27
|
print,
|
|
28
|
+
specifiedDirectives,
|
|
29
|
+
visit,
|
|
25
30
|
} from "graphql";
|
|
26
31
|
|
|
27
32
|
import type {
|
|
@@ -259,6 +264,27 @@ const introspectionOf = <Value>(parsed: Value): object | undefined => {
|
|
|
259
264
|
: undefined;
|
|
260
265
|
};
|
|
261
266
|
|
|
267
|
+
/**
|
|
268
|
+
* SDL with every use of an undeclared directive removed. Subgraph and platform
|
|
269
|
+
* schemas lean on directives their server defines out of band — Apollo
|
|
270
|
+
* Federation's `@key` and `@link`, AppSync's `@aws_*` — and strict SDL
|
|
271
|
+
* validation rejects each one as `Unknown directive`. The reference renders
|
|
272
|
+
* none of them, so they are dropped rather than declared; every other check
|
|
273
|
+
* (syntax, unknown types, duplicates) still runs.
|
|
274
|
+
*/
|
|
275
|
+
const withoutUnknownDirectives = (document: DocumentNode): DocumentNode => {
|
|
276
|
+
const known = new Set(specifiedDirectives.map((directive) => directive.name));
|
|
277
|
+
for (const definition of document.definitions) {
|
|
278
|
+
if (definition.kind === Kind.DIRECTIVE_DEFINITION) {
|
|
279
|
+
known.add(definition.name.value);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return visit(document, {
|
|
283
|
+
// `null` deletes the node; `undefined` leaves it in place.
|
|
284
|
+
Directive: (node) => (known.has(node.name.value) ? undefined : null),
|
|
285
|
+
});
|
|
286
|
+
};
|
|
287
|
+
|
|
262
288
|
/**
|
|
263
289
|
* Build the document from schema text: an introspection JSON result (the raw
|
|
264
290
|
* `{ __schema }` shape or a `{ data: { __schema } }` response envelope) or
|
|
@@ -289,5 +315,5 @@ export const buildGraphqlDocument = (text: string): GraphqlDocument => {
|
|
|
289
315
|
)
|
|
290
316
|
);
|
|
291
317
|
}
|
|
292
|
-
return documentOf(
|
|
318
|
+
return documentOf(buildASTSchema(withoutUnknownDirectives(parse(text))));
|
|
293
319
|
};
|